如何从 Git 中的特定修订版检索单个文件?
我有一个 Git 存储库,我想看看一些文件几个月前的样子。 我在那个日期找到了修订版; 它是27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
。 我需要查看一个文件的样子,并将其另存为(“新”)文件。
我设法使用 gitk 查看该文件,但它没有保存它的选项。 我尝试使用命令行工具,最接近的是:
git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt
但是,此命令显示差异,而不是文件内容。 我知道我稍后可以使用诸如 PAGER=cat 之类的东西并将输出重定向到文件,但我不知道如何获取实际的文件内容。
基本上,我正在寻找类似 svn cat 的东西。
I have a Git repository and I'd like to see how some files looked a few months ago. I found the revision at that date; it's 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
. I need to see what one file looks like, and also save it as a ("new") file.
I managed to see the file using gitk
, but it doesn't have an option to save it. I tried with command-line tools, the closest I got was:
git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt
However, this command shows a diff, and not the file contents. I know I can later use something like PAGER=cat
and redirect output to a file, but I don't know how to get to the actual file content.
Basically, I'm looking for something like svn cat.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
使用 git show
来完成您自己的答案,语法确实是
该命令采用通常的修订风格,这意味着您可以使用以下任何内容:
HEAD
+ x^
字符数提示 记住这一点很重要使用“
git show
”时,始终指定存储库根目录的路径,而不是当前目录位置。(尽管 Mike Morearty 提到,至少在 git 1.7.5.4 中,您可以通过输入“来指定相对路径”
./
”位于路径开头。例如:)
使用
git Restore
对于 Git 2.23+(2019 年 8 月),您还可以使用
git Restore
替换 令人困惑的git checkout
命令这只会在工作树上恢复“源”中存在的文件(
-s
) 提交 SHA1 或分支somebranch
。要恢复索引:(
-SW
:--staged --worktree
的缩写)如 评论,作者:starwarswii
使用低级 git 管道命令
在 git1.5.x 之前,这是通过一些管道完成的:
git ls-tree
显示提交中一个或多个“blob”对象的列表
git cat-file blob
cat 一个文件,因为它已在特定修订版中提交(类似于 svn
猫)。
使用 git ls-tree 检索给定文件 sha1 的值
git-ls-tree 列出修订版中的 $file 的对象 ID
$REV
,这是从输出中删除并用作git-cat-file
的参数,它实际上应该被称为git-cat-object< /code>,然后简单地将该对象转储到
stdout
。注意:从 Git 2.11(2016 年第 4 季度)开始,您可以对
git cat-file
输出应用内容过滤器。看
提交 3214594,
提交 7bcf341(2016 年 9 月 9 日),
提交 7bcf341(2016 年 9 月 9 日),以及
提交 b9e62f6,
提交 16dcc29(2016 年 8 月 24 日),作者:约翰内斯·辛德林 (
dscho
)。(由 Junio C Hamano --
gitster
-- 合并于 提交 7889ed2,2016 年 9 月 21 日)注意:“
git cat-file - -textconv
”最近(2017 年)开始出现段错误,已在 Git 2.15(2017 年第 4 季度)中得到纠正。请参阅 提交 cc0ea7c(2017 年 9 月 21 日),作者:Jeff King (
peff
).(由 Junio C Hamano --
gitster
-- 合并于 提交 bfbc2fc,2017 年 9 月 28 日)正如 Kira 在评论:
Using
git show
To complete your own answer, the syntax is indeed
The command takes the usual style of revision, meaning you can use any of the following:
HEAD
+ x number of^
charactersTip It's important to remember that when using "
git show
", always specify a path from the root of the repository, not your current directory position.(Although Mike Morearty mentions that, at least with git 1.7.5.4, you can specify a relative path by putting "
./
" at the beginning of the path. For example:)
Using
git restore
With Git 2.23+ (August 2019), you can also use
git restore
which replaces the confusinggit checkout
commandThat would restore on the working tree only the file as present in the "source" (
-s
) commit SHA1 or branchsomebranch
.To restore also the index:
(
-SW
: short for--staged --worktree
)As noted in the comments by starwarswii
Using low-level git plumbing commands
Before git1.5.x, this was done with some plumbing:
git ls-tree <rev>
show a list of one or more 'blob' objects within a commit
git cat-file blob <file-SHA1>
cat a file as it has been committed within a specific revision (similar to svn
cat).
use
git ls-tree
to retrieve the value of a given file-sha1git-ls-tree
lists the object ID for$file
in revision$REV
, this is cut out of the output and used as an argument togit-cat-file
, which should really be calledgit-cat-object
, and simply dumps that object tostdout
.Note: since Git 2.11 (Q4 2016), you can apply a content filter to the
git cat-file
output.See
commit 3214594,
commit 7bcf341 (09 Sep 2016),
commit 7bcf341 (09 Sep 2016), and
commit b9e62f6,
commit 16dcc29 (24 Aug 2016) by Johannes Schindelin (
dscho
).(Merged by Junio C Hamano --
gitster
-- in commit 7889ed2, 21 Sep 2016)Note: "
git cat-file --textconv
" started segfaulting recently (2017), which has been corrected in Git 2.15 (Q4 2017)See commit cc0ea7c (21 Sep 2017) by Jeff King (
peff
).(Merged by Junio C Hamano --
gitster
-- in commit bfbc2fc, 28 Sep 2017)As noted by Kira in the comments:
如果您希望使用先前提交或不同分支中的文件内容替换/覆盖当前分支中的文件内容,您可以使用以下命令来执行此操作:
或者
您将必须提交这些更改才能使它们在当前分支中生效。
If you wish to replace/overwrite the content of a file in your current branch with the content of the file from a previous commit or a different branch, you can do so with these commands:
or
You will then have to commit those changes in order for them to be effective in the current branch.
您需要提供文件的完整路径:
You need to provide the full path to the file:
最简单的方式是这样写:
其中:
示例
这将从修订版 27cf8e 中保存 my_file.txt > 作为一个名为 my_file.txt.OLD 的新文件
它已使用 Git 2.4.5 进行了测试。
如果您想检索已删除的文件,可以使用
HASH~1
(指定HASH之前的一次提交)。例子:
The easiest way is to write:
where:
Example
This will save my_file.txt from revision 27cf8e as a new file with name my_file.txt.OLD
It was tested with Git 2.4.5.
If you want to retrieve deleted file you can use
HASH~1
(one commit before specified HASH).EXAMPLE:
此命令从特定提交获取复制的文件。
this command get the copied file from specific commit.
在 Windows 中,使用 Git Bash:
git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > 旧的.ext
In Windows, with Git Bash:
git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
除了其他答案列出的所有选项之外,您还可以将 git reset 与 Git 对象(哈希、分支、HEAD~x、标签...)一起使用兴趣和文件路径:
在您的示例中:
它的作用是将
my_file.txt
恢复到索引中提交27cf8e8
的版本,同时保留它在工作目录中保持不变(因此在当前版本中)。从那里,事情变得非常简单:
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 commit
和git 恢复 file.txt
)。最后,如果运行,您甚至可以交互地选择在第一步中要重置的块:
因此带有路径的 git reset 为您提供了很大的灵活性来检索特定版本的文件与当前签出的版本进行比较,如果您选择这样做,则可以完全恢复或仅部分恢复到该版本。
编辑:我刚刚意识到我没有回答你的问题,因为你想要的不是差异或检索部分或全部旧版本的简单方法,而只是
cat那个版本。
当然,您仍然可以在重置文件后执行以下操作:
输出到标准输出或
但如果这就是您想要的,请直接使用
git show 27cf8e8:file.txt 运行
当然更直接。git show
正如其他人所建议的那样,不过,我将保留这个答案,因为直接运行 git show 可以让您立即获取旧版本,但如果您想用它做点什么,那么从如果您在索引中重置该版本,就会出现这种情况。
In addition to all the options listed by other answers, you can use
git reset
with the Git object (hash, branch,HEAD~x
, tag, ...) of interest and the path of your file:In your example:
What this does is that it will revert
my_file.txt
to its version at the commit27cf8e8
in the index while leaving it untouched (so in its current version) in the working directory.From there, things are very easy:
git diff --cached my_file.txt
git restore --staged file.txt
(or, prior to Git v2.23,git reset file.txt
) if you decide that you don't like itgit commit -m "Restore version of file.txt from 27cf8e8"
andgit restore file.txt
(or, prior to Git v2.23,git checkout -- file.txt
)git add -p file.txt
(thengit commit
andgit restore file.txt
).Lastly, you can even interactively pick and choose which hunk(s) to reset in the very first step if you run:
So
git reset
with a path gives you lots of flexibility to retrieve a specific version of a file to compare with its currently checked-out version and, if you choose to do so, to revert fully or only for some hunks to that version.Edit: I just realized that I am not answering your question since what you wanted wasn't a diff or an easy way to retrieve part or all of the old version but simply to
cat
that version.Of course, you can still do that after resetting the file with:
to output to standard output or
But if this was all you wanted, running
git show
directly withgit show 27cf8e8:file.txt
as others suggested is of course much more direct.I am going to leave this answer though because running
git show
directly allows you to get that old version instantly, but if you want to do something with it, it isn't nearly as convenient to do so from there as it is if you reset that version in the index.为了很好地将其转储到文件中(至少在 Windows 上) - Git Bash:
需要
"
引号,以便保留换行符。And to nicely dump it into a file (on Windows at least) - Git Bash:
The
"
quotes are needed so it preserves newlines.这将帮助您在提交之间获取所有已删除的文件,而无需指定路径,如果删除了大量文件,这很有用。
This will help you get all deleted files between commits without specifying the path, useful if there are a lot of files deleted.
正如其他人已经指出的那样,使用 git show $REV:$FILE 可能是正确的答案。 我发布了另一个答案,因为当我尝试此方法时,有时会从 git 收到以下错误:
当文件路径的部分内容是符号链接时,就会出现问题。 在这些情况下,
git show $REV:$FILE
方法将不起作用。 重现步骤:问题是,像
realpath
这样的实用程序在这里没有帮助,因为符号链接可能不再存在于当前提交中。 我不知道有什么好的通用解决方案。 就我而言,我知道符号链接只能存在于路径的第一个组成部分中,因此我通过使用 git show $REV:$FILE 方法两次解决了该问题。 有效的,因为当在符号链接上使用 git show $REV:$FILE 时,会打印其目标:而对于目录,该命令将输出一个标头,后跟目录内容:
这是 我的情况,我只是检查了第一次调用 git show $REV:$FILE 的输出,如果它只是一行,那么我用要解析的结果替换了路径的第一个组件通过 git 的符号链接。
Using
git show $REV:$FILE
as it was already pointed out by others is probably the right answer. I'm posting another answer because when I tried this method, I sometimes got the following error from git:The problem occurs when parts of the path to the file are a symbolic link. In those cases, the
git show $REV:$FILE
method will not work. Steps to reproduce:The problem is, that utilities like
realpath
don't help here, because the symlink might not exist in the current commit anymore. I don't know about a good general solution. In my case, I knew that the symlink could only exist in the first component of the path, so I solved the problem by using thegit show $REV:$FILE
method twice. This works, because whengit show $REV:$FILE
is used on a symlink, then its target gets printed:Whereas with directories, the command will output a header, followed by the directory content:
So in my case, I just checked the output of the first call to
git show $REV:$FILE
and if it was only a single line, then I replaced the first component of my path with the result to resolve the symlink through git.通过检出先前的提交并复制文件来获取先前提交的文件。
git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
git checkout theBranchYouNoted
code>git commit -m "added file ?? from previous commit"
Get the file from a previous commit through checking-out previous commit and copying file.
git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
git checkout theBranchYouNoted
git commit -m "added file ?? from previous commit"
如果您更喜欢使用 GUI 来执行此操作,并且您知道文件大约何时发生更改,则以下操作将起作用。
在安装了 Git 扩展的 Visual Studio 上:
If you prefer to use GUI to do this, the following will work if you know when approximately the file got changed.
On Visual Studio with Git Extension installed: