我可以在 GIT 中进行部分恢复吗

问题描述 投票:0回答:5

是否可以在多文件提交中仅恢复单个文件或文件中的某些更改?

完整故事 我提交了一堆文件。经过多次提交后,一个无名的人(JACK!!!)将一个文件复制到他的存储库中并提交了几个文件,覆盖了我所做的一些更改。我想恢复被破坏的一个文件,或者更好,进入并恢复该文件中的两个更改。这必须是一个单独的恢复提交,因为它是被拉动和推送的。

git
5个回答
289
投票

您可以通过添加

--no-commit
选项来恢复提交,而无需创建新的提交。这会将所有恢复的文件留在暂存区域中。

从那里,我将执行混合重置(重置的默认设置)以取消暂存文件,并添加我真正想要的更改。然后,提交(如果需要多次提交,您可以添加并提交更多文件),最后,签出当前目录以清除由

revert
产生的任何未提交和未暂存的修改。对于示例工作流程:

git revert <sha-of-bad-commit> --no-commit
git reset   # This gets them out of the staging area

# ...edit bad file to look like it should, if necessary

git add <bad-file>
git commit
git checkout . # This wipes all the undesired reverts still hanging around in the working copy

97
投票

您可以使用

checkout
命令以交互方式应用旧版本的文件。

例如,如果您知道要添加回来的代码被删除的

COMMIT
,则可以运行以下命令:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git 会提示您添加回当前版本文件中缺少的块。您可以使用

e
创建更改的补丁,然后再将其应用回来。


44
投票

您可以使用

git checkout
手动查看要恢复的文件中旧的、好的内容。例如,如果您想将
my-important-file
恢复到
abc123
版本中的版本,您可以这样做

git checkout abc123 -- my-important-file

现在您已经恢复了

my-important-file
的旧内容,如果您愿意,甚至可以编辑它们,并像往常一样进行提交,这将恢复他所做的更改。如果您只想恢复他提交的某些部分,请使用
git add -p
从您正在提交的补丁中仅选择几个部分。


35
投票

我在 Git 邮件列表上找到了一种方法:

git show <commit> -- <path> | git apply --reverse

来源:http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

变化

如果补丁没有完全应用,则该命令会失败(不会导致任何更改),但是使用

--3way

,您会遇到冲突,然后可以手动解决(在这种情况下,
Casey 的答案可能更实用):

git show <commit> -- <path> | git apply --reverse --3way

您还可以使用它来部分还原多个提交,例如:

git log -S<string> --patch | git apply --reverse

恢复任何提交中与

<string>

 匹配的更改的文件。这正是我在用例中所需要的(一些单独的提交对不同文件引入了类似的更改,以及以我不想恢复的不相关方式更改了其他文件)。

如果您在

diff.noprefix=true

 中设置了 
~/.gitconfig
,那么您需要将 
-p0
 添加到 
git apply
 命令,例如 

git show <commit> -- <path> | git apply -p0 --reverse
    

0
投票
恢复提交中除一个文件之外的所有更改

我的情况与提问者类似,只是我想恢复除一个文件之外的整个提交。我喜欢自动生成的恢复提交消息,因为它非常清楚发生了什么,所以我不想使用

git revert --no-commit

 选项。我调整了自动生成的恢复提交消息,以澄清哪些更改未恢复。

解决方案

$ git revert COMMIT # Revert the revert. This means our files will be in the same state # as they were before the revert, which is what we want for # the one file we didn't want to change. $ git revert HEAD --no-commit # Since we want to revert most of the files, unstage them so we can # remove their changes. Don't unstage the file you want to remain # untouched in the end $ git reset file1 file2 $ git checkout file1 file2 # Make sure the one file we don't want to change is still staged $ git status # Amend the autogenerated revert commit to remove # the file we didn't want to touch $ git commit --amend -C HEAD # View the revert commit and make sure the file we didn't want # to touch isn't there! $ git show # Done! $ git push
为什么有人想要这样做?

就我而言,我创建了一个提交,将配置更新为所需的最终状态,同时还添加了迁移逻辑来处理之前和之后的状态。一旦所有内容都更新为使用所需的最终状态配置,只需删除我提交中的迁移逻辑,而不需要更改配置文件。因此需要从提交中恢复除一个文件之外的所有文件。

© www.soinside.com 2019 - 2024. All rights reserved.