文章目录
前言
这一节主要介绍git cherry-pick
与git rebase
的原理及使用。
一、Git cherry-pick
Git cherry-pick
的作用为移植提交。比如在dev
分支错误地进行了两次提交2nd
和3rd
,如果想要将这两次提交移植到master
分支上。采用先删除再添加的方法将会很繁琐,而使用cherry-pick
就能轻松实现这一需求。
首先在版本库中创建了两个分支master
和dev
,并模拟上述场景:
可以看到,在dev
分支上进行了两次提交,在master
分支上只进行了一次提交。现在想要将这两次提交移植到master
分支上。整体分为两步:
- **第一步:**将
dev
分支上多余的两次提交移植到master
分支上; - **第二步:**删除
dev
分支上多余的两次提交;
1.第一步
git cherry-pick commit_id
首先切换到master
分支,然后使用如下命令将dev
分支上的两次提交移植到master
分支上:
//移植2nd提交
git cherry-pick 009dd
//移植3rd提交
git cherry-pick aec8c
009dd
和aec8c
分别表示需要移植的提交2nd
和3rd
的SHA1
值:
移植过程为:
-
如上图所示,执行了两次
cherry-pick
指令,创建了两个内容与2nd、3rd
一致的提交对象50477
和f05a0
。所以,cherry-pick
指令移植提交的实质是:先将需要移植的提交复制一份,再拼接到master
分支上,简称先复制,再拼接; -
上面按照顺序先移植了提交
2nd
再移植提交3rd
,不会发生冲突; -
不按顺序移植,如先移植提交
3rd
会发生合并冲突,需要手动解决:
通过vi test.txt
查看发生合并冲突的test.txt
文件:
可以发现master
分支上initial commit
提交中的文件test.txt
直观上并不与提交3rd
中的test.txt
冲突,如下图所示:
但是为什么会发生合并冲突呢?原因在于三方合并原则:
如上图所示,当想要将dev
中的提交E
与master
分支的提交B
合并时,首先要找到B
和E
的公共父节点A
,在A
的基础上根据B
和E
进行三方合并;
了解了三方合并原则后就能解释上面发生合并冲突的原因了:
-
由于提交
3rd
是基于提交2nd
创建的,因此3rd
中保留了2rd
中对文件的操作记录; -
如果直接将
3rd
拼接到initial commit
后面,就会失去提交2nd
的记录; -
由此提交
3rd
就不能通过提交2nd
找到公共提交节点init
,这就会导致合并失败;
所以,无论内容是否冲突,合并过程都会出现冲突:
**解决方法:**手动合并三步曲:
- 首先,选择要保留的内容,解决冲突:
- 然后,通过
git add
将修改信息纳入暂存区:
- 最后,通过
git commit
提交修改信息:
完成后查看master
分支的提交历史:
可以看到解决冲突,手动合并后,成功完成了整个cherry-pick
过程。并且新增的提交是手动合并时进行的提交,而不是直接复制的提交3rd
:
2.第二步
此时两分支的状态为:
接下来就要删除dev
分支上错误的两次提交2nd
和3rd
,相当于版本回退;可以使用三种方法:revert
、reset
和checkout
,这里演示checkout
和reset
两种方法。
使用checkout
首先切换到dev
分支,然后通过以下指令切换到提交initial commit
:
//dd703是提交initial_commit的SHA1值
git checkout dd703
此时该节点处于游离状态:
然后再删除dev
分支:
由于之前修改的dev
分支没有与master