讲解
git pull 是「取回并合并」的一条龙服务,但很多时候你想先看看远程有什么新动静,再决定要不要合。git fetch 就是只取回、不动你工作的部分:它把远程的最新历史下载到本地,更新 remotes/origin/main 这类「远程跟踪分支」,但你的当前分支和工作区一个字节都不变。fetch 是绝对安全的命令,随时执行都没有副作用。
fetch 之后,本地就同时存在两个视角:你的 main 和远程的 origin/main。这时可以用熟悉的工具做对比:git status 会告诉你当前分支领先/落后远程多少;git log --oneline HEAD..origin/main 列出远程有而你没有的提交;git diff HEAD origin/main 看具体改了什么。看完之后想合并,git merge origin/main——这一步加上前面的 fetch,正好等价于一次 git pull。
所以 pull = fetch + merge,区别只在「自动合并」这一步。什么时候用哪个?日常同步、确定要合时用 pull,图省事;review 别人的提交、想看清楚再决定时用 fetch + log/diff + merge,多一分掌控。还有两个 pull 的常用变体值得知道:git pull --rebase 用变基代替合并(你的本地提交被挪到远程提交之后,历史更线性,rebase 下一章讲);git config --global pull.ff only 让 pull 只做快进,不能快进时报错,避免意外的合并提交。
示例
让队友先推一个提交,然后我们只 fetch 不 pull,看清楚了再手动合并:
git remote add origin ../origin.git
git push -q -u origin main
git clone -q ../origin.git ../teammate
cd ../teammate
git config user.name "队友"
git config user.email "teammate@example.com"
echo "队友的更新" > news.txt
git add news.txt
git commit -qm "feat: 队友的更新"
git push -q origin main
cd ../repo
git fetch origin
git status
git log --oneline HEAD..origin/main
git diff HEAD origin/main --stat
git merge origin/main --no-edit
git log --oneline -2
fetch 之后 status 提示「落后于 origin/main 1 个提交」,HEAD..origin/main 列出那个提交的内容摘要,确认无误后 merge——整个过程远程的每一步都在你眼皮底下。
常见坑
- 以为 fetch 会更新工作区:fetch 只更新 origin/* 这些跟踪分支,你的文件不会变。看不到队友的代码不是 fetch 没生效,是还差 merge。
- git diff main origin/main 方向写反:想看「远程比我多什么」用 HEAD..origin/main 或 diff HEAD origin/main;反过来看到的是「我比远程多什么」。
- pull 出来一个意外的合并提交:本地和远程都有新提交时 pull 默认合并。不想要合并提交就用 pull --rebase 或配置 pull.ff only。
- 多人共用分支时闷头 pull --rebase:rebase 改写本地未推送的提交没问题,但分支上已有你推过的提交时,rebase 会制造分叉历史,团队协作分支慎用。
小结
fetch 只下载不合并,随时安全;pull = fetch + merge(或 rebase)。先 fetch 看清楚再 merge 是更稳妥的同步姿势。下一章深入这个让历史变线性的利器:rebase。