我目前正在学习Git,并且在了解Git如何从分支机构检索文件时遇到问题。
据我所知,分支只是一个指向提交的指针。所以我相信当你签出一个分支时,它会从指针所在的提交开始跟踪从父到父的所有提交。但是我不明白它如何选择一个拥有多个父项的提交的父项,就像在合并中一样。
例如:
假设我想查看master
,Git如何知道C5
点应该是C4
而不是C8
。或者我完全误解了这个?
当您结帐分支时,Git如何知道要在工作树中放入哪些文件?
答案 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实际上只使用一个可执行位,因此模式始终为mode
或100644
)。对于特殊情况,还有一些模式(例如,符号链接),但我们现在可以忽略它们。在任何情况下,每个条目都有另一个唯一的SHA-1,这就是git如何找到下一个项目(子树或blob)。
每个 blob对象包含实际文件。例如,100755
blob
是git版本生成器脚本:
GIT-VERSION-GEN
因此,要提取提交,git只需要:
$ git cat-file -p 2b97352dd3b113b46bbd53248315ab91f0a9356b
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.9.0
[snip]
或HEAD
等符号名称翻译为提交的SHA-1 (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需要访问一个提交,以便能够重新创建整个存储库。
因此,提交是否有一个或多个父母并不重要。