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 值。我们常常看到其简略形式:
如上图的 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)。
如上图,我们目前位于 G 点。执行 git pull
之后,,从分歧点 E 开始的远程差异 A,B,C 将会被下载下来,打包成一个新的本地合并提交,也即下图的 H:
这是默认的第一种策略:合并(Merge)
变基策略(Rebase)
命令: git pull --rebase
还是以这张图为例
变基策略会把 A,B,C 所在链插入到 D、E 之间,从而让 E 将 C 作为新的上级。
使用变基的好处是,历史流是线性的,避免了多余的分叉。
快进合并(fast-forward only)
这其实是 merge 的一种。
加入我们从下图的 B 开了一个 bugfix 分支。而 master 分支之后没有提交代码,则可以直接把 bugfix 分支移动上去即可。
参考
Git Pull | Atlassian Git Tutorial
[Git - Git 引用 (git-scm.com)](https://git-scm.com/book/zh/v2/Git - 内部原理 - Git - 引用)