Git
1、修改历史信息
要修改历史信息,可使用--amend
参数来修改最后一次Commit的信息,但这仅限于最后一次,如果要改动其他更早的信息,就得使用其他方法了。
前面介绍过的git rebase
指令有一种强大的互动模式,接下来的几节内容都是介绍怎样使用这种模式来改动过去的历史记录。首先看一下当前的状况:
git log --oneline
1.1、启动互动模式
下面使用Rebase指令整理一下:
git rebase -i 4cb958a
-i参数是指要进入Rebase指令的“互动模式”,而后面的4cb958a是指这次Rebase指令的应用范围为“从现在到4cb958a这个Commit”,也就是最开始的那个Commit。这个指令会弹出一个Vim编辑器:
这里需注意以下两点:
- 上面的顺序与git log指令的结果是相反的,但在SourceTree界面中是一样的。
- 上面的pick是指“保留这次的Commit,不做改动”,其他指令稍后会介绍。
修改指令,选取两行把pick改成reword(r):
存档并离开之后,会立即弹出另一个Vim编辑器画面:
修改第一个Commit信息,然后保存:
修改第二个Commit信息,然后保存:
再次查看历史记录:
1.2、修改Commit信息的影响
看起来好像只是改了信息,只涉及单纯的文字变动,其实没有那么简单。如果仔细看,就会发现那两次Commit的SHA-1值都变了,这两次的Commit已经是全新的Commit对象了。
进行Rebase时,Commit对象并不是剪切、粘贴而已,因为要接的前一个Commit不同(其实时间也不同),所以会重新计算并做出一个新的Commit对象。
这里也是一样,看起来只是改字,但因为Commit对象的信息也会影响SHA-1的计算,所以Git会做出新的Commit对象来替代原来的Commit对象。
不止这样,因为这两个Commit对象被换掉了,在它之后的Commit因为前面的历史信息被改了,所以后面整串的Commit全部都重做新的Commit对象来替代旧的Commit对象。
1.3、取消Rebase
如果想要取消这次的Rebase,只需这样做:
git reset ORIG_HEAD --hard
2、多个Commit合并位一个Commit
新增两个文件并分两次提交:
echo "111" > 1.txt
echo "222" > 2.txt
git add .
git commit 1.txt -m "add 1"
git commit 2.txt -m "add 2"
查看记录:
如果把这2个Commit合并为一个,就会让Commit看起来更简洁。可以使用互动模式的Rebase来处理:
git rebase -i d249c0f
这里使用squash
指令,把上面的内容改为:
上面的改动表示cc722b0
这个Commit会和前一个05b8f3e
Commit合并在一起。
随后修改合并后的Commit信息:
再次查看记录,合并成功:
3、一个Commit拆解成多个Commit
继续使用上文中的案例,目的是把51422de
这个Commit拆分为2个Commit,每个Commit只有一个文件即可。
git rebase -i d249c0f
这次把要拆解的那个Commit的pick改成edit:
保存后,Rebase在执行到51422de这个Commit时就会停下来:
这时,因为要把当前这个Commit拆解成两个Commit,所以要使用Reset指令:
git reset HEAD^
然后查看一下状态:
可以看到,1.txt和2.txt都被拆解出来放在工作目录中,且处于Untracked状态。还记得怎么Commit文件吗?就是用add + commit二段式指令:
git add .
git commit 1.txt -m "add 1"
git commit 2.txt -m "add 2"
最后执行
git rebase --continue
以完成rebase交互。
查看记录,完成了拆分:
4、在某些Commit之间插入新的Commit
还是使用上面案例,在(69204dc)add 2和(e061b15)add 1之间插入一个Commit。
git rebase -i d249c0f
处于Rebase状态的Commit列表与平常看到的记录是相反的,所以如果想在某两个Commit之间再增加Commit,要注意停下来的那个点是不是正确的点。例如,要加在add 2和add 1之间增加Commit,需要停在add 1
上:
保存后,Rebase操作执行,停在add 1的Commit上:
此时,就可以新增Commit了:
echo "1.5" > 1.5.txt
git add 1.5.txt
git commit 1.5.txt -m "add 1.5"
随后继续执行Rebase操作:
git rebase --continue
查看记录,插入Commit成功:
5、删除Commit
继续使用上述案例,删除掉add 1.5这个Commit。
要删除Commit很简单,在Rebase的过程中,把原来的pick改成drop,甚至直接将其删掉也可以。
git rebase -i d249c0f
如果想删掉add 1.5,可以把该行的pick改成drop,或者直接删除掉该行:
存档、离开后便会开始进行Rebase。然后查看记录,删除成功:
6、调整Commit的顺序
继续使用上述案例,假设先在要互换add 1和add 2这两个Commit的顺序。
git rebase -i d249c0f
只需要互换两个记录的顺序即可:
存档、离开后,Rebase就会继续做它的工作。然后查看记录,顺序已经调整成功:
7、Revert指令
7.1、取消Commit
继续使用上文案例,假设要取消最后的add 1这个Commit。
git revert HEAD --no-edit
这样就把最后一次Commit的内容删掉了。虽然文件不见了,但是Commit增加了。
Revert指令是“再做一个新的Commit,来取消你不要的Commit”,所以Commit的数量才会增加。
7.2、取消Revert
如果做出来的Revert不想要了,可用以下几种方式来处理:
1、再开一个Revert
可以再开一个新的Revert,来Revert刚才那个Revert:
git revert HEAD --no-edit
刚刚被删掉的1.txt又出现了,这样Commit又变多了。
2、直接使用Reset
如果要“砍掉”这个Revert,只需直接使用Reset指令:
git reset HEAD^ --hard
8、Reset、Rebase和Revert区别
指令 | 修改历史记录 | 说明 |
---|---|---|
Reset | 是 | 把当前状态设置成某个指定Commit的状态,通常适用于尚未推出去的Commit |
Rebase | 是 | 不管是新增、改动、删除Commit,还是用来整理、编辑还没有推出去的Commit,都相当方便,但通常只适用于尚未推出去的Commit |
Revert | 否 | 新增一个Commit来反转(或说取消)另一个Commit的内容,原来的Commit依旧会保留在历史记录中。虽然会因此而增加Commit数量,但通常比较适用于已经推出去的Commit,或者不允许使用Reset或Rebase来修改历史记录指令的情景 |