如何将文件重置或恢复到特定版本?
Posted
技术标签:
【中文标题】如何将文件重置或恢复到特定版本?【英文标题】:How can I reset or revert a file to a specific revision? 【发布时间】:2010-09-07 07:25:56 【问题描述】:我对已作为一组文件的一部分提交了几次的文件进行了一些更改,但现在想将其上的更改重置/恢复为以前的版本。
我已经完成了git log
和git diff
以找到我需要的修订,但只是不知道如何将文件恢复到过去的状态。
【问题讨论】:
还原后,检查git diff
时不要忘记--cached
。 link
我在谷歌搜索时发现了你的问题。但是在我阅读了解决方案之后,我检查了我的日志并发现,我将 thouse 更改作为一个独立的提交进行了,所以我为那个提交做了 git revert ,其他的一切都保持了我想要的状态。不是解决方案,有时只是另一种方法。
我使用这个手动解决方案: $ git revert git checkout -- foo
这会将foo
重置为 HEAD。您还可以:
git checkout HEAD^ foo
返回一个修订版,等等。
【讨论】:
我建议使用语法git checkout -- foo
以避免任何错误,如果foo
是特殊的(如目录或名为-f
的文件)。使用 git,如果您不确定,请始终在所有文件和目录前加上特殊参数 --
。
对 Mikko 评论的附加说明:--
不是 git 命令,对 git 来说也不是特别的。它是一个内置的 bash,用于表示命令选项的结束。您也可以将它与许多其他 bash 命令一起使用。
@matthaeus 它既不是特定于 bash 也不是 shell 功能。这是一个在许多不同命令中实现的约定(并由 getopt 支持)。
不,--
不是 bash 中的内置特殊词。但它是许多命令行解析器支持并被许多 CLI 使用的通用约定,包括 git。【参考方案2】:
有趣的是,如果工作副本位于名为 foo
的目录中,git checkout foo
将无法工作;但是,git checkout HEAD foo
和 git checkout ./foo
都会:
$ pwd
/Users/aaron/Documents/work/foo
$ git checkout foo
D foo
Already on "foo"
$ git checkout ./foo
$ git checkout HEAD foo
【讨论】:
【参考方案3】:但请注意,git checkout ./foo
和 git 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
修改之前这样做。
【讨论】:
【参考方案4】:假设你想要的提交的哈希是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:有没有办法扭转它,所以它是紧随其后的版本? @aliteralmind:不,不幸的是,Git 历史快捷方式符号只会在历史中倒退。 如果您要为 abcde 使用分支名称(例如develop
),您将需要 git checkout develop -- file/to/restore
(注意双破折号)
@alliteralmind:实际上,是的,有一种方法可以做到:“git log --reverse -1 --ancestry-path yourgitrev..master”,然后使用适当的选项来获取混帐转。 --ancestry-path 将在两次提交之间“画一条线”,-1 将只显示一个版本,而 --reverse 将确保发出的第一个条目是最旧的。
我个人觉得 HEAD^ 比 HEAD~1 更容易输入 :)【参考方案5】:
我必须在这里插入EasyGit,这是一个包装器,可以让新手更容易接受 git,而不会混淆经验丰富的用户。它所做的一件事是give more meanings to git revert
。在这种情况下,您只需说:
@987654323@ <b>foo/bar foo/baz</b>
【讨论】:
应该是eg revert --in REVISON -- FILENAME
。 --in
很重要。对于那里的 Windows 用户:打开 git bash。执行echo %PATH
。第一个路径应该在以bin
结尾的用户目录中。创建该路径。将eg 存储在那里。将其命名为eg
。不是eg.txt
。【参考方案6】:
我想我找到了....来自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 从不删除任何东西”是不正确的。【参考方案7】:
您可以使用 diff 命令快速查看对文件所做的更改:
git diff <commit hash> <filename>
然后要将特定文件恢复到该提交,请使用重置命令:
git reset <commit hash> <filename>
如果您有本地修改,您可能需要使用--hard
选项。
管理航点的一个很好的工作流程是使用标签来清晰地标记时间轴中的点。我不太明白你的最后一句话,但你可能想要的是从前一个时间点分出一个分支。为此,请使用方便的结帐命令:
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 checkoutgit 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>
【参考方案8】:
git revert <hash>
将还原给定的提交。听起来您认为 git revert
只会影响最近的提交。
这并不能解决您的问题,如果您想恢复特定文件中的更改并且该提交的更改比该文件更多。
【讨论】:
【参考方案9】:说“回滚”时必须小心。如果您曾经在提交 $A 中有一个文件版本,然后在两个单独的提交 $B 和 $C 中进行了两次更改(所以您看到的是文件的第三次迭代),并且如果您说“我想回滚到第一个”,你真的是这个意思吗?
如果你想摆脱第二次和第三次迭代的变化,这很简单:
$ git checkout $A file
然后你提交结果。该命令询问“我想从提交 $A 记录的状态中检出文件”。
另一方面,您的意思是摆脱第二次迭代(即提交 $B)带来的更改,同时保留提交 $C 对文件所做的更改,您希望恢复 $B
$ git revert $B
请注意,创建提交 $B 的人可能不是很自律,并且可能在同一次提交中提交了完全不相关的更改,并且此还原可能会触及 file 以外的文件,您会看到有问题的更改,所以这样做后您可能需要仔细检查结果。
【讨论】:
我这样做了,但是“git 日志文件”会说我在原始提交上,HEAD。似乎“git checkout”失败了。但是,git status 显示该文件实际上已更改,并且“git diff --staged 文件”将显示实际更改。此外,“git status”显示文件也已更改。所以不要在这里使用“git log”来跟踪哪些文件发生了变化。 @FrederickOllinger - 这种行为是有道理的,因为git log
显示提交,而您还没有提交更改(还原)。如果您在恢复后执行git commit
,则git log
将显示更改。【参考方案10】:
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结帐 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>
... 进行快进合并以将所有<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>
【讨论】:
【参考方案11】:如果您知道需要返回多少次提交,您可以使用:
git checkout master~5 image.png
这假设您在 master
分支上,并且您想要的版本是 5 次提交。
【讨论】:
【参考方案12】:您可以使用对 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”。【参考方案13】:
我刚才遇到了同样的问题,我发现this answer 最容易理解(commit-ref
是您要返回的日志中更改的 SHA 值):
git checkout [commit-ref] [filename]
这会将旧版本放在您的工作目录中,如果需要,您可以从那里提交它。
【讨论】:
迄今为止最好的答案【参考方案14】:这对我有用:
git checkout <commit hash> file
然后提交更改:
git commit -a
【讨论】:
【参考方案15】:使用git log
获取特定版本的hash key,然后使用git checkout <hashkey>
注意:不要忘记在最后一个之前输入哈希。最后一个哈希指向您当前的位置(HEAD)并且没有任何改变。
【讨论】:
【参考方案16】:显然有人需要写一本关于 git 的通俗易懂的书,或者需要在文档中更好地解释 git。面对同样的问题,我猜是
cd <working copy>
git revert master
将撤消似乎要做的最后一次提交。
伊恩
【讨论】:
【参考方案17】:要恢复到最常需要的最后提交版本,您可以使用这个更简单的命令。
git checkout HEAD file/to/restore
【讨论】:
这个(git checkout HEAD file/to/restore)和git reset --hard file/to/restore有什么区别??? 1) 更容易记住更通用的方式 2) 输入文件名之前不用担心按 Enter 【参考方案18】:git checkout ref|commitHash -- 文件路径
例如
git checkout HEAD~5 -- foo.bar
or
git checkout 048ee28 -- foo.bar
【讨论】:
【参考方案19】:如果您想将文件恢复到以前的提交(以及您要恢复的文件已经提交),您可以使用
git checkout HEAD^1 path/to/file
或
git checkout HEAD~1 path/to/file
然后只需暂存并提交“新”版本。
知道在合并的情况下提交可以有两个父级,您应该知道 HEAD^1 是第一个父级,而 HEAD~1 是第二个父级。
如果树中只有一个父级,任何一个都可以工作。
【讨论】:
【参考方案20】:为了转到文件的先前提交版本,请获取提交号,例如 eb917a1 那么
git checkout eb917a1 YourFileName
如果你只需要回到上次提交的版本
git reset HEAD YourFileName
git checkout YourFileName
这只会带您进入文件的最后提交状态
【讨论】:
【参考方案21】:git-aliases、awk 和 shell 函数来救援!
git prevision <N> <filename>
其中<N>
是文件<filename>
要回滚的文件修订版数。
例如,要检查单个文件 x/y/z.c
的上一个版本,运行
git prevision -1 x/y/z.c
How git prevision works?
将以下内容添加到您的gitconfig
[alias]
prevision = "!f() git checkout `git log --oneline $2 | awk -v commit="$1" 'FNR == -commit+1 print $1'` $2; ;f"
命令基本
对指定文件执行git log
并 在文件历史记录中选择适当的提交 ID 并 对指定文件的提交 ID 执行git checkout
。
基本上,在这种情况下,所有手动操作, 包裹在一个漂亮、高效的 git 别名中 - git-prevision
【讨论】:
【参考方案22】:这里有很多建议,大部分是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
【讨论】:
如果您不确定自己想要哪个提交版本并且需要“查看”而不覆盖您的工作目录,这是一个不错的选择。【参考方案23】:这里的许多答案声称使用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
你可以用<sha>^!
代替<sha>^ <sha>
【参考方案24】:
这是我的方式。
a) 在 android Studio 中,打开文件。
b) git -> Show History,找到我想要恢复的上一个提交。获取 commit_id(即提交哈希)。
c)git checkout commit_id file_path
【讨论】:
你的方式正是接受答案的方式。【参考方案25】:对我来说,没有一个回复看起来很清楚,因此我想添加我的,这看起来超级简单。
我有一个提交 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. 【参考方案26】:目标文件的第一个重置头
git reset HEAD path_to_file
第二次签出该文件
git checkout -- path_to_file
【讨论】:
+1,但不确定重置 HEAD 的意图。它可能需要也可能不需要。在我的情况下,我只想将一个特定文件恢复为存储库中的版本(保持剩余的本地更改完好无损。只需运行上面的第二步对我来说就足够了 是的,我只需要运行第二个命令。喜欢 --> shellhacks.com/git-revert-file-to-previous-commit【参考方案27】:如果您使用 Git 扩展并且只想恢复到文件的父提交,则可以选择包含要恢复的更改的提交,然后在详细信息窗格中选择“差异”选项卡,右键单击要还原的文件,然后“将文件重置为” ....,然后单击“A”(父级)
【讨论】:
【参考方案28】:您可以分 4 步完成:
-
使用您要专门恢复的文件恢复整个提交 - 它会在您的分支上创建一个新提交
提交的软重置 - 删除提交并将更改移动到工作区
手动选择要还原并提交的文件
删除工作区中的所有其他文件
您需要在终端中输入的内容:
git revert <commit_hash>
git reset HEAD~1
git add <file_i_want_to_revert>
&& 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"
新的分支提示反映了除还原文件之外的所有更改。【参考方案29】:
如果您在上次提交中提交了错误的文件,请按照说明操作:
-
开源树,改到这个提交
-
更改行并找到您提交的错误文件作为提交发送的提交
-
您可以在该提交中看到您的更改列表
选择它,然后单击...右侧的按钮...单击反向文件
然后您可以在左下角的文件状态选项卡上看到它
然后点击取消暂存:
-
打开您的 Visual Studio 代码并通过提交已删除的文件来恢复
在所有这些之后,您可以在源代码树中看到上次提交的结果
【讨论】:
【参考方案30】:这是一个非常简单的步骤。签出文件到我们想要的提交 id,这里是之前的一个提交 id,然后只需 git commit amend 就完成了。
# git checkout <previous commit_id> <file_name>
# git commit --amend
这很方便。如果我们想将任何文件带到提交顶部的任何先前提交 id,我们可以轻松做到。
【讨论】:
谢谢,阿布舍克。根据您的回答,我制作了这个 Shellscipt:gist.github.com/ivanleoncz/c20033e5f4b24304cbc39e0bac1d43e8 随时改进:)。以上是关于如何将文件重置或恢复到特定版本?的主要内容,如果未能解决你的问题,请参考以下文章