93

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

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

现在这是我们遇到问题的地方。我们对 master 有一个压缩策略,这意味着合并到 master 中的功能分支必须压缩到单个提交中。

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. 当我尝试将依赖分支重新定位到 master 或尝试将 master 合并到其中时,git 对重写/压缩的历史感到困惑,并且基本上将每个更改标记depedendent_branch为冲突。这是一个 PITA,基本上是重新做或消除dependent_branch. 有什么解决办法吗?有时,我会手动创建一个补丁并将其应用到 master 的新分支上,但如果与它有任何真正的冲突,修复起来会更糟糕。

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.

有任何想法吗?我知道这是因为在壁球期间重写了历史,但这是我无法改变的要求。什么是最好的解决方案/解决方法?有什么我可以做的魔法吗?或者是否有更快的方法来完成手动创建差异所涉及的所有步骤?

4

4 回答 4

121

关于为什么会发生这种情况的一点点:

在功能分支合并后,我将O成为“原始大师”并FB成为“新大师”:

feature_branch看起来像:

O - A - B - C 

dependent_feature除此之外还有一些额外的提交:

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

您将原始功能分支合并到 master 并将其压缩,从而为您提供:

O - FB

现在,当您尝试重新设置依赖分支时,git 将尝试找出这些分支之间的共同祖先。虽然最初应该是C,但如果您没有压缩提交,git 反而会发现O它是共同的祖先。结果,git 试图重放A,BC已经包含在 中的内容FB,你会遇到一堆冲突。

出于这个原因,您不能真正依赖典型的 rebase 命令,您必须通过提供--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
于 2014-03-23T16:03:33.897 回答
2

在这种特殊情况下,您似乎“知道”只有您最初处理的分支的压缩工作已被放入主控。

因此,每次发生冲突时,您都可以通过保留更改来愉快地合并。有一个选项:

git merge -Xours master

有关详细信息,请参阅https://git-scm.com/docs/git-rebase 。

于 2016-10-21T15:47:10.487 回答
0

我非常不同意“将每个功能开发合并到一个提交中”的政策,但这是他们的要求......

我会保持分支原样,并在一个特殊的分支中创建一个混合提交仅用于发布。能够一步一步地跟随发展是有价值的,即使管理层不相信它。通过“真实”分支中的标签标记壁球的位置,您还可以添加带有指向真实提交的消息的壁球间标记。

于 2014-03-23T16:48:56.780 回答
0

如果您的依赖分支有多个重要的更改,那么像@joshtkling 建议的那样重新设置基础可能会变得很痛苦。我经常转向一种可能更容易的替代策略。这并不意味着使用 rebase 是错误的或任何事情,我只是想提供一个替代方案。它使用“我们的”策略,但与@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 的新合并基础。这样 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 应该容易得多。

于 2021-10-29T11:59:53.573 回答