Git - 获取所有提交以及它们创建的文件块

16

是否有一个git命令可以为每个提交输出以下内容:

  1. id
  2. 主题
  3. 它创建的blob及其路径和大小(类似于git ls-tree -l -r <commit>,但仅适用于创建的blob)
6个回答

28

获取提交记录(全部)并每行输出一个提交记录:

git rev-list --all --pretty=oneline

然后按照限制为2的空格拆分提交,并获取每个提交ID和消息。

要获取由提交创建的blob(递归到子目录,显示合并提交,检测重命名和复制,在第一行不显示提交ID):

git diff-tree -r -c -M -C --no-commit-id <commit-sha>

对每行进行一些解析并排除其中一些行 - 我们得到新Blob的列表和它们在提交中的路径。

最后是获取Blob的大小:

git cat-file --batch-check < <list-of-blob-shas>

还有一次稍微解析一下


1
你可以使用--stdin选项来加快速度。例如,git rev-list --all | git diff-tree -r --root --diff-filter=AMC --pretty=oneline --stdin - Jed
1
maxschlepzig的下面的回答很重要:如果你想做像从仓库历史中删除一个大文件这样的事情,你需要确保找到每一个提交,即使有些提交在未合并的分支上! - peterflynn

12
依靠git rev-list并不总是足够的,因为它只列出了由给定提交的父链接可到达的提交。(git help rev-list)因此,它不会列出其他分支上的提交,也不会列出任何分支都无法到达的提交(可能是由于某些rebase和/或游离状态操作而创建的)。类似地,git log只是从当前签出的提交中跟随父链接。同样,你看不到其他分支引用的提交或处于游离状态的提交。你可以像这样使用命令真正获取所有提交:
for i in `(find .git/objects  -type f |
             sed 's@^.*objects/\(..\)/\(.\+\)$@\1\2@' ;
           git verify-pack -v .git/objects/pack/*.idx  |
             grep commit |
             cut -f1 -d' '; ) | sort -u`
  do
  git log -1 --pretty=format:'%H %P %ai %s%n'  $i
done
为了简单起见,循环体为每个提交打印一行,包含其哈希值、父哈希值、日期和主题。请注意,要遍历所有提交,您需要考虑已打包和未打包的对象。
您可以通过在循环体中调用“git diff-tree $i”(并在第五列中搜索大写A)来打印引用的blob文件(仅限已创建的)。

使用 git log --all 怎么样?文档似乎暗示这将包括每个(可达)提交... - peterflynn
@ytpete,我在我的回答中明确提到了无法访问的提交。 - maxschlepzig

5
您可以直接使用此工具,但大小需要自行调整。这个很接近实际情况:
git log --name-status

它是做什么的? - pdem

5

基于tig的答案,有一个解决方案:

#!/usr/bin/perl

foreach my $rev (`git rev-list --all --pretty=oneline`) {
  my $tot = 0;
  ($sha = $rev) =~ s/\s.*$//;
  foreach my $blob (`git diff-tree -r -c -M -C --no-commit-id $sha`) {
    $blob = (split /\s/, $blob)[3];
    next if $blob == "0000000000000000000000000000000000000000"; # Deleted
    my $size = `echo $blob | git cat-file --batch-check`;
    $size = (split /\s/, $size)[2];
    $tot += int($size);
  }
  print "$tot $rev" if $tot > 1000000; # Show only if > 1MiB
}

也许不是最好的代码,但应该能帮助您解决大部分问题。

2

嗯,你能否评论一下这个踩的原因 - 如果回答有误导性或错误,我会将其删除! - starsinmypockets

0

你也可以使用以下命令获取包括悬空提交在内的所有提交记录:

git log --walk-reflogs | grep -E -o '[0-9a-f]{40}'

将此行命令添加到 gitk 的新视图设置中(在最后一个输入字段中,生成额外提交的命令),您将获得一个显示项目“遗忘历史”的树形结构。


1
对我来说不起作用:git log --walk-reflogs 给出的列表比仅使用 git log 要 _短_。根据手册所述,引用日志不能保证是所有提交或所有分支的详尽列表... - peterflynn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接