使用DVCS合并中间分支的更改

时间:2011-08-17 18:29:18

标签: git mercurial dvcs plasticscm

我一直在使用Plastic SCM工作一段时间,但最近才发现我的心理模型中存在一个关于分支中变更集如何工作的缺陷。

考虑这个简单的场景:

  • 假设我有一个文件foo.txt
  • 的分支A.
  • 我将A的最新变更集分支到子分支B。
  • 我将工作区切换到B并结帐foo.txt并进行一些更改,我会检查这些内容。
  • 我将B的最后一个更改集分支到C。
  • 我尝试将C合并到A

简而言之:分支到B,在B中更改foo.txt,分支到C,将C合并到A.

令我惊讶的是,忽略了对B中间分支中的foo.txt所做的更改,因为我没有对C中的foo.txt进行更改。因此,在从C到A的合并之后,A包含分支出B之前的原始foo.txt。

我希望在执行从C到A的完全合并时合并B中的中间更改,但显然我对分支中的更改集的理解是错误的。当神秘地失去变化时,这已经引起了相当多的清理。

Git和Mercurial或其他DVCS的行为是否相似?

编辑:

塑料版本< = 3仅合并源分支中的更改,而不是中间分支。

Plastic> = 4合并整个分支路径。

2 个答案:

答案 0 :(得分:4)

Git不会这样工作。在Git中,分支实际上只是一个指向系列中最后一次提交的指针。当你在那个分支上进行新的提交时,指针会向前移动到新的提交。

因此,当您从现有分支创建新分支时,您现在只需要指向同一个提交的两个指针。两个分支都有相同的历史。

你在谈论的场景在Git中会是这样的:

           A
           ↓
a1 ← a2 ← a3    B
             ↖  ↓
               a4   C
                 ↖  ↓
                   a5

在Git中你只有一系列的提交,但其中一些恰好有分支标签指向它们。指向a3(知道a2是其父级); B指向a4,其中a3作为其父级,依此类推。因此,默认情况下,如果您将C合并到A中,Git会执行“快进”合并(这意味着A没有任何更改),您就会得到这个:

                B    A, C
                ↓    ↓
a1 ← a2 ← a3 ← a4 ← a5

现在你可以摆脱B改变,如果你想。一种方法是使用交互式rebase:

git rebase -i

这将显示提交列表,您只需从该列表中删除B提交。如果没有那个,Git会重放您的提交。另一种方法是从A开始,然后使用

git cherry-pick a5

将a5更改作为a3之后的下一个更改集。但这两件事都是你必须要做的特别事情。默认情况下,B将包含在合并中。

答案 1 :(得分:4)

Mercurial与分支的工作方式不同于git。在Mercurial中,变更集的分支名称实际上是变更集的一部分。书签的行为与git的分支有些相似。仍然存在差异,this article在处理hg书签和git分支方面做得很好。

无论是使用Mercurial书签还是命名分支(甚至只是匿名分支),您仍然可以获得:

@__    merged C into A (branch A again)
|  \
|   o  add c.txt (branch C; a commit is necessary to start named branch)
|  / 
| o    appended to a.txt (branch B)
|/
o      added a.txt (branch A)

在合并之后,A包含:在第二个变更集中完成附加文本的a.txt(以及在第三个变更集中添加的c.txt)。