Git 合并信息是每个文件还是每个目录

  • 本文关键字:文件 Git 合并 信息 git
  • 更新时间 :
  • 英文 :


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

两者都不是。

Subversion 在这里有点奇特,因为它是建立在基本上处理目录的系统之上的。 这意味着你可以使用 Subversion 查看一个特定的目录——嗯,有点:你也可以得到它的子目录。 但它从一个目录开始:因此目录级合并信息。

Git 的基本单位既不是文件也不是目录,而是提交。 您不能少于整个提交。1当你运行git checkoutcommit-specifier时,Git 将整个提交的树复制到你的索引/暂存区——这占用的空间相对较少;请参阅脚注 1 — 然后将所有这些文件从索引复制到工作树中,您可以在其中处理它们。

每个 Git 提交都是项目中所有文件的完整快照,或者更准确地说,是提交时索引中的所有文件。 由于索引从当前提交中的所有文件开始,因此在下一次提交中也将继续包含所有文件。 合并提交在这里与任何其他提交没有什么不同:它拥有所有文件,在其完整和完整的荣耀中,但压缩、冻结和 Git 化,就像任何提交中的所有文件被压缩、冻结和 Git 化一样。 由于它们被冻结了(您永远无法更改任何提交的任何部分),如果它们保持不变,它们就会被共享,因此,如果您提交 100 MB 的文件十次,甚至一百万次,该文件使用的磁盘空间量与您只提交 100 MB 文件一次相同 — 因为实际上, 你做到了。 (每次提交都会在文件顶部添加一点空间,用于提交的元数据,但是如果您熟悉Unix/Linux系统上链接的想法,则可以将每个提交视为具有指向一个底层文件的硬链接

同时,提交合并的事实通过存储在每个提交的哈希 ID 或 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——都是完整和完整的快照,所以如果我们想看看顶部链提交是如何通过合并底层链来修改HL提交到其中的,我们可以比较HM。 如果我们想看看底层链提交是如何通过将顶链提交H合并到其中来修改L的,我们可以比较LM。 例如,当我们想查看H是如何被修改时,这些是我们所做的相同比较:我们比较GH,这是两个快照,以查看从GH的变化。

如果我们想看看两条链最初分道扬镳的位置,我们只需要一个更广阔的视野:

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

如果F的父级是E,而J的父级是I父级是E的,那么我们可以看到E是我们合并HL时的合并基础。 由于所有提交都始终被冻结,如果E是合并基础,那么E现在仍然是合并基础。

这意味着您的问题的答案是:根本没有明确的合并信息。 存在合并的事实以及重复合并所需的信息由提交图暗示。提交图是您(或 Git)通过读取各个提交派生的数据结构。 由于提交是基本单元,因此您始终有一个完整的提交。阿拉伯数字层克隆中,您可以缺少较早的提交,但您可以通过返回克隆的任何地方并"取消浅表"克隆(或者只是将其加深到足够远以查看您需要看到的内容)来填充这些提交。


1Git 确实支持稀疏结帐的概念,但您仍然可以获得整个提交。它的所有文件仍会复制到索引中。 稀疏签出仅限制然后将哪些文件从索引复制到工作树。 由于索引副本大部分是冻结的,可以直接共享提交中的副本,因此这减少了所需的磁盘空间量,因为某些文件永远不需要从冻结的提交中解压缩出来。 你做的下一个提交,如果你做了另一个,是根据索引中的内容而不是从工作树中的内容进行的,所以新的提交继续拥有所有文件,尽管签出很稀疏。

2Git 添加了允许某种占位符的想法,以promisor 包的形式,您可以在其中提交但缺少一些内部数据。 也就是说,提交本身仍然是基本单元,但是虽然你知道提交C有树 T,但你可能缺少对象T本身,直到有东西明确要求它,此时 Git 会尝试通过打电话回家来履行承诺谁做出承诺。 这实际上还没有在 Git 中,但它正在慢慢进入代码库。

请注意,这有点类似于浅层克隆。 在浅层克隆的情况下,你知道提交 C 有父 P,但你缺少对象P,因为有一个浅层移植,这使得 Git 的某些部分假装C根本没有父级。使用git fetch --deepen=number,你可以让 Git 获得 P,但也许可以浅嫁接P的一些祖父母。 这只是用该祖父母的新移植点替换浅移植点,或者如果您已经获得了所有父母,例如,通过git fetch --unshallow,则完全删除浅移植点。

最新更新