【问题标题】:How to re-merge a branch, after a partial merge was performed执行部分合并后如何重新合并分支
【发布时间】:2014-12-10 14:14:14
【问题描述】:

所以我执行了部分合并(通过git merge --no-commit),只从 featureA 分支中引入一些更改。然后合并到一个 featureB 分支中。现在我需要 featureA 的其余更改。 Git 说如果我再次合并 featureA 就没什么可做的了,因为 Git 认为它已经被合并了。

下面是试图解释我正在尝试做的事情

       featureB ,-------.
               /         \(merge)
master----+---+-----+-----+------------+---  
           \       /(partial merge)   /(TODO: merge in rest of featureA)
   featureA `-----'..................'
                   (no changes here)

在 git 中是否有一个简单的命令可以做到这一点?

【问题讨论】:

  • 你觉得扔掉你的两个合并并重做它们怎么样?

标签: git merge git-merge


【解决方案1】:

以下文本的 tl;dr 是:master 反映了自错误合并 A 以来累积的差异。您希望将正确的合并结果作为错误合并的子项提交,因此当您将正确的结果合并回 master 并合并两个提示时,它会看到并合并错误合并和正确合并之间的差异。

这里是如何,叙述或多或少反映了我是如何得到这个结果的。


您现在拥有的合并基础,功能提示,您不想要。此后没有任何更改与master 上的更改合并。如果您在原始合并中完成了整个工作,您需要合并历史记录和结果。提交图的精简版本,供参考:

#            /-B.....-\         featureB
#   ---A0---B0---APM---BM---?   master [APM, featureA partial merge, is bad]
#       \-A...../??????????/    featureA [can keep history, merge rest of A?]

第一步是首先得到你想要的合并结果:

# redo the original merge to get the right parents and the right content
git checkout $APM^        # checkout the original merge parent
git merge $APM^2          # do the correct merge with its other parent
git checkout -b AM        # give this work a name

现在你有:

#            /-B......\
#   ---A0---B0---APM---BM---?
#       \     \-/-AM
#        \-A.../-/

其中AM$APM 具有相同的父级,但结果正确。无论$APM 做对了什么现在都在AM 中:AM 体现了需要对$APM 进行的更改以获得正确的结果。 $APM 提交中的所有内容都已生效(按字面意思)合并到 AM

git merge -s ours $APM   # $APM is correctly incorported in AM. Tell git.

这使得历史正确:AM 反映了对$APM 的一组更改,master 反映了另一组更改。是时候合并它们了:

git checkout master
git merge AM

git branch -d AM 如果我做对了,你就完成了。


以防万一我有什么问题,但作为提醒或谨慎,请在临时存储库中执行上述操作:

git clone -s . ../wip  # safety play: sandbox the changes
# do the above, and when you're satisfied you've got `master` correct,
cd ../$mainrepo
git checkout master    # okay, incorporate the results
git pull               # .
rm -rf ../wip          # (everything in wip is now also here)

测试:

# drop this as file `script` in an empty directory and
# say `sh script` to recreate the described situation:

set -x
git init --template=
for f in {1..5}; do seq -ffile$f%4.0fx 10 >f$f; done
git add .
git commit -m'Initial commit'
git checkout -b featureA
sed -si s/4x/4-featureA/ f2 f3
git commit -am4featureA-f2f3
git checkout master
sed -si s/1x/1-master/ f1 f2 f3
git commit -am1master-f1f2f3
git checkout -b featureB
sed -si s/8x/8-featureB/ f3 f4
git commit -am8featureB-f3f4
git checkout master
git merge --no-commit featureA
git checkout HEAD f3
git commit -m'Merge branch featureA - less the f3 changes'
git tag APM
git merge --no-edit featureB

# and test the given solution:

git checkout -b AM APM^
git merge --no-edit featureA
git merge --no-edit -s ours APM
git checkout master
git merge --no-edit AM

# say `rm -rf f* .git` to cleanup

【讨论】:

  • 太好了,让我试试看。
  • 我修复了分支创建命令,抱歉编辑晚了。
  • 感谢您的尝试,但这没有奏效……Git 对我们这些凡人来说仍然太聪明了,无法欺骗。我认为唯一的选择就是回到过去,重新合并一切。
  • 请看上面的测试脚本。除非我误读了某些内容,否则它会重新创建您给定的提交图并给出请求的结果。
  • 哦,是的,它确实有效!我在没有标记部分合并的情况下尝试了它,只使用了 SHA1 ID。我一定搞砸了什么。使用标签更容易感谢负载!!!
【解决方案2】:

您所描述的 IMO 部分合并是邪恶的,因为您现在遇到的原因和其他事情。

例如:任何使用您的存储库的开发人员都希望master 包含来自featureA 的所有更改。这可能会导致很多混乱。


注意:我假设您当前位于存储库的根目录和主分支上。

您实际上有两个简单的选择:

  1. 您使用git checkout --merge featureA -- .featureA 的剩余更改合并到master - 在这种情况下您不会有合并提交

  2. 您在featureA 上进行空提交 (git commit --allow-empty),然后再次合并

如您所见,这两种解决方案都不是最优的,这是您的部分合并的结果。

最干净的方法是还原您的旧合并,将featureA 拆分为多个提交并仅合并必要的提交。然后您可以稍后合并剩余的。
这显然也是工作量最大的方法。

我个人建议选择 1. 或 2. 并避免将来发生此类合并。


编辑 我尝试使用this answer 中描述的方法手动创建合并提交。但似乎 git 认识到 featureA 已经被合并并丢弃了第二个父级这一事实,这导致了一个简单的而不是合并提交。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-29
    • 2016-01-29
    • 1970-01-01
    • 2011-05-08
    • 2017-04-29
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    相关资源
    最近更新 更多