如何将文件重置或还原到特定版本?

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

20
回滚后,检查 git diff 时不要忘记加上 --cached 参数。 - Geoffrey Hale
7
当我谷歌搜索我的问题时,发现了你的问题。但是当我阅读解决方案后,我检查了我的日志并发现我将这些更改作为独立提交进行了更改,所以我对该提交进行了git还原,而其他一切都像我想要的那样保留下来。这不是解决方案,只是另一种有时可以做到的方法。 - sudo97
我使用以下手动解决方案:$ git revert <commit>,然后取消隐藏所需更改,然后将这些所需更改上传到新提交中。 - Intenzion
36个回答

58

在说"rollback"时必须小心。如果你曾经在提交$A中有一个文件的先前版本,然后稍后又进行了两次独立的提交$B和$C的更改(所以你看到的是该文件的第三个迭代版本),如果你说"我想回到第一个版本",那么你真的是这个意思吗?

如果你想要摆脱第二和第三次迭代的更改,那么非常简单:

$ git checkout $A file

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

另一方面,如果您想要摆脱第二次迭代(即提交$B)带来的更改,同时保留提交$C对文件所做的更改,则需要还原$B。

$ git revert $B

请注意,创建提交 $B 的人可能不太有纪律性,并且可能在同一次提交中提交了完全不相关的更改,因此此还原操作可能会触及除您所看到的有问题的 file 之外的其他文件,因此建议您在执行还原操作后仔细检查结果。

我曾经遇到过这种情况,但是“git log file”显示我仍在原始提交(HEAD)。看起来“git checkout”失败了。然而,“git status”显示文件实际上已经更改,并且“git diff --staged file”会显示实际更改内容。此外,“git status”也显示文件已更改。因此,在此处不要使用“git log”来跟踪哪些文件发生了更改。 - Frederick Ollinger
@FrederickOllinger - 这种行为是有道理的,因为 git log 显示的是 提交,而你还没有 提交 这个更改(回滚)。如果你在回滚之后执行 git commit,那么 git log 就会显示这个更改。 - ToolmakerSteve

45
  1. 如何将Git中的文件还原到某个特定提交版本
git checkout Last_Stable_commit_Number -- fileName

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

git checkout branchName_Which_Has_stable_Commit fileName

42

有趣的是,如果工作副本在名为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

34

以下是 rebase 的工作原理:

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

假设你有以下内容:

---o----o----o----o  master
    \---A----B       <my branch>

第一和第二个命令... 提交 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'  <my branch>
最后两个命令...
git checkout master
git merge <my branch>

执行快进合并,将所有<我的分支>的更改应用到master上。如果没有这一步,变基提交将不会被添加到master中。最终结果如下:

...

---o----o----o----o----A'----B'  master, <my branch>

master<my branch> 都指向 B'。同时,从这个点开始,可以安全地删除 <my branch> 的引用。

git branch -d <my branch>

27

为目标文件执行首次重置操作

git reset HEAD path_to_file

第二次检查那个文件

git checkout -- path_to_file

4
+1,但不确定重置HEAD的意图。它可能需要也可能不需要。在我的情况下,我只想将一个特定的文件还原到存储库中的版本(同时保留其余本地更改)。仅运行上述第二步就足够了。 - fkl
是的,我只需要运行第二个命令。类似于--> https://www.shellhacks.com/git-revert-file-to-previous-commit/ - javaPlease42

25

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

git checkout HEAD^1 path/to/file
或者
git checkout HEAD~1 path/to/file

然后只需将"新"版本进行分阶段和提交。

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

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


1
那个文件不应该已经自动分阶段吗?我更感兴趣的是如何在不自动分阶段的情况下检出文件。当然,我也可以手动取消分阶段,但了解如何避免自动分阶段会很有趣。 - kriegaex

23

使用git别名,awk和shell函数来解决问题!

git prevision <N> <filename>

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

git prevision -1 x/y/z.c

Git如何进行版本回退?

将以下内容添加到您的gitconfig文件中。

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

该命令基本上:

  • 对指定的文件执行git log
  • 从文件历史记录中选择适当的提交ID,并
  • 为指定的文件执行git checkout到提交ID。

实际上,所有在这种情况下手动执行的操作都被包含在一个美丽高效的Git别名中 - git-prevision


23

这里提出了许多建议,大多数建议是使用 git checkout $revision -- $file 这样的命令。还有几种较为晦涩的替代方法:

git show $revision:$file > $file

而且,我经常使用这个功能来暂时查看特定的版本:

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

(提示: 如果$file是相对路径,则需要在前面加上./,以便git show $revision:$file正常工作)

甚至更奇怪的是:

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

2
如果您不确定想要哪个提交版本并且需要“窥视”周围而不覆盖工作目录,则这是一个不错的替代方法。 - wisbucky

22
我必须在这里介绍 EasyGit,它是一个包装器,可以使初学者更容易地使用git,并不会困惑经验丰富的用户。 它做的事情之一是赋予更多意义给 git revert。 在这种情况下,您只需要说:

eg revert foo/bar foo/baz


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

19

请注意,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表示从索引中还原路径./foo;添加HEAD指令告诉Git在执行还原之前将该路径在索引中还原为HEAD版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接