如何将文件重置或恢复到特定版本?

git version-control git-checkout

如何在特定的提交哈希(我通过 git loggit diff 确定)处将修改后的文件恢复到其先前的版本?

还原后,检查 git diff 时不要忘记 --cachedlink

当我用谷歌搜索我的问题时,我发现了你的问题。但是在我阅读了解决方案之后,我检查了我的日志并发现,我将 thouse 更改作为一个独立的提交进行了,所以我为那个提交做了 git revert,其他的一切都保持了我想要的状态。不是解决方案,有时只是另一种方法。

我使用这个手动解决方案: $ git revert 然后 unstash 想要的更改,然后将这个想要的更改上传到新的提交中。

G
Greg Hewgill

假设您想要的提交的哈希是 c5f567

git checkout c5f567 -- file1/to/restore file2/to/restore

git checkout 手册页提供了更多信息。

如果您想恢复到 c5f567 之前的提交,请附加 ~1(其中 1 是您要返回的提交数,可以是任何值):

git checkout c5f567~1 -- file1/to/restore file2/to/restore

作为旁注,我一直对这个命令感到不舒服,因为它既用于普通事物(在分支之间更改),也用于不寻常的破坏性事物(丢弃工作目录中的更改)。

还有一个新的 git restore 命令专门用于恢复已修改的工作副本文件。如果您的 git 足够新,您可以使用此命令,但文档附带警告:

此命令是实验性的。行为可能会改变。

@shadowhand:有没有办法扭转这种情况,所以它是紧随其后的版本?

@alliteralmind:不,不幸的是,Git 历史快捷方式符号只会在历史上倒退。

如果您要为 abcde 使用分支名称(例如 develop),您将需要 git checkout develop -- file/to/restore(注意双破折号)

@alliteralmind:实际上,是的,有一种方法可以做到:“git log --reverse -1 --ancestry-path yourgitrev..master”,然后使用适当的选项来获取 git rev。 --ancestry-path 将在两个提交之间“画一条线”,-1 将只显示一个版本,而 --reverse 将确保发出的第一个条目是最旧的条目。

就我个人而言,我发现 HEAD^ 比 HEAD~1 更容易输入 :)

C
Chris Lloyd

您可以使用 diff 命令快速查看对文件所做的更改:

git diff <commit hash> <filename>

然后要将特定文件还原为该提交,请使用 reset 命令:

git reset <commit hash> <filename>

如果您有本地修改,您可能需要使用 --hard 选项。

管理航点的一个很好的工作流程是使用标签在您的时间线中清晰地标记点。我不太明白你的最后一句话,但你可能想要的是从前一个时间点分出一个分支。为此,请使用方便的 checkout 命令:

git checkout <commit hash>
git checkout -b <new branch name>

然后,当您准备好合并这些更改时,您可以根据您的主线重新设置:

git checkout <my branch>
git rebase master
git checkout master
git merge <my branch>

'git checkout ' 命令让我恢复了旧版本的项目,这正是我正在寻找的项目 谢谢克里斯。

恢复文件 git checkout <commit hash> <filename> 对我来说比 git reset 效果更好

我想要单个文件的早期版本,因为我用错误选择的复制/粘贴覆盖了 150 行。 git checkout <commit hash> <filename> 为我工作。恕我直言,这不应该是公认的答案。 git reset 没有。

无法使用 git reset 重置单个文件,您将收到错误 fatal: Cannot do hard reset with paths

什么 slier 说:你不能git reset --hard <commit hash> <filename>。这将与 fatal: Cannot do hard reset with paths. Motti Strom 所说的错误:使用 git checkout <commit hash> <filename>

G
George Stocker

您可以使用对 git 提交的任何引用,如果最方便的话,包括 SHA-1。关键是命令看起来像这样:

git checkout [commit-ref] -- [filename]

这个有 -- 的答案与没有的已接受答案有什么区别?

在 git 中,文件列表前的“--”告诉 git 所有下一个参数都应该被解释为文件名,而不是分支名或其他任何东西。有时它是一个有用的消歧器。

'--' 不仅是一个 git 约定,而且是你在 *nix 命令行的不同位置找到的东西。 rm -- -f(删除一个名为 -f 的文件)似乎是典型的例子。 More detail here

