Équivalent en git de «hg cat» ou «svn cat»


84

Je souhaite extraire une copie de la dernière version d'un fichier conservé dans un référentiel git et la transmettre dans un script pour un traitement. Avec svn ou hg, j'utilise simplement la commande "cat":

Imprimez les fichiers spécifiés tels qu'ils étaient à la révision donnée. Si aucune révision n'est donnée, le parent du répertoire de travail est utilisé, ou pointe si aucune révision n'est extraite.

(cela vient de la description de hg cat dans la documentation hg)

Quelle est la commande équivalente pour faire cela avec git?


4
Ma solution finale a été d'utiliser d'abord "git ls-files --full-name <filepath>" pour obtenir le chemin complet relatif au sommet du dépôt, puis "git show HEAD: <full-filepath>"
Richard Boulton


Réponses:


113
git show rev:path/to/file

rev est la révision.

Voir http://git.or.cz/course/svn.html pour une comparaison des commandes git et svn.


1
Cela fonctionne pour moi, yay! (En utilisant HEAD comme révision) Je pense que je dois utiliser le chemin relatif au sommet du référentiel, ce qui est un peu pénible, mais réalisable.
Richard Boulton

@Richard Boulton: c'est moins douloureux si vous utilisez la complétion par tabulation
ks1322

@pimlottc a bien fonctionné pour moi sans le ./ - pourrait dépendre de la version git
Trejkaz

9

il y a "git cat-file" que vous pouvez exécuter comme ceci:

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

où vous pouvez remplacer 'v1.0' par la branche, la balise ou le commit SHA que vous voulez, puis 'path / to / file' par le chemin relatif dans le référentiel. Vous pouvez également passer «-s» pour voir la taille du contenu si vous le souhaitez.

peut être plus proche des commandes 'cat' auxquelles vous êtes habitué, bien que le 'show' mentionné précédemment fasse à peu près la même chose.


6

git showest la commande que vous recherchez. De la documentation:

   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.

Cela ne semble pas fonctionner: exécuter "git show next ~ 1: README" produit un argument fatal: ambigu "next ~ 1: README": révision inconnue ou chemin non dans l'arborescence de travail. Utilisez '-' pour séparer les chemins des révisions
Richard Boulton

1
Avez-vous une succursale appelée «next»? Si vous voulez la branche actuelle, utilisez plutôt 'HEAD'.
Andrew Aylett

3

Travaillez également avec les noms de branche (comme HEAD dans le 1er p):

git show $branch:$filename


2

J'ai écrit un script shell git cat, qui est sur github


1
Regarder le code pour cela a été utile, même si je voulais un script python autonome et que je n'avais pas besoin de toutes les fonctionnalités de git cat. Merci.
Richard Boulton

1

Il ne semble pas y avoir de substitut direct . Cette entrée de blog explique comment faire l'équivalent en déterminant le dernier commit, puis en déterminant le hachage du fichier dans ce commit, puis en le vidant.

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

(l'entrée de blog a des fautes de frappe et utilise ce qui précède avec la commande svn)


L'entrée du blog a été utile, malgré les fautes de frappe.
Richard Boulton

0

Aucune des git showsuggestions ne satisfait vraiment parce que (essayez comme je pourrais), je ne peux pas trouver un moyen de ne pas obtenir les métadonnées crues du haut de la sortie. L'esprit de cat (1) est juste de montrer le contenu. Ceci (ci-dessous) prend un nom de fichier et un numéro facultatif. Le nombre correspond à la manière dont vous souhaitez revenir en arrière. (Les validations qui ont modifié ce fichier. Les validations qui ne modifient pas le fichier cible ne sont pas comptabilisées.)

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

affiche le contenu de filename.txt à partir du dernier commit de filename.txt et le contenu de 3 commits avant cela.

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

Pour ceux qui utilisent bash, la fonction suivante est utile:

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

Mettez-le dans votre .bashrcfichier (vous pouvez utiliser le nom de votre choix autre quegcat .

Exemple d'utilisation:

> gcat
Usage: gcat [rev] file

ou

> gcat subdirectory/file.ext

ou

> gcat rev subdirectory/file.ext
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.