为什么合并分支上的 git 提交显示在我的主分支上?

Chr*_*oba 5 git merge branch git-branch

我目前有一个 git 提交树,看起来像这样,括号中带有指针(?):

*   305f Merge branch 'develop' (HEAD->master, origin/master, origin/HEAD)
|\
| * d97b Some other commit on dev branch (develop) 
| * df14 Some commit on dev branch
|/
* 7a761b6 Initial commit
Run Code Online (Sandbox Code Playgroud)

我已将 master 分支推送到远程(Gitlab,如果重要的话),当我在 Gitlab UI 中查看 master 分支上的提交时,所有 4 个提交都存在,而我原本期望只有“合并分支 'develop” '”和“初始提交”提交出现在主分支上。

我的理解是,它master指的是我刚刚列出的两个提交,而develop指的是“其他一些...”,“一些提交...”,也可能是“初始提交”,因为它是祖先。

我哪里错了?

tor*_*rek 5

在某些版本控制系统中,当您在分支B上提交C时,提交C永远在分支B上。任何获得提交C的人都会获得分支B。如果他们之前有自己的分支B,那么现在他们的分支B中有一个新的提交C。

\n\n

Git这样做。提交不会永久附加到分支。然而,提交大多永久性的,1并且永久地固定在它们出现在提交图中的位置。为了使这项工作正常进行,并没有在任何分支上真正进行提交。相反,分支名称只是一个标签。多个标签可以都指向同一个 commit,如下所示:

\n\n
\n
*   305f Merge branch 'develop' (HEAD->master, origin/master, origin/HEAD)\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这里masterorigin/master2都标识 commit 305fbr2如果您现在创建一个新分支,该名称将指向 commit 305f

\n\n

Commit305f两个父级:(7a761b6它的第一个父级)和d97b(它的第二个父级)。的全名305f是其完整哈希 ID 的值。这一点永远不会改变;并且该哈希 ID 永远保留给提交,该提交始终具有相同的两个父代。该承诺将永远冻结并且永远不会移动。

\n\n

Git 中移动的东西是分支名称。目前,master意味着305f. 然而,刚才的master意思是7a761b6。提交永远保留在原位,如通过其原始哈希 ID 发现的那样。分支名称四处移动。

\n\n

所有这一切的结果是,当我们创建和销毁分支名称时,包含一些提交的分支集会动态更改。此时,该名称master可以让您找到所有四个提交。master如果您允许 Git以 Git 喜欢的方式移动名称,那么这四个提交将继续可访问,方法是305f从其两个父级开始,然后查看其父级d97b(然后从d97b您返回到7a761b6您已经锯)。请注意,提交只会添加到图表中。一般来说,每个新提交都会有一些现有提交作为其父级\xe2\x80\x94,如果它是典型提交,则它是唯一的父级,如果它是合并提交,则它是两个父级之一。3

\n\n

如果我们把这些东西画在侧面,就会容易一些。为了让它变得更简单,我们可以使用单个大写字母来代替 Git 使用的难以理解的哈希 ID:

\n\n
        D--E   <-- br1\n       /\nA--B--C\n       \\\n        F--G   <-- br2\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这里,名称br1允许我们找到 commit E,它会找到D、then C、then B、then A(并停止,因为A这是第一次提交)。该名称br2允许我们找到G、then F、then C、then B、then A(然后停止)。因此,前三个提交都在两个分支上,而两个提交每个都只有一个分支。

\n\n

删除名称 br1会导致提交DE变得无法找到。最终 Git 会真正把它们扔掉。git checkout br1如果我们通过执行 、 、git add、 和来添加新的提交git commit,我们会得到一个新的哈希 IDH并提前名称br1以包含它:

\n\n
        D--E--H   <-- br1\n       /\nA--B--C\n       \\\n        F--G   <-- br2\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在有 6 个提交可以从 到达br1,从 开始H并向后进行。如果我们创建一个新名称br3来记住位置E,我们将需要重新绘制图形:

\n\n
             H   <-- br2\n            /\n        D--E   <-- br3\n       /\nA--B--C\n       \\\n        F--G   <-- br2\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,所有提交实际上都没有改变:我们只是H向上推,为标签腾出空间br3

\n\n

如果我们稍后删除该名称 br3,那也没关系:没有通过唯一br3找到的提交。提交E不会消失,因为br1找到了H哪个找到了E

\n\n
\n\n

1主要是通过可达性实现的。您可以从某个分支或标记名称开始查找提交,这些名称提供原始哈希 ID。然后,找到提交后,您可以使用其父哈希 ID 来查找其前任提交。然后你使用这些提交来找到他们的父母,等等。

\n\n

通过从每个引用执行此过程\xe2\x80\x94see脚注2\xe2\x80\x94Git找到所有可到达的提交。存储库中存在的任何提交(此过程无法访问)最终都会被垃圾收集并删除。

\n\n

2该名称master是分支机构名称。它的全名是 real refs/heads/master,全名开头的名称refs/heads/是分支名称。相比之下,origin/master实际上是一个远程跟踪名称:它的全名以 开头refs/remotes/,然后继续说origin/master。Git 有时只删除refs/该名称的一部分,以便您看到remotes/origin/master.

\n\n

标签(如果有的话)位于refs/tags/. 这些东西统称为refsreferencesreflogs中还保存了其他隐藏的引用。reflog 只是一个日志文件,保存值\xe2\x80\x94(之前的哈希 ID\xe2\x80\x94),这些值在您或 Git 更新之前存储在 ref 中。这些引用日志条目最终会过期,这就是故意放弃的提交\xe2\x80\x94(您已替换为具有新哈希 ID 的新改进版本(例如\xe2\x80\x94))最终被清除的原因。

\n\n

3合并提交的技术定义是它至少有两个父项。因此,您也可以创建具有 3 个或更多父级的合并提交\xe2\x80\x94,但很少有理由这样做。我还应该提到的是,可以创建一个没有父提交的新提交。除了第一个提交\xe2\x80\x94(我A在横向图形绘图中标记\xe2\x80\x94)之外,在正常实践中你也不会这样做。

\n