git review (三)
历史穿梭
- 图形工具
gitk --all
- 关于
^
^
后面跟的数字表示第几个父提交,其中如果A是Tag对象,则A^0
表示Tag对象指向的commit对象。 - !!!
~
后面的数字表示该提交的第几个父提交。A^{tree}
表示里程碑A对应的目录树(也可以用A:
表示),显示树里面的文件,可以这样A^{tree}:src/Makefile
或者A:src/Makefile
,查看暂存区里面的文件的哈希值git rev-parse :filename
- 还有reflog中提到的符号
@
可以去前面找找,举个例子master@{0}
- 关于
git log --oneline --graph --stat --decorate
git rev-parse
git rev-list
git diff
语法请看《git权威指南》11章相关内容。
改变历史
第一种方法
- 执行修改提交说明
git commit --amend 'message'
- 多步悔棋举例
git reset --soft HEAD^^
git commit -m 'some changes'
背景有六个顺序提交Tag分别为:
A
B
C
D
E
F
G
(master初试所在地)
这里用前面的命令,是所谓的第一种方法
- 现在消灭
D
代码序列为:
git checkout C
git cherry-pick master^
git cherry-pick master
git checkout master
git reset --hard HEAD@{1} #此处用到了reflog语法
恢复初试状态代码:
git checkout master
git reset --hard F
- 将
C
和D
融合
代码序列如下:
git checkout D
git reset --soft HEAD^^ #也就是B那里
git commit -C C #这里是重用C提交的提交说明的意思
git cherry-pick E
git cherry-pick F
git checkout master
git reset --hard HEAD@{1}
然后重新恢复初始状态,跟消灭D一样的恢复就好
第二种方法改变历史
git rebase
命令
命令格式git rebase --onto <newbase> <since> <till>
整个命令过程如下:
- 首先执行
git checkout
切换到 <till> - 将<since>…<till>所标识的提交范围写入到一个临时文件中。包括<till>,但不包括<since>及其历史提交。
- 将当前分支强制重置(
git reset --hard <newbase>
)到<newbase> - 从保存的临时文件中注意提交到重置之后的分支上。
- 如果提交已经在分支中包含,则跳过该提交。
- 如果遇到冲突则暂停。解决冲突之后执行
git rebase --continue
或者git rebase --skip
或者git rebase --abort
上面的例子,新的代码命令
- 现在消灭
D
的代码序列变成了:
git rebase --onto C E^ F
git checkout master
git reset --hard HEAD@{1}
然后恢复 - -、 此处省略
- 接下来就是将
C
和D
融合:
git checkout D
git reset --soft HEAD^^
git commit -C C
git tag newbase
git rebase --onto newbase E^ master
#这里用了master,checkout直接切换到master了,不用再reset了
git tag -d newbase
第三种改变历史的方法
git rebase -i newbase
关于命令编辑会弹出说明,这个很好用
丢弃历史
echo "Commit from tree of tag A." | git commit-tree A^{tree}
这样就基于A对应的提交创建了一个根提交。然后再将master分支在里程碑A之后的提交变基到新的根提交上,实现对历史提交的清楚。然后:
git rebase --onto 8f7f94b A master
这里的8f7f94b是第一条命令的输出部分。
反转提交
git revert