Äquivalent in git von "hg cat" oder "svn cat"

84

Ich möchte eine Kopie der neuesten Version einer Datei extrahieren, die sich in einem Git-Repository befindet, und sie zur Verarbeitung an ein Skript übergeben. Mit svn oder hg benutze ich einfach den Befehl "cat":

Drucken Sie die angegebenen Dateien so, wie sie bei der angegebenen Revision waren. Wenn keine Revision angegeben ist, wird das übergeordnete Element des Arbeitsverzeichnisses verwendet, oder Tipp, wenn keine Revision ausgecheckt ist.

(das ist aus der Beschreibung von hg cat in der hg Dokumentation)

Was ist der entsprechende Befehl, um dies mit git zu tun?

Richard Boulton
quelle
4
Meine endgültige Lösung bestand darin, zuerst "git ls-files --full-name <Dateipfad>" zu verwenden, um den vollständigen Pfad relativ zum oberen Rand des Repositorys abzurufen, und dann "git show HEAD: <vollständiger Dateipfad>"
Richard Boulton
1
Mögliches Duplikat von Gibt es einen schnellen git-Befehl, um eine alte Version einer Datei anzuzeigen?
Ciro Santilli 法轮功 冠状: 六四 事件 10

Antworten:

112
git show rev:path/to/file

Wo rev die Revision ist.

Unter http://git.or.cz/course/svn.html finden Sie einen Vergleich der Befehle git und svn.

Tor Valamo
quelle
1
Das funktioniert bei mir, yay! (Verwenden von HEAD als Revision) Ich denke, ich muss den Pfad relativ zum oberen Rand des Repositorys verwenden, was ein bisschen schmerzhaft, aber praktikabel ist.
Richard Boulton
@ Richard Boulton: Dies ist weniger schmerzhaft, wenn Tab-Vervollständigung verwenden
ks1322
@pimlottc funktionierte gut für mich ohne die ./ - könnte von der Git-Version abhängen
Trejkaz
9

Es gibt eine "Git Cat-Datei", die Sie folgendermaßen ausführen können:

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

Hier können Sie 'v1.0' durch den gewünschten Zweig, Tag oder Commit-SHA ersetzen und dann 'path / to / file' durch den relativen Pfad im Repository. Sie können auch '-s' übergeben, um die Größe des Inhalts anzuzeigen, wenn Sie möchten.

Möglicherweise näher an den 'cat'-Befehlen, an die Sie gewöhnt sind, obwohl die zuvor erwähnte' show 'fast dasselbe bewirkt.

Scott Chacon
quelle
5

git showist der Befehl, den Sie suchen. Aus der Dokumentation:

   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
quelle
Das scheint nicht zu funktionieren: Das Ausführen von "git show next ~ 1: README" führt zu einem schwerwiegenden: mehrdeutigen Argument "next ~ 1: README": unbekannte Revision oder Pfad nicht im Arbeitsbaum. Verwenden Sie '-', um Pfade von Revisionen zu trennen
Richard Boulton
1
Haben Sie eine Filiale namens "next"? Wenn Sie den aktuellen Zweig möchten, verwenden Sie stattdessen 'HEAD'.
Andrew Aylett
3

Arbeiten Sie auch mit Filialnamen (wie HEAD im 1. S.):

git show $branch:$filename
RzR
quelle
2

Verwenden Sie git show, wie in git show commit_sha_id:path/to/some/file.cs.

John Feminella
quelle
2

Ich habe ein Git Cat Shell-Skript geschrieben, das auf Github läuft

RyanWilcox
quelle
1
Das Anschauen des Codes war hilfreich, obwohl ich ein eigenständiges Python-Skript wollte und nicht alle Funktionen von git cat benötigte. Vielen Dank.
Richard Boulton
1

Es scheint keinen direkten Ersatz zu geben. In diesem Blogeintrag wird beschrieben, wie Sie das Äquivalent erstellen, indem Sie das letzte Commit ermitteln, dann den Hash für die Datei in diesem Commit ermitteln und dann ausgeben.

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

(Der Blogeintrag enthält Tippfehler und verwendet die oben genannten mit dem Befehl svn)

Brian Agnew
quelle
Der Blogeintrag war trotz der Tippfehler hilfreich.
Richard Boulton
0

Keiner der git showVorschläge ist wirklich zufriedenstellend, da ich (wie ich es auch versuchen könnte) keinen Weg finden kann, die Metadaten-Cruft nicht vom oberen Rand der Ausgabe abzurufen. Der Geist der Katze (1) besteht nur darin, den Inhalt zu zeigen. Dies (unten) nimmt einen Dateinamen und eine optionale Nummer an. Die Zahl gibt an, wie festgeschrieben werden soll. (Commits, die diese Datei geändert haben. Commits, die die Zieldatei nicht ändern, werden nicht gezählt.)

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

Zeigt den Inhalt von filename.txt ab dem letzten Commit von filename.txt und den Inhalt von 3 Commits zuvor an.

#!/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
quelle
0

Für diejenigen, die bash verwenden, ist Folgendes eine nützliche Funktion:

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

Fügen Sie es in Ihre .bashrcDatei ein (Sie können einen beliebigen Namen verwenden, außergcat .

Anwendungsbeispiel:

> gcat
Usage: gcat [rev] file

oder

> gcat subdirectory/file.ext

oder

> gcat rev subdirectory/file.ext
Matt
quelle