3

我使用 Plastic SCM 已经有一段时间了,但直到最近才发现我的心智模型中存在一个缺陷,即分支中的变更集如何工作。

考虑这个简单的场景:

  • 假设我有一个带有文件的分支 Afoo.txt
  • 我将 A 的最新更改集分支到子分支 B。
  • 我将工作区切换到 B 并结帐foo.txt并进行一些更改,然后签入。
  • 我将 B 的最后一个更改集分支到 C。
  • 我试图将 C 合并到 A

简而言之:A分支到B,B中变化foo.txt,分支到C,C合并到A。

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

当执行从 C 到 A 的完全合并时,我原以为我在 B 中的中间更改会被合并,但显然我对分支中的更改集的理解是错误的。当更改神秘地丢失时,这会导致不时进行相当多的清理。

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

编辑:

Plastic version <= 3 仅合并源分支中的更改,而不合并中间分支。

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

4

2 回答 2

4

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

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

您正在谈论的场景在 Git 中将如下所示:

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

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

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

现在,如果您愿意,您可以摆脱 B 更改。一种方法是使用交互式变基:

git rebase -i

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

git cherry-pick a5

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

于 2011-08-17T20:07:35.813 回答
4

Mercurial 在分支上的工作方式与 git 不同。在 Mercurial 中,变更集的分支名称实际上是变更集的一部分。书签的行为有点类似于 git 的分支。仍然存在差异,这篇文章很好地涵盖了 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)。

于 2011-08-17T20:30:50.940 回答