952

我有一个 Git 存储库,我想看看几个月前一些文件的样子。我在那个日期找到了修订版;它是27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8。我需要查看一个文件的外观,并将其另存为(“新”)文件。

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

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

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

基本上,我正在寻找类似svn cat的东西。

4

11 回答 11

877

使用git show

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

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

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

  1. 分支名称(由ash建议
  2. HEAD+ x^字符数
  3. 给定修订版的 SHA1 哈希
  4. 给定 SHA1 哈希的前几个(可能是 5 个)字符

提示请务必记住,在使用“ git show”时,始终指定从存储库根目录开始的路径,而不是当前目录位置。

(尽管Mike Morearty提到,至少在 git 1.7.5.4 中,您可以通过将“ ./”放在路径的开头来指定相对路径。例如:

git show HEAD^^:./test.py

)

使用git restore

使用 Git 2.23+(2019 年 8 月),您还可以使用git restore which 替换令人困惑的git checkout命令

git restore -s <SHA1>     -- afile
git restore -s somebranch -- afile

这将仅在工作树上恢复“源”(-s提交 SHA1 或分支中存在的文件somebranch
要恢复索引:

git restore -s <SHA1> -SW -- afile

( -SW: 缩写--staged --worktree)


正如starwarswii的评论中所指出的那样

它允许您将内容通过管道传输到文件中,如果您只想快速比较提交中的文件,这非常有用。

例如,您可以这样做:

git show 1234:path/to/file.txt > new.txt 
git show 1234~:path/to/file.txt > old.txt

然后比较它们。


使用低级 git 管道命令

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

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

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

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

git-ls-tree列出了$file在修订中的对象 ID $REV,这被从输出中删除并用作 的参数git-cat-file,它应该真正被调用git-cat-object,并且只是将该对象转储到stdout.


注意:从 Git 2.11(2016 年第四季度)开始,您可以将内容过滤器应用于git cat-file输出。

请参阅 Johannes Schindelin ( )的提交3214594、 提交7bcf341 ( 2016 年 9 月 9 日)、 提交 7bcf341(2016 年 9 月 9 日)和 提交 b9e62f6提交 16dcc29(2016 年 8 月 24 日) 。(由Junio C Hamano 合并——提交 7889ed2中,2016 年 9 月 21 日)dscho
gitster

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

注意:“ git cat-file --textconv”最近(2017 年)开始出现段错误,已在 Git 2.15(2017 年第四季度)中更正

请参阅Jeff King ( )提交的 cc0ea7c (2017 年 9 月 21 日) 。(由Junio C Hamano 合并——提交 bfbc2fc中,2017 年 9 月 28 日)peff
gitster

于 2009-03-04T12:22:46.363 回答
536

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

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

或者

git checkout mybranchname path/to/file.txt

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

于 2010-11-18T19:41:15.470 回答
159

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

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
于 2009-03-04T11:46:35.593 回答
125

简单的方法是写:

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

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

它使用 Git 2.4.5 进行了测试。

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

例子:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt
于 2015-07-07T13:55:10.950 回答
12

在 Windows 中,使用 Git Bash:

  • 在您的工作区中,将 dir 更改为文件所在的文件夹
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
于 2015-03-02T16:17:24.793 回答
12
git checkout {SHA1} -- filename

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

于 2019-09-28T19:42:48.537 回答
8

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

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

引号是必需的",因此它保留换行符。

于 2014-01-01T16:56:44.750 回答
7

除了其他答案列出的所有选项之外,您还可以使用感兴趣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"您可以使用and恢复旧版本git restore file.txt(或者,在 Git v2.23 之前,git checkout -- file.txt
  • git add -p file.txt您可以通过运行(然后git commit和)将更新从旧版本添加到新版本git restore file.txt

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

git reset -p 27cf8e8 my_file.txt

因此git reset,使用路径为您提供了很大的灵活性来检索文件的特定版本以与其当前签出的版本进行比较,如果您选择这样做,则可以完全或仅将某些大块恢复到该版本。


编辑:我刚刚意识到我没有回答您的问题,因为您想要的不是差异或检索部分或全部旧版本的简单方法,而只是检索cat该版本。

当然,您仍然可以在使用以下命令重置文件后执行此操作:

git show :file.txt

输出到标准输出或

git show :file.txt > file_at_27cf8e8.txt

但是,如果这就是您想要的,那么按照其他人的建议git show直接运行git show 27cf8e8:file.txt当然要直接得多。

我将留下这个答案,因为git show直接运行可以让你立即获得那个旧版本,但是如果你想用它做一些事情,那么从那里这样做并不像你重置那个版本那样方便在索引中。

于 2020-09-13T23:58:58.313 回答
5

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

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1
于 2014-07-24T02:34:05.370 回答
2

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 解析符号链接的结果。

于 2020-12-23T11:42:54.813 回答
0

通过检出先前的提交和复制文件从先前的提交中获取文件。

  • 注意你在哪个分支:git branch
  • 签出您想要的上一个提交:git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • 将您想要的文件复制到临时位置
  • 签出您开始的分支: git checkout theBranchYouNoted
  • 复制您放置在临时位置的文件
  • 将您的更改提交到 git:git commit -m "added file ?? from previous commit"
于 2011-07-22T15:05:16.167 回答