git恢复到某些提交而不更改历史记录并创建像git revert这样的新提交

时间:2018-03-20 15:26:45

标签: git revert git-revert

有没有办法在不更改远程历史记录的情况下恢复到某个提交,基本上在git revert中撤消新提交中该提交的所有更改?

例如 - 我有3次提交 提交A - > B - > C,我的头目前在C 我想现在创建另一个提交D,它将具有与A相同的代码,以便我可以将该提交推送到远程分支而不更改历史记录。

2 个答案:

答案 0 :(得分:5)

小心"还原"

当人们说'#34;我想恢复"在Git中,它们有时意味着git revert所做的事情,更多的是退出操作,有时意味着你做了什么,这是从早期版本恢复源代码库

为了说明,假设我们的提交只有一个文件README和三个提交:

A <-B <-C   <-- master (HEAD)

修订版A中README的版本说&#34;我是自述文件&#34;,只有一行。

修订版B中README的版本说&#34;我是自述文件。&#34;和以前一样,但是添加了第二行,&#34;这个文件长五行。&#34;

修订版C中的README版本已更正,其第二行显示为&#34;此文件长两行。&#34;

Git&#39; git revert可以撤消更改,因此,现在,正在运行git revert <hash-of-B>将尝试删除添加的行。这将失败,因为该行不再匹配(我们可以运行git revert --abort放弃)。同样,运行git revert <hash-of-C>会尝试撤消更正。这将成功,有效地将恢复为版本B

这个问题,Undo a particular commit in Git that's been pushed to remote repos,都是关于退出的回归。虽然这有时会导致恢复 - 恢复,但它并不相同。根据你的问题,你想要的更多:&#34;让我一个新的提交D,它具有与提交A相同的源代码&#34; 。您希望还原为版本A

Git没有恢复的用户命令,但很容易

这个问题,How to revert Git repository to a previous commit?,充满了关于使用git reset --hard的答案,而git checkout 0d1d7fc32 . 正在完成这项工作,但却是通过砍掉历史来实现的。但是,accepted answer包括其中一个键,特别是:

0d1d7fc32

此命令告诉Git从给定的commit .中提取该快照和当前目录(.)中的所有文件。如果当前目录是工作树的顶部,那么将从所有目录中提取文件,因为$ echo new file > newfile $ git add newfile $ git commit -m 'add new file' 递归地包含子目录文件。

这样做的一个问题是,是的,它会提取所有文件,但它不会删除(来自索引和工作树)你拥有的任何文件不想要。为了说明,让我们回到我们的三个提交存储库并添加第四个提交:

A <-B <-C <-D   <-- master (HEAD)

现在我们有四个提交:

D

其中,提交README具有正确的两行newfile新文件$ git checkout <hash-of-A> -- .

如果我们这样做:

README

我们将使用commit A中的版本覆盖README的索引和工作树版本。我们将回到单行newfile。但是,在我们的索引和工作树中,我们仍然会有文件$ git rm -r -- .

要解决这个问题,我们应该从删除索引中的所有文件开始,而不是仅仅检出提交中的所有文件:

A

然后从提交$ git checkout <hash> -- . 重新填充索引和工作树是安全的:

--

(我尝试在这里自动使用-f,以防我想要的路径名称类似于选项或分支名称或类似名称;即使我只想查看文件或目录,它也可以使用例如,名为git commit

完成这两个步骤后,git read-tree结果就安全了。

次要:快捷方式

由于Git实际上只是从索引进行提交,所以你要做的就是将所需的提交复制到索引中。 $ git read-tree -u <hash> 命令执行此操作。您可以让它同时更新工作树,所以:

 SELECT TOP (1) [ECB_ID] AS id
   ,[ECB_PASSWORD_GENERATED] AS pass
   ,[ECB_CONSECUTIVE_NUMBER] AS CONSECUTIVE...

足以代替remove-and-checkout。 (你必须像往常一样进行新的提交。)

答案 1 :(得分:0)

  1. git reset --hard <Commit A>
  2. git reset --soft <Commit C>
  3. git add . && git commit -m "Commit D"

现在在D处,先前的提交A,B和C已全部保留