只需添加@HawkeyeParker 所说的, rm 命令使用 getopt(3) 解析其参数。 getopt 是解析命令参数的命令。 gnu.org/software/libc/manual/html_node/Getopt.html

@Honey 是的,这就是我的意思,是的,可能根本不常见。我已经在不同的地方看到过这个例子,也许只是为了让它有点令人难忘: rm -f 众所周知是可怕/危险的。但是,关键是,在 *nix 中,文件名可以以“-”开头,这会使各种命令行解释器感到困惑,当它们看到“-”时,会期望后面跟着一个命令选项。它可以是任何以'-'开头的文件;例如,“-mySpecialFile”。

G
Greg Hewgill
git checkout -- foo

这会将 foo 重置为 HEAD。你也可以:

git checkout HEAD^ foo

一次修订,等等。

如果 foo 有任何特殊(例如目录或名为 -f 的文件),我建议使用语法 git checkout -- foo 以避免任何错误。对于 git,如果您不确定,请始终在所有文件和目录前加上特殊参数 --

Mikko 评论的附加说明:-- 不是 git 命令,对 git 来说并不特殊。它是一个内置的 bash,用于表示命令选项的结束。您也可以将它与许多其他 bash 命令一起使用。

@matthaeus 它也既不是特定于 bash 也不是 shell 功能。这是在许多不同命令中实现的约定(并由 getopt 支持)。

不,-- 不是 bash 中的内置特殊词。但它是许多命令行解析器支持的通用约定,并被许多 CLI 使用,包括 git。

C
CDR

并且要恢复到最常需要的最后提交的版本,您可以使用这个更简单的命令。

git checkout HEAD file/to/restore

这(git checkout HEAD file/to/restore)和 git reset --hard file/to/restore 有什么区别???

1)更容易记住更通用的方式 2)不用担心在输入文件名之前按 Enter

这是对“真实”问题的更有效答案。

C
Community

我刚才遇到了同样的问题,我发现 this answer 最容易理解(commit-ref 是您要返回的日志中更改的 SHA 值):

git checkout [commit-ref] [filename]

这会将旧版本放在您的工作目录中,如果需要,您可以从那里提交它。

m
mjarosie

从 git v2.23.0 开始,有一个新的 git restore 方法应该假设 git checkout 负责的部分内容(即使接受的答案也提到 git checkout 非常令人困惑)。请参阅 github blog 上的变化亮点。

此命令的默认行为是使用来自 source 参数的内容(在您的情况下将是提交哈希)恢复工作树的状态。

因此,根据 Greg Hewgill 的回答(假设提交哈希为 c5f567),命令将如下所示:

git restore --source=c5f567 file1/to/restore file2/to/restore

或者如果你想恢复到 c5f567 之前的一次提交的内容:

git restore --source=c5f567~1 file1/to/restore file2/to/restore

我想这是一种死线,但这是正确的“现代”答案。

这是截至 2021 年的最佳答案。

c
chim

如果您知道需要返回多少次提交,您可以使用:

git checkout master~5 image.png

这假设您在 master 分支上,并且您想要的版本是 5 次提交。

Z
ZMorek

我想我找到了....来自 http://www-cs-students.stanford.edu/~blynn/gitmagic/ch02.html

有时你只想回到过去,忘记过去的每一个变化,因为它们都是错误的。

从...开始:

$ git log

它向您显示了最近提交的列表,以及它们的 SHA1 哈希值。

接下来,键入:

$ git reset --hard SHA1_HASH

将状态恢复到给定的提交并从记录中永久删除所有较新的提交。

Git 从不删除任何东西。您的旧提交仍然存在,但除非有指向它们的分支提示,否则它们不再可访问。 git reflog 仍然会显示它们,直到你用 git-gc 清理你的存储库。

@Bombe:感谢您提供的信息。我检查了一个旧版本的文件。阅读您的评论后,我能够使用“gitref”查找部分 SHA1 哈希,并使用“checkout”返回到最新版本。其他 git 用户可能会发现此信息很有帮助。

可能后跟一个 git push --force

如果您有未提交的更改,如果执行 git reset --hard,您将丢失它们

@Bombe - “Git 从不删除任何东西。你的旧提交仍然存在,但除非有指向它们的分支提示,否则它们不再可访问。” - 但是像这样的提交会在一段时间后被修剪,所以“Git 从不删除任何东西”是不真实的。

