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


4511

我对文件进行了一些更改,该文件已作为一组文件的一部分提交了几次,但现在想将其更改重置/还原为以前的版本。

我已经做了git log连同git diff找到的修订我需要,但只是不知道如何让过去的文件恢复到以前的状态。


11
还原后,--cached检查时不要忘记git diff链接
Geoffrey Hale 2015年

5
我用谷歌搜索时发现了您的问题。但是,在阅读解决方案之后,我检查了日志并发现,我以独立提交的方式进行了thouse更改,因此我对该提交进行了git revert,其他所有操作都保持了我想要的状态。不是解决方案,有时是另一种方法。
sudo97

Answers:


6129

假设所需的提交哈希为c5f567

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

git的结帐手册页提供了更多的信息。

如果您想还原到c5f567,append 之前的提交~1(其中1是您要返回的提交数,则可以是任意值):

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

附带说明一下,对于该命令,我一直感到不舒服,因为它既用于普通事物(在分支之间切换)又用于异常,破坏性的事物(丢弃工作目录中的更改)。


12
@shadowhand:有一种方法可以解决这个问题,所以它就是紧随其后的版本吗?
aliteralmind 2014年

16
@aliteralmind:不,不幸的是,Git历史记录的快捷方式仅在历史上倒退了。
Greg Hewgill 2014年

45
如果要使用abcde的分支名称(例如develop),则需要git checkout develop -- file/to/restore(注意双破折号)
Ohad Schneider 2014年

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

6
我个人认为HEAD ^比
HEAD〜1

606

您可以使用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>

7
“ git checkout <commit hash>”命令已将我的较旧版本的项目还给了我,正是我要搜索的项目。谢谢克里斯。
vidur punj

48
还原文件git checkout <commit hash> <filename>对我来说比git reset
-Motti Strom

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

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

13
斯利尔说的是:你不能git reset --hard <commit hash> <filename>。这将与fatal: Cannot do hard reset with paths.Motti Strom所说的错误:使用git checkout <commit hash> <filename>
Hawkeye Parker

366

您可以使用对git commit的任何引用,如果方便的话可以使用SHA-1。关键是该命令如下所示:

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


22
有答案的答案--与没有答案的答案有什么区别?
2014年

80
在git中,文件列表前的'-'告诉git所有下一个参数应解释为文件名,而不是分支名称或其他名称。有时这是一个有用的消除歧义的方法。
foxxtrot 2014年

49
“-”不仅是git约定,而且还是您在* nix命令行上的不同位置找到的东西。 rm -- -f(删除名为的文件-f)似乎是典型的示例。这里的更多细节
鹰眼帕克

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

2
@Honey是的,这就是我的意思,是的,可能根本不常见。我在各个地方都看到了这个示例,也许只是为了使它令人难忘:众所周知,rm -f令人恐惧/危险。但是,关键是,在* nix中,文件名可以以'-'开头,这会混淆各种命令行解释器,当他们看到'-'时,它们会期望跟随命令选项。它可以是任何以'-'开头的文件;例如,“-mySpecialFile”。
Hawkeye Parker

287
git checkout -- foo

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

git checkout HEAD^ foo

一回修订等


12
git checkout -- foo如果foo有特殊之处(例如目录或称为的文件-f),我建议使用语法来避免任何错误。如果不确定,请使用git始终为所有文件和目录添加特殊参数--
Mikko Rantalainen

8
对Mikko的注释的附加说明:--不是git命令,并且不是git专用的。它是内置的bash,用于表示命令选项的结尾。您也可以将其与许多其他bash命令一起使用。
matthaeus

14
@matthaeus它也不是专门针对bash或shell功能。这是在许多不同命令中实现的约定(并由getopt支持)。
Greg Hewgill '16

2
不,--不是在bash一个内置特殊的词。但这是许多命令行解析器支持的通用约定,并且由许多CLI(包括git)使用。
埃米尔·隆伯格

123

要恢复到最常用的最后提交版本,可以使用此更简单的命令。

git checkout HEAD file/to/restore

