Odpowiednik w git „hg cat” lub „svn cat”

84

Chcę wyodrębnić kopię najnowszej wersji pliku przechowywanego w repozytorium git i przekazać ją do skryptu w celu przetworzenia. W przypadku svn lub hg używam po prostu polecenia „cat”:

Wydrukuj określone pliki tak, jak były w danej wersji. Jeśli nie podano żadnej wersji, używany jest katalog macierzysty katalogu roboczego lub wskazówka, jeśli żadna wersja nie jest pobierana.

(to z opisu hg cat w dokumentacji hg)

Jakie jest równoważne polecenie, aby zrobić to z git?

Richard Boulton
źródło
4
Ostatnim rozwiązaniem było użycie najpierw „git ls-files --full-name <ścieżka pliku>”, aby uzyskać pełną ścieżkę względem początku repozytorium, a następnie „git show HEAD: <pełna ścieżka pliku>”
Richard Boulton
1
możliwy duplikat Czy istnieje szybkie polecenie git, aby wyświetlić starą wersję pliku?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

113
git show rev:path/to/file

Gdzie rev jest wersją.

Zobacz http://git.or.cz/course/svn.html w celu porównania poleceń git i svn.

Tor Valamo
źródło
1
U mnie to działa! (Używając HEAD jako wersji) Myślę, że muszę użyć ścieżki względem góry repozytorium, co jest trochę uciążliwe, ale wykonalne.
Richard Boulton,
@Richard Boulton: jest to mniej bolesne, jeśli używasz uzupełniania kart
ks1322
@pimlottc działało dobrze dla mnie bez ./ - może zależeć od wersji git
Trejkaz
9

jest "git cat-file", który możesz uruchomić w ten sposób:

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

gdzie możesz zamienić „v1.0” na gałąź, tag lub zatwierdzenie SHA, które chcesz, a następnie „ścieżkę / do / pliku” na ścieżkę względną w repozytorium. Możesz także podać „-s”, aby zobaczyć rozmiar zawartości, jeśli chcesz.

może być bliżej poleceń 'cat', do których jesteś przyzwyczajony, chociaż wcześniej wspomniane polecenie 'show' zrobi mniej więcej to samo.

Scott Chacon
źródło
6

git showto polecenie, którego szukasz. Z dokumentacji:

   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.
Andrew Aylett
źródło
To wydaje się nie działać: uruchomienie „git show next ~ 1: README” daje fatalny: niejednoznaczny argument „next ~ 1: README”: nieznana wersja lub ścieżka poza drzewem roboczym. Użyj znaku „-”, aby oddzielić ścieżki od wersji
Richard Boulton
1
Czy masz oddział o nazwie „następny”? Jeśli chcesz mieć bieżącą gałąź, użyj zamiast tego „HEAD”.
Andrew Aylett
3

Pracuj także z nazwami gałęzi (jak HEAD w pierwszym p):

git show $branch:$filename
RzR
źródło
2

Użyj git show, jak w git show commit_sha_id:path/to/some/file.cs.

John Feminella
źródło
2

Napisałem skrypt powłoki git cat, który jest na githubie

RyanWilcox
źródło
1
Spojrzenie na kod było pomocne, chociaż chciałem mieć samodzielny skrypt w Pythonie i nie potrzebowałem wszystkich funkcji git cat. Dzięki.
Richard Boulton,
1

Wydaje się, że nie ma bezpośredniego substytutu. Ten wpis w blogu szczegółowo opisuje, jak zrobić odpowiednik, określając najnowsze zatwierdzenie, następnie określając skrót dla pliku w tym zatwierdzeniu, a następnie zrzucając go.

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

(wpis na blogu zawiera literówki i używa powyższego z poleceniem svn)

Brian Agnew
źródło
Wpis na blogu był pomocny pomimo literówek.
Richard Boulton,
0

Żadna z git showsugestii nie jest prawdziwie zadowalająca, ponieważ (chociaż mogę spróbować), nie mogę znaleźć sposobu, aby nie uzyskać metadanych z góry wyniku. Duch kota (1) służy tylko do pokazania zawartości. To (poniżej) przyjmuje nazwę pliku i opcjonalny numer. Liczba określa, jak zmiany chcesz cofnąć. (Zatwierdzenia, które zmieniły ten plik. Zatwierdzenia, które nie zmieniają pliku docelowego, nie są liczone).

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

pokazuje zawartość nazwy_pliku.txt od ostatniego zatwierdzenia nazwy_pliku.txt oraz zawartość trzech wcześniejszych zatwierdzeń.

#!/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 );
}
neniu
źródło
0

Dla osób używających basha przydatna jest następująca funkcja:

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

Umieść go w swoim .bashrcpliku (możesz użyć dowolnej nazwy innej niż gcat.

Przykładowe użycie:

> gcat
Usage: gcat [rev] file

lub

> gcat subdirectory/file.ext

lub

> gcat rev subdirectory/file.ext
Matt
źródło