将命令应用于所有提交

时间:2012-02-04 10:02:23

标签: git

为了收集一些关于Git存储库的统计信息,我正在寻找一种方法来执行以下操作:

  • 对于每次提交,执行命令(例如du -h)。
  • 该命令应该在提交后“看起来像”一样从存储库基目录运行。
  • 理想情况下,该命令可以访问提交哈希和时间戳。

以准Bash表示的一个应用程序将运行

echo $HASH $TIME `du -hs --exclude=".git" . | awk '{ print $1; }'` >> ../sizeovertime

在所有提交中了解存储库的增长。

(不知何故,感觉应该可以使用git filter-branch --tree-filter,但这对我来说看起来很可怕。)

2 个答案:

答案 0 :(得分:7)

要计算repo中每个提交的大小,检查每个提交都会很慢。首先,您正在复制批次的工作,因为您将重新计算不变的文件大小。此外,您将不断检查文件系统。 这是一个查询git repo以获取所需信息的脚本。主要的好处是你从来没有真正查看任何blob来计算它们的大小,但只是请git告诉你。此外,您只需查询每个blob一次的git(通过Memoize的魔力) 毫无疑问,这个脚本需要工作(一个autodie来捕获任何git失败将是一个好主意),但它应该给你一个开始的地方。 (我从原始发布中修改了这个,以包含一个可以用作refspec的参数。如果没有参数调用,则会打印历史记录中每个提交的信息。您可以将ref-spec作为rev-list传递给限制工作。例如,如果你有标签v0和v1,你可以传递“v0..v1”作为第一个参数。)

#!/usr/bin/env perl

use warnings;
use strict;
use Memoize;

my $rev_list = $ARGV[ 0 ] || "--all";

# Query git for the size of a blob.  This is memoized, so we only
# ask for any blob once.
sub get_blob_size($) {
    my $hash = shift;
    my $size = qx( git cat-file -s $hash );
    return int( $size );
}
memoize( 'get_blob_size' );

# Recursively compute the size of a tree.  Note that git cat-file -s
# does not give the cumulative size of all the blobs in a tree.
sub compute_tree_size($);
sub compute_tree_size($) {
    my $sha = shift;
    my $size;
    open my $objects, '-|', "git cat-file -p $sha";
    while( <$objects> ) {
        my ( $mode, $type, $hash, $name ) = split;
        if( $type eq 'blob' ) {
            $size += get_blob_size( $hash );
        } elsif( $type eq 'tree' ) {
            $size += compute_tree_size( $hash );
        }
    }
    return $size;
}
memoize( 'compute_tree_size' );

# Generate a list of all commits
open my $objects, '-|', "git rev-list $rev_list |
    git cat-file --batch-check";

# Traverse the commit list and report on the size of each.
while( <$objects> ) {
    my( $commit, $type, $size ) = split;
    my( $tree, $date ) = split( '@',
        qx( git show --format="%T@%ci" $commit | sed 1q ));
    chop $date;
    printf "$date: %d\n", compute_tree_size $tree;
}

答案 1 :(得分:2)

我没有看到如何在不检查每个提交的情况下执行此操作,因此在大型存储库中需要一段时间。

以下是你如何用bash来解决这个问题:

#! /bin/bash

while read co dt ; do
    git checkout $co > /dev/null 2>&1
    size=$(du -hs --exclude=.git|cut -f1)
    echo $co $size $dt
done < <(git rev-list --pretty=format:"%H %ci" --all --date-order |grep -v "^commit")

警告:这将使您处于最早的提交状态,这是一个不太好的地方。