一尘不染

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

git

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

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

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

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

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


阅读 131

收藏
2022-02-20

共2个答案

一尘不染

使用git show

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

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

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

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

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

至少在 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)

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

例如,您可以这样做:

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

2022-02-20
一尘不染

除了其他答案列出的所有选项之外,您还可以使用感兴趣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直接运行可以让你立即获得那个旧版本,但是如果你想用它做一些事情,那么从那里这样做并不像你重置那个版本那样方便在索引中。

2022-02-20