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


831

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

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

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

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

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


73
此处的键:(git show无助)对冒号使用不同的语法。git show 2c7cf:my_file.txt
史蒂夫·贝内特

4
为了进一步说明,上述命令要求git显示两个单独的对象,即修订版和文件。下面接受的答案在两个项目之间使用冒号,要求在特定版本中使用特定文件。
jhclark 2012年

2
在* nix上,您不需要PAGER,只需使用>
Konstantin Pelepelin


对于那些希望将内容导出到某些文件的人,Checat有一个重要的评论。您需要这样的内容:git show {sha}:my_file.txt> old_my_file.txt
ormurin 2014年

Answers:


743

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

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”时,请始终指定从存储库根目录开始的路径,而不是当前目录位置。

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

git show HEAD^^:./test.py


在Git 2.23+(2019年8月)中,您也可以使用git restore 它代替令人困惑的git checkout命令

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

那将只在工作树上还原“ source”(-s提交SHA1或branch中存在的文件somebranch
要恢复索引:

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

-SW:的缩写--staged --worktree


在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列出了修订版$ REV中$ file的对象ID,它从输出中切出并用作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

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

即使“ git hash-objects”(用于获取文件系统上的数据流并将其放入Git对象存储的工具)也可以执行“外部世界到Git”转换(例如,行尾转换和应用程序清理过滤器),并且从很早开始就默认启用该功能,其反向操作“ git cat-file”从Git对象存储中获取一个对象并进行外部化以供外界使用,但缺少与之等效的机制运行“ Git到外部世界”

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()的commit cc0ea7c(2017年9月21日(由Junio C Hamano合并--commit bfbc2fc中,2017年9月28日)peff
gitster


请注意,要覆盖/替换具有过去内容的文件,您不应再使用令人困惑的git checkout命令,而应使用git restore(Git 2.23 +,2019年8月)

git restore -s <SHA1> -- afile

那只会在工作树上仅还原“源”(-s)中提交SHA1的文件。
要恢复索引:

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

-SW:的缩写--staged --worktree


6
@Oscar因为git show本质上是将内容转储到stdout(标准输出)上,所以您可以简单地将该输出重定向到所需的任何文件(tldp.org/LDP/abs/html/io-redirection.html)。
VonC 2012年

8
git checkout [branch | revision] filepath是正确的命令
Gaui

12
@Gaui,但git checkout会使用另一个版本来覆盖您的文件,与相对git show,它允许您以其他名称保存文件,以便获取和查看这两个文件(当前版本和旧版本)。从这个问题尚不清楚,OP是否要用旧版本替换其当前版本。
VonC

9
我想请注意,^^^也可以更一般地写为~~~,或者更好的,~3。使用波浪号还具有不触发某些外壳程序(例如zsh)的文件名匹配的优点。
Eric O Lebigot 2013年

2
我没有足够老的git来检查:1.5.x之前的版本是否git rev-parse处理rev:path语法?(在较新的git中,您也可以git cat-file -p $REV:path。但是,它也git show适用于目录路径,因此它不仅更短,而且通常更接近人们想要的内容。)
torek 2014年

510

如果您希望先前提交或其他分支中的文件内容替换/覆盖当前分支中的文件内容,可以使用以下命令:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

要么

git checkout mybranchname path/to/file.txt

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


4
最简单的解决方案,这就是git-checkout设计的目的-指定路径名意味着仅检出匹配的文件。来自git-checkout手册页:git checkout
master〜2

1
然后,如何在运行此命令之前返回到先前的状态?
弗林特

@Flint如果您来自HEAD状态,则就像git checkout HEAD一样简单-[完整路径]。
Tiago Espinha

72
请注意,这会覆盖该路径中的现有文件,而git show SHA1:PATH解决方案仅打印到stdout。
Flimm 2014年

真好!通过查看,我将无法弄清楚git help checkout。我必须从某个日期起签出一个子目录,并且使用这种方法,我可以使此语法正常工作:git checkout @{YYYY-MM-DD} sub-dir
haridsv

150

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

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

7
不必是完整的路径。git根目录的路径(进来的人git show --name-only也足够
Mohsen 2013年

7
Erm,从存储库根目录开始的完整路径。更好地看一下我给出的示例。“ full”之前没有斜杠。
米兰Babuškov2013年

7
仅供参考,如果您位于子目录中,则也可以成功使用./filename.ext。
旅行者

我认为关键是,如果您进入full/repo/path/to并尝试:git show 27cf8e84:my_file.txt,则会得到如下消息: 致命:致命:存在路径“ full / repo / path / to / my_file.txt”,但不存在“ my_file.txt” 。 您是说'27cf8e84:full / repo / path / to / my_file.txt'又名'27cf8e84:./ my_file.txt'吗?就像Git可以直接提供帮助一样,但是选择在这里做书呆子。
Ed Randall

101

最简单的办法就是写:

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

1
附加信息:您可以使用git log获得
哈希-xotix

@xotix谢谢。我使用git log file/path/name.ext
Sriram Kannan


8

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

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

"需要引号,因此保留了换行。


好一个。+1。git show我在上面提到的语法上有很好的补充。
VonC 2014年

23
我真的不明白为什么要使用echo,无论是否加上引号。而且我不明白您为什么要输出重定向的追加形式。简单写一下会不会更好:git show 60d8bdfc:src / services / LocationMonitor.java> LM_60d8bdfc.java如果出于某种原因您实际上想强制使用dos样式的行尾,则可以通过unix2dos对其进行管道传输。但是我从来没有发现在Windows上保留dos行尾有什么用处,因为我在Windows上使用过的除记事本之外的任何文本工具都可以很好地处理unix样式的行。
sootsnoot

4
git show 60d8bdfc:src / services / LocationMonitor.java >> LM_60d8bdfc.java为我工作。
Mike6679 2015年

@麦克:你在窗户上吗?
Mr_and_Mrs_D 2015年

2
不要使用双引号,因为如果您的文件字符看起来像shell变量,例如$ LANG,它将被替换。@LưuVĩnhPhúc是保护程序。也不要使用>>,它将附加文件(如果存在)并可能导致错误
theguy

3

这将帮助您在两次提交之间获取所有已删除的文件,而无需指定路径,如果删除了很多文件,则很有用。

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

1
git checkout {SHA1} -- filename

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


-2

通过检出上一个提交并复制文件,从上一个提交中获取文件。

  • 注意您所在的分支:git branch
  • 检出您想要的上一个提交: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • 将您想要的文件复制到一个临时位置
  • 签出您从中开始的分支: git checkout theBranchYouNoted
  • 复制到您放置在临时位置的文件中
  • 提交对git的更改: git commit -m "added file ?? from previous commit"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.