问题:
当涉及到几个相关的功能分支时,我总是遇到同样的问题。
master ---A---B---C
\
feature1 D---E---F
\
feature2 G---H
我有类似的东西。假设这两个分支都已经过审核,我会将feature1
合并到master
。然后结帐并提取master
,然后结帐并将feature2
重新定位到master
。这样做,我总是一遍又一遍地看到相同的冲突,特别是有几个分支。
良好的变基:
我在网上看到,在上面的例子中,首先我应该做这样的事情,以确保我正确地重新定位:
Rebase feature1
至master
master ---A---B---C
\ \
feature1 \ D'--E'--F'
\
feature2 D---E---F---G---H
将feature2
重新投放到新的feature1
提交
master ---A---B---C
\
feature1 D'--E'--F'
\
feature2 G'--H'
我会使用git rebase --onto feature1 feature1@{1} feature2
执行此操作。
混乱:
据我了解,最好像这样进行rebase,因为当你进行rebase时,你的分支实际上会包含全新的提交(即上面的F
和F'
),这可能导致不必要的冲突。
考虑到所有这些,正确的方法是什么:
feature1
合并到master
feature2
合并到master` 我想尝试学习一种推荐的方法,在这种方法中我可以确信每次都会因为几个依赖的分支而无法获得痛苦的冲突。
答案 0 :(得分:1)
注意,这个答案分为两部分。第一个是关于rebase的机制,第二个是rebase vs merge。
我会使用
执行此操作git rebase --onto feature1 feature1@{1} feature2
是的:这可以通过将参数拆分为rebase来实现:而不仅仅是feature1
,它现在是--onto feature1 feature1@{1}
。
通常,我们会运行git rebase name
,例如git rebase feature1
。我们必须先git checkout feature2
。将feature2
添加到命令的末尾(如上所述)只为我们执行此git checkout
步骤。因此,在我调用" normal"在这里,git rebase
只有一个参数,通常是另一个分支名称,如feature1
。
但是git rebase
做的是复制一些提交,要做到这一点,它需要知道两个的事情:
这一个论点feature1
为这两个做了很多工作。这很棒当它有效,但是要将feature2
重新定位到已经重新定位的feature1
上,它并不总是有效。
它不起作用的原因(当它不起作用时)与你绘制的图表有关。你以一种奇怪的方式绘制它们,左边是分支名称。这种绘图具有误导性:它意味着每次提交都在一个分支上,但这不是真的。
这是第一张图:
master ---A---B---C
\
feature1 D---E---F
\
feature2 G---H
问:哪个分支提交A
? (招数问题!)
答:所有分支机构。
应使用左侧的提交和右侧上的标签绘制这些图表,标签指向一个特定的提交 - 因为这些事情在Git中实际上是如何运作的。这是相同的图表,重新绘制:
--A--B--C <-- master
\
D--E--F <-- feature1
\
G--H <-- feature2
从右边开始,在(从内部,总是向后)父链接从提交到提交之后,我们可以看到C
,B
和A
已打开主; F
,E
,D
和A
位于feature1
;例如,H
,G
,F
,E
,D
和A
位于feature2
。
现在我们可以在第一个git rebase
之后绘制第二个图表,如下所示:
D'-E'-F' <-- feature1
/
--A--B--C <-- master
\
D--E--F [reflog: feature1@{1}]
\
G--H <-- feature2
这是git rebase
的分裂参数的来源。
通常,Git会找到git rebase
将使用以下内容复制的提交集:
git rev-list <argument>..<current-branch>
这里是feature1..feature2
。这意味着可以从feature2
访问所有提交,但可以从feature1
访问的所有提交除外。现在,之前我们移动feature1
,这是正确的提交集:它是H
和G
。但我们移动了feature1
,现在它是错误的提交集,因为它也包含F
通过D
。
但是,一旦我们说feature1@{1}..feature2
,我们就会再次获得正确的提交。但是现在我们已经失去了复制的地方,这就是为什么我们需要--onto
:
当第二个rebase结束时,我们应该像这样绘制最终结果:
G'-H' <-- feature2
/
D'-E'-F' <-- feature1
/
--A--B--C <-- master
\
D--E--F [reflog: feature1@{1}]
\
G--H [reflog: feature2@{1}]
由于reflog通常是不可见的,我们可以完全放弃图的下半部分。
据我了解,最好像这样改变因为......
更好是一个非常滑的术语。
rebase有两个问题:
复制提交,然后放弃原件以支持新副本。还有其他人有原件吗?如果是这样,你也为他们制造了困难:他们也必须放弃原件,转而支持新副本。
复制提交。新副本至少与原件有些不同(否则它们实际上是原件)。准确地说,副本中有什么不同?那很重要么?你有没有在这个过程中打破一些东西,即引入错误?
使用git merge
可以避免这些问题。相反,它会插入自己的问题:
历史现在纠结了。如果有必要弄清楚发生了什么,那么正在探索历史的人可能不得不低头看看这两条腿&#34;合并。有些人认为这是积极的,而不是消极的,因为这是真正的历史,而不是后来被清理的人为历史。
(我倾向于赞成清理过的历史,但这个论点的双方都有其优点。)
合并本身可能会引入错误。
如果你有一套非常好的测试,那么这有助于同时引入错误&#34;问题。
如果它有足够的帮助,它只会留下一个 rebase问题(假设你足够聪明,或者有一个很好的工具,就像这种情况那样做你自己的复杂rebase):有人吗还有原件吗?根据你对纠结历史是否糟糕的答案,平衡你对这个问题的答案,以便决定合并与变基。
如果你没有有好的测试,那么......: - )