回溯历史版本

git reset

通过前面学习的操作,我们已经学会如何在实现功能后进行提交,累积提交日志作为历史记录,借此不断培育一款软件。

Git的另一特征便是可以灵活操作历史版本。借助分散仓库的优势,可以在不影响其他仓库的前提下对历史版本进行操作。

在这里,为了让各位熟悉对历史版本的操作,我们先回溯历史版本,创建一个名为fix-B的特性分支。

回溯到创建feature-A分支前

让我们先回溯到上一节feature-A分支创建之前,创建一个名为fix-B的特性分支。

要让仓库的HEAD、暂存区、当前工作树回溯到指定状态,需要用到git reset --hard命令。只要提供目标时间点的哈希值,就可以完全恢复至该时间点的状态。让我们执行下面的命令。

$ git log

commit a5f6cbf52a36dd104e131e32e67531656640c0c3

Merge: c87f9ae 320739b

Author: frankphper <1678723151@qq.com>

Date:   Mon Apr 11 08:16:48 2016 +0800


    Merge branch 'feature-A'


commit 320739b163a92ab90e24abfb814ab7fc09e9c9a0

Author: frankphper <1678723151@qq.com>

Date:   Mon Apr 11 07:59:05 2016 +0800


    Add feature-A


commit c87f9ae6da0ccffedda289c55e55e7bc7900dfe0

Author: frankphper <1678723151@qq.com>

Date:   Sun Apr 10 23:33:16 2016 +0800


    Add #Git学习


commit c75e47ad83d604e234eac38bb3aec57226f79974

Author: frankphper <1678723151@qq.com>

Date:   Sun Apr 10 23:01:24 2016 +0800


    测试使用编辑器记述详细提交信息


commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc

Author: frankphper <1678723151@qq.com>

Date:   Sun Apr 10 22:49:19 2016 +0800


    My first commit


$ git reset --hard c87f9ae6da0ccffedda289c55e55e7bc7900dfe0 

HEAD is now at c87f9ae Add #Git学习

我们已经成功回溯到特性分支(feature-A)创建之前的状态。由于所有文件都回溯到了指定哈希值对应的时间点上,README.md文件的内容也恢复到了当时的状态。

创建fix-B分支

现在我们来创建特性分支(fix-B)

我们在README.md文件中添加一行文字。

Git Learn

#Git学习

fix-B

然后直接提交README.md文件。

$ git add README.md

$ git commit -m "fix-B"

[fix-B 6814da3] fix-B

 1 file changed, 1 insertion(+)

接下来,我们的目标是主干分支合并feature-A分支的修改后,又合并了fix-B的修改。

推进至feature-A分之合并后的状态

首先恢复到feature-A分支合并后的状态。不妨称这一操作为“推进历史”。

git log命令只能查看以当前状态为终点的历史日志。所以这里要使用git reflog命令,查看当前仓库的操作日志。在日志中找出回溯历史之前的哈希值,通过git reset --hard命令恢复到回溯历史前的状态。

首先执行git reflog命令,查看当前仓库执行过的操作的日志。

$ git reflog

6814da3 HEAD@{0}: commit: fix-B

c87f9ae HEAD@{1}: reset: moving to c87f9ae6da0ccffedda289c55e55e7bc7900dfe0

a5f6cbf HEAD@{2}: checkout: moving from master to fix-B

a5f6cbf HEAD@{3}: merge feature-A: Merge made by the 'recursive' strategy.

c87f9ae HEAD@{4}: checkout: moving from feature-A to master

320739b HEAD@{5}: checkout: moving from master to feature-A

c87f9ae HEAD@{6}: checkout: moving from feature-A to master

320739b HEAD@{7}: commit: Add feature-A

c87f9ae HEAD@{8}: checkout: moving from master to feature-A

c87f9ae HEAD@{9}: commit: Add #Git学习

c75e47a HEAD@{10}: commit: 测试使用编辑器记述详细提交信息

858ba4b HEAD@{11}: commit (initial): My first commit

在日志中,我们可以看到commit、checkout、reset、merge等Git命令的执行纪律。只要不进行Git的GC(Garbage Collection,垃圾回收),就可以通过日志随意调取近期的历史状态,就像给时间机器指定一个时间点,在过去未来中自由穿梭一般。即便开发者错误执行了Git操作,基本也都可以利用git reflog命令恢复到原先的状态。

从上面数第四行表示feature-A特性分支合并后的状态,对应哈希值为a5f6cbf。我们将HEAD、暂存区、工作树恢复到这个时间点的状态。

$ git checkout master

Switched to branch 'master'

$ git reset --hard a5f6cbf

HEAD is now at a5f6cbf Merge branch 'feature-A'

之前我们使用git reset --hard命令回溯了历史,这里又再次通过它恢复到了回溯前的历史状态。