"hg cat" 或者 "svn cat" 在 git 中的等价命令是什么?

90
我想从git仓库中提取最新版本的文件副本,并将其传递到脚本进行处理。对于svn或hg,我只需使用“cat”命令:

按给定修订版打印指定的文件。如果没有给出修订版,则使用工作目录的父级,如果没有检出修订版,则使用tip。

(这是来自hg文档中hg cat的描述)
那么在git中,如何执行相同的操作呢?

4
我的最终解决方案是,首先使用“git ls-files --full-name <文件路径>”获取相对于代码库顶部的完整路径,然后使用“git show HEAD:<完整文件路径>”。 - Richard Boulton
1
可能是重复的问题:如何从Git的特定版本中检索单个文件? - ks1322
1
可能是Is there a quick git command to see an old version of a file?的重复问题。 - Ciro Santilli OurBigBook.com
9个回答

122

1
这对我有用,耶!(使用HEAD作为修订版本)我认为我需要使用相对于存储库顶部的路径,这有点麻烦,但可行。 - Richard Boulton
@Richard Boulton:如果使用制表符自动完成,这将会更加轻松。 - ks1322
@pimlottc 对我来说运行得很好,不需要加上 ./ ,可能取决于 git 版本。 - Hakanai
1
该链接 http://git.or.cz/course/svn.html 返回403禁止访问。 - David Dyck

11

有一个名为 "git cat-file" 的命令,可以这样运行:

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

你可以将 'v1.0' 替换为所需的分支、标签或提交的SHA值,然后将 'path/to/file' 替换为仓库中文件的相对路径。如果需要,你也可以传递 '-s' 参数来查看内容大小。

这个命令可能更接近你所熟悉的 'cat' 命令,虽然前面提到的 'show' 命令也会完成类似的工作。


7

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”会产生以下错误:fatal: ambiguous argument 'next~1:README': unknown revision or path not in the working tree. Use '--' to separate paths from revisions - Richard Boulton
1
你有一个名为“next”的分支吗?如果你想要当前的分支,请使用“HEAD”代替。 - Andrew Aylett

3
使用 git show 命令,例如:git show commit_sha_id:path/to/some/file.cs

3

同时也适用于分支名称(例如第一个段落中的HEAD):

git show $branch:$filename

2
我写了一个git cat的shell脚本,它在github上发布了。

1
看那段代码很有帮助,但我需要一个独立的Python脚本,而不需要git cat的所有功能。谢谢。 - Richard Boulton

1

似乎没有一个直接的替代方法。这篇博客文章详细介绍了如何通过确定最新提交,然后确定该提交中文件的哈希值,最后将其转储来实现等效操作。

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

(博客文章有错别字,并使用上述命令svn


博客文章虽然有错别字,但还是很有帮助的。 - Richard Boulton

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

0

没有一个git show的建议真正满足我的需求,因为(尽我所能地尝试),我找不到一种方法来避免在输出顶部获取元数据垃圾。cat(1)的精神只是显示内容。 下面的代码接受一个文件名和一个可选的数字。这个数字表示你想要回溯多少次提交。(只计算那些改变了该文件的提交。没有改变目标文件的提交不计入其中。)

gitcat.pl filename.txt
gitcat.pl -3 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 );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接