41.3.2 浅克隆
上一节介绍的稀疏检出,可以部分检出版本库中的文件,但是版本库本身仍然包含所有的文件和历史。如果只对一个大的版本库的最近的部分历史提交感兴趣,而不想克隆整个版本库,稀疏检出是解决不了这个问题的,应采用本节介绍的浅克隆。
实现版本库的浅克隆非常简单,只需要在执行git clone或git fetch操作时用—depth<depth>参数设定要获取的历史提交的深度(<depth>大于0),就会把源版本库分支上最近的<depth>+1个历史提交作为新版本库的全部历史提交。
通过浅克隆方式克隆出来的版本库,每一个提交的SHA1哈希值和源版本库都相同,包括提交的根节点也是如此,但是Git通过特殊的实现,使得浅克隆的根节点提交看起来没有父提交。正因为浅克隆的提交对象的SHA1哈希值和源版本库一致,所以浅克隆版本库可以执行git fetch或git pull从源版本库获取新的提交。但是浅克隆版本库也存在着很多限制,如:
不能从浅克隆版本库克隆出新的版本库。
其他版本库不能从浅克隆版本库中获取提交。
其他版本库不能推送提交到浅克隆版本库。
不要从浅克隆版本库推送提交至其他版本库,除非确认推送的目标版本库包含浅克隆版本库中缺失的全部历史提交,否则会因为目标版本库包含不完整的提交历史而导致版本库无法操作。
在浅克隆版本库中执行合并操作时,如果所合并的提交出现在浅克隆版本库的历史中,则可以顺利合并,否则会出现大量的冲突,就好像和无关的历史进行合并一样。
由于浅克隆包含上述限制,因此浅克隆一般用于对远程版本库的查看和研究,如果在浅克隆版本库中进行了提交,最好通过git format-patch命令导出为补丁文件再应用到远程版本库中。
下面的操作使用git clone命令创建一个浅克隆。注意:源版本库如果是本地版本库,就要使用file://协议,若直接使用本地路径则不会实现浅克隆。
$git clone—depth 2 file:///path/to/repos/hello-world.git shallow1
然后进入到本地克隆目录中,会看到当前分支上只有3个提交。
$git log—oneline
c4acab2 Translate for Chinese.
683448a Add I18N support.
d81896e Fix typo:-help to—help.
查看提交的根节点d81896e,会看到该提交实际上也包含父提交。
$git cat-file-p HEAD^^
tree f9d7f6b0af6f3fffa74eb995f1d781d3c4876b25
parent 10765a7ef46981a73d578466669f6e17b73ac7e3
author user1<user1@sun.ossxp.com>1294069736+0800
committer user2<user2@moon.ossxp.com>1294591238+0800
Fix typo:-help to—help.
而查看该提交的父提交,Git会报错。
$git log 10765a7ef46981a73d578466669f6e17b73ac7e3
fatal:bad object 10765a7ef46981a73d578466669f6e17b73ac7e3
对于正常的Git版本库来说,如果对象库中丢失一个提交绝对是大问题,版本库不可能被正常使用。而浅克隆之所以看起来一切正常,是因为Git使用了类似嫁接(下一节即将介绍)的技术。
在浅克隆版本库中存在一个文件.git/shallow,这个文件中罗列了应该被视为提交根节点的提交SHA1哈希值。查看这个文件会看到提交d81896e正在其中:
$cat.git/shallow
b56bb510a947651e4717b356587945151ac32166
d81896e60673771ef1873b27a33f52df75f70515
e64f3a216d346669b85807ffcfb23a21f9c5c187
列在.git/shallow文件中的提交会构建出对应的嫁接提交,使用类似嫁接文件.git/info/grafts(下节讨论)的机制,当Git访问这些对象时就好像这些对象是没有父提交的根节点一样。