我有一个(大)提交树,其中包含几个我想要重新绑定到另一个提交的合并提交。执行正常的rebase会导致git要求我解决合并冲突。我不想审查每个合并,因为这将是很多工作。在找到--preserve-merges选项(详细解释为here)后,我认为我找到了完成此任务的完美工具。但是,我似乎无法让它正常工作。我创建了一个演示问题的玩具示例。
从空文件夹开始,我们首先创建一个带有合并的分支和另一个我们将在其上重新分支的分支。
A---B--
\ \
---C---D
\
---E
master 指的是 B , branch 指的是 D 和 goodbye-branch 指的是 E 。
git init
echo Hello > Hello.txt
git add Hello.txt
git commit -m "Create Hello.txt (commit A)"
git tag start
echo World! >> Hello.txt
git commit -am "Change to Hello World (commit B)"
git checkout start
git checkout -b branch
echo Dave >> Hello.txt
git commit -am "Change to Hello Dave (commit C)"
git merge master
echo Hello World, Dave! > Hello.txt
git add Hello.txt
git commit -m "Merge branch master into branch (commit D)"
git checkout start
git checkout -b goodbye-branch
echo Goodbye > Goodbye.txt
git add Goodbye.txt
git commit -m "Add Goodbye.txt (commit E)"
到目前为止,一切都很顺利。合并冲突,但我们解决了。现在我们尝试将 branch 重新绑定到 E ,最终得到以下提交树:
A---E----B'
\ \
C'---D'
git checkout branch
git rebase -p goodbye-branch
这结束时出现以下错误:
Auto-merging Hello.txt
CONFLICT (content): Merge conflict in Hello.txt
Automatic merge failed; fix conflicts and then commit the result.
Error redoing merge f567809e2cc91244cc7fdac210e1771dc75e4d86
该文件包含以下内容:
Hello
<<<<<<< HEAD
Dave
=======
World!
>>>>>>> 0437403c97f33f229e41ec9584ce891a50052e48
我做错了什么?我希望git能够使用commit D 来解决它在重新定位时遇到的合并冲突。
我正在使用Git 1.9.4.msysgit.1,这是目前最新的版本。
答案 0 :(得分:26)
--preserve-merges
标志只是告诉git-rebase
尝试重新创建合并提交而不是忽略它们。它不会让git rebase
能够记住合并冲突是如何解决的,即它不记录冲突解决方案以备将来使用。您想要使用的是rerere
。
在您的玩具示例中,rebase期间产生的冲突与您在前一次合并期间解决的冲突完全相同。如果您在合并之前激活了rerere
,那么您将不必在rebase期间再次解决该冲突。
如果您预计要合并,然后重新绑定分支,则应激活rerere
,以便将来只需要解决一次给定的合并冲突,而不是多次。
让我们打破你的玩具示例。
git init
echo Hello > Hello.txt
git add Hello.txt
git commit -m "Create Hello.txt (commit A)"
git tag start
echo World! >> Hello.txt
git commit -am "Change to Hello World (commit B)"
git checkout start
git checkout -b branch
echo Dave >> Hello.txt
git commit -am "Change to Hello Dave (commit C)"
到目前为止,这么好。在您的第一个git merge
命令之前,您的仓库看起来像这样:
在提交A中,Hello.text
包含
Hello
在提交B中,Hello.text
包含
Hello
World!
在提交C中,Hello.text
包含
Hello
Dave
现在,当您尝试通过运行
将master
合并到branch
时
git merge master
Git报告合并冲突,因为它无法自行确定合并后Hello.txt
的内容是否应该
Hello
World!
Dave
或
Hello
Dave
World!
或其他......
您可以通过使用Hello.txt
覆盖Hello World, Dave!
的内容,暂存更改以及完成合并提交来解决该冲突。
echo "Hello World, Dave!" > Hello.txt
git add Hello.txt
git commit -m "Merge branch master into branch (commit D)"
您的回购现在看起来像这样:
然后你运行
git checkout start
git checkout -b goodbye-branch
echo Goodbye > Goodbye.txt
git add Goodbye.txt
git commit -m "Add Goodbye.txt (commit E)"
在那个阶段,您的仓库看起来如下:
现在你运行
git checkout branch
git rebase -p goodbye-branch
但遇到冲突。在解释为什么会出现这种冲突之前,让我们看看如果git-rebase
操作成功(即无冲突),您的回购将会是什么样子:
现在让我们看看为什么你在Hello.txt
遇到与第一次合并时相同的冲突; Goodbye.txt
在任何方面都没有问题。实际上可以通过一系列更基本的操作(checkout
s和cherry-pick
s)来分解rebase;更多关于http://think-like-a-git.net/sections/rebase-from-the-ground-up.html的信息。
长话短说......在git rebase
操作过程中,您的仓库将如下所示:
情况与您第一次合并之前的情况非常相似:
在提交B&#39;中,Hello.text
包含
Hello
World!
在提交C&#39;中,Hello.text
包含
Hello
Dave
然后Git尝试创建合并B&#39;和C&#39;,但出现合并冲突的原因与您遇到的第一次合并冲突完全相同:Git无法确定Dave
行应该在World!
之前还是之后线。因此,rebase操作会停止运行,Git会要求您在完成rebase之前解决该合并冲突。
rerere
Git&#39; s rerere
是你的朋友,在这里。
该名称代表&#34;重复使用记录的分辨率&#34;顾名思义,它允许你让Git记住你是如何解决一个大块冲突的,以便下次看到同样的冲突时,Git会自动为你解决它。
[...]如果你想要一个你合并的分支并修复了一堆冲突,然后决定改变它 - 你可能不会再次做同样的冲突。
如果已启用rerere
,
git config --global rerere.enabled true
在合并之前 ,然后Git会记录您在创建提交D时如何解决合并冲突,并且在后续rebase期间遇到相同的冲突时会应用相同的解决方案。冲突仍然会中断rebase操作,但它会自动解决。你所要做的只是git rebase --continue
。
但是,看起来rerere
在合并之前尚未激活,这意味着Git必须没有记录您第一次如何解决冲突。在此阶段,您可以立即激活rerere
并再次手动解决所有相同的冲突,或使用rerere-train.sh
脚本(另请参阅此blog post)使用现有历史记录预先播种rerere
缓存。