Git:显示两次提交之间的总文件大小差异?


78

是否可以显示两次提交之间的总文件大小差异?就像是:

$ git file-size-diff 7f3219 bad418 # I wish this worked :)
-1234 bytes

我试过了:

$ git diff --patch-with-stat

这样就可以显示差异中每个二进制文件的文件大小差异,但对于文本文件则没有,总文件大小差异也没有。

有任何想法吗?


3
这是3行bashscript,为您提供了某些提交的大小stackoverflow.com/a/23985353/2062041
Stas Dashkovsky 2014年

Answers:


90

git cat-file -s将以git为单位输出对象的大小(以字节为单位)。git diff-tree可以告诉您一棵树与另一棵树之间的差异。

将它们放到git-file-size-diff位于PATH某处的脚本中,即可调用git file-size-diff <tree-ish> <tree-ish>。我们可以尝试如下操作:

#!/bin/bash
USAGE='[--cached] [<rev-list-options>...]

Show file size changes between two commits or the index and a commit.'

. "$(git --exec-path)/git-sh-setup"
args=$(git rev-parse --sq "$@")
[ -n "$args" ] || usage
cmd="diff-tree -r"
[[ $args =~ "--cached" ]] && cmd="diff-index"
eval "git $cmd $args" | {
  total=0
  while read A B C D M P
  do
    case $M in
      M) bytes=$(( $(git cat-file -s $D) - $(git cat-file -s $C) )) ;;
      A) bytes=$(git cat-file -s $D) ;;
      D) bytes=-$(git cat-file -s $C) ;;
      *)
        echo >&2 warning: unhandled mode $M in \"$A $B $C $D $M $P\"
        continue
        ;;
    esac
    total=$(( $total + $bytes ))
    printf '%d\t%s\n' $bytes "$P"
  done
  echo total $total
}

在使用中,它看起来如下所示:

$ git file-size-diff HEAD~850..HEAD~845
-234   Documentation/RelNotes/1.7.7.txt
112    Documentation/git.txt
-4     GIT-VERSION-GEN
43     builtin/grep.c
42     diff-lib.c
594    git-rebase--interactive.sh
381    t/t3404-rebase-interactive.sh
114    t/test-lib.sh
743    tree-walk.c
28     tree-walk.h
67     unpack-trees.c
28     unpack-trees.h
total 1914

通过使用git-rev-parse它应该接受所有指定提交范围的常用方法。

编辑:更新以记录累积总数。请注意,bash在子外壳程序中运行while读取,因此,额外的花括号可避免在子外壳程序退出时丢失总计。

编辑:通过使用--cached参数调用git diff-index而不是,添加了将索引与另一个树状索引进行比较的支持git diff-tree。例如:

$ git file-size-diff --cached master
-570    Makefile
-134    git-gui.sh
-1  lib/browser.tcl
931 lib/commit.tcl
18  lib/index.tcl
total 244

+1谢谢!如果它将在底部打印出总大小差异,那将是绝对完美的。我想查看在两个ref之间的整个项目范围内添加/删除了多少个字节(不仅是每个文件,而且总数也是如此)。
Mathias Bynens 2012年

另一个问题:您为什么在这里采购git-sh-setup?您似乎没有使用它定义的任何功能。就是想!
Mathias Bynens 2012年

3
如果您在不是git存储库的目录中运行此命令,它将执行基本检查,例如生成有意义的消息。它还可以帮助抽象出一些平台差异。虽然大多习惯。编写git脚本时-首先引入git-sh-setup文件。
patthoyts 2012年

1
感谢您的脚本!我将其归档为要点(gist.github.com/cschell/9386715),希望您不要介意。不耐烦的人现在可以做类似的事情curl -s https://gist.githubusercontent.com/cschell/9386715/raw/43996adb0f785a5afc17358be7a43ff7ee973215/git-file-size-diff | bash -s <tree-ish> <tree-ish>
csch 2014年

