Git fetch 从远端刷新本地分支 commit 记录
从远端分支刷新本地分支 commit 记录
- 将某个远程主机的更新,全部刷新回本地。
git fetch
将远程 origin 主机的 master 分支 commit 刷新到本地。 默认情况下,刷新回来的数据在.git/FETCH_HEAD 中
git fetch origin master
fetch 到底改了什么
理解 fetch 的关键是:它只更新远程跟踪分支,绝不动你的工作区和本地分支。
远程跟踪分支是 .git/refs/remotes/origin/ 下的那些引用,本地写作 origin/master。它们是「我上次看到远端时,远端长什么样」的快照。git fetch 做的就是把这些快照更新到最新,同时把缺失的 commit 对象下载进本地仓库。
所以 fetch 之后:
git log origin/master能看到远端的新提交。git log master还是原样,你的分支一步没动。- 工作区文件一个字节都没变。
这个「只读」特性让 fetch 成为最安全的同步命令。我的习惯是先 fetch 看清情况,再决定怎么合:
git fetch origin
# 我落后了几个提交、领先了几个
git rev-list --left-right --count master...origin/master
# 输出 "2 5" 表示本地领先 2 个、远端领先 5 个
# 看远端多了什么
git log master..origin/master --oneline
# 看我本地多了什么
git log origin/master..master --oneline
# 图形化看两边关系
git log --oneline --graph --all -20
FETCH_HEAD 是什么
原文提到的 .git/FETCH_HEAD 是一个临时文件,记录这一次 fetch 抓回来的所有分支的 SHA 和描述。带 refspec 的 fetch(git fetch origin master)主要就是往这里写。
它可以当一个引用直接用:
git fetch origin master
git diff FETCH_HEAD # 和刚抓回来的内容比差异
git merge FETCH_HEAD # 合并它,这其实就是 git pull 的第二步
git log FETCH_HEAD --oneline -5
git pull = git fetch + git merge FETCH_HEAD,这个等价关系记住了很多行为就能自己推出来。
注意 git fetch origin master 这种带具体分支名的写法,在较老的 Git 版本里不会更新 origin/master,只写 FETCH_HEAD。Git 2.x 之后行为改成了同时更新远程跟踪分支,所以现在两者差别不大了。但要抓所有分支还是直接 git fetch origin 或 git fetch --all 更清楚。
fetch 的常用参数
# 抓所有远端(多个 remote 时有用)
git fetch --all
# 清理已在远端删除的分支对应的本地跟踪引用
git fetch --prune
git fetch -p
# 连 tag 一起抓(默认只抓能到达的 tag)
git fetch --tags
# 抓完顺便把当前分支 rebase 到上游(等于 git pull --rebase)
git fetch && git rebase @{u}
# 只抓某个分支到指定的本地引用
git fetch origin master:refs/remotes/origin/master
# 加深浅克隆的历史
git fetch --deepen=50
git fetch --unshallow # 拉全部历史
--prune 值得设成默认。团队里分支删得频繁的话,git branch -r 里会攒下一堆早已不存在的分支,补全时非常干扰:
git config --global fetch.prune true
不切分支更新本地分支
有个实际场景:我在 feature 分支上工作,想把本地的 master 更新到和远端一致,但不想 git checkout master(工作区有改动,切来切回麻烦)。
如果本地 master 没有独有提交(可以快进),直接用 refspec 写:
git fetch origin master:master
这条命令的含义是「把远端的 master 抓下来,直接更新本地的 master 引用」。前提是必须能快进,本地 master 有远端没有的提交时会报 rejected ... non-fast-forward,这时候就必须老实切过去处理。
Git 2.23+ 还有 git switch 配合的更简洁的写法,但要更新非当前分支还是上面这条最直接。
fetch 之后怎么合
抓回来只是第一步,把远端的改动并入自己的分支有三种方式:
# 1. merge:产生一个合并提交,历史是真实的分叉图
git merge origin/master
# 2. rebase:把自己的提交摘下来重放到远端最新提交之上,历史是直线
git rebase origin/master
# 3. 快进:本地没有独有提交时,merge 会自动快进,不产生合并提交
选哪个是团队约定问题。共享分支(master、develop)上用 merge,因为 rebase 会改写已推送的提交 SHA,别人拉下来会乱;自己的 feature 分支上用 rebase,历史干净,review 时好看。
想让 git pull 默认走 rebase:
git config --global pull.rebase true
# 或者干脆禁止隐式合并,强制每次显式选择
git config --global pull.ff only
Git 2.27 之后不配 pull.rebase 会在每次 pull 时给一段警告,提示你显式选择策略。我选 pull.ff only——它只允许快进,需要合并时直接报错让我自己决定用 merge 还是 rebase,避免误产生一堆无意义的合并提交。
只想看不想下载
git ls-remote 连都不连本地仓库,直接问远端有哪些引用,适合快速确认某个分支/tag 是否存在:
git ls-remote --heads origin
git ls-remote --tags origin
git ls-remote origin refs/heads/feature/*

还没有留言,来发表第一条吧~