v
v2k

这对我有用:

git checkout <commit hash> file

然后提交更改:

git commit -a
佚名

当你说“回滚”时,你必须小心。如果您曾经在提交 $A 中有一个文件版本,然后在两个单独的提交 $B 和 $C 中进行了两次更改(所以您看到的是文件的第三次迭代),如果您说“我想回滚到第一个”,你真的是这个意思吗?

如果你想摆脱第二次和第三次迭代的变化,这很简单:

$ git checkout $A file

然后你提交结果。该命令询问“我想从提交 $A 记录的状态中签出文件”。

另一方面,您的意思是摆脱第二次迭代(即提交 $B)带来的更改,同时保留提交 $C 对文件所做的更改,您希望恢复 $B

$ git revert $B

请注意,创建提交 $B 的人可能不是很自律,并且可能在同一次提交中提交了完全不相关的更改,并且此还原可能会触及文件以外的文件,而不是您看到有问题的更改,因此您可能需要在执行后仔细检查结果所以。

我这样做了,但随后一个“git 日志文件”会说我在原始提交上,HEAD。似乎“git checkout”失败了。但是,git status 显示该文件实际上已更改,并且“git diff --staged 文件”将显示实际更改。此外,“git status”显示文件也已更改。所以不要在这里使用“git log”来跟踪哪些文件发生了变化。

@FrederickOllinger - 这种行为是有道理的,因为 git log 显示 commits,而您还没有 commit 更改(还原)。如果您在恢复后执行 git commit,则 git log 将显示更改。

l
leiyc

有趣的是,如果工作副本位于名为 foo 的目录中,git checkout foo 将不起作用;但是,git checkout HEAD foogit checkout ./foo 都会:

$ pwd
/Users/aaron/Documents/work/foo
$ git checkout foo
D   foo
Already on "foo"
$ git checkout ./foo
$ git checkout HEAD foo
c
cxxl

Git 将文件还原为特定的提交

git checkout Last_Stable_commit_Number -- 文件名

2.Git 将文件还原到特定分支

git checkout branchName_Which_Has_stable_Commit 文件名

G
George Stocker

rebase 的工作原理如下:

git checkout <我的分支> git rebase master git checkout master git merge <我的分支>

假设你有

---o----o----o----o master \---A----B <我的分支>

前两个命令 ... commit git checkout git rebase master

...查看要应用到 master 分支的更改分支。 rebase 命令从 <my branch> 获取提交(在 master 中找不到)并将它们重新应用到 master 的头部。换句话说,<my branch> 中第一个提交的父级不再是 master 历史中的先前提交,而是 master 的当前头部。这两个命令是一样的:

git rebase master <my branch>

记住这个命令可能更容易,因为“base”和“modify”分支都是明确的。

.最终的历史结果是:

---o----o----o----o master \----A'----B' <我的分支>

最后两个命令...

git checkout master
git merge <my branch>

... 进行快进合并以将所有 <my branch> 更改应用到 master。如果没有这一步,rebase 提交不会添加到 master。最终结果是:

---o----o----o----o----A'----B' master, <我的分支>

master<my branch> 都引用 B'。此外,从这一点开始,删除 <my branch> 引用是安全的。

git branch -d <my branch>
G
Gulshan Maurya

目标文件的第一个重置头

git reset HEAD path_to_file

第二次签出该文件

git checkout -- path_to_file

