第12章 改变历史

我是电影《回到未来》的粉丝,偶尔会做梦,梦见穿梭到未来拿回一本2000-2050体育年鉴。操作Git也可以体验到穿梭时空的感觉,因为Git像极了一个时光机器,不但允许你在历史中穿梭,而且还能够改变历史。

本章的最开始将介绍两种最简单和最常用的历史变更操作——“悔棋”操作,就是对刚刚进行的一次或几次提交进行修补或撤销。对于跳跃式的历史记录的变更,即仅对过去某一个或某几个提交做出改变,会在“回到未来”小节详细介绍。在“丢弃历史”小节会介绍一种版本库瘦身的方法,这可能会在某些特定的场合用到。

作为分布式版本控制系统,一旦版本库被多人共享,改变历史就可能是无法完成的任务。在本章的最后,介绍还原操作以实现在不改变历史提交的情况下还原错误的改动。

12.1 悔棋

在日常的Git操作中,会经常出现这样的状况,输入git commit命令刚刚敲下回车键就后悔了:可能是提交说明中出现了错别字,或者有文件忘记提交,或者有的修改不应该提交,诸如此类。

像Subversion那样的集中式版本控制系统是“落子无悔”的系统,只能叹一口气责怪自己太不小心了。然后根据实际情况弥补:马上做一次新提交改正前面的错误;或者只能将错就错,错误的提交说明就让它一直错下去吧。因为大部分Subversion管理员不敢或不会放开修改提交说明的功能,从而导致无法对提交说明进行修改。

Git提供了“悔棋”的操作,甚至因为“单步悔棋”是如此经常的发生,乃至于Git提供了一个简洁的操作——修补式提交,命令是:git commit—amend。

看看当前版本库最新的两次提交:


$cd/path/to/my/workspace/demo

$git log—stat-2

commit 822b4aeed5de74f949c9faa5b281001eb5439444

Author:Jiang Xin<jiangxin@ossxp.com>

Date:Wed Dec 8 16:27:41 2010+0800

测试使用qgit提交。

README|1+

src/hello.h|2—

2 files changed,1 insertions(+),2 deletions(-)

commit 613486c17842d139871e0f1b0e9191d2b6177c9f

Author:Jiang Xin<jiangxin@ossxp.com>

Date:Tue Dec 7 19:43:39 2010+0800

偷懒了,直接用-a参数直接提交。

src/hello.h|1+

1 files changed,1 insertions(+),0 deletions(-)


最新一次的提交的确是在上一章使用qgit进行的提交,但这和提交内容无关,因此需要改掉这个提交的提交说明。使用下面的命令即可做到。


$git commit—amend-m "Remove hello.h,which is useless."

[master 7857772]Remove hello.h,which is useless.

2 files changed,1 insertions(+),2 deletions(-)

delete mode 100644 src/hello.h


上面的命令使用了-m参数是为了演示的方便,实际上完全可以直接输入git commit—amend,在弹出的提交说明编辑界面修改提交说明,然后保存退出完成修补提交。

下面再看看最近两次的提交说明,可以看到最新的提交说明更改了(包括提交的SHA1哈希值),而它的父提交(即前一次提交)没有改变。


$git log—stat-2

commit 78577724305e3e20aa9f2757ac5531d037d612a6

Author:Jiang Xin<jiangxin@ossxp.com>

Date:Wed Dec 8 16:27:41 2010+0800

Remove hello.h,which is useless.

README|1+

src/hello.h|2—

2 files changed,1 insertions(+),2 deletions(-)

commit 613486c17842d139871e0f1b0e9191d2b6177c9f

Author:Jiang Xin<jiangxin@ossxp.com>

Date:Tue Dec 7 19:43:39 2010+0800

偷懒了,直接用-a参数直接提交。

src/hello.h|1+

1 files changed,1 insertions(+),0 deletions(-)


如果最后一步操作不想删除文件src/hello.h,而只是想修改README,则可以按照下面的方法进行修补操作,具体操作过程如下。

(1)还原删除的src/hello.h文件。


$git checkout HEAD^—src/hello.h


(2)此时查看状态,会看到src/hello.h被重新添加回暂存区。


$git status

On branch master

Changes to be committed:

(use "git reset HEAD<file>…"to unstage)

#

new file:src/hello.h

#


(3)执行修补提交,不过提交说明是不是也要更改呢,因为毕竟这次提交不会删除文件了。


$git commit—amend-m "commit with—amend test."

[master 2b45206]commit with—amend test.

1 files changed,1 insertions(+),0 deletions(-)


(4)再次查看最近的两次提交,会发现最新的提交不再删除文件src/hello.h了。


$git log—stat-2

commit 2b452066ef6e92bceb999cf94fcce24afb652259

Author:Jiang Xin<jiangxin@ossxp.com>

Date:Wed Dec 8 16:27:41 2010+0800

commit with—amend test.

README|1+

1 files changed,1 insertions(+),0 deletions(-)

commit 613486c17842d139871e0f1b0e9191d2b6177c9f

Author:Jiang Xin<jiangxin@ossxp.com>

Date:Tue Dec 7 19:43:39 2010+0800

偷懒了,直接用-a参数直接提交。

src/hello.h|1+

1 files changed,1 insertions(+),0 deletions(-)