导语
很多程序员刚学 Git 时。
都会觉得这几个命令特别像:
git pull
git fetch
git merge
尤其是 pull。
很多人每天都在用:
git pull origin main
但真问一句:
“pull 到底做了什么?”
很多人其实答不上来。
于是团队协作里,经常出现:
- 代码突然冲突
- 本地历史混乱
- merge 一脸懵
- pull 完项目直接跑不起来
最后只能开始:
git stash
git reset
git reflog
现场像灾难片。
问题的根源其实很简单:
很多人会用 Git,但并不理解 Git。
这篇文章,我们就彻底讲清楚:
- fetch 到底在干什么
- merge 为什么会产生 commit
- pull 为什么容易“翻车”
- 为什么很多老程序员更喜欢 fetch
- 多人协作时最推荐的工作流是什么
看完之后。
你会第一次真正理解:
Git 同步代码,本质上到底发生了什么。
命令速查表
git fetch # 拉取远程更新(不自动合并)
git merge origin/main # 合并远程分支
git pull # fetch + merge
git pull --rebase # fetch + rebase
git log --graph --oneline # 查看提交结构
git status # 查看当前状态
git branch -vv # 查看本地分支跟踪关系
一个很多人没意识到的真相
Git 其实有:
- 本地仓库
- 远程仓库
两套历史。
例如:
你电脑里的 main
≠
远程服务器里的 main
很多问题。
其实都来自:
“本地和远程已经不一致了。”
而:
- fetch
- merge
- pull
本质上都是在处理:
“怎么同步两边历史”。
先理解:Fetch 到底在做什么?
来看:
git fetch
很多人第一次看到它。
会很迷惑:
执行完了……
但项目什么都没变?
因为:
Fetch 只负责“下载”。
它会:
- 获取远程最新 commit
- 更新远程分支信息
- 不修改你的工作代码
例如:
远程仓库:
A -> B -> C(origin/main)
你的本地:
A -> B(main)
执行:
git fetch
之后:
本地 main:
A -> B
远程 origin/main:
A -> B -> C
注意:
你的代码完全没动。
只是:
Git 知道远程更新到了 C。
为什么很多高手更喜欢 Fetch?
因为:
它安全。
Fetch 最大优点:
“先看,再合并”
你可以:
git fetch
git log --graph --oneline
先观察:
- 远程改了什么
- 有没有危险提交
- 会不会冲突
确认没问题后:
再决定怎么处理。
这种方式。
在大型团队非常常见。
Merge 又在干什么?
来看:
git merge origin/main
这时候:
Git 才开始:
“真正修改你的本地历史”。
例如:
当前:
main:
A -> B
origin/main:
A -> B -> C
执行:
git merge origin/main
结果:
A -> B -> C
你的本地代码:
真正更新了。
Merge 为什么有时候会生成新 Commit?
因为:
Git 需要记录:
“两条历史被合并过”。
例如:
你本地也开发了:
A -> B -> D(main)
远程:
A -> B -> C(origin/main)
这时候 merge:
C
/
A -> B
\
D
Git 会生成:
C
/ \
A -> B M
\ /
D
M 就是 merge commit。
它记录:
“C 和 D 被合并了”。
Pull 到底是什么?
重点来了。
很多人天天用:
git pull
却不知道:
它其实等于:
git fetch
git merge
也就是说:
Pull 本质上是:
- 先下载远程更新
- 再自动帮你 merge
这也是为什么:
Pull 有时候会突然冲突。
因为:
它直接替你开始合并了。
为什么 git pull 容易“翻车”?
因为很多人:
git pull
之后。
还没反应过来。
Git 已经:
- 自动 merge
- 自动改历史
- 自动产生冲突
尤其是:
你本地也改过代码时。
场面很容易变成:
CONFLICT
于是开始:
- 慌乱
- reset
- stash
- force push
事故就来了。
一个真实团队里的常见工作流
很多成熟团队。
其实更推荐:
git fetch
git log
git merge
而不是:
git pull
原因很简单:
把“下载”和“合并”拆开。
更可控。
Pull --rebase 又是什么?
来看:
git pull --rebase
它其实等于:
git fetch
git rebase
区别在于:
普通 pull:
产生 merge commit
而 rebase:
改写历史,让提交更直
例如:
普通 merge:
A -> B -> C
\
D -> M
rebase:
A -> B -> C -> D'
历史更干净。
为什么有人讨厌 Merge Commit?
因为:
项目历史会变成:
一团蜘蛛网
例如:
git log --graph
可能长这样:
|\
| * C
* | D
|/
大型项目里。
如果每次 pull 都 merge。
历史会非常乱。
所以很多团队:
会统一:
git pull --rebase
保持提交历史线性。
但 Rebase 也不是银弹
因为:
Rebase 会改写历史。
如果:
你 rebase 的 commit。
别人已经 pull 了。
那协作可能直接混乱。
所以通常建议:
公共分支
谨慎 rebase。
自己本地开发分支
可以大胆 rebase。
一个特别容易误解的点
很多人以为:
fetch = 更新代码
其实不是。
Fetch 只是:
“同步远程信息”。
真正修改本地代码的。
是:
- merge
- rebase
这一点非常重要。
推荐一个多人协作习惯
我自己长期更推荐:
日常同步
git fetch
看看差异
git log --graph --oneline
再决定:
- merge
- rebase
- 或手动处理
这种方式。
比直接 pull 安全很多。
一个形象理解
你可以这样记:
| 命令 | 像什么 |
|---|---|
| fetch | “先把资料拿回来” |
| merge | “正式整合进来” |
| pull | “自动帮你全做了” |
所以:
pull 方便,但也更容易失控。
结尾
很多 Git 问题。
本质上都不是:
“命令不会用”
而是:
“不知道命令背后发生了什么”。
记住今天最重要的 4 个点:
- fetch 只下载,不改代码
- merge 才真正修改历史
- pull = fetch + merge
- rebase 会改写提交历史
理解这些之后。
你会第一次真正明白:
Git 同步代码,到底同步的是什么。
而不是:
每天机械地:
git pull
然后默默祈祷别冲突。
本文由 楸木 原创,转载请注明出处。