Git - 在多个分支上合并功能分支

时间:2013-12-17 14:42:14

标签: git merge feature-branch

我对git和良好做法有一些疑问......

git存储库的状态是:

V1.0  :       B.A--B.B
V1.1  :      /  C.A--C.B
            /  /
master: A--B--C--D

我有一个主人,有两个版本:1.0和1.1。

必须开发一个新功能,并且必须在2个分支上应用:V1.1和master。

更好的方法是什么?我想我必须创建一个功能分支,但基于哪一个? master还是V1.1?

开发验证后,最佳合并策略是什么?合并?樱桃挑?变基?

功能分支将被推送到上游,因为我不会是唯一一个处理它的人。还会有多个提交。

感谢您的帮助!


如果功能分支基于master,我将拥有:

V1.0  :       B.A--B.B
otherbranch :/  C.A--C.B
            /  /
master: A--B--C--D
                  \
topicbranch:       E--F--G

功能开发完成后,我可以轻松合并master和topicbranch,将新功能添加到master中。

但是如何将提交E,F和G添加到otherbranch(就在C.B之后)?这就是我认为的地方

checkout otherbranch;
git merge topicbranch;

不起作用,因为它还会添加提交D。

2 个答案:

答案 0 :(得分:0)

一般来说,主分支用于开发新功能。所以你会

git checkout master HEAD^
git branch --track topicbranch

您将使用topicbranch开发新功能。这样每次更新主分支时都可以

git checkout topicbranch
git pull

将更新从上游/主流分支中提取到您的分支中,没有太多困难。

你所建议的最大问题是特定的“版本”永远不会改变。它应该位于开发历史记录中,并使用v1.0之类的标记进行回顾。如果您希望其他主题分支也可以访问您的新主题分支,则可以执行

git checkout otherbranch
git merge topicbranch

并将otherbranch的上游视为topicbranch


根据经验,您始终希望使用git merge在存储库中组合两个引用,并创建单独的分支来保存每个引用。这是因为git merge具有许多功能,使一切都更清洁。 git cherry-pick之类的内容仅适用于您在将更改提交到某个分支后犯错或遇到顿悟时。

答案 1 :(得分:0)

你是对的:将新主题分支合并到V1.1将引入提交D。 (将其合并到V1.0会同时带来C D。)

我只是假设我们正在处理V1.1;这同样适用于V1.0,但有时还需要做更多工作来处理C。 (而且我不确定你为什么在编辑中将V1.1更改为otherbranch,但我会使用下面的otherbranch,因为我做了大量的复制粘贴....)

您至少有以下选项:

  • 通过“真实”合并(如果需要,使用--no-ff)进入D,尽管不是),然后还原它。
  • 使用--no-ff进行“真实”合并(就像使用--no-commit),然后反向应用D(最简单的git revert --no-commit,但您也可以{{例如,1}},并提交结果。
  • 执行“压缩”合并,然后删除git show D | git apply -R -,就像“真正的”合并一样。
  • 挑选樱桃(包含或不包含D--no-commitEF

这些都会导致一些不同的提交图,除了壁球合并和“取消应用”G然后进行一次提交产生与挑选{{1}相同的图形(和文件) } - 通过 - DE然后提交结果。

真正的合并为您提供实际的合并提交:

G

如果允许--no-commit进行提交(并且能够自行完成),生成的树将包含自{{1}的合并库以来V1.0 : B.A--B.B otherbranch :/ C.A--C.B-----M / / / master: A--B--C--D / \ / topicbranch: E--F--G 中所做的更改并且git merge是提交D。但是,如果您禁止提交,然后在工作目录中退出提交otherbranch中所做的更改,并且只有然后提交结果工作 - 目录文件,提交topicbranch将省略C中的更改。

缺点是,将来尝试将DM合并到D时,git会认为master的更改在那里(因为它们< em>是,你刚删除它们。)

为D进行单独的恢复提交会给出以下图表:

topicbranch

其中otherbranch是“还原D”更改。同样,将来V1.0 : B.A--B.B otherbranch :/ C.A--C.B-----M--R / / / master: A--B--C--D / \ / topicbranch: E--F--G R合并到D的尝试不会尝试从提交master引入更改,因为git可以告诉它们已经被放入。 (这个和前一个场景之间的唯一区别在于你把topicbranch取出的事实被明确记录为一个单独的提交 - 并不是任何人都可能注意到它,除非它们看起来,但它们可能更容易查找是否/何时去查看,而不是将它们合并到合并提交otherbranch中。)

在git中,“squash merge”提交与常规合并提交完全相同,但D只有一个父提交。 Git像往常一样经历相同的合并机制,它只是不进行最终提交,也没有进行设置,以便您的手册D将进行双父提交。所以你得到这个图:

M

(在这里调用这个提交M是一种谎言,因为它不是合并,而是哎呀:-))。您可以再次选择是否在提交git commit之前或之后撤消V1.0 : B.A--B.B otherbranch :/ C.A--C.B-----M / / master: A--B--C--D \ topicbranch: E--F--G ,并应用相同的推理。但是,在任何一种情况下,由于M不是实际的合并提交,稍后在分支中合并的尝试将尝试引入D,因为合并库具有没动。 (当然,它也会尝试再次通过M引入M。如果你运气好,git就会知道他们已经在那里了,合并只会自动“思考”类似“哦,好的,已经存在,继续!”。如果没有,你会做一些手动清理工作。)

最后,挑选提交会复制他们的更改,或者使用D - 只应用他们的更改并跳过提交部分。因此,假设您将所有三个组合成一个提交E,您可以将其作为图表:

G

如果您将它们分开,则会得到--no-commit(如果您N这些提交基本上与V1.0 : B.A--B.B otherbranch :/ C.A--C.B---N / / master: A--B--C--D \ topicbranch: E--F--G {{}}所见的修补程序匹配,则这些名称表示您将看到的修补程序{1}},E'--F'--G'git show)。如果您将它们组合成一个新的大补丁git show,那么E看起来非常类似于F在壁球合并案例中看起来的方式,除了您不必“取消申请“G,因为你不会带来这些改变。

无论哪种方式,您都必须重复分支N的整个过程。

(但请注意:如果您有一个提交N的提交M,您可以D V1.0 N。这实际上并不容易而不是一个E+F+G的樱桃选择,除了想想。)