如何实现简化的合并提交

How to achieve simplified merge-commits

理性:内外环境审核发生在此处表示为 master> 的分支上。我想压缩(更好:合并)提交,以便将对某个开发步骤的所有更改放在一起。因此:

如何从左到右?

                                                   master> * C <feature  
                                                           |\
            * H <feature   - just local                    | * H     (merged)
            |                                              | |
            * G     - pushed to remote          =??=>      | * G     (merged)
master> B * |       - pushed to remote                   B * |
          | * F     - pushed to remote                     | * F     (merged)
          |/                                               |/
          *                                              A *                

实际上,功能路径上的提交数量很大 (10+),我想将它们全部压扁。其中的一部分已经发布到远程存储库(不应更改或更改)。但是我只想在 master 分支上创建一个单一的提交。

git merge --squash 显然执行此操作,但它不会将提交标记为已合并。因此,如果我继续在 <feature-Branch 上工作,下一次调用 git merge 将导致很多冲突。我发现了一个 explanation on Whosebug: git merge --squash 导致了一个与源代码提交无关的补丁。

所以,我想要实现的是从右到左的情况,所有在featurebranch(FGH)上的提交都将被标记为merged*) - 如果我继续在 Featurebranch 上工作,下一次合并不会导致与我自己的更改发生冲突。如果 Featurebranch 上的所有更改未发布到远程存储库(请参阅 ),此问题已解决。

PS:当然,将提交单独标记为已合并就足够了,但我既不知道该怎么做,也不知道git如何管理它的合并信息。

PSS:正常合并会执行此操作,但如果 master 上没有提交则失败。

*): "marked as merged" 意味着,在 gitk - 如果你 select 提交,分支列表包括功能,remotes/origin/feature,master,remotes/origin/master。因此,这些提交将不会在后续调用 git merge 中被考虑。

您的描述(图片和文字)需要定期合并:

git checkout master
git merge feature

如果这不是你想要的并且你坚持压缩提交,那么你不能继续你在分支 feature 上的工作,但必须尽快从 master 分支一个新的功能分支它具有 squash 合并的旧功能分支。

没有办法做你想做的事

当 Git 进行合并时,它会计算合并基础,即 大致 两个分支的共同祖先提交。典型合并中考虑的三个(也是唯一的)三个点是合并基础和两个头。如果你进行正常的合并,那么你将在主分支上产生一个新的提交,并且该提交或其后代之一通常将在将来用作合并基础,这意味着 Git 不会再次考虑您的更改。

如果您进行压缩合并,那么合并基础就是原始分叉点,因此后续合并会将您视为进行了多次相同更改的提交,从而导致您所看到的冲突。

除非使用自定义合并驱动,否则无法自定义合并基础检测,因此您需要采用其他解决方案或学习处理冲突。

你可以做的是删除现有分支并从 master 分支重新创建它(或者只是将它重置为 master 上的最新提交),这将意味着未来的工作基于关闭提交,包括所有以前的工作。这将避免您的冲突。

您也可以使用标准合并而不是挤压合并,这将使合并碱基检测做正确的事情。

最后,您可以编写一个自定义合并驱动程序,以某种方式直观地了解有关您的分支的信息。我不推荐这种方法,因为它涉及大量工作,而且很容易出错并弄乱所有数据。

但归根结底,鉴于您的工作流程限制,可供您选择的选项并不多。我个人建议采用不同的、更标准的工作流程,限制更少;合乎逻辑的独立提交;和标准的合并策略。

经过一些研究,我了解到以下内容:git 将 select 方法如何根据所涉及分支的状态进行合并 - 在琐碎的(图 b)从我下面的草图中) git selects fast-forward,这就是两个分支中只有一个发生变化的时候。在这种情况下,可能会发生来自 feater-branch 的所有更改都将放在 master 分支之上。

题外话:如果不止一个涉及的分支发生变化(图 a)来自我下面的草图)git select s merge-Strategie 根据相关分支的当前状态和 git-configuration。此外,您还可以使用命令行来强制执行某些行为 (https://git-scm.com/docs/merge-strategies or http://gitbu.ch/ch03.html)。

有了这些知识,我的问题就有了答案:

答案:--squash 更喜欢 --no-ff 如果我想避免 "fast-forward" 合并,你应该使用

git merge --no-ff --no-commit feature

然后你应该将功能同步到 main

git checkout feature
git merge --ff-only master

这使您从左到右离开问题中的草图,并且每个提交到 feature-分支的原始提交将在 master 分支上标记为存在(显示此信息在 gitk 当你 select 提交时)。

可能还有另一个原因要避免 "fast-foreward":已实现的情况将记录在案,其中更改最初签入到功能分支,而这些更改已完成到主分支。

快进示意图:

    a) real merge                          b) trivial - no chanes on master

                * H <feature                           * H <feature
                |                                      |
                * G <feature/origin                    * G  <feature/origin
    master> B * |                                      |
              | * F                                    * F 
              |/                                      /
              *                            master> A *                

a) 是双方提交的常见情况,其中涉及 mergestrategi 来解决它们。 b) 是简单的情况,其中快进是可能的。

总结: 在任何一种情况下,给定的命令都将 feature 分支上的所有工作提交合并到 master 上的单个提交,而不会丢失合并信息。