ChatGPT解决这个技术问题 Extra ChatGPT

何时在 Git 中使用“--no-ff”合并选项

A Successful Git Branching Model 建议在合并分支时使用 --no-ff

--no-ff 标志使合并始终创建一个新的提交对象,即使可以使用快进执行合并。这样可以避免丢失有关功能分支的历史存在的信息,并将所有添加该功能的提交组合在一起。 [...] 是的,它会创建更多(空)提交对象,但收益比成本要大得多。不幸的是,我还没有找到一种方法使 --no-ff 成为 git merge 的默认行为,但它确实应该是。

但是,Understanding the Git Workflow 建议不要使用 --no-ff

所以你添加了一条新规则:“当你在你的特性分支中合并时,使用 --no-ff 来强制一个新的提交。”这样就完成了工作,然后您继续前进。 […] --no-ff 创可贴、断线和责备之谜都是您将螺丝刀用作锤子的症状。 […]

对于不同的场景,这两种方法似乎都是合理的,但什么被认为是“好的做法”?

您什么时候使用 --no-ff,什么时候不使用,为什么?

在我的工作中,我们使用'--no-ff',但隔壁的团队没有(他们变基)。各有各的。
在这里,我们使用 git rebase,但最终的合并是使用 --no-ff 完成的。
我遇到了这个问题,因为在 git merge -h 上没有关于 --no-ff 的帮助信息(git 版本 2.7.4)

P
Paolo

这真的取决于你想要做什么。我的经验法则是,如果合并“有意义”,我使用 --no-ff 选项。当合并实际上没有任何意义并且您可能使用了变基时,没有理由使用 --no-ff

git 的特点是它是一个非常强大的工具,您可以通过多种方式使用它——其中大部分都没有错。问什么是“正确的方式”去做这件事就像问什么是画一幅画的正确方式。

至少对我来说,这是我喜欢的一套不断发展的方式,团队中经常讨论我们希望如何在代码上进行协作——由此我们试图得出一种“这里是如何完成的”标准,但是这只是我们的做法。


接受这个答案,因为它让我理解了这个选项的主观使用,基于我们想要的工作流程。谢谢,@托马斯。
佚名

对于带有单个提交的已完成分支的情况,不要使用 --no-ff,只需快进它,因为历史记录会简单得多,也不那么混乱。很难说 --no-ff 在这种情况下会给您带来任何好处,因为看到一个并行的开发分支只有一个提交,而不是一个连续行中的单个提交,这很无趣:

# No fast-forward
$ git merge --no-ff awesome-feature
*   3aa649c Merge branch 'awesome-feature'
|\
| * 35ec88f Add awesome feature
|/
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

# versus fast-forward
$ git merge awesome-feature
* 35ec88f Add awesome feature
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

对于包含多个提交的已完成分支的情况,是否要保留分支开发并行与顺序发生的事实取决于您。我可能会在多次提交中使用 --no-ff,这样我就可以直观地看到这个分支工作,并且如果必须的话,我可以使用单个 git revert -m 1 <sha-of-merge-commit> 轻松操作它。

# No fast-forward
$ git merge --no-ff epic-feature
*   d676897 Merge branch 'epic-feature'
|\
| * ba40d93 Add octocat.txt
| * b09d343 Add bye.txt
| * 75e18c8 Add hello.txt
|/
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

# versus fast-forward
$ git merge epic-feature
* ba40d93 Add octocat.txt
* b09d343 Add bye.txt
* 75e18c8 Add hello.txt
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

看看在这种快进合并的情况下,在提交消息本身没有附加信息的情况下,很难说最后 3 次提交实际上属于一个特性吗?


关于撤消与 git revert -m 1 <sha-of-merge-commit> 的合并的论点倾向于使用 --no-ff,即使在具有单个提交的分支的情况下也是如此。
J
Jonatan Goebel

这实际上取决于您的工作流程,以及您如何使用分支。

假设您有一个“master”和两个功能分支,“foo”和“bar”,正在开发中。

在这种情况下,分支的存在只是为了让不同的开发人员工作而不会发生冲突,当特性完成后,它们需要合并到 master 中,而知道这些特性是否在不同的分支中实现并不重要。

但是你可以有一个不同的工作流程,分支“foo”和“bar”是指系统中的独立模块。

在这种情况下,某些提交可能会更改模块范围之外的文件。当您将这两个分支合并到主分支时,特定模块之外的文件日志可能会变得混乱并且难以知道这些更改来自何处。

您需要确定分支合并的历史对您的工作流程是否重要。

根据评论,我更喜欢 rebasepull --rebase 工作流程。


谢谢,乔纳森。您是否有一些文章或其他材料的链接,解释了典型的“rebasepull --rebase 工作流程”?我也有兴趣了解更多关于这些方法的信息。
@Leif 你读过关于 rewriting history from the Pro Git book 的章节吗?它谈到了变基。变基是 Git 的关键基础工具之一。人们经常使用它而不是 merge 来与其他开发线同步分支,因为它不留下任何合并提交,从而有助于保持历史简单。它适用于您能想到的所有可能的工作流程。 Code School 在他们的 [Git Real 课程] 中有一个很好的关于变基的视频)codeschool.com/courses/git-real)。
@Leif 澄清,rebase 经常用于同步 feature 和 bugfix 分支与对上游/主要开发分支所做的更改。 不常用将这些分支重新集成到主要开发分支中,在这种情况下,您应该决定是否需要使用 merge --no-ff 的并行分支历史,或者,如果您只想将主分支快速合并到功能/错误修复分支的尖端以获取线性历史记录。
@Leif rebase 让您的历史更清晰。这适用于临时分支。这也允许任何冲突都将在提交中解决,而不是额外的。关于文档,Cupcake 提到的那些真的很好,而且这个githowto.com/rebasing更直接地说明了何时使用rebasemerge。正如我所提到的,我更喜欢使用 rebase,但并不总是可行的。
@Leif 另一个资源供您考虑,GitHub Flow 而不是 git flow。