2
git checkout HEAD file / to / restore和git reset --hard file / to / restore有什么区别?
Motti Shneor '16

2
1)更容易记住的更一般的方式2)无后顾之忧,按输入文件名前输入
罗马王莲香

105

我刚才遇到了同样的问题,我发现这个答案最容易理解(commit-ref是您想返回的日志更改的SHA值):

git checkout [commit-ref] [filename]

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


91

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

git checkout master~5 image.png

假设您在master分支上,并且想要的版本是5 commits。


80

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

有时您只是想回去,忘记经过某个特定点的所有更改,因为它们都是错误的。

从...开始:

$ git log

它显示了最近提交及其SHA1哈希的列表。

接下来,键入:

$ git reset --hard SHA1_HASH

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


24
Git从不删除任何东西。您的旧提交仍然存在,但是除非有分支提示指向它们,否则它们将不再可用。git reflog仍将显示它们,直到您使用git-gc清理存储库为止。
孟买

1
@Bombe:谢谢您提供的信息。我已经签出了旧版本的文件。阅读您的评论后,我可以使用“ gitref”查找部分SHA1哈希,并使用“ checkout”返回最新版本。其他git用户可能会发现此信息有用。
温斯顿·C·杨

4
可能之后是git push --force
bshirley 2012年

4
如果您有未提交的更改,你将失去他们,如果做一个git的复位-硬
Boklucius

5
@Bombe-“ Git从不删除任何内容。您的旧提交仍然存在,但是除非有分支提示指向它们,否则它们将不再可用。” -但是像这样的提交会在设定的时间后被修剪,因此“ Git从不删除任何内容”是不正确的。
Bulwersator 2014年

61

这为我工作:

git checkout <commit hash> file

然后提交更改:

git commit -a

54

说“回滚”时必须小心。如果您以前在$ A提交中拥有文件的一个版本,然后又在$ B和$ C的两个单独提交中进行了两次更改(那么您看到的是文件的第三次迭代),并且如果您说“我想回滚到第一个”,您是真的吗?

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

$ git checkout $A file

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

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

$ git revert $B

请注意,无论谁创建的提交$ B可能都没有受到严格的纪律,并且可能在同一提交中提交了完全不相关的更改,并且此还原可能会涉及您看到有问题的更改以外的文件,因此您可能需要在执行后仔细检查结果所以。


我这样做了,但是然后,一个“ git日志文件”会说我在原始提交HEAD上。似乎“ git checkout”失败了。但是,git状态表明该文件实际上已更改,而“ git diff --staged文件”将显示实际更改。另外,“ git status”显示文件也已更改。因此,请勿在此处使用“ git log”来跟踪哪些文件已更改。
Frederick Ollinger

37

有趣的是,git checkout foo如果工作副本位于一个名为的目录中,它将不起作用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

26
git checkout -- foo
knittl

32

下面是如何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>

记住此命令可能会更容易,因为“基本”和“修改”分支都是显式的。

。最终的历史记录结果是:

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

最后两个命令...

git checkout master
git merge <my branch>

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

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

master并且<my branch>都参考B'。同样,从这一点来看,删除<my branch>引用是安全的。

git branch -d <my branch>

26

从git v2.23.0开始,有一个新的git restore方法,该方法应该假定是其中的一部分git checkout(即使已接受的答案git checkout也很令人困惑)。在github博客上查看更改的要点。

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

因此,根据Greg Hewgill的答案(假设commit hash为c5f567),该命令将如下所示:

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

或者,如果您想还原到c5f567之前的一次提交的内容,请执行以下操作:

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

24

目标文件的第一个重置头

git reset HEAD path_to_file

第二次结帐该文件

git checkout -- path_to_file

