如何从Git中的特定修订中检索单个文件

时间:2009-03-04 11:43:13

标签: git single-file

我有一个Git存储库,我想看看几个月之前有些文件的样子。我在那个日期找到了修订版,它是27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8。我需要查看一个文件的外观,并将其保存到文件中。

我设法使用gitk查看该文件,但它没有保存选项。我尝试使用命令行工具,我得到的最接近的是:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

但是,此命令显示diff而不是文件内容。我知道我以后可以使用类似PAGER=cat的内容并将输出重定向到文件,但我不知道如何获取实际的文件内容。

基本上,我正在寻找像 svn cat 这样的东西。

11 个答案:

答案 0 :(得分:654)

要完成自己的答案,语法确实是

git show object
git show $REV:$FILE
git show somebranch:from/the/root/myfile.txt
git show HEAD^^^:test/test.py

该命令采用通常的修订方式,这意味着您可以使用以下任何一种方法:

  1. 分支机构名称(由suggested提供ash
  2. HEAD + x个^个字符
  3. 给定修订版的SHA1哈希值
  4. 给定SHA1哈希的前几个(可能是5个)字符
  5. 提示请务必记住,使用“git show”时,始终指定来自存储库根目录的路径,而不是当前目录位置。

    (虽然Mike Morearty提到,至少在git 1.7.5.4中,你可以通过在路径的开头放置“./”来指定相对路径 - 例如:

    git show HEAD^^:./test.py
    


    在git1.5.x之前,这是通过一些管道完成的:

    git ls-tree <rev>
      显示提交中的一个或多个“blob”对象的列表

    git cat-file blob <file-SHA1>
      cat一个文件,因为它已在特定修订版本中提交(类似于svn   猫)。   使用git ls-tree来检索给定文件的值-sha1

    git cat-file -p $(git-ls-tree $REV $file | cut -d " " -f 3 | cut -f 1)::
    

    git-ls-tree列出了$ REV版本中$ file的对象ID,这是从输出中删除并用作git-cat-file的参数,它应该被称为git-cat-object,并简单地将该对象转储到stdout。


    注意:自Git 2.11(2016年第4季度)起,您可以将内容过滤器应用于git cat-file输出!

    请参阅commit 3214594commit 7bcf341(2016年9月9日),commit 7bcf341(2016年9月9日)和commit b9e62f6commit 16dcc29(2016年8月24日) Johannes Schindelin (dscho)
    (由Junio C Hamano -- gitster --合并于commit 7889ed2,2016年9月21日)

      

    cat-file:以批处理模式支持--textconv / --filters

         

    即使“git hash-objects”是一个获取文件系统数据流并将其放入Git对象存储库的工具,但允许执行“外部世界到Git”的转换(例如行结束转换和清理过滤器的应用),默认情况下从早期就开始使用它的反向操作“git cat-file”,它从Git对象存储中获取一个对象并进行外部化对于外界的消费,缺乏运行“Git-to-outside-world”的等效机制

    git config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <"
    git cat-file --textconv --batch
    

    注意:“git cat-file --textconv”最近(2017年)启动了segfaulting,其中 已在Git 2。5(2017年第4季度)中更正

    commit cc0ea7cJeff King (peff)(2017年9月21日) Junio C Hamano -- gitster --合并于commit bfbc2fc,2017年9月28日)

答案 1 :(得分:467)

如果您希望替换/覆盖当前分支中的文件内容与来自先前提交或不同分支的文件内容,您可以使用以下命令执行此操作:< / p>

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

git checkout mybranchname path/to/file.txt

然后,您必须提交这些更改,以使它们在当前分支中生效。

答案 2 :(得分:136)

您需要提供文件的完整路径:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt

答案 3 :(得分:78)

最简单方式是写:

git show HASH:file/path/name.ext > some_new_name.ext

其中:

  • HASH 是Git修订版SHA-1哈希编号
  • file / path / name.ext 是您要查找的文件的名称
  • some_new_name.ext 是应保存旧文件的路径和名称

实施例

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:my_file.txt > my_file.txt.OLD

这会将 my_file.txt 从修订版 27cf8e 保存为名为 my_file.txt.OLD 的新文件

使用Git 2.4.5测试。

如果您想检索已删除的文件,可以使用HASH~1(在指定的HASH之前提交一次)。

实施例

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt

答案 4 :(得分:10)

在Windows中,使用Git Bash:

  • 在您的工作区中,将dir更改为文件所在的文件夹
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext

答案 5 :(得分:6)

很好地将其转储到一个文件中(至少在Windows上) - Git Bash:

$ echo "`git show 60d8bdfc:src/services/LocationMonitor.java`" >> LM_60d8bdfc.java

需要"引号,因此它会保留换行符。

答案 6 :(得分:3)

这将帮助您在不指定路径的情况下在提交之间获取所有已删除的文件,如果删除了大量文件,则非常有用。

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1

答案 7 :(得分:2)

除了其他答案列出的所有选项之外,您还可以将git reset与感兴趣的Git对象(哈希,分支,HEAD~x,标签,...)以及您的路径一起使用文件:

git reset <hash> /path/to/file

在您的示例中:

git reset 27cf8e8 my_file.txt

这是因为它将在索引的提交my_file.txt处将27cf8e8还原到其版本,同时在工作目录中保持不变(以当前版本为准)。

从那里开始,事情很简单:

  • 您可以将文件的两个版本与git diff --cached my_file.txt
  • 进行比较
  • 如果您认为自己不喜欢文件的旧版本,可以使用git restore --staged file.txt(或者,在Git v2.23之前为git reset file.txt)。
  • 您可以使用git commit -m "Restore version of file.txt from 27cf8e8"git restore file.txt(或在Git v2.23之前的git checkout -- file.txt)恢复旧版本
  • 通过运行git add -p file.txt(然后是git commitgit restore file.txt),您只能为某些功能块将旧版本的更新添加到新版本。

最后,如果您运行,甚至可以在第一步中交互式地选择要重置的大块:

git reset -p 27cf8e8 my_file.txt

因此,git reset带路径为您提供了很大的灵活性,可以检索文件的特定版本以与当前检出的版本进行比较,如果选择这样做,则可以完全还原或仅还原某些版本帅到那个版本。


编辑:我只是意识到我没有回答您的问题,因为您想要的不是获取部分或全部旧版本的差异或简单方法,而是简单地{{1 }}该版本。

当然,您可以通过以下方式重置文件:

cat

输出到标准输出或

git show :file.txt

但是,如果这就是您想要的,那么按照其他人的建议直接与git show :file.txt > file_at_27cf8e8.txt 运行git show当然会更直接。

我将留下这个答案,因为直接运行git show 27cf8e8:file.txt可以让您立即获得该旧版本,但是如果您要使用它进行某些操作,从那里开始这样做并不方便就像您在索引中重置该版本一样。

答案 8 :(得分:1)

使用其他人已经指出的 git show $REV:$FILE 可能是正确的答案。我发布了另一个答案,因为当我尝试这种方法时,有时会从 git 中收到以下错误:

fatal: path 'link/foo' exists on disk, but not in 'HEAD'

当文件路径的一部分是符号链接时会出现问题。在这些情况下,git show $REV:$FILE 方法将不起作用。重现步骤:

$ git init .
$ mkdir test
$ echo hello > test/foo
$ ln -s test link
$ git add .
$ git commit -m "initial commit"
$ cat link/foo
hello
$ git show HEAD:link/foo
fatal: path 'link/foo' exists on disk, but not in 'HEAD'

问题是,像 realpath 这样的实用程序在这里没有帮助,因为符号链接可能不再存在于当前提交中。我不知道一个好的通用解决方案。就我而言,我知道符号链接只能存在于路径的第一个组件中,因此我通过使用 git show $REV:$FILE 方法两次解决了该问题。这是有效的,因为当 git show $REV:$FILE 用于符号链接时,它的目标会被打印:

$ git show HEAD:link
test

对于目录,该命令将输出一个标题,然后是目录内容:

$ git show HEAD:test
tree HEAD:test

foo

因此,在我的情况下,我只是检查了对 git show $REV:$FILE 的第一次调用的输出,如果它只是一行,那么我将路径的第一个组件替换为结果以通过 git 解析符号链接.

答案 9 :(得分:0)

git checkout {SHA1} -- filename

此命令从特定提交中获取复制的文件。

答案 10 :(得分:-2)

通过签出先前的提交和复制文件来获取先前提交的文件。

  • 请注意您所在的分支:git branch
  • 查看您想要的上一次提交:git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • 将您想要的文件复制到临时位置
  • 查看您开始的分支:git checkout theBranchYouNoted
  • 复制您放置在临时位置的文件
  • 将您的更改提交给git:git commit -m "added file ?? from previous commit"