+1,但不确定重置 HEAD 的意图。它可能需要也可能不需要。在我的情况下,我只想将一个特定文件恢复到存储库中的版本(保持剩余的本地更改完好无损。只需运行上面的第二步对我来说就足够了

是的,我只需要运行第二个命令。喜欢--> shellhacks.com/git-revert-file-to-previous-commit

M
ModernIncantations

如果您想将文件恢复到以前的提交(以及要恢复的文件已经提交),您可以使用

git checkout HEAD^1 path/to/file

或者

git checkout HEAD~1 path/to/file

然后只需暂存并提交“新”版本。

有了在合并的情况下提交可以有两个父级的知识,您应该知道 HEAD^1 是第一个父级,而 HEAD~1 是第二个父级。

如果树中只有一个父级,则任何一个都可以。

该文件不应该已经自动成为阶段吗?我宁愿对如何在不自动暂存文件的情况下签出感兴趣。当然,我也可以手动取消暂存,但知道如何避免自动暂存会很有趣。

C
Community

git-aliases、awk 和 shell 函数来救援!

git prevision <N> <filename>

其中 <N> 是要为文件 <filename> 回滚的文件的修订版本数。
例如,要检出单个文件 x/y/z.c 的上一个修订版本,请运行

git prevision -1 x/y/z.c

git prevision 是如何工作的?

将以下内容添加到您的 gitconfig

[alias]
        prevision = "!f() { git checkout `git log --oneline $2 |  awk -v commit="$1" 'FNR == -commit+1 {print $1}'` $2;} ;f"

该命令基本上对指定文件执行 git log 并在文件的历史记录中选择适当的 commit-id 并对指定文件的 commit-id 执行 git checkout。

基本上,在这种情况下,所有需要手动执行的操作,
都包含在一个漂亮、高效的 git 别名中 - git-prevision

P
Peter V. Mørch

这里有很多建议,大部分与 git checkout $revision -- $file 类似。几个不起眼的选择:

git show $revision:$file > $file

而且,我经常使用它来临时查看特定版本:

git show $revision:$file

或者

git show $revision:$file | vim -R -

(OBS: $file 需要以 ./ 为前缀,如果它是 git show $revision:$file 工作的相对路径)

更奇怪的是:

git archive $revision $file | tar -x0 > $file

如果您不确定您想要哪个提交版本并且需要“查看”而不覆盖您的工作目录,这是一个不错的选择。

A
Aristotle Pagaltzis

我必须在此处插入 EasyGit,这是一个包装器,可以让 git 对新手更容易上手,而不会让经验丰富的用户感到困惑。它所做的其中一件事是give more meanings to git revert。在这种情况下,您只需说:

eg revert foo/bar foo/baz

它应该是 eg revert --in REVISON -- FILENAME--in 很重要。对于那里的 Windows 用户:打开 git bash。执行echo %PATH。第一个路径应位于以 bin 结尾的用户目录中。创建该路径。将 eg 存储在那里。将其命名为 eg。不是eg.txt

G
George Stocker

但是请注意,git checkout ./foogit checkout HEAD ./foo 不是完全相同的东西;一个例子:

$ echo A > foo
$ git add foo
$ git commit -m 'A' foo
Created commit a1f085f: A
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 foo
$ echo B >> foo
$ git add foo
$ echo C >> foo
$ cat foo
A
B
C
$ git checkout ./foo
$ cat foo
A
B
$ git checkout HEAD ./foo
$ cat foo
A

(第二个 add 将文件暂存到索引中,但它没有被提交。)

Git checkout ./foo 表示从 index 恢复路径 ./foo;添加 HEAD 指示 Git 在执行此操作之前将索引中的该路径恢复为其 HEAD 修订版。

d
desmond13

对我来说,没有一个答复似乎很清楚,因此我想添加我的,这似乎超级简单。

我有一个提交 abc1,之后我对文件 file.txt 进行了多次(或一次修改)。

现在说我在文件 file.txt 中搞砸了一些东西,我想回到之前的提交 abc1

1.git checkout file.txt :如果您不需要它们,这将删除本地更改

2.git checkout abc1 file.txt:这会将您的文件带到您的想要的版本

3.git commit -m "Restored file.txt to version abc1" :这将提交您的还原。

git push :这将推送远程存储库中的所有内容

在第 2 步和第 3 步之间,您当然可以执行 git status 来了解发生了什么。通常您应该会看到已添加的 file.txt,这就是不需要 git add 的原因。

好的,所以我猜步骤 1. 和 2. 是互斥的:如果 abc1 是您的最后一次提交,则不需要 2. 如果在 abc1 之后还有其他提交,您可以直接执行 2.

V
Vince

这里的许多答案都声称使用 git reset ... <file>git checkout ... <file>,但这样做,您将失去在要恢复的提交之后提交的对 <file> 的所有修改。

如果您只想恢复对单个文件的一次提交的更改,就像 git revert 只会对一个文件(或者说是提交文件的子集)所做的那样,我建议同时使用 git diffgit apply像那样(使用 <sha> =您要恢复的提交的哈希):

git diff <sha>^ <sha> path/to/file.ext | git apply -R

基本上,它将首先生成与您要还原的更改相对应的补丁,然后反向应用补丁以删除这些更改。

当然,如果恢复的行已被 <sha1>HEAD 之间的任何提交修改(冲突),它将不起作用。

这应该是批准的答案。我可以建议一个稍微简化的版本:git show -p <sha> path/to/file.ext|git apply -R

您可以使用 <sha>^! 而不是 <sha>^ <sha>

s
shah1988

为了转到文件的先前提交版本,获取提交号,然后说 eb917a1

git checkout eb917a1 YourFileName

如果您只需要返回到上次提交的版本

git reset HEAD YourFileName
git checkout YourFileName

这只会带您进入文件的最后提交状态

A
Abhishek Dwivedi

这是一个非常简单的步骤。将文件签出到我们想要的提交 id,这里之前是一个提交 id,然后只需 git commit amend 就完成了。

# git checkout <previous commit_id> <file_name>
# git commit --amend

这非常方便。如果我们想将任何文件带到提交顶部的任何先前提交 id,我们可以轻松做到。

谢谢,阿布舍克。根据您的回答,我制作了这个 Shellscipt:gist.github.com/ivanleoncz/c20033e5f4b24304cbc39e0bac1d43e8 随时改进 :)。

