如何在之前的提交中撤销一次文件更改

7

我在git中已经进行了2次提交(但我还没有推送),其中“提交2”是最近的一次提交:

 git log -2
commit 791962d776f66253d656586b097b2677eaa983d1
Author: michael <michael@michael-laptop.(none)>
Date:   Tue Jun 29 23:20:58 2010 -0700

    Commit 2

commit b743075e81f6fe25fe48ddbef2b5e7cc06623533
Author: michael <michael@michael-laptop.(none)>
Date:   Tue Feb 16 23:09:53 2010 -0800

    Commit 1

在我的提交 1 b743075e81f6fe25fe48ddbef2b5e7cc06623533 中,我触及/更改了许多文件:

   dir1/file1.cpp
   dir1/file1.h
   dir1/file2.cpp
   dir1/file2.h

我的问题是,如何回滚我对提交1中 dir1/file2.cpp 和 dir1/file2.h 所做的更改?同时保留其他所有内容不变?
谢谢。
3个回答

6

最简单的解决方案是,从您最新的提交(HEAD)到:

  • 检出旧版本的这两个文件,
  • 添加它们,
  • 然后提交。
    git checkout b743075e81 -- dir1/file2.cpp
    git checkout b743075e81 -- dir1/file2.h
    git add dir1/file2.cpp # 仅在您进行了其他更改时才需要
    git add dir1/file2.h   # 仅在您进行了其他更改时才需要
    git commit -m "还原dir1/file2.cpp和dir1/file2.h"

Chris Johnsen在评论中提到的:

git checkout使用路径规范更新索引(就像使用路径规范的git reset一样),并且工作树,因此除非在检出之后进行了其他更改,否则不需要使用git add


如果您已经使用git push将提交推送到源,则实际上这是您唯一明智的选择。 - Blair Holloway
使用路径规范更新索引(就像使用路径规范的 git reset 一样)和工作树,因此除非在 checkout 后进行了其他更改,否则不需要使用 git add - Chris Johnsen
@michael:那么,Blair回答中描述的git rebase --interactive应该会引起你的兴趣。 - VonC

3
如果您已经将提交推送到远程仓库,那么这里描述的其他解决方案(使用git resetgit checkout,然后是git commit)是您唯一明智的选择。
但是,如果您还没有推送更改,并且想要删除所有文件曾经被提交的痕迹,则交互式变基是一个不错的选择。使用以下命令来变基您最近的两个提交:
git rebase --interactive HEAD~2

一个编辑器将打开,显示您的两个提交。您希望编辑文件以显示以下内容,然后保存;特别地,您想将第一个提交前面的 pick 更改为 edit:
edit b743075 Commit 1
pick 791962d Commit 2

接下来,Git会把我们放到一个状态中,让我们可以编辑第一个提交记录(而不影响第二个提交记录)。它说你可以用git commit --amend修改提交记录,但实际上我们想要重置到head之前的提交记录,并完全撤销它:

git reset HEAD^

这将把提交1中的更改放回您的工作树。然后,只需要git add要保留的文件,并使用git commit重新提交它们:

git add dir1/file1.cpp
git add dir1/file1.h
git commit -m "Commit 1"

最后,进行硬重置以从工作树中删除您不想保留的文件,并完成变基:

git reset --hard
git rebase --continue

完成变基后,您的代码库将拥有这两个提交,但file2.*文件将不再存在。

0
使用以下命令根据需要还原的提交哈希值和文件名回滚到先前提交的文件:
 git reset <commit hash> <filename>

根据您的需求使用

 git reset b743075e81f6fe25fe48ddbef2b5e7cc06623533 dir1/file2.cpp

 git reset b743075e81f6fe25fe48ddbef2b5e7cc06623533 dir1/file2.h

这个方法可以工作,但可能会令人困惑,因为它只“回滚”索引条目,而不是工作树(与git checkout treeish -- pathspecs不同,后者会同时更新索引和工作树)。 - Chris Johnsen

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