1. 概述

git rebase 是编写干净代码提交历史的最佳实践,特别是在多开发者代码库中。手动完成此操作后,我们可能希望恢复到原始状态。

在这个教程中,我们将探讨几种撤销git rebase操作的方法

2. 设置

让我们创建一个测试环境,模拟一个多开发者代码仓库,其中包含多个分支。我们可以假设development分支是项目的单一真相,每个开发者使用特定功能分支来开发特定功能:

现在,假设项目已准备好这种版本控制,让我们切换到feature2分支:

$ git branch --show-current
feature2

最后,让我们查看feature1feature2分支的代码提交历史:

$ git log feature1
commit e5e9afbbd82e136fc20957d47d05e72a38d8d10d
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:27:22 2022 +0530

    Add feature-1

commit 033306a06895a4034b681afa912683a81dd17fed
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:27:22 2022 +0530

    Add .gitignore file

$ git log feature2
commit 9cec4652f34f346e293b19a52b258d9d9a49092e
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:27:22 2022 +0530

    Add feature-2

commit 033306a06895a4034b681afa912683a81dd17fed
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:27:22 2022 +0530

    Add .gitignore file

在后续章节中,我们将反复使用这个基础场景,先进行一次git rebase操作,然后依次应用每种方法来撤销重置操作。

3. 使用ORIG_HEAD

首先,在一个干净的场景下检查feature2分支的当前提交:

$ git log HEAD
commit 728ceb3219cc5010eae5840c992072cac7a5da00 (HEAD -> feature2)
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add feature-2

commit 6ed8a4d2a961fdfc4d5e4c7c00b221ed6f283bf4 (development)
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add .gitignore file

现在,我们将feature2分支基于feature1分支进行重置:

$ git rebase feature1

完成重置操作后,查看HEAD引用:

$ git log HEAD
commit 9d38b792d0c9a8d0cd8e517fcb2ca5260989cc4a
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add feature-2

commit 1641870338662a016d5c8a17ef5cada0309f107e
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add feature-1

commit 6ed8a4d2a961fdfc4d5e4c7c00b221ed6f283bf4
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add .gitignore file

进一步验证ORIG_HEAD仍然指向728ceb3219cc5010eae5840c992072cac7a5da00提交:

$ git log ORIG_HEAD
commit 728ceb3219cc5010eae5840c992072cac7a5da00
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add feature-2

commit 6ed8a4d2a961fdfc4d5e4c7c00b221ed6f283bf4
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add .gitignore file

最后,使用ORIG_HEAD参考执行reset操作

$ git reset --hard ORIG_HEAD
$ git log HEAD -1
commit 728ceb3219cc5010eae5840c992072cac7a5da00
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 16:46:56 2022 +0530

    Add feature-2

就这样!借助ORIG_HEAD,我们成功地撤销了重置操作。

4. 使用git reflog

再次,从一个全新的场景设置开始:

$ git log HEAD
commit 07b98ef156732ba41e2cbeef7939b5bcc9c364bb
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add feature-2

commit d6c52eb601e3ba11d65e7cb6e99ec6ac6018e272
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add .gitignore file

现在,进行一次重置并检查提交历史:

$ git rebase feature1
$ git log HEAD
commit b6ea25bf83ade2caca5ed92f6c5e5e6a3cb2ca7b
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add feature-2

commit d2cabe48747699758e2b14e76fb2ebebfc49acb1
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add feature-1

commit d6c52eb601e3ba11d65e7cb6e99ec6ac6018e272
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add .gitignore file

接下来,使用git reflog命令以详细级别查看事件记录

$ git reflog
b6ea25b HEAD@{0}: rebase (continue) (finish): returning to refs/heads/feature2
b6ea25b HEAD@{1}: rebase (continue): Add feature-2
d2cabe4 HEAD@{2}: rebase (start): checkout feature1
07b98ef HEAD@{3}: commit: Add feature-2
d6c52eb HEAD@{4}: checkout: moving from feature1 to feature2
d2cabe4 HEAD@{5}: commit: Add feature-1
d6c52eb HEAD@{6}: checkout: moving from development to feature1
d6c52eb HEAD@{7}: Branch: renamed refs/heads/master to refs/heads/development
d6c52eb HEAD@{9}: commit (initial): Add .gitignore file

我们可以看到git在内部以粒度维护引用,重置操作前HEAD的位置由HEAD@{3}引用表示。

因此,作为最后一步,通过git reset恢复先前状态:

$ git reset --hard HEAD@{3}
$ git log HEAD
commit 07b98ef156732ba41e2cbeef7939b5bcc9c364bb
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add feature-2

commit d6c52eb601e3ba11d65e7cb6e99ec6ac6018e272
Author: Tapan Avasthi <[email protected]>
Date:   Sun Jul 31 17:53:35 2022 +0530

    Add .gitignore file

太好了!我们也成功掌握了这种方法。然而,这种方法利用了git的一些底层细节,只适用于高级git用户

5. 总结

在这篇文章中,我们使用了一个git仓库的测试场景,学习了两种撤销git rebase操作的流行方法。