Git pull 到底做了什么?一文彻底搞懂 fetch 和 merge

预计阅读时间:8 分钟

导语

很多程序员刚学 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 介绍与操作流程 来看:

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 合并流程图解 来看:

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 pull

却不知道:

它其实等于:

git fetch
git merge

也就是说:

Pull 本质上是:

  1. 先下载远程更新
  2. 再自动帮你 merge

这也是为什么:

Pull 有时候会突然冲突。

因为:

它直接替你开始合并了。


为什么 git pull 容易“翻车”?

因为很多人:

git pull

之后。

还没反应过来。

Git 已经:

  • 自动 merge
  • 自动改历史
  • 自动产生冲突

尤其是:

你本地也改过代码时。

场面很容易变成:

CONFLICT

于是开始:

  • 慌乱
  • reset
  • stash
  • force push

事故就来了。


一个真实团队里的常见工作流

很多成熟团队。

其实更推荐:

git fetch
git log
git merge

而不是:

git pull

原因很简单:

把“下载”和“合并”拆开。

更可控。


Pull --rebase 又是什么?

Git merge vs 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
|/

大型项目里。

如果每次 pullmerge

历史会非常乱。

所以很多团队:

会统一:

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 个点:

  1. fetch 只下载,不改代码
  2. merge 才真正修改历史
  3. pull = fetch + merge
  4. rebase 会改写提交历史

理解这些之后。

你会第一次真正明白:

Git 同步代码,到底同步的是什么。

而不是:

每天机械地:

git pull

然后默默祈祷别冲突。


本文由 楸木 原创,转载请注明出处。

相关推荐

发现更多