4
+1,尽管不确定重置HEAD的意图。可能需要也可能不需要。在我的情况下,我只想将一个特定的文件还原到存储库中的版本(这样可以保持其余的本地更改完好无损。只需运行上面的第二步就足够了
fkl

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

22

git-aliases,awk和shell函数可以解救!

git prevision <N> <filename>

其中<N>是要回滚给file的文件修订版本号<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对指定的文件 执行
  • 在文件的历史记录中选择适当的提交ID,然后
  • git checkout对指定文件执行commit-id。

本质上,在这种情况下,所有需要手动执行的操作都将
打包成一个漂亮而有效的git-alias- git-prevision


20

我必须插入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.txt
koppor

20

如果您想将文件还原为先前的提交(以及想要还原已提交的文件),则可以使用

git checkout HEAD^1 path/to/file

要么

git checkout HEAD~1 path/to/file

然后只需上台并提交“新”版本。

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

如果树中只有一个父级,则任何一种都将起作用。


19

这里有很多建议,大部分与相似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

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

18

但是请注意,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在执行此操作之前将索引中的路径还原为其 修订版本。


14

对我而言,没有一个答案似乎很明确,因此我想补充一下,这似乎超级容易。

我有一个提交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".:这将提交您的还原。

  1. git push :这会将所有内容推送到远程存储库中

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


2
行,所以我猜步骤1和2是相互排斥的:如果ABC1是你最后一次提交有没有必要2.如果有ABC1后,就可以直接做2.其他提交
让·保罗·

13
  1. git将文件还原为特定提交
git checkout Last_Stable_commit_Number -- fileName

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

git checkout branchName_Which_Has_stable_Commit fileName

11

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

git checkout eb917a1 YourFileName

如果您只需要返回上一个提交的版本

git reset HEAD YourFileName
git checkout YourFileName

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


10

git checkout ref | commitHash-filePath

例如

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

10

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

如果你想恢复的变化,从一个在单个文件提交而已,就像git revert会做,但只有一个文件(或说的一个子集提交文件),我建议同时使用git diff,并git 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
Amaury D

您可以使用<sha>^!代替<sha>^ <sha>
夸张的

8

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

注意:不要忘记在最后一个字符之前输入哈希值。最后一个哈希点指向您当前的位置(HEAD),并且保持不变。


7

显然,有人需要编写有关git的可理解书籍,或者需要在文档中对git进行更好的解释。面对同样的问题,我猜想

cd <working copy>
git revert master

将撤消似乎正在执行的最后一次提交。

伊恩


7

您可以通过4个步骤进行操作:

  1. 使用您要专门还原的文件还原整个提交-它将在您的分支上创建一个新的提交
  2. 提交的软复位-删除提交并将更改移动到工作区
  3. 手动选择文件以还原并提交
  4. 将所有其他文件放到工作区中

您需要在终端中输入什么

  1. git revert <commit_hash>
  2. git reset HEAD~1
  3. git add <file_i_want_to_revert> && git commit -m 'reverting file'
  4. git checkout .

祝好运


那不是还原所有更改吗?
arcee123 '18 -10-29

1
@ arcee123是,但是随后的重置将撤消所有更改的还原。问题是git-revert只能对整个仓库进行操作,因此要进行补偿,我们必须撤消其他所有事务。
蒂莫西

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

@ greg-hewgill的答案更好,更准确。这是糟糕的,不应该使用。
Daniel Tranca

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

7

这是非常简单的步骤。签出文件到我们想要的提交ID,这里是一个提交ID,然后是git commit修改,我们就完成了。

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

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


5
git revert <hash>

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

如果您想还原特定文件中的更改,并且提交的更改比该文件的更改多,那并不能解决您的问题。


5

如果您在最后一次提交中提交了错误的文件,请遵循以下说明:

  1. 开源树,更改为此提交

开源树

  1. 更改行并找到您的提交,即作为提交发送的错误文件

在此处输入图片说明

  1. 您可以看到该提交中的更改列表 源代码树中的文件列表
  2. 选择它,然后单击右侧的按钮...单击反向文件
  3. 然后您可以在左下角的文件状态标签上看到它,然后单击取消登台:

文件状态标签

  1. 打开Visual Studio代码并通过提交已删除的文件来还原
  2. 毕竟,您可以在源树中的最后一次提交中看到结果

在此处输入图片说明

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.