Git如何从分支中检索所有文件?

时间:2014-04-16 20:31:22

标签: git git-branch git-merge git-commit

我目前正在学习Git,并且在了解Git如何从分支机构检索文件时遇到问题。

据我所知,分支只是一个指向提交的指针。所以我相信当你签出一个分支时,它会从指针所在的提交开始跟踪从父到父的所有提交。但是我不明白它如何选择一个拥有多个父项的提交的父项,就像在合并中一样。

例如:

enter image description here

假设我想查看master,Git如何知道C5点应该是C4而不是C8。或者我完全误解了这个?

当您结帐分支时,Git如何知道要在工作树中放入哪些文件?

3 个答案:

答案 0 :(得分:3)

Git与大多数其他版本控制系统(VCS)不同。

大多数VCS-es存储"增量"各种形式。例如,如果整个存储库中的最尖端提交是C9并由master标识,并且您将其解压缩,那么您可能会按原样获取存储库中的所有文件,而如果您提取{{ 1}}(先前从C5提交),您从所有最新文件开始,然后C9说"撤消此操作,撤消该操作,撤消其他内容&#34 ;并且版本控制系统撤消那些,并且从提交C5开始,它将使您处于状态。

同样,git 这样做。

相反,git的存储库存储了git调用的对象"对象"。有四种类型的对象:"提交","带注释的标签","树"和" blob"。我们将忽略带注释的标签(为此目的不需要它们),只考虑其他三个。

每个对象都有一个唯一的160位名称,表示为SHA-1哈希。通过计算对象内容的SHA-1(加上其类型)来构造散列的值。 Git假设存储库中没有两个不同的对象会计算相同的SHA-1(如果他们这样做,git会乱码;但这从未发生过)。 (但请注意,相同的对象 - 例如,许多提交中的C5文件 - 只有一个唯一的SHA-1。)

提交对象如下所示:

foo.c

也就是说,它有一个$ git cat-file -p 5f95c9f850b19b368c43ae399cc831b17a26a5ac tree 972825cf23ba10bc49e81289f628e06ad44044ff parent 9c8ce7397bac108f83d77dfd96786edb28937511 author Junio C Hamano <gitster@pobox.com> 1392406504 -0800 committer Junio C Hamano <gitster@pobox.com> 1392406504 -0800 Git 1.9.0 Signed-off-by: Junio C Hamano <gitster@pobox.com> ,一个tree列表,一个parent - 和 - 日期,一个author - 和 - 日期以及一个文本信息。那个所有它也有。每个committer是父提交的SHA-1;根提交没有父节点,合并有多个父节点,但大多数提交只有一个父节点,这就是你发布的图表中的箭头。

树对象如下所示:

parent

树为您提供了与该提交一起使用的顶级目录。大多数树条目是$ git cat-file -p 972825cf23ba10bc49e81289f628e06ad44044ff 100644 blob 5e98806c6cc246acef5f539ae191710a0c06ad3f .gitattributes 100644 blob b5f9defed37c43b2c6075d7065c8cbae2b1797e1 .gitignore 100644 blob 11057cbcdf4c9f814189bdbf0a17980825da194c .mailmap 100644 blob 536e55524db72bd2acf175208aef4f3dfc148d42 COPYING 040000 tree 47fca99809b19aeac94aed024d64e6e6d759207d Documentation 100755 blob 2b97352dd3b113b46bbd53248315ab91f0a9356b GIT-VERSION-GEN [snip lots more] s;子目录更多blob s。 blob的tree为您提供可执行位(这些看起来像Unix文件模式,但git实际上只使用一个可执行位,因此模式始终为mode100644)。对于特殊情况,还有一些模式(例如,符号链接),但我们现在可以忽略它们。在任何情况下,每个条目都有另一个唯一的SHA-1,这就是git如何找到下一个项目(子树或blob)。

每个 blob对象包含实际文件。例如,100755 blob是git版本生成器脚本:

GIT-VERSION-GEN

因此,要提取提交,git只需要:

  1. $ git cat-file -p 2b97352dd3b113b46bbd53248315ab91f0a9356b #!/bin/sh GVF=GIT-VERSION-FILE DEF_VER=v1.9.0 [snip] HEAD等符号名称翻译为提交的SHA-1
  2. 提取提交对象以查找顶级树
  3. 提取顶级树对象以查找所有文件和子树
  4. 为每个文件提取文件对象;并且对于每个子树,递归地提取该树及其对象。
  5. (Git对象以压缩方式存储,最终进一步压缩为&#34;打包文件&#34;其中使用增量,但与其他VCS-es的方式完全不同。 #39; s不需要针对先前版本的master对文件foo.c进行增量压缩;例如,git可以相互增量压缩树,或者对某些文档使用某些C代码。确切的包文件格式也经历了几次修改:如果某个未来的版本有更好的压缩方式,那么包格式可以从版本4更新到版本5.例如,在任何情况下,&#34;松散&# 34;对象只是zlib压缩而不是delta压缩。这使得访问和更新它们非常快。包文件用于更多静态项 - 未修改的文件 - 以及用于网络传输。它们是在{}期间构建的{1}},以及推送和获取操作[使用名为&#34的变体;尽可能使用#&#34; pack]。)

    更多的git&#34; plumbing&#34;允许您读取和写入单个对象的命令,请参阅the Pro Git book(提醒自gatkin's answer)。

答案 1 :(得分:1)

Git会在每次提交时存储所有跟踪文件的完整快照,而不仅仅是差异。除了父提交ID之外,C9(以及每个提交)都有一个树ID。你可以用

看到这个
git log --pretty=format:%T HEAD -1

该命令打印树的SHA1哈希,如果您在该哈希上执行git show,您将获得项目中顶层文件夹的列表,这是树的开头。在内部,树对象具有指向文件的其他对象和子文件夹的其他树的指针。

有关详细信息,请参阅chapter 9 of Pro Git

答案 2 :(得分:0)

Git与大多数其他版本控制系统不同。它不依赖于修订版之间的差异来重新创建存储库中的文件。与subversion不同,例如,通常需要访问父提交及其关联的差异以重新创建文件,git不需要。

换句话说,在任何时候,所有git需要访问一个提交,以便能够重新创建整个存储库。

因此,提交是否有一个或多个父母并不重要。