答案 0 :(得分:29)
答案 1 :(得分:13)
打包引用存在的原因是为了加速使用数以万计的引用的回购中的访问 - 使用多行来查看单个文件比为每个引用查看文件系统一次更容易。 git中需要了解refs的任何东西都可以通过代码来读取refs目录和压缩的refs文件。打开它会破坏它的目的。如果要访问refs,请使用管道命令(例如show-ref,for-each-ref,update-ref ...)。我无法想到任何类型的访问,使用目录结构比使用管道命令更快更容易(特别是for-each-ref可用)。
是的,打包的对象(如打包引用)是为了提高性能而创建的,但是有很大的不同。打包的refs文件只是一堆独立的行。您可以,基本上免费,添加或删除它。没有必要解压缩它来修改它。另一方面,打包的对象是delta压缩的,因此内部的对象彼此依赖。它们大大减少了磁盘的使用,并且可以以合理的成本从它们中读取对象,但是尝试修改包中的对象集比修改松散的对象要昂贵得多,所以它只是由git repack
定期完成(称为虽然我不相信git gc
实际上解包了对象 - 它只是从包文件中读取它们,用松散包装它们,然后制作一个新包。
但是,当从远程传输包时,它会在本地解压缩。我在git repack
源代码中看到了对解包方法的调用,git receive-pack
联机帮助页显示:
git unpack-objects命令可以读取打包存档并将包中包含的对象扩展为“单文件单对象”格式;这通常是通过智能拉动命令完成的,当一个包即时创建时,可以由同行进行有效的网络传输。
答案 2 :(得分:2)
问题1的另一个答案:
我假设您已经使用了这样的循环来使用git unpack-objects:
mkdir CLONE mv .git/objects/pack/* CLONE/ for pack in CLONE/*.pack; do git unpack-objects < $pack done rm -rf CLONE/
解包所有对象,但将打包的分支头留在文件.git / packed-refs
感谢Clee的答案,我在这里重复使用,我发现需要以下命令来打开分支头并清理:
( IFS=$'\n'; # set the input field separator to new line for f in $(git show-ref --heads); do ref_hash="$(echo $f | cut -c1-40)" ref_label="$(echo $f | cut -c42-)" echo " unpack: $ref_hash $ref_label" echo "$ref_hash" > ".git/$ref_label"; sed -i "s~^${ref_hash} ${ref_label}\$~~" .git/packed-refs sed -i '/^$/d' .git/packed-refs done rm .git/info/refs rm .git/objects/info/packs )
请注意Clee的回答:
A)打包的引用从.git / packed-refs文件中删除,
B)文件.git / info / refs和.git / objects / info / packs被删除。
我承认删除.git文件夹中的文件可能不是一个好主意,但这是我需要做的,以便进行干净的解压缩。
问题2仍未得到解答。
答案 3 :(得分:0)
有一种解决方法对我有用,可能适合你们中的一些人:
基本上,在本地删除所有标签(从打包引用中删除它),然后再次获取它。
git tag | xargs git tag -d && git fetch --tags