Git是按文件还是按目录合并信息?

时间:2019-02-20 06:41:43

标签: git

在Perforce中,合并信息(例如合并历史记录)是每个文件的。 在Subversion中,合并信息是按目录的。 在Git中,合并信息是按文件还是按目录?

1 个答案:

答案 0 :(得分:0)

都不是。

Subversion在这里有点特殊,因为它是建立在基本处理目录的系统之上的。这意味着您可以使用Subversion检出一个特定目录-有点:您也可以获得其子目录。但它始于目录:因此是目录级合并信息。

Git的基本单位既不是文件也不是目录,而是 commit 。您不能获得少于一个完整的提交。 1 运行git checkout commit-specifier时,Git将整个提交树复制到索引/暂存区中-这相对而言空间很小;请参阅脚注1,然后将所有这些文件从索引复制到您的工作树中,您可以在其中工作。

每个Git提交都是项目中 all 文件的完整完整快照,或更准确地说,是提交时索引中所有文件的完整快照。由于索引从当前提交中的所有文件开始,因此它也继续在下一次提交中包含所有文件。合并提交在这里与其他任何提交都没有什么不同:它具有所有文件的全部内容和完整信息,但是经过压缩,冻结和Git修饰,即任何提交中的所有文件都经过压缩,冻结和Git修饰的方式。由于它们是冻结的-您永远无法更改 any 提交的 any 部分-如果它们未更改,它们将共享 shared ,因此,如果您提交一个100兆字节的文件十倍,甚至一百万倍,该文件使用相同的磁盘空间,就好像您一次提交100兆字节的文件一样-因为实际上,您 did 。 (每个提交都会在文件顶部添加一点空间,用于保存提交的元数据,但是如果您熟悉Unix / Linux系统上的 link 的想法,则可以考虑每次提交因为它具有到一个基础文件的硬链接。)

同时,通过 parent 哈希ID记录每个提交中的提交 是合并的事实。每个提交都记住该特定提交之前紧接的提交的原始哈希ID(即真实名称)。对于大多数提交,只有一个这样的哈希ID,并且我们使用了向后看的链,因此,如果我们从最近提交开始,其提交是一些大的丑陋哈希,我们将只需调用H,我们就可以找到其父级,我们将其哈希称为G。然后,我们可以使用G查找G的父级,我们将其称为F,然后使用F查找F的父级,等等:

... <-F <-G <-H

我们只需要知道以下问题的答案:此链中最后个提交的哈希ID是什么?要找到该答案,我们查找一个分支名称,例如master名称包含最新哈希ID-仅此而已!其他一切都来自提交。

关于合并提交的唯一特别之处在于,它至少记录了两个父哈希:

...--F--G--H
            \
             M--...
            /
...--J--K--L

合并信息在于M有两个父母HL的事实。从M起,我们可以向后退回到H,并遵循该链条,也可以向后退回到L,并遵循该链条。 MHL这三个提交都是完整和完整的快照,因此如果我们想了解如何通过合并顶部提交H来修改底部链L提交,我们可以比较HM。如果我们想了解如何通过将顶部链提交L合并到底部链提交H中来进行修改,则可以比较LM。这些是我们进行的相同比较,例如,当我们想查看H如何被修改时:我们比较GH,这是两个快照,以查看从GH的变化。

如果我们想看看两个链首先在哪里分开,我们只需要更广阔的视野:

...--E---F---G----H
      \            \
       \            M--...
        \          /
         I--J--K--L

如果F的父母是E,而J的父母是I,其父母是E,那么我们可以看到{{ 1}}是我们合并EH时的合并基础。由于所有提交都会一直冻结,因此如果L是合并基础,那么E仍然是合并基础。

这意味着您的问题的答案是:根本没有明确的合并信息。提交图暗示了合并的事实以及重复合并所需的信息。提交图是您(或Git)通过读取单个提交而得出的数据结构。由于提交是基本单位,因此您始终拥有完整的提交。 2 shallow 克隆中,允许您丢失更早的提交,但是您可以通过返回到克隆的位置并“取消隐藏”克隆(或将其深化到足以看到所需内容的位置)来填充这些内容。


1 Git确实支持 sparse checkout 的概念,但是您仍然可以得到整个提交。 所有的文件仍会复制到您的索引中。稀疏签出仅限制了那些文件中的哪些然后从索引复制到您的工作树。由于索引副本大部分是冻结的,并且可以直接共享提交的副本,因此这减少了所需的磁盘空间,因为某些文件永远不需要从其冻结的提交的形式中解压缩。下一次提交(如果要进行下一次提交)是根据索引中的内容(而不是工作树中的内容)进行的,因此尽管存在,所有新提交仍具有文件的所有稀疏的结帐。

2 Git添加了允许以 promisor packs 形式出现的一种占位符的想法,您可以在其中进行提交但缺少一些内部数据。也就是说,提交本身仍将是基本单位,但是当您知道提交 C 具有树 T 时,您可能会缺少对象 T < / em>本身,直到有明确的要求为止,然后Git会尝试通过打电话给做出承诺的人家来履行承诺。这实际上还没有在Git中,但是它正在逐步进入代码库。

请注意,这有点类似于浅克隆。对于浅表克隆,您知道提交 C 的父对象 P ,但是由于对象浅,所以缺少对象 P 。使Git假装 C 的某些部分的嫁接根本没有父母。使用E,您可以让Git获取 P ,但也可以将某些 P 的祖父母嫁接。这只是用该祖父母的新嫁接点替换了浅嫁接点,或者如果您已经通过git fetch --deepen=number获得了所有父母,则完全删除了浅嫁接点。