Как найти количество слов в каждом коммите git в истории репозитория? - PullRequest
3 голосов
/ 12 февраля 2012

Это касается количества слов, но я думаю, что это также касается запуска любой программы через все коммиты git в репозитории. Я пишу проект и поздно понял, что хочу программно генерировать количество слов после каждого коммита. Только для текстовых файлов. Но тогда, как получить счет за жизнь проекта? Я не мог найти простой способ сделать это, поэтому я спрашиваю об этом.

Мое решение состояло в том, чтобы автоматизировать ручной процесс проверки ветви для каждого отдельного коммита в жизни проекта и запустить мои маленькие сценарии shell / sed / perl, чтобы получить дату и количество слов:

#!/usr/bin/env perl

use strict;
use warnings;
use 5.014;
use App::gh::Git;
use IPC::System::Simple qw(capture);

my $repo = Git->repository( Directory => '/home/amiri/MyProject/.git' );
my @commits
    = reverse $repo->command( 'rev-list', '--all', '--date', 'short' );

my $command
    = qq{find /home/amiri/MyProject -name "*.tex" | xargs wc -w | grep total | sed 's/[a-zA-Z[:space:]]//g'};

my $command2
    = q{git log | grep "Date:" | sed -n 1p | perl -pi -e "s/^Date:\s+//g" | perl -pi -e "s/2011 -\d+$/UTC 2011/g"};

for my $commit (@commits) {
    $repo->command( "checkout", "-b", "$commit", "$commit" );
    my $count = capture($command);
    my $date  = capture($command2);
    chomp $date;
    say "$date,$count";
    $repo->command( "checkout", "master" );
    $repo->command( 'branch', "-d", $commit );
}

Итак, это работает, но я не могу не чувствовать, что есть лучший способ сделать это? Кажется немного неприглядным.

1 Ответ

4 голосов
/ 12 февраля 2012

Если вы хотели что-то более простое в реализации и не возражаете быть немного неоптимальным и глупым, вы можете сделать это:

for commit in `git rev-list --all`; do
    git log -n 1 --pretty=%ad $commit
    git archive $commit | tar -x -O | wc -w
done

Это намного короче, чем у вас, и я подозреваю, что это также может быть быстрее, потому что это избавляет от необходимости извлекать файлы на диск, чтобы просто прочитать их снова для подсчета слов. (Чтобы ограничить его только определенными файлами, вы можете передать их в качестве дополнительных аргументов git archive и заметить, что вы можете получить список всех файлов в данном коммите с помощью git ls-tree -r --name-only <commit>.)

Строка git log просто печатает дату фиксации. Если вы хотите больше, посмотрите на man git-log описание того, что вы можете сделать - по сути, есть тонны заполнителей, таких как %ad для даты автора, %s для темы коммита и так далее. Следующая строка делает работу. git archive предназначен для упаковки данного дерева в tar / zip для распространения; мы сразу распаковываем его и считаем слова. (Очевидно, что вы можете настроить выходной формат и заменить его в своем собственном механизме подсчета на wc -w, если хотите.)

Это уже довольно быстро - на многолетнем ноутбуке на коммит в репо с рабочим деревом 20 МБ уходит около четверти секунды.

Конечно, если вы действительно заботитесь о производительности, то, вероятно, абсолютный самый быстрый метод будет заключаться в том, чтобы при каждом коммите проходить по дереву, суммировать количество слов по каплям и хранить количество слов для каждого капли. так что вам не нужно пересчитывать их. Это чертовски много работы для реализации, хотя. Псевдокод может выглядеть так:

word_counts(range)
    for (commit in `git rev-list <range>`)
        sum = 0
        for (blob in second_field_of(`git ls-tree -r commit`))
            if (!counts[blob])
                counts[blob] = word_count(`git cat-file blob`)
             total_count += counts[blob]
         print pretty_format(commit), total_count

 pretty_format(commit)
     return `git log -n 1 --pretty=... commit`

Это позволяет избежать ненужных промежуточных шагов и дополнительно оптимизировать, избегая необходимости повторного чтения любых неизмененных файлов. В крошечных репозиториях это может быть не так уж важно, но в больших репозиториях это очень сложно - представьте себе репо объемом 20 МБ, в котором фиксируются в среднем сенсорные файлы общим размером 20 КБ.

...