0

我有一些关于 git 和良好实践的问题......

git仓库的状态是:

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

我有一个大师,有 2 个版本:1.0 和 1.1。

必须开发一个新功能,并且必须在 2 个分支上应用:V1.1 和 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 中(就在 CB 之后)?这就是我认为的地方

checkout otherbranch;
git merge topicbranch;

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

4

2 回答 2

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组合存储库中的两个 ref 并创建单独的分支来保存其中的每一个。这是因为git merge有许多功能可以让一切变得更干净。诸如此类的事情git cherry-pick仅适用于您犯错误或仅在您对一个分支进行更改后才经历顿悟的情况。

于 2013-12-17T14:56:39.457 回答
0

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

我只是假设我们正在努力V1.1;这同样适用于V1.0除了有时还会有更多的事情要做C。(而且我不确定你为什么在编辑中更改V1.1otherbranch,但我会在otherbranch下面继续,因为我做了很多复制粘贴......)

您至少有以下选择:

  • 通过“真正的”合并引入 D(--no-ff如果需要,尽管不是),然后恢复它。
  • 用 进行“真正的”合并(就像用--no-ff--no-commit,然后反向应用D(用 最简单git revert --no-commit,但你也可以git show D | git apply -R -,例如),并提交结果。
  • 做一个“壁球”合并,然后D像任何一个“真实”合并一样删除。
  • 樱桃采摘(带或不带--no-commitEFG

这些都导致了一些不同的提交图,除了 squash-merging 和“取消应用”D然后进行一次提交会产生与cherry-picking-through-然后提交结果相同的图(和文件E)。G--no-commit

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

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

如果您允许git merge提交(并且它能够自己这样做),则生成的树将包含D自合并基础以来所做的更改otherbranchtopicbranch是 commit C。但是,如果您禁止提交,然后在工作目录中撤回在 commit 中所做的更改D,然后才提交生成的工作目录文件,则提交M将忽略D.

缺点是,在未来尝试合并mastertopicbranch进入otherbranch时,git 会认为更改D在那里(因为它们,你只是删除了它们)。

对 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”变化在哪里。同样,未来的合并mastertopicbranch合并otherbranch尝试不会尝试引入来自提交的更改,D因为 git 可以告诉他们已经放入。(这个和前面的场景之间的唯一区别是你取出的事实D是明确的记录为一个单独的提交——除非他们去查看,否则任何人都不会注意到,但他们可能更容易找到他们是否/何时查看,而不是这只是混合到合并提交M中。)

在 git 中,“壁球合并”提交与常规合并提交完全相同,只是M只有一个父级。Git 像往常一样通过相同的合并机制,它只是没有进行最终提交,也没有进行设置,以便您的手册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不是实际的合并提交,所以稍后在分支中合并的尝试将尝试引入D,因为合并基础没有移动。(当然,它也会尝试再次引入。如果幸运的话,git 将能够告诉他们它们已经在那里,并且合并会自动“思考”类似“哦,好的,已经在那里EG继续!”。如果没有,您将需要进行一些手动清理。)

最后,挑选提交会复制他们的更改,或者——使用——--no-commit只是应用他们的更改并跳过提交部分。因此,假设您将所有三个组合成一个 commit N,您将得到以下图表:

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

如果您将它们分开,您会得到E'--F'--G'(这些名称表示您将看到的补丁,如果您git show的提交基本上与您看到的git showof EF和的补丁匹配G)。如果您将它们组合成一个新的大补丁N,那么看起来与 squash-merge 案例中的N外观非常相似M,只是您不必“取消应用” D,因为您不会带来这些更改。

无论哪种方式,您都必须为 branch 重复整个过程V1.0

(但请注意:如果您有一个按原样N引入E+F+G的提交,您可以执行其中git cherry-pick之一N。这实际上并不比一个樱桃挑选容易E F G,除非可能要考虑。)

于 2013-12-17T18:21:15.927 回答