Git快进VS没有快进合并

Git合并允许我们执行快进和不快进的分支合并。什么时候使用快进合并,什么时候不使用快进合并?

186059 次浏览

当你想对你的特性分支有一个清晰的概念时,--no-ff选项是有用的。因此,即使在此期间没有提交,FF也是可能的——有时你仍然希望主线中的每个提交都对应于一个特性。因此,您将带有一堆提交的特性分支视为单个单元,并将它们合并为单个单元。从你的历史记录中可以清楚地看到,当你用--no-ff合并特性分支时。

如果你不关心这样的事情——你可能会在任何可能的时候使用FF。这样你会有更像svn的工作流程的感觉。

例如,这个文章的作者认为--no-ff选项应该是默认的,他的推理接近于我上面概述的:

考虑这样一种情况,在“feature”分支上的一系列小的提交共同组成了一个新特性:如果你只做“git merge feature_branch”而没有--no-ff,“从git历史中不可能看到哪些提交对象一起实现了一个特性——你必须手动读取所有的日志消息。”恢复整个特性(即一组提交)是一个真正令人头痛的问题[如果没有使用--no-ff],而如果使用--no-ff标志[因为它只是一次提交],则很容易完成。”

图形显示如何-no-ff组一起从特征分支提交到主分支上的一次提交

也有可能有人想要有个性化的功能分支,代码只是放在一天结束的时候。这样就可以更详细地跟踪开发过程。

我不想用无法工作的代码污染主开发,因此——no-ff可能正是人们所寻找的。

作为旁注,可能没有必要在个性化分支上提交工作代码,因为历史可以被重写git rebase -i并强制到服务器上,只要没有其他人在同一分支上工作。

我可以举一个项目中常见的例子。

在这里,选项--no-ff(即真正的融合)创建了一个具有多个父节点的新提交,并提供了更好的历史跟踪。否则,默认为--ff(即快速合并)。

$ git checkout master
$ git checkout -b newFeature
$ ...
$ git commit -m 'work from day 1'
$ ...
$ git commit -m 'work from day 2'
$ ...
$ git commit -m 'finish the feature'
$ git checkout master
$ git merge --no-ff newFeature -m 'add new feature'
$ git log
// something like below
commit 'add new feature'         // => commit created at merge with proper message
commit 'finish the feature'
commit 'work from day 2'
commit 'work from day 1'
$ gitk                           // => see details with graph


$ git checkout -b anotherFeature        // => create a new branch (*)
$ ...
$ git commit -m 'work from day 3'
$ ...
$ git commit -m 'work from day 4'
$ ...
$ git commit -m 'finish another feature'
$ git checkout master
$ git merge anotherFeature       // --ff is by default, message will be ignored
$ git log
// something like below
commit 'work from day 4'
commit 'work from day 3'
commit 'add new feature'
commit 'finish the feature'
commit ...
$ gitk                           // => see details with graph

(*)注意,这里如果newFeature分支被重用,git将不得不进行--no-ff合并,而不是创建一个新的分支。这意味着快进合并并不总是合格的。

当我们在开发环境中工作并将我们的代码合并到登台/生产分支时,Git没有快进可能是一个更好的选择。通常,当我们在一个特性的开发分支中工作时,我们倾向于多次提交。在以后使用多次提交跟踪更改可能会很不方便。如果我们使用Git合并登台/生产分支,那么它将只有1次提交。任何时候我们想要还原特性,只要还原那个提交。生活很简单。

Git可视化

以下是不同的git日志可视化。这些是树的样子,从dev创建三个分支,称为1 2 3,然后合并和不快速前进。我将把设置代码放在底部。您可以将一段命令粘贴到您的终端中,以快速设置和重置不同的git场景,这对学习git非常有帮助。

注意,使用快进,git甚至没有指示合并。

--no-ff         --ff (default)


* Merge 3
| * 3
* | Merge 2     * Merge 3
| | * 2         | * 3
| |/            * | Merge 2
* / Merge 1     | | * 2
|/              | |/
| * 1           * / 1
|/              |/
* main          * main

将这种方法与重基方法进行比较是值得的。

安装/拆卸

你可以重复运行它,它会删除并重新初始化repo。它适用于windows,所以我认为你只需要改变文件路径和rd删除目录命令,如果你是*nix。

要查看快进的行为,请从最后的合并命令中删除--no-ff。如果你想查看提交id,移除--pretty部分。

cd \user\docs\code\learning\github\sandbox
rd /s /q 0.git 1 2 3
git init --bare 0.git
git clone 0.git 1
cd 1
git config user.name "user"
git config user.email "user@email.com"
git commit --allow-empty -m main
git switch -c 1 main
git commit --allow-empty -m 1
git switch -c 2 main
git commit --allow-empty -m 2
git switch -c 3 main
git commit --allow-empty -m 3
git switch main
git merge --no-ff 1
git merge --no-ff 2
git merge --no-ff 3
git log --graph --oneline --first-parent --all --pretty=%s

除了上面提到的使用--no-ff的原因,另一个原因是在目标分支中保持正确的父顺序。

使用--no-ff,结果分支中最后一次提交的父订单将独立于你正在合并的分支中最后一次提交的父订单,它的第一个父订单将在目标分支中,而不是在你合并的分支中。如果执行ff,您正在合并的分支的最后一次提交将作为最后一次提交合并到目标分支,因此目标分支中最后一次提交的第一个父节点将指向主线外的提交。这可能不是你想要的。

例如,你可以使用--first-parent来过滤一个分支的历史记录,以只看到对分支的主要更改,或者想要在默认使用第一个父类的情况下执行其他操作,如revert。如果分支没有保持正确的父引用,结果将与预期不同。