1
@ mr5 HEAD〜850是HEAD之前的850次提交。它只是提交的另一种表示法,是的,您可以使用特定的提交ID或标记或可以解析为提交的任何内容。该脚本使用的方式是完整的git rev-parse,请参见git-rev-parse文档中的手册“指定修订”部分。(git-scm.com/docs/git-rev-parse
patthoyts

20

您可以通过管道输出

git show some-ref:some-path-to-file | wc -c
git show some-other-ref:some-path-to-file | wc -c

并比较两个数字。


8
+1这非常适合快速检查版本之间文件的大小差异。但是,如何使用它来获取两次提交之间的总文件差异?我想看看在两个引用之间在项目范围内添加/删除了多少字节。
Mathias Bynens 2012年

1
| wc -c如果您使用-cat-file -s而不是可以跳过show
neu242

使用@ neu242建议的改进,我编写了此bash函数: gdbytes () { echo "$(git cat-file -s $1:$3) -> $(git cat-file -s $2:$3)" } 它使您可以轻松地查看自上次提交以来文件大小如何变化,例如gdbytes @~ @ index.html
–tknomad

如果some-ref:部分被跳过,您是否在工作目录中获得文件大小?
40名侦探


3

扩展matthiaskrgr的答案,可以像其他脚本一样使用https://github.com/matthiaskrgr/gitdiffbinstat

gitdiffbinstat.sh HEAD..HEAD~4

Imo它确实运行良好,比这里发布的任何其他东西都快得多。样本输出:

$ gitdiffbinstat.sh HEAD~6..HEAD~7
 HEAD~6..HEAD~7
 704a8b56161d8c69bfaf0c3e6be27a68f27453a6..40a8563d082143d81e622c675de1ea46db706f22
 Recursively getting stat for path "./c/data/gitrepo" from repo root......
 105 files changed in total
  3 text files changed, 16 insertions(+), 16 deletions(-) => [±0 lines]
  102 binary files changed 40374331 b (38 Mb) -> 39000258 b (37 Mb) => [-1374073 b (-1 Mb)]
   0 binary files added, 3 binary files removed, 99 binary files modified => [-3 files]
    0 b  added in new files, 777588 b (759 kb) removed => [-777588 b (-759 kb)]
    file modifications: 39596743 b (37 Mb) -> 39000258 b (37 Mb) => [-596485 b (-582 kb)]
    / ==>  [-1374073 b (-1 Mb)]

输出目录与.​​/c/data ...比较时髦,因为/ c实际上是文件系统的根目录。


您无需评论Matthias的帖子-您可以建议对其进行编辑,并提供他未提供的这些详细信息。按照当前的标准,他的答案将被认为是“仅链接的答案”,并且会被删除,因此这些细节非常重要。
Mogsdad '16

谁可以接受我的答案并将其纳入matthias?
来宾

如果需要,可以建议自己进行编辑。(根据我的经验,它可能会被审稿人拒绝,但是“编辑摘要”中的明确解释可能会有所帮助。)但是也许我对您的评论并不明确...您的答案是独立的答案,是Matthias较早答案的很好的更新。您仅需包含解释要发表评论的文字即可。我对答案的编辑方式应给予马蒂亚斯以应有的重视。您不需要做更多的事情。
Mogsdad '16

2

脚本的注释:git-file-size-diff,由patthoyts建议。该脚本非常有用,但是,我发现了两个问题:

  1. 当有人更改文件权限时,git在case语句中返回另一种类型:

    T) echo >&2 "Skipping change of type"
    continue ;;
    
  2. 如果不存在sha-1值(由于某种原因),脚本将崩溃。您需要在获取文件大小之前验证sha:

    $(git cat-file -e $D) if [ "$?" = 1 ]; then continue; fi

完整的case语句将如下所示:

case $M in
      M) $(git cat-file -e $D)
         if [ "$?" = 1 ]; then continue; fi
         $(git cat-file -e $C)
         if [ "$?" = 1 ]; then continue; fi
         bytes=$(( $(git cat-file -s $D) - $(git cat-file -s $C) )) ;;
      A) $(git cat-file -e $D)
         if [ "$?" = 1 ]; then continue; fi
         bytes=$(git cat-file -s $D) ;;
      D) $(git cat-file -e $C)
         if [ "$?" = 1 ]; then continue; fi
         bytes=-$(git cat-file -s $C) ;;
      T) echo >&2 "Skipping change of type"
         continue ;;
      *)
        echo >&2 warning: unhandled mode $M in \"$A $B $C $D $M $P\"
        continue
        ;;
    esac
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.