Equivalent in git of "hg cat" or "svn cat"

GitVersion Control

Git Problem Overview


I want to extract a copy of the latest version of a file held in a git repository, and pass it into a script for some processing. With svn or hg, I just use the "cat" command:

> Print the specified files as they were at the given revision. If > no revision is given, the parent of the working directory is used, > or tip if no revision is checked out.

(that's from the description of hg cat in the hg documentation)

What's the equivalent command to do this with git?

Git Solutions


Solution 1 - Git

git show rev:path/to/file

Where rev is the revision.

See http://git.or.cz/course/svn.html for a comparison of git and svn commands.

Solution 2 - Git

there is "git cat-file" which you can run like this:

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

where you can replace 'v1.0' with the branch, tag or commit SHA you want and then 'path/to/file' with the relative path in repository. You can also pass '-s' to see the size of the content if you want.

might be closer to the 'cat' commands you are used to, though the previously mentioned 'show' will do much the same thing.

Solution 3 - Git

git show is the command you are looking for. From the 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.

Solution 4 - Git

Also work with branch names (like HEAD in the 1st p) :

git show $branch:$filename

Solution 5 - Git

Use git show, as in git show commit_sha_id:path/to/some/file.cs.

Solution 6 - Git

I wrote a git cat shell script, which is up on github

Solution 7 - Git

There doesn't appear to be a direct substitute. This blog entry details how to do the equivalent by determining the latest commit, then determining the hash for the file in that commit, and then dumping it out.

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

(the blog entry has typos and uses the above with the command svn)

Solution 8 - Git

None of the git show suggestions truly satisfy because (try as I might), I can not find a way not to get the metadata cruft from the top of the output. The spirit of cat(1) is just to show the contents. This (below) takes a file name and an optional number. The number is how commits you want to go back. (Commits that changed that file. Commits that do not change the target file are not counted.)

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

shows the contents of filename.txt as of the latest commit of filename.txt and the contents from 3 commits before that.

#!/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 );
}

Solution 9 - Git

For those using bash the following is a useful function:

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

Put it in your .bashrc file (you can use whatever name you like other than gcat.

Example usage:

> gcat
Usage: gcat [rev] file

or

> gcat subdirectory/file.ext

or

> gcat rev subdirectory/file.ext

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRichard BoultonView Question on Stackoverflow
Solution 1 - GitTor ValamoView Answer on Stackoverflow
Solution 2 - GitScott ChaconView Answer on Stackoverflow
Solution 3 - GitAndrew AylettView Answer on Stackoverflow
Solution 4 - GitRzRView Answer on Stackoverflow
Solution 5 - GitJohn FeminellaView Answer on Stackoverflow
Solution 6 - GitRyanWilcoxView Answer on Stackoverflow
Solution 7 - GitBrian AgnewView Answer on Stackoverflow
Solution 8 - GitneniuView Answer on Stackoverflow
Solution 9 - GitMattView Answer on Stackoverflow