Git - 如何列出数据库中的所有对象

kbr*_*bro 51 git git-show git-rev-list

是否有比做库得到SHA1s的原始列表中的所有对象的一种更好的方式ls .git/objects/??/\*cat .git/objects/pack/*.idx | git show-index

我知道,git rev-list --all但只列出.git/refs引用的提交对象,我正在寻找包括由git-hash-object,git-mktree等创建的未引用对象的所有内容.

seh*_*ehe 36

尝试

 git rev-list --objects --all
Run Code Online (Sandbox Code Playgroud)

编辑 Josh提出了一个很好的观点:

 git rev-list --objects -g --no-walk --all
Run Code Online (Sandbox Code Playgroud)

列表对象可从ref-logs中获取.

要查看无法访问的提交中的所有对象:

 git rev-list --objects --no-walk \
      $(git fsck --unreachable |
        grep '^unreachable commit' |
        cut -d' ' -f3)
Run Code Online (Sandbox Code Playgroud)

把它们放在一起,真正得到输出格式的所有对象rev-list --objects,你需要类似的东西

{
    git rev-list --objects --all
    git rev-list --objects -g --no-walk --all
    git rev-list --objects --no-walk \
        $(git fsck --unreachable |
          grep '^unreachable commit' |
          cut -d' ' -f3)
} | sort | uniq
Run Code Online (Sandbox Code Playgroud)

要以稍微有用的方式对输出进行排序(通过树/ blob的路径,首先提交),请使用另一个| sort -k2对相同路径的所有不同blob(修订版)进行分组.


小智 26

我不知道这个选项何时存在,但你可以

git cat-file --batch-check --batch-all-objects
Run Code Online (Sandbox Code Playgroud)

根据手册页,这给了你

存储库中的所有对象和任何备用对象存储(不仅仅是可到达的对象)

(强调我的).

默认情况下,这会产生对象类型及其大小以及每个哈希值,但您可以轻松删除此信息,例如使用

git cat-file --batch-check --batch-all-objects | cut -d' ' -f1
Run Code Online (Sandbox Code Playgroud)

或者通过提供自定义格式--batch-check.

  • 我知道谢谢你的评论在StackOverflow上不受欢迎,但你已经为我节省了一个星期的工作量.我的安装是FUBAR,reflog和ref-list不起作用. (3认同)
  • 这个答案优于其他答案,因为输出还显示了对象的 **类型** 和 **大小**。(用示例输出更新了答案,以明确这一点,因为我一直在寻找这个命令一段时间了。) (2认同)

Ari*_*zis 10

Markwillkill的回答中,这是一个更正确,更简单,更快速的脚本再现.

  • 它用于rev-parse --git-path查找objects目录,即使在更复杂的Git存储库设置中(例如,在多工作树情况下或诸如此类).

  • 它避免了所有不必要的使用find,grep,perl,sed.

  • 即使您没有松散的物体或没有包装(或者如果您倾向于在新的存储库上运行它),也可以优雅地工作.

  • 然而,它确实需要从这个千年开始的Bash(2.02或者更新,特别是这个extglob位).

分享和享受.

#!/bin/bash
set -e
shopt -s nullglob extglob

cd "`git rev-parse --git-path objects`"

# packed objects
for p in pack/pack-*([0-9a-f]).idx ; do
    git show-index < $p | cut -f 2 -d ' '
done

# loose objects
for o in [0-9a-f][0-9a-f]/*([0-9a-f]) ; do
    echo ${o/\/}
done
Run Code Online (Sandbox Code Playgroud)


wil*_*kil 9

编辑: 亚里士多德发布了一个更好的答案,应该标记为正确.

经过一些修改后,Mark的回答对我有用:

  • 用来grep -v代替--git-dir支持裸回购
  • 没有包时避免错误
  • 二手--show-cdup因为OS X山狮的BSD风格的perl不支持sed

#!/bin/sh

set -e

cd "$(git rev-parse --git-dir)"

# Find all the objects that are in packs:

find objects/pack -name 'pack-*.idx' | while read p ; do
    git show-index < $p | cut -f 2 -d ' '
done

# And now find all loose objects:

find objects/ \
    | egrep '[0-9a-f]{38}' \
    | grep -v /pack/ \
    | perl -pe 's:^.*([0-9a-f][0-9a-f])/([0-9a-f]{38}):\1\2:' \
;
Run Code Online (Sandbox Code Playgroud)


Von*_*onC 8

Erki Der Loony答案中git cat-file --batch-check --batch-all-objects建议的命令可以通过新的Git 2.19(Q3 2018)选项更快地执行。--unordered

该API会迭代所有学习到的对象,以便有选择地按照对象在packfiles中出现的顺序列出对象,如果在枚举对象时调用方访问这些对象,则可以帮助访问本地性。

请参阅Jeff King()的提交0889aae提交79ed0a5提交54d2f0d提交ced9fff(2018年8月14日)和提交0750bb5提交b1adb38提交aa2f5ef提交736eb88提交8b36155提交a7ff6f5提交202e7f1(2018年8月10日(由Junio C Hamano合并--commit 0c54cda中,2018年8月20日)peffgitster

cat-file:支持“ unordered”的输出--batch-all-objects

如果要访问packfile中每个对象的内容,通常以打包顺序(而不是哈希顺序)进行访问更为有效。这增加了packfile中访问的位置,这又对delta基本缓存更友好,因为packfile将相关的delta彼此相邻放置。相反,由于sha1与内容没有可辨别的关系,因此哈希顺序实际上是随机的。

该补丁引入了一个“ --unordered”选项,cat-file可在引擎盖下按包顺序迭代包。转储所有文件内容时,您可以看到结果:

$ time ./git cat-file --batch-all-objects --buffer --batch | wc -c
  6883195596

real 0m44.491s
user 0m42.902s
sys  0m5.230s

$ time ./git cat-file --unordered \
                    --batch-all-objects --buffer --batch | wc -c
  6883195596

real 0m6.075s
user 0m4.774s
sys  0m3.548s
Run Code Online (Sandbox Code Playgroud)

输出相同,顺序不同,速度更快。即使最终以不同的过程访问对象内容,也可以应用相同的提速,例如:

git cat-file --batch-all-objects --buffer --batch-check |
grep blob |
git cat-file --batch='%(objectname) %(rest)' |
wc -c
Run Code Online (Sandbox Code Playgroud)

--unordered在第一个命令中添加“ ”可将运行时间git.git从24秒降至3.5秒。

旁注:实际上,现在可以进一步加快处理速度。由于我们是在实际Pack迭代期间输出对象内容的,因此我们知道在哪里可以找到对象,并且可以跳过进行的额外查找oid_object_info()。该补丁没有进行优化,因为基础API尚未准备好让我们发出这些直接请求。

那么,如果--unordered好得多,为什么不将其设置为默认值呢?两个原因:

  1. 我们已经在文档中承诺--batch-all-objects以哈希顺序输出。由于cat-file存在管道问题,人们可能会依赖该默认值,因此我们无法更改它。

  2. 在某些情况下,它实际上要慢一些。我们必须计算包revindex才能按包顺序进行。而且我们的重复数据删除步骤使用的是oidset,而不是sort-and-deedup,这最终会变得更加昂贵。

例如,如果我们只是访问每个对象的类型和大小,例如:

git cat-file --batch-all-objects --buffer --batch-check
Run Code Online (Sandbox Code Playgroud)

我的5个最佳热缓存时序使用,从900ms变为1100ms --unordered。尽管在冷缓存或内存压力下,我们可能会做得更好,因为我们在packfile中具有更好的局部性。

最后一个问题:为什么是“ --unordered”而不是“ --pack-order”?答案还是双重的:

  1. 在整个对象集合中,“打包顺序”并不是一个明确定义的东西。我们打松对象,以及为对象在多个包,唯一订购我们看好的是一个单一的包。其余的显然是随机的。

  2. 这里的重点是优化。因此,我们不想承诺任何特定的排序,而只是说我们将选择一种可能对访问对象内容有效的排序。这为将来进行进一步更改打开了大门,而无需添加其他兼容性选项


在Git 2.20(Q4 2018)中,它甚至更快:

提交8c84ae6提交8b2f8cb提交9249ca2提交22a1646提交bf73282(2018年10月4日),由勒内Scharfe( )rscharfe
(由Junio C gitsterHamano合并--commit 82d0a8c中,2018年10月19日)

oidset: 使用 khash

重新实现oidset使用khash.h以减少其内存占用并使其更快。

主要使用oidset master和Clang 6.0.1 检查命令是否重复的命令的性能:

$ cmd="./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'"

$ /usr/bin/time $cmd >/dev/null
0.22user 0.03system 0:00.25elapsed 99%CPU (0avgtext+0avgdata 48484maxresident)k
0inputs+0outputs (0major+11204minor)pagefaults 0swaps

$ hyperfine "$cmd"
Benchmark #1: ./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'

Time (mean ± ?):     250.0 ms ±   6.0 ms    [User: 225.9 ms, System: 23.6 ms]

Range (min … max):   242.0 ms … 261.1 ms
Run Code Online (Sandbox Code Playgroud)

并与此补丁:

$ /usr/bin/time $cmd >/dev/null
0.14user 0.00system 0:00.15elapsed 100%CPU (0avgtext+0avgdata 41396maxresident)k
0inputs+0outputs (0major+8318minor)pagefaults 0swaps

$ hyperfine "$cmd"
Benchmark #1: ./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'

Time (mean ± ?):     151.9 ms ±   4.9 ms    [User: 130.5 ms, System: 21.2 ms]

Range (min … max):   148.2 ms … 170.4 ms
Run Code Online (Sandbox Code Playgroud)

Git 2.21(Q1 2019)通过遵循通常的打包顺序访问对象的模式,进一步优化了代码路径以写出提交图。

提交d7574c9通过(2019年1月19日)ÆvarArnfjörðBjarmason( )avar
(由Junio C gitsterHamano合并--commit 04d67b6中,2019年2月5日)

通过使用FOR_EACH_OBJECT_PACK_ORDER,稍微优化“提交图形写入”步骤 for_each_object_in_pack()
Derrick Stolee 在Windows上进行了自己的测试,结果显示精度提高了2%。


Git 2.23(2019年第三季度)改进了“ git rev-list --objects”功能,该功能通过“ --no-object-names”选项来学习,以压制该对象的路径,该路径用作打包对象的分组提示。

参见Emily Shaffer(提交42357b4(2019年6月19日(由Junio C Hamano合并--commit f4f7e75中,2019年7月9日)nasamuffin
gitster

rev-list:教--no-object-names如何启用管道

cat-file通过给rev-list选项仅打印未提交对象的OID而没有任何其他信息,可以简化解析。
这是一个短期垫片。稍后,rev-list应该教如何以类似于的格式打印找到的对象类型cat-file

在此提交之前,rev-list需要先对来自的输出进行按摩,然后再将其通过管道传输到cat文件,如下所示:

git rev-list --objects HEAD | cut -f 1 -d ' ' |
    git cat-file --batch-check
Run Code Online (Sandbox Code Playgroud)

在处理根树时,这尤其出乎意料,因为OID的末尾存在不可见的空格:

git rev-list --objects --filter=tree:1 --max-count=1 HEAD |
    xargs -I% echo "AA%AA"
Run Code Online (Sandbox Code Playgroud)

现在,可以直接通过管道传递它,如添加的测试用例中所示:

git rev-list --objects --no-object-names HEAD | git cat-file --batch-check
Run Code Online (Sandbox Code Playgroud)

因此,两者之间的区别在于:

vonc@vonvb:~/gits/src/git$ git rev-list --objects HEAD~1..
9d418600f4d10dcbbfb0b5fdbc71d509e03ba719
590f2375e0f944e3b76a055acd2cb036823d4b44 
55d368920b2bba16689cb6d4aef2a09e8cfac8ef Documentation
9903384d43ab88f5a124bc667f8d6d3a8bce7dff Documentation/RelNotes
a63204ffe8a040479654c3e44db6c170feca2a58 Documentation/RelNotes/2.23.0.txt
Run Code Online (Sandbox Code Playgroud)

并且,使用--no-object-name

vonc@vonvb:~/gits/src/git$ git rev-list --objects --no-object-names HEAD~1..
9d418600f4d10dcbbfb0b5fdbc71d509e03ba719
590f2375e0f944e3b76a055acd2cb036823d4b44
55d368920b2bba16689cb6d4aef2a09e8cfac8ef
9903384d43ab88f5a124bc667f8d6d3a8bce7dff
a63204ffe8a040479654c3e44db6c170feca2a58
Run Code Online (Sandbox Code Playgroud)


Mar*_*air 6

我不知道一个明显更好的方法,而不仅仅是查看所有松散的目标文件和所有包文件的索引.git存储库的格式非常稳定,使用这种方法,您不必依赖于具有完全正确的选项git fsck,这被归类为瓷器.我认为这种方法也更快.以下脚本显示存储库中的所有对象:

#!/bin/sh

set -e

cd "$(git rev-parse --show-cdup)"

# Find all the objects that are in packs:

for p in .git/objects/pack/pack-*.idx
do
    git show-index < $p | cut -f 2 -d ' '
done

# And now find all loose objects:

find .git/objects/ | egrep '[0-9a-f]{38}' | \
  sed -r 's,^.*([0-9a-f][0-9a-f])/([0-9a-f]{38}),\1\2,'
Run Code Online (Sandbox Code Playgroud)

(我的这个脚本的原始版本基于这个有用的脚本来查找包文件中的最大对象,但我转而使用git show-index,如你的问题所示.)

我把这个脚本变成了GitHub的要点.