13修改老旧commit的message
前言
对于最近一次提交的commit的修改可以使用git commit --amend
来进行,而对历史版本的commit修改则需要通过git rebase -i
来进行。
git rebase -i
命令拆解:
- rebase: 表示基于某个父commit修改其下的子commit
- -i: 表示交互
比如,我们需要把第二个commit的信息Second commit
来进行修改。
1 | G:\mygitea\GitLearn\learn03 master |
此时会跳到交互信息页面,Commands标题下展示了交互式页面的命令,我们参考命令对commit进行修改。比如这里我们只是想修改commit dab1693e的message,则需要使用reword命令(简写 r)来修改。
修改后:
保存退出,会跳到需要修改分支的交互式信息页面,对提交信息进行修改:
保存退出,可以看到修改后第二个分支的message变了,同时其commit id也跟着改变了。
1 | [detached HEAD c18b52f] The Second commit # 使用到了分离头指针 |
原理解析
rebase操作是基于分离头指针进行的。
- 首先git对要修改的commit分离头指针;
- 接着对分离头指针的commit上做调整;
- 调整后将最新的commit用一个指针指向它;—
updated refs/heads/master
(即当前工作的master分支不指向原先的c1be25了,而是新的cca417,但是文件内容没有变化)
就是说commit对应的树,树对应的对象blob没有发生变化。
注意:这里的rebase操作仅限于在自己当前的未集成到团队的分支上进行,如果是以及集成到了团队的分支则无法进行此操作。
即当前我们讲的内容都是基于在个人的分支上的操作,还未涉及到团队集成的分支操作内容。
总结
Q1:那如果要更改的是第一次提交,他的父节点是谁呢?
搜索工具可以根据 “how to rebase the oldest commit” 可以搜到 how do i git rebase the first commit, https://stackoverflow.com/questions/22992543/how-do-i-git-rebase-the-first-commit 里面告诉我们执行 “git rebase -i —root” 即可
Q2:方便说下,为什么 rebase -i git 会分离头指针,git 这么设计的目的是什么呢? 谢谢老师
git rebase工作的过程中,就是用了分离头指针。rebase意味着基于新base的commit来变更部分commits。它处理的时候,把HEAD指向base的commit,此时如果该commit没有对应branch,就处于分离头指针的状态,然后重新一个一个生成新的commit,当rebase创建完最后一个commit后,结束分离头状态,Git让变完基的分支名指向HEAD。 后续课程我们再把这个过程通过详细的图示给大家展示一下。这个阶段不妨先尝试用一下。
Q3:我修改了first_commit的message,咋second_commit, third_commit, fourth_commit的commit hash都变了呢
很好的发现! 那是因为 message 也是commit的属性,是确定commit的hash值的一个因子。其次,second_commit 有个 parent 的属性,parent的内容发生了变化,因此,second_commit 的hash也变了。 以此类推,后面的commit也发生了变化。
Q4:可以看到修改了老message后,自父亲commit以下,所有commit都变了,这是为什么,为什么不只修改2个commit,就像链表操作一样,只需要修改当前节点和当前节点的子节点就可以了,是因为git不允许修改commit对象吗?只允许新建commit对象。
blob是只看内容的,两个文件如果内容相同,对应的blob是相同的,即使这俩文件在不同的git仓库。 但commit还包括commit的message,作者,变更时间,父亲等属性,这些🀄️的一个发生变化了,在git眼里就是不同的commit。 如果前3个commit的message变了,前3哥commit就变了,它一变,前2个commit的parent就变了,因此前2个commit也要变,依此类推
Q5:听完之后有个问题就是被变commit的父级commit是怎么识别出来的,就比如视频里的Add refering projects 的父级commit为什么是 Add js这个commit
这个版本树如果是自己创建的,我们肯定事先知道哪个commit先建,哪个commit后建,由此知道哪个是parent。这是一种方法。 其他用git命令的方式也很多。 比如: git show —pretty=format:%P HEAD 这个命令可以返回HEAD指针的父commit。 再比如:gitk 打开的界面上直接显示Parent
初次听老师讲述变基(base),还以为老师发错音了,以为修改message就是对它进行编辑,结果原来是rebase,对基(base)进行变更: 在变基的时候,因为新的base的commit没有基于任何一个分支,所以处于分离头指针状态,git接下来会在我们修改message那个commit往后依次对后面的commit修改hash值但不更改commit的文件内容,让后续的commit的hash值都是基于修改mseeage之前的那个commit依次更新!