Mercurial / Git流程 - 何时创建新头?

时间:2017-12-28 15:28:39

标签: mercurial

我们有一门课程,我们学习Mercurial。我有一个关于Mercurial的问题,但我相信Git在这里的行为完全相同。

为了回答这个问题,我使用了Mercurial Workbench,并在每个命令后跟随图表。

这是一个问题: 对于以下序列的mercurial操作,解释哪一行 导致任何引用的存储库中的磁头数量发生变化(比如说哪个 存储库受影响,为什么)。假设主存储库最初只有一个 头,有一些现有的数据:

(我已经加粗了我认为新头脑的线条)

  1. /家/使用者> hg clone http://remoteserver/mainrepository clone1

  2. /家/使用者> hg clone http://remoteserver/mainrepository clone2

  3. /家/使用者> cd clone1
  4. /家庭/用户/ clone1> hg tag initial
  5. /家庭/用户/ clone1> echo one> a.txt#创建一个包含“one”
  6. 的新文件“a.txt”
  7. /家庭/用户/ clone1>回声二> b.txt#创建一个包含“two”的新文件“b.txt”
  8. /家庭/用户/ clone1> hg add a.txt
  9. /家庭/用户/ clone1> hg commit -m“添加了一个文件”
  10. /家庭/用户/ clone1> hg tag file-one
  11. /家庭/用户/ clone1> hg push -f ../ clone2
  12. /家庭/用户/ clone1> cd ../ clone2
  13. /家庭/用户/ clone2> echo 3> c.txt#创建一个包含的新文件“c.txt” “三”
  14. /家庭/用户/ clone2> hg add c.txt
  15. /家庭/用户/ clone2> hg commit -m“添加了另一个文件”
  16. /家庭/用户/ clone2> hg push -f ../ clone1
  17. /家庭/用户/ clone2> cd ../ clone1
  18. /家庭/用户/ clone1> hg up initial
  19. /家庭/用户/ clone1> hg add b.txt
  20. /家庭/用户/ clone1> hg commit -m“添加了另一个文件”
  21. /家庭/用户/ clone1> hg up file-one
  22. /家庭/用户/ clone1> hg push -f ../ clone2
  23. 我得出了这个结论:

    • 在第14行,在clone2
    • 上创建了一个新头
    • 在第15行,在clone1上创建了一个新头
    • 在第19行,在clone1上创建了一个新头
    • 在第21行,在clone2上创建了一个新头

    我们最终得到了克隆1中的3个头和克隆2中的3个头。

    我的问题是:

    1. 这是对的吗?
    2. 你能解释一下在每一步添加新行会发生什么吗? 我试图提出自己的理由,但我需要专家意见。
    3. 谢谢

1 个答案:

答案 0 :(得分:1)

对于(1):是的,这是对的。对于(2),我不确定你要问的是什么("在每一步添加一个新行" - 行这里的意思是?)。 [按评论编辑]让我们看一下前面步骤的步骤14,15,19和21。

在第14步,您运行hg commit -m "Added another file"当前提交不是现有的提示提交,因为在步骤12中您进入了" clone2"目录/克隆,其当前提交与您进行克隆时相同(步骤2)。也就是说,如果当前提交在步骤2中是numeric-ID 0和hash-ID a1234567....,那么仍然是当前提交,即使步骤10向该存储库添加了更多提交。 (当前分支可能是default,虽然这不太重要,因为clone1和clone2都在同一个分支上,并且添加到clone1的提交现在出现在clone2中,在同一个分支上。关键项是由于推入提交,clone2中的当前 commit 不是clone2中当前分支的头部。)

在更典型的情况下,例如在步骤7中,当您进行新提交时,您将进行头部提交(没有子级的提交)。进行新提交会创建新提交,并将当前提交作为其父提交,以便 一个头(没有子节点)的提交不再是头(具有子节点);而新的承诺本身就是新的,没有孩子,因此是一个头脑。因此,头数被调整为-1(前一个头的丢失)和+1(通过新提交获得新头)。

但是你在步骤14中做出的新提交有一个非头脑 - 不再提交作为其父。它的头脑"在{10}获得子提交时,git push在早期被删除。现在它有两个孩子,这使得它不是一个头;并且作为新提交的新子提交具有 no 子项,使其成为一个头。因此,头数被调整为+1而没有偏移-1。

在第15步,您运行hg push -f ../clone1。这会将您刚刚在步骤14中创建的新提交放入clone1。由于您所做的新提交是一个头,因此clone1获得了新的头脑。

步骤19类似,但我们回到了clone1(由于步骤16)。由于步骤17(hg up initial使用标记来查找要切换到的提交),当前提交不是现有的头。你做了一个新的提交,这是一个新的头;但是你将这个新提交添加为新子提交的提交本身并不是一个头,所以人数增加了一个。第21步简单地将这个新提交推送到clone2:它是clone2的新手,因此它是一个新头,但它不会将任何现有头转换为非头部。

你还没有来​​到这里,但是......

请注意,当您使用hg branch <newbranch>然后使用hg commit时,您为当时的当前提交创建了一个新子项,但该新子项是在另一个分支中。成为当前提交的新提交是新(现在)分支的新头,并且它曾经是当前提交的子代这一事实是无关紧要的,因为&#34; head -ness&#34;由同一分支中的子提交确定

更一般地说(预编辑文本在下面继续)

  

......我相信Git的行为完全相同

提交而言,但不是 head

Mercurial将 head 定义为任何提交,没有传出的弧进入(子提交)同一分支。 Mercurial的分支与Git非常不同,Git或多或少将头定义为&#34;任何具有直接指向它的分支名称的提交&#34; (虽然Git称这些 tip 提交,并将分支名称本身称为&#34; head&#34;)。

Git的分支没有永久性:它们的存在只是因为分支名称本身存在,并且分支名称只有在您不告诉Git删除它时才存在。删除名称后,分支就不再存在。 提交,直到不再有对它们的引用,此时垃圾收集器(一旦运行)丢弃它们。一些引用在 reflogs 中被删除,并且每个分支都有一个单独的reflog(删除分支时删除)加上一个特殊名称HEAD never < / em>已删除),因此即使分支的reflog引用消失,HEAD reflog引用也会使delete-branch提交保持活动一段时间。

如果从某些其他分支可以访问这些(in-Git)提交,那么它们会继续保持不变。同时,Git中的每个提交通常可以同时从 N 分支到达( N 是任何非负整数,通常 N ≥1) 。我们说那些提交包含在那些分支中。相比之下,Mercurial中的每个提交都在一个分支上,其分支在提交时被选中,并且它永远不会改变。

换句话说,我们可以说Mercurial中的分支的存在依赖于分支上的提交; 但是在Git, commit 的存在取决于包含该提交的(分支和其他)名称。 任何名称都可以,包括标记名称 - Git在这里有一个比Mercurial更大的命名空间,因为它的标签存储在外部(这使得它们没有版本化,这意味着所有这些)。

使用Mercurial工作,&#34; head-ness&#34;是一个提交的自动属性,并使这个工作在Git,&#34; head-ness&#34; (或branch-tip-ness)由手动管理。要使其主要 - 自动,git commit将自动更新当前分支(其名称存储在HEAD中)以指向刚刚进行的新提交。

两个VCS都以相同的方式添加新提交:它们采用Git 索引中存储的建议提交中的任何内容,或Mercurial的工作状态,如下所示: hg summary - 并将其打包成真正的提交,其父级是当前提交。在Mercurial中,我们已经完成了这项工作,我们已经做到了:因为没有孩子,它会自动成为头脑。在Git中,在完成新提交之后,我们的最后一项任务是将提交的ID写入当前分支名称,以便分支名称现在指向新的提示提交。