我们有以下情况:
A --- B --- C --- ... --- iphone
/
... --- last-working --- ... --- master
在上次工作和iPhone之间,进行了32次提交。在last-working和master之间,提交了许多。
我现在想要的是一个新分支,我将iphone和当前主人合并在一起。稍后,这应该合并到主人。
首先,我打算这样做:
git checkout iphone -b iphone31
git merge master
但后来我想,如果做得更好:
git checkout master -b iphone31
git merge iphone
现在我在想。 结果会有什么不同?合并会有不同的行为吗?
我已经尝试了两种方式,正如我所料,我遇到了很多冲突,因为与主人相比,iphone真的很老了。现在我想知道合并它们的最简单方法。
甚至可能从master开始并将每个iphone的提交合并到它中会更容易?喜欢这样做:
git checkout master -b iphone31
git merge A
git merge B
git merge C
...
git merge iphone
最后,当这个合并完成时(即所有冲突都已解决且工作正常),我想这样做:
git checkout master
git merge iphone31
答案 0 :(得分:42)
关于替代方案
git checkout iphone -b iphone31
git merge master
和
git checkout master -b iphone31
git merge iphone
他们会有同样的轻松或困难,就像争论一杯是半满或半空。
我们如何看待版本树在某种程度上只是我们的任意感知。 假设我们有一个如下所示的版本树:
A----------+
| |
| |
\_/ \_/
B X
| |
| |
\_/ \_/
C Y
|
|
\_/
D
|
|
\_/
E
让我们说我们想要从Y签出一个新版本Z. 基于从C到E的变化,但不包括从中做出的更改 A到C.
“哦,这很难,因为没有共同的起点。” 好吧不是真的。如果我们只是放置不同的对象 在像这样的图形布局
/
C+---------+
| \ |
| |
\_/ |
D B
| / \
| |
\_/ |
E A
|
|
\_/
X
|
|
\_/
Y
现在情况开始变得很有希望了。请注意,我没有 改变了这里的任何关系,箭头都指向同样的方式 在上一张图片和版本A仍然是共同的基础。 只更改了布局。
但现在想象一个不同的树
是微不足道的 C'---------+
| |
| |
\_/ \_/
D B'
| |
| |
\_/ \_/
E A
|
|
\_/
X
|
|
\_/
Y
任务只是正常合并版本E.
所以你可以合并你想要的任何东西,唯一影响的东西 容易或困难是在哪里之间完成的变化的总和 您选择作为起点或公共基地以及合并到的位置。 您不仅限于使用自然起点 版本工具建议。
对于某些版本控制系统/工具,这可能并不简单,
但如果一切都失败了
没有什么可以阻止你手动执行此操作
检出版本C并将文件另存为file1,
检出版本E并将文件另存为file2,
检出版本Y并将文件另存为file3,
并运行kdiff3 -o merge_result file1 file2 file3
。
现在针对您的具体情况,很难准确说出具体情况 战略会产生最少的问题,但是 如果有很多变化会造成某种冲突呢 可能更容易拆分和合并较小的部分。
我的建议是那样的 因为last-working和iphone之间有32次提交, 例如,你可以通过分支master然后开始 在前16次提交中合并。如果结果是 太麻烦了,还原并尝试合并8个第一次提交。 等等。在最坏的情况下,您最终会逐个合并32个提交中的每个提交, 但它可能比处理所有的更容易 在一次合并操作中积累的冲突(和 在这种情况下,您正在使用真正分歧的代码库。)
在纸上画一个版本树并用箭头记下你想要的东西 合并。如果你分开这个过程就会完成它们的工作 分几个步骤。这将使您更清楚地了解您想要的内容 实现,到目前为止你做了什么,剩下什么。
我真的可以推荐KDiff3,它是一个出色的差异/合并工具。
答案 1 :(得分:8)
有区别。
在合并期间始终检查目标分支(即,如果将A合并到B,结帐B)。
人们经常说合并方向并不重要,但这是错误的。虽然无论合并方向如何,结果内容都是相同的,但有几个方面是不同的:
详细说明,想象一下这个夸张的例子:
这些数据不仅无用,而且很难读懂正在发生的事情。大多数可视化工具都会让你看起来像你的开发系统一直是主要的,有1000个提交。
我的建议如下:在合并期间始终检查目标分支(即,如果将A合并到B,结帐B)。
在我看来,日志的可读性很重要。
答案 2 :(得分:6)
最好的方法实际上取决于其他人是否拥有代码的远程副本。如果 master 分支仅在本地计算机上,则可以使用rebase命令以交互方式将功能从功能分支应用到master:
git checkout master -b iphone-merge-branch
git rebase -i iphone
请注意,这会改变新 iphone-merge-branch 分支的提交历史记录,这可能会导致其他人尝试将更改提取到结帐时出现问题。相比之下,merge命令将更改应用为新提交,这在协作时更安全,因为它不会影响分支历史记录。有关使用rebase的一些有用提示,请参阅this article。
如果您需要保持提交历史记录同步,则最好执行合并。您可以使用 git mergetool 使用可视化差异工具逐个交互式修复冲突(有关此问题的教程可以是found here):
git checkout master -b iphone-merge-branch
git merge iphone
git mergetool -t kdiff3
如果您想要对流程进行绝对控制,第三个选项是使用 git cherry-pick 。您可以使用gitk(或您最喜欢的历史查看器)查看iphone分支中的提交哈希值,记下它们,然后将它们单独挑选到合并分支中 - 随时修复冲突。对此过程的解释可以是found here。这个过程将是最慢的,但如果其他方法不能解决,可能是最好的后备选项:
gitk iphone
<note down the 35 commit SHA hashes in this branch>
git checkout master -b iphone-merge-branch
git cherry-pick b50788b
git cherry-pick g614590
...
答案 3 :(得分:2)
你说:
与主人相比,iphone分支很老了
你真的想把它们合并成一个新的分支吗?
master和iphone分支的目的现在已经非常不同了(因为iphone非常老)。合并iphone与祖先大师的新分支会更好吗?想一想。
我强烈建议您阅读Fun with merges and purposes of branches。
如果您仍然觉得想要合并iphone和master,那么阅读那篇文章后,@ seanhodges会解释如何正确处理冲突。
答案 4 :(得分:1)
您可能希望在试验之前对您的作品进行本地备份,这样您就可以重新启动,如果您不再了解发生了什么。
制作工作的备份分支,以便在变基期间不要丢失它,如果你想保留它以供参考。
git checkout iphone -b iphone_backup
从主人
创建一个新分支git checkout master -b iphone31
然后在它上面重新加注。
git rebase -i --onto iphone31 iphone
对于每次应用一次提交的rebase,上面的Sean是正确的。但是不要担心你重新加入的分支上的现有提交 - 它们不会被更改。 Rebase将新的(改编的)提交放在它们之上。虽然一次完成一次提交,但您可以更好地控制冲突。重要的是,你必须在主人之上改变你的工作而不是反过来,所以主人的历史不会改变。
或者,你只能做
git rebase -i master iphone
如果你不关心备份iphone分支。查看rebase文档以获取详细信息和备选方案http://git-scm.com/docs/git-rebase。