Эквивалент git «hg cat» или «svn cat»

84

Я хочу извлечь копию последней версии файла, хранящегося в репозитории git, и передать ее в сценарий для некоторой обработки. С svn или hg я просто использую команду "cat":

Распечатать указанные файлы в том виде, в котором они были в данной ревизии. Если ревизия не указана, используется родительский рабочий каталог или подсказка, если ревизия не извлечена.

(это из описания hg cat в документации hg)

Какая эквивалентная команда делает это с помощью git?

Ричард Бултон
источник
4
Моим окончательным решением было сначала использовать «git ls-files --full-name <filepath>», чтобы получить полный путь относительно верхней части репозитория, а затем «git show HEAD: <full filepath>»
Ричард Бултон
1
возможный дубликат. Есть ли быстрая команда git для просмотра старой версии файла?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ответы:

113
git show rev:path/to/file

где rev - это ревизия.

См. Http://git.or.cz/course/svn.html для сравнения команд git и svn.

Тор Валамо
источник
1
У меня это работает, ура! (Использование HEAD в качестве ревизии) Я думаю, мне нужно использовать путь относительно верхней части репозитория, что немного неудобно, но работает.
Ричард Бултон
@Richard Boulton: это менее болезненно, если использовать завершение табуляции
ks1322
@pimlottc отлично работал у меня без ./ - может зависеть от версии git
Trejkaz
9

есть "git cat-file", который можно запустить следующим образом:

$ git cat-file blob v1.0:path/to/file

где вы можете заменить «v1.0» на нужный SHA ветки, тега или фиксации, а затем «путь / к / файлу» на относительный путь в репозитории. Вы также можете передать '-s', чтобы увидеть размер содержимого, если хотите.

может быть ближе к командам «cat», к которым вы привыкли, хотя ранее упомянутое «show» будет делать то же самое.

Скотт Чакон
источник
6

git showэто команда, которую вы ищете. Из документации:

   git show next~10:Documentation/README
          Shows the contents of the file Documentation/README as they were
          current in the 10th last commit of the branch next.
Эндрю Айлетт
источник
Похоже, это не работает: запуск «git show next ~ 1: README» дает фатальный: неоднозначный аргумент «next ~ 1: README»: неизвестная версия или путь не в рабочем дереве. Используйте '-' для отделения путей от исправлений
Ричард Бултон
1
У вас есть ветка под названием «следующая»? Если вам нужна текущая ветка, используйте вместо нее «HEAD».
Эндрю Айлетт
3

Также работайте с именами веток (например, HEAD в первом p):

git show $branch:$filename
RzR
источник
2

Используйте git show, как в git show commit_sha_id:path/to/some/file.cs.

Джон Феминелла
источник
2

Я написал сценарий оболочки git cat, который находится на github

Райан Уилкокс
источник
1
Было полезно взглянуть на код для этого, хотя я хотел автономный скрипт python и не нуждался во всех функциях git cat. Благодарю.
Ричард Бултон,
1

Похоже, прямой замены нет. В этой записи блога подробно описывается, как сделать эквивалент, определяя последнюю фиксацию, затем определяя хэш для файла в этой фиксации и затем выгружая его.

git log ...
git ls-tree ...
git show -p ...

(запись в блоге содержит опечатки и использует указанное выше с командой svn)

Брайан Агнью
источник
Запись в блоге была полезной, несмотря на опечатки.
Ричард Бултон,
0

Ни одно из git showпредложений по-настоящему не удовлетворяет, потому что (как бы я ни старался) я не могу найти способ не получить ненужные метаданные из верхней части вывода. Суть кота (1) в том, чтобы показать содержимое. Это (ниже) принимает имя файла и необязательный номер. Число - это то, как вы хотите вернуться. (Коммиты, которые изменили этот файл. Коммиты, которые не изменяют целевой файл, не учитываются.)

gitcat.pl filename.txt
gitcat.pl -3 filename.txt

показывает содержимое filename.txt на момент последней фиксации filename.txt и содержимое 3 коммитов до этого.

#!/usr/bin/perl -w

use strict;
use warnings;
use FileHandle;
use Cwd;

# Have I mentioned lately how much I despise git?

(my $prog = $0) =~ s!.*/!!;
my $usage = "Usage: $prog [revisions-ago] filename\n";

die( $usage ) if( ! @ARGV );
my( $revision, $fname ) = @ARGV;

if( ! $fname && -f $revision ) {
    ( $fname, $revision ) = ( $revision, 0 );
}

gitcat( $fname, $revision );

sub gitcat {
    my( $fname, $revision ) = @_;

    my $rev = $revision;
    my $file = FileHandle->new( "git log --format=oneline '$fname' |" );

    # Get the $revisionth line from the log.
    my $line;
    for( 0..$revision ) {
        $line = $file->getline();
    }

    die( "Could not get line $revision from the log for $fname.\n" ) 
        if( ! $line );

    # Get the hash from that.
    my $hash = substr( $line, 0, 40 );
    if( ! $hash =~ m/ ^ ( [0-9a-fA-F]{40} )/x ) {
        die( "The commit hash does not look a hash.\n" );
    }

    # Git needs the path from the root of the repo to the file because it can
    # not work out the path itself.
    my $path = pathhere();
    if( ! $path ) {
        die( "Could not find the git repository.\n" );
    }

    exec( "git cat-file blob $hash:$path/'$fname'" );
}


# Get the path from the git repo to the current dir.
sub pathhere {
    my $cwd = getcwd();
    my @cwd = split( '/', $cwd );
    my @path;

    while( ! -d "$cwd/.git" ) {
        my $path = pop( @cwd );
        unshift( @path, $path );
        if( ! @cwd ) {
            die( "Did not find .git in or above your pwd.\n" );
        }
        $cwd = join( '/', @cwd );
    }
    return join( '/', map { "'$_'"; } @path );
}
Нениу
источник
0

Для тех, кто использует bash, полезна следующая функция:

gcat () { if [ $# -lt 1 ]; then echo "Usage: $FUNCNAME [rev] file"; elif [ $# -lt 2 ]; then git show HEAD:./$*; else git show $1:./$2; fi }

Поместите его в свой .bashrcфайл (вы можете использовать любое имя, кроме gcat.

Пример использования:

> gcat
Usage: gcat [rev] file

или же

> gcat subdirectory/file.ext

или же

> gcat rev subdirectory/file.ext
Мэтт
источник