将一个分支合并到主分支后,再将第一个分支压缩并合并到主分支时,如何合并一个分支的子分支

100

这是我在工作中经常处理的工作流程。

git checkout -b feature_branch
# Do some development
git add .
git commit
git push origin feature_branch

现在我的功能分支已经提交给同事进行审核,但我希望继续开发依赖于 feature_branch 的其他功能。因此,在feature_branch 正在接受审核时...

git checkout feature_branch
git checkout -b dependent_branch
# Do some more development
git add .
git commit

现在我根据feature_branch上的代码审查做出了一些更改

git checkout feature_branch
# Do review fixes
git add .
git commit
git checkout dependent_branch
git merge feature_branch

现在问题来了。我们的主分支有一个压缩提交的策略,这意味着合并到主分支的特性分支必须被压缩为单个提交。

git checkout feature_branch
git log # Look for hash at beginning of branch
git rebase -i  first_hash_of_branch # Squash feature_branch into a single commit
git merge master

除了dependent_branch,一切都很好。当我尝试将dependent_branch变基到主分支或者尝试将主分支合并到它时,由于重写/压缩的历史记录,Git会对dependent_branch中的每个更改都标记为冲突,导致混乱。必须逐个处理dependent_branch中的所有更改以重新排列或解决冲突,非常麻烦。有没有什么解决方法?有时,我会手动创建一个补丁,并在主版本的新分支上应用它,但如果存在任何真正的冲突,则更难修复。

git checkout dependent_branch
git diff > ~/Desktop/dependent_branch.diff
git checkout master
git checkout -b new_dependent_branch
patch -p1 < ~/Desktop/dependent_branch.diff
# Pray for a clean apply.

有什么想法吗?我知道这是由于在压缩时重新编写历史记录导致的,但这是我无法更改的要求。最好的解决方案/解决方法是什么?我能做些什么魔术吗?还是有一种更快的方法可以完成手动创建差异所涉及的所有步骤?


顺便提一下,git add. 是完全有害的,并且最终会在你提交不想提交的内容时伤害到你。您应该使用 git add -p 或至少是 git add -u .. - user229044
1
一旦您完成了代码审查更改,应将dependent_branch重新基于feature分支。然后,在准备好进入主分支时,将feature分支重新基于主分支,并压缩提交,然后将feature分支合并到主分支中。 - Tim
4个回答

129

关于这件事情的一些背景:

我将使用O代表"原始主分支",FB代表"新的主分支",表示某个功能分支已经被合并后:

假设feature_branch长成这样:

O - A - B - C 
< p > dependent_feature 在此基础上有几个额外的提交:

O - A - B - C - D - E - F

你将原始功能分支合并到主分支(master)中并压缩它,使你获得:

O - FB

现在,当您尝试变基依赖分支时,Git 会尝试找出这些分支之间的公共祖先。如果您没有将提交压缩,那么最初的公共祖先应该是C,但是现在Git会找到 O作为公共祖先。因此,Git 正在尝试重放ABC,而这些提交已经包含在FB中了,所以你会得到一堆冲突。

因此,您不能真正依靠典型的变基命令,而必须通过提供--onto参数来更明确地进行操作:

git rebase --onto master HEAD~3  # instruct git to replay only the last
                                 # 3 commits, D E and F, onto master.

根据您的分支需要,修改HEAD~3参数,并且您不需要处理任何多余的冲突解决。

如果您不喜欢指定范围并且尚未删除原始功能分支,则可以使用一些替代语法:

git rebase --onto master feature_branch dependent_feature

                                 # replay all commits, starting at feature_branch
                                 # exclusive, through dependent_feature inclusive 
                                 # onto master

我希望看到使用--onto时主分支的git树有何不同。或者也许还有其他方法可以更好地了解--onto的差异。 - Abhishek Anand
5
--onto 选项允许您更加有选择性地将提交记录“replay”到一个分支上。默认情况下,git 会尝试“找出”应该被回放的提交记录。当您使用 --onto 时,您明确指示 git 要回放一定范围内的提交记录。在我的例子中,如果您不使用 --onto,您最终会得到 O - FB - A - B - C - D - E - F,并且会有大量合并冲突,因为 FB 和 A - B - C 包含相同的更改。通过使用 --onto 并指定最后的三个提交记录,您最终得到 O - FB - D - E - F,这正是原问题提出者想要的结果。 - joshtkling
1
为了让操作更加简便,不必尝试回溯提交次数,你可以从 git log 输出中复制 C 的提交哈希值。通过使用 --onto 并指定 C 的提交哈希值,你仍然会得到 O - FB - D - E - F,但对于其他读者来说,这将更清晰地展示此示例如何遵循你在代码注释中提供的文档。 :) - Speeddymon

2
在这种情况下,你似乎“知道”只有分支上压缩的工作被合并到了主分支。因此,每当出现冲突时,你可以通过保留你的更改来愉快地进行合并。有一个选项可以实现这一点: git merge -Xours master 详情请参见https://git-scm.com/docs/git-rebase

1
不幸的是,情况可能并非如此。如果在对 feature_branch 和 dependent_branch 进行代码审查之间有时间,那么 feature_branch 可能会被合并和推送,而在 dependent_branch 被落地之前,其他人可能会添加一些冲突的内容。 - Mike

0

我非常不赞同“将每个功能开发压缩成一个提交”的政策,但这是他们的决定...

我会保留分支不变,并在特殊分支中创建一个混合提交以供发布。即使管理层不相信,能够逐步跟踪开发过程也很有价值。在“真实”分支中通过标签标记压缩的位置,您还可以添加介于压缩之间的标签,并附带指向真实提交的消息。


我其实很喜欢那种压缩方式,但这是因为它是由arccanist完成的,所有与功能分支相关的开发/提交/代码审查都存储在phabricator中...但我当然理解你的观点。 - Mike

0
如果您的依赖分支有多个非平凡更改,像@joshtkling建议的那样进行变基可能会变得痛苦。我经常转向一种可能更容易的替代策略。这并不意味着使用变基是错误的或其他什么,我只是想提供一种替代方案。它使用“ours”策略,但与@nha的答案相比,它也适用于主分支上有更多工作的情况。
假设起始情况如下:
O - A - B - C (feature_branch) - D - E - F (dependent_branch)
  \
   - D - Cs (squash merged feature branch) - G - H (master)

其中D、G和H是由其他人完成的工作,可能是从未在此处显示的其他分支进行的压缩合并。

将dependent_branch合并到master中很可能会产生冲突,因为A、B和C的更改是重复的。为了告诉git不需要考虑这些更改,我们可以引入一个新的合并基础,将C和Cs组合起来,通过创建一个临时分支,然后将其合并到我们的dependent_branch中。这样,git就有了更多的合并知识。

git checkout -b temp Cs
git merge C --strategy ours
git checkout dependent_branch
git merge temp
git branch -d temp

第二次合并可能会产生一些冲突,但根据我的经验,与使用rebase时相比,这些冲突较少且更容易解决。之后合并dependent_branch和master应该会容易得多。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接