Git Pull 的三种策略

执行 pull 看到如下信息:

> git pull
warning: Pulling without specifying how to reconcile divergent branches is
discouraged. You can squelch this message by running one of the following
commands sometime before your next pull:

  git config pull.rebase false  # merge (the default strategy)
  git config pull.rebase true   # rebase
  git config pull.ff only       # fast-forward only

这三种方式有何不同呢?

Refs & Heads

我们从内部实现说起。Git 中的每个提交(commit)都会有一个唯一的 SHA1 值。我们常常看到其简略形式:

image-20210904161549100

如上图的 6e293e1,709be83. 但是记忆和使用这东西很麻烦,因此我们想到使用别名。这样的别名在 Git 被称为 Refs(引用)。你可以执行:

> ls .\.git\refs


    目录: C:\Repo\buqi-admin-vue\.git\refs


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          2021/9/4     16:06                heads
d-----          2021/9/3     20:42                remotes
d-----          2021/9/3     20:42                tags

看到 refs 目录下有三个子目录。heads 下有文件 main,其内容非常简单:

709be83a6aacb0285e4297791db5f77860ee2646

正是一个 SHA1 值。

Git 分支的本质:一个指向某一系列提交之首的指针或引用。

你可以创建 heads,remotes,tags 类型的 refs。理论上还能创建自定义的类型。

HEAD 类型的引用

HEAD 是一种特殊的类型,HEAD 文件的内容是如下形式的:

ref: refs/remotes/origin/main

然后我们追溯这个 main 文件,可以得到内容:

709be83a6aacb0285e4297791db5f77860ee2646

由此可知,HEAD 是一个二级指针。它指向一个最新的提交

Pull 做了什么

合并策略

git pull 会通过 git fetch 下载远端仓库,然后执行 git merge 将远程的 refs 和 heads 并入一个新的本地合并提交(local merge commit)

Main on remote origin vs main on repo

如上图,我们目前位于 G 点。执行 git pull 之后,,从分歧点 E 开始的远程差异 A,B,C 将会被下载下来,打包成一个新的本地合并提交,也即下图的 H:

Remote origin/main merged to local main

这是默认的第一种策略:合并(Merge)

变基策略(Rebase)

命令: git pull --rebase

还是以这张图为例 Main on remote origin vs main on repo

变基策略会把 A,B,C 所在链插入到 D、E 之间,从而让 E 将 C 作为新的上级。

rebase

使用变基的好处是,历史流是线性的,避免了多余的分叉。

快进合并(fast-forward only)

这其实是 merge 的一种。

加入我们从下图的 B 开了一个 bugfix 分支。而 master 分支之后没有提交代码,则可以直接把 bugfix 分支移动上去即可。

分支

img

参考

Git Pull | Atlassian Git Tutorial

[Git - Git 引用 (git-scm.com)](https://git-scm.com/book/zh/v2/Git - 内部原理 - Git - 引用)

分支的合并【分支】| 猴子都能懂的 GIT 入门 | 贝格乐(Backlog)