【问题标题】:Git - get all commits and blobs they createdGit - 获取他们创建的所有提交和 blob
【发布时间】:2010-11-21 20:17:33
【问题描述】:

是否有git命令可以为每次提交输出:

  1. 身份证
  2. 主题
  3. 它使用路径和大小创建的 blob(如 git ls-tree -l -r <commit>,但仅适用于创建的 blob)

【问题讨论】:

    标签: git blob commit


    【解决方案1】:

    获取提交(所有并每次提交输出一行):

    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>
    

    还有一次解析

    【讨论】:

    • 您可以通过使用--stdin 选项到diff-tree 来加快速度。例如,git rev-list --all | git diff-tree -r --root --diff-filter=AMC --pretty=oneline --stdin
    • maxschlepzig 在下面的回答很重要:如果您尝试做类似delete a large file from the repo history 的事情,您需要确保找到每个提交,即使有些提交位于未合并的分支上!
    【解决方案2】:

    依赖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(并且仅创建的blob)。

    【讨论】:

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

    除了尺寸之外,您可以开箱即用。这个很接近:

    git log --name-status
    

    【讨论】:

    • 它有什么作用?
    【解决方案4】:

    基于 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
    }
    

    也许不是最好的代码,但应该可以帮助您完成大部分工作。

    【讨论】:

      【解决方案5】:

      搜索时另一个有用的命令

      git fsck --lost-found
      

      将显示悬空提交。我需要使用它来查找我用不合时宜的重置擦除的提交 --hard

      但不要相信我的话:

      https://www.kernel.org/pub/software/scm/git/docs/git-fsck.html

      【讨论】:

      • 嗯,你能评论一下否决票吗?如果答案有误或误导,我会删除!
      【解决方案6】:

      您还可以通过以下方式获取 所有 个提交(包括悬空提交)的列表:

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

      在 gitk 中的新视图设置中包含这一行(在最后一个输入字段中,生成额外提交的命令),您将获得一棵树,其中还显示了项目的“被遗忘的历史记录”。

      【讨论】:

      • 对我不起作用:git log --walk-reflogs 提供的列表比git log 提供的列表更短。从the man page 来看,reflog 不能以任何方式保证是所有提交或所有分支的详尽列表...
      猜你喜欢
      • 2011-06-14
      • 2013-08-18
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-07
      • 2018-04-28
      相关资源
      最近更新 更多