git 恢复到某个提交而不更改历史并创建新的提交,如 git 恢复
git revert back to certain commit without changing history and creating a new commit like git revert
有没有办法在不更改远程历史记录的情况下恢复到某个提交,基本上是在新提交中撤消该提交的所有更改,就像 git 恢复一样?
例如 - 我有 3 次提交
提交 A -> B -> C,我的头目前在 C
我现在想创建另一个提交 D,它将具有与 A 相同的代码,以便我可以将该提交推送到远程分支而不更改历史记录。
注意单词"revert"
当人们在 Git 中说 "I want to revert" 时,他们有时指的是 git revert
所做的,更像是 back out 操作,并且有时意味着您所做的,即从早期版本.
恢复源代码库
为了说明,假设我们有一个只有一个文件的提交,README
,以及三个提交:
A <-B <-C <-- master (HEAD)
修订版 A 中 README
的版本说 "I am a README file",只有一行长。
修订版 B 中的 README
版本与以前一样显示 "I am a README file.",但添加了第二行,"This file is five lines long."
修订版 C 中 README
的版本已更正,因为它的第二行显示 "This file is two lines long."
Git 的 git revert
可以 撤消 更改,因此,现在 运行ning 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,都是关于 backing-out 那种回溯的。虽然这有时会导致 reverting-to 类型的恢复,但这并不相同。根据您的问题,您想要的是更多:"make me a new commit D
that has the same source code as commit A
"。您想要恢复到 版本A
。
Git 没有 恢复到 的用户命令,但很容易
不过,这个问题 How to revert Git repository to a previous commit?, is full of answers talking about using git reset --hard
, which does the job—but does it by lopping off history. The accepted answer 包含其中一个关键点,特别是这个:
git checkout 0d1d7fc32 .
此命令告诉 Git 从给定的提交 0d1d7fc32
中提取 该快照和当前目录中的所有文件 ( .
)。如果您的当前目录是 work-tree 的顶部,那将从所有目录中提取文件,因为 .
递归地包含 sub-directory 个文件。
这样做的一个问题是,是的,它会提取所有文件,但不会删除(从索引和work-tree)任何文件你有你不想要的。为了说明,让我们回到我们的 three-commit 存储库并添加第四次提交:
$ echo new file > newfile
$ git add newfile
$ git commit -m 'add new file'
现在我们有四个提交:
A <-B <-C <-D <-- master (HEAD)
其中提交 D
具有正确的 two-line README
、 和 新文件 newfile
.
如果我们这样做:
$ git checkout <hash-of-A> -- .
我们将用提交 A
的版本覆盖 README
的索引和 work-tree 版本。我们会回到 one-line README
。但是在我们的索引和 work-tree 中,我们仍然会有文件 newfile
.
要解决这个问题,我们应该从 删除 索引中的所有文件开始,而不是仅仅从提交中检出所有文件:
$ git rm -r -- .
然后 re-fill 索引和 work-tree 来自提交 A
:
是安全的
$ git checkout <hash> -- .
(我尝试在此处自动使用 --
,以防我想要的路径名称类似于选项或分支名称或类似名称;即使我只想签出文件,它也能正常工作或名为 -f
的目录)。
完成这两个步骤后,git commit
结果就安全了。
次要:快捷方式
因为Git实际上只是从索引中进行提交,所以您所要做的就是将所需的提交复制到索引中。 git read-tree
命令执行此操作。您可以让它同时更新 work-tree,因此:
$ git read-tree -u <hash>
足以代替 remove-and-checkout。 (您仍然必须像往常一样进行新的提交。)
git reset --hard <Commit A>
git reset --soft <Commit C>
git add . && git commit -m "Commit D"
现在在 D 并且之前的提交 A、B 和 C 都已保留
有没有办法在不更改远程历史记录的情况下恢复到某个提交,基本上是在新提交中撤消该提交的所有更改,就像 git 恢复一样?
例如 - 我有 3 次提交 提交 A -> B -> C,我的头目前在 C 我现在想创建另一个提交 D,它将具有与 A 相同的代码,以便我可以将该提交推送到远程分支而不更改历史记录。
注意单词"revert"
当人们在 Git 中说 "I want to revert" 时,他们有时指的是 git revert
所做的,更像是 back out 操作,并且有时意味着您所做的,即从早期版本.
为了说明,假设我们有一个只有一个文件的提交,README
,以及三个提交:
A <-B <-C <-- master (HEAD)
修订版 A 中 README
的版本说 "I am a README file",只有一行长。
修订版 B 中的 README
版本与以前一样显示 "I am a README file.",但添加了第二行,"This file is five lines long."
修订版 C 中 README
的版本已更正,因为它的第二行显示 "This file is two lines long."
Git 的 git revert
可以 撤消 更改,因此,现在 运行ning 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,都是关于 backing-out 那种回溯的。虽然这有时会导致 reverting-to 类型的恢复,但这并不相同。根据您的问题,您想要的是更多:"make me a new commit D
that has the same source code as commit A
"。您想要恢复到 版本A
。
Git 没有 恢复到 的用户命令,但很容易
不过,这个问题 How to revert Git repository to a previous commit?, is full of answers talking about using git reset --hard
, which does the job—but does it by lopping off history. The accepted answer 包含其中一个关键点,特别是这个:
git checkout 0d1d7fc32 .
此命令告诉 Git 从给定的提交 0d1d7fc32
中提取 该快照和当前目录中的所有文件 ( .
)。如果您的当前目录是 work-tree 的顶部,那将从所有目录中提取文件,因为 .
递归地包含 sub-directory 个文件。
这样做的一个问题是,是的,它会提取所有文件,但不会删除(从索引和work-tree)任何文件你有你不想要的。为了说明,让我们回到我们的 three-commit 存储库并添加第四次提交:
$ echo new file > newfile
$ git add newfile
$ git commit -m 'add new file'
现在我们有四个提交:
A <-B <-C <-D <-- master (HEAD)
其中提交 D
具有正确的 two-line README
、 和 新文件 newfile
.
如果我们这样做:
$ git checkout <hash-of-A> -- .
我们将用提交 A
的版本覆盖 README
的索引和 work-tree 版本。我们会回到 one-line README
。但是在我们的索引和 work-tree 中,我们仍然会有文件 newfile
.
要解决这个问题,我们应该从 删除 索引中的所有文件开始,而不是仅仅从提交中检出所有文件:
$ git rm -r -- .
然后 re-fill 索引和 work-tree 来自提交 A
:
$ git checkout <hash> -- .
(我尝试在此处自动使用 --
,以防我想要的路径名称类似于选项或分支名称或类似名称;即使我只想签出文件,它也能正常工作或名为 -f
的目录)。
完成这两个步骤后,git commit
结果就安全了。
次要:快捷方式
因为Git实际上只是从索引中进行提交,所以您所要做的就是将所需的提交复制到索引中。 git read-tree
命令执行此操作。您可以让它同时更新 work-tree,因此:
$ git read-tree -u <hash>
足以代替 remove-and-checkout。 (您仍然必须像往常一样进行新的提交。)
git reset --hard <Commit A>
git reset --soft <Commit C>
git add . && git commit -m "Commit D"
现在在 D 并且之前的提交 A、B 和 C 都已保留