A
Amos Folarin

git checkout ref|commitHash -- 文件路径

例如

git checkout HEAD~5 -- foo.bar
or 
git checkout 048ee28 -- foo.bar
N
Nir M.

您可以通过 4 个步骤完成:

使用您要专门恢复的文件恢复整个提交 - 它将在您的分支上创建一个新提交 软重置该提交 - 删除提交并将更改移动到工作区域 手动选择要恢复的文件并提交它们 删除所有其他文件在你的工作区

您需要在终端中输入的内容:

git revert git reset HEAD~1 git add && git commit -m 'reverting file' git checkout 。

祝你好运

这不会恢复所有更改吗?

@arcee123 是的,但随后的重置会撤消所有更改的还原。问题是 git-revert 只在整个 repo 上运行,因此为了补偿我们必须撤消其他所有内容。

我建议使用: 1. git revert --no-commit <commit_hash> 2. git reset HEAD 这可以节省额外的提交,并且只在您的工作目录中进行所有更改。

@greg-hewgill 的答案更好而且很准确。这个很糟糕,不应该使用。

这正是真正还原特定文件所需要的。我需要撤消对已经推送到远程存储库的早期提交中的一些文件的更改。我还原、重置并提交了结果:git revert _oldcommit_ --no-commit git reset -- _unchanged1_ _unchanged2_ ... git commit -m "branch without changes to specific files" 新的分支提示反映了除还原文件之外的所有更改。

v
vicvicvic

使用 git log 获取特定版本的哈希键,然后使用 git checkout <hashkey>

注意:不要忘记在最后一个之前键入哈希。最后一个哈希指向您当前的位置(HEAD)并且没有任何改变。

C
Chadwick

显然有人需要写一本关于 git 的通俗易懂的书,或者需要在文档中更好地解释 git。面对同样的问题,我猜想

cd <working copy>
git revert master

将撤消似乎要做的最后一次提交。

伊恩

O
Otto
git revert <hash>

将还原给定的提交。听起来您认为 git revert 只会影响最近的提交。

这并不能解决您的问题,如果您想恢复特定文件中的更改并且该提交更改的内容多于该文件。

s
saber tabatabaee yazdi

如果您在最后一次提交中提交了错误的文件,请按照说明进行操作:

开源树,改到这个提交

https://i.stack.imgur.com/ag9HP.png

更改行并找到错误文件作为提交发送的提交

https://i.stack.imgur.com/0990p.png

您可以在该提交中看到您的更改列表选择它然后单击...按钮右侧...单击反向文件然后您可以在左下角的文件状态选项卡上看到它然后单击取消暂存:

https://i.stack.imgur.com/VOhZZ.png

打开您的 Visual Studio 代码并通过在所有文件之后提交已删除的文件来恢复,您可以在源树中的最后一次提交中看到结果

https://i.stack.imgur.com/3gpgo.png