书接上回,直入主题!这篇继续实践剩下的几个命令。

现在的SourceTree状态如下:

cherry-pick - 妈妈,我也要

cherry-pick其实在工作中还挺常用的,一种常见的场景就是,比如我在A分支做了几次commit以后,发现其实我并不应该在A分支上工作,应该在B分支上工作,这时就需要将这些commit从A分支复制到B分支去了,这时候就需要cherry-pick命令了,B分支指着这些commit说:妈妈,我也要!比如说,我们在master分支上继续做两次提交,第一次添加一行”test 10”,git commit -am "commit 10",第二次添加“test 11”,到达如下图的状态:

这个时候我们发现,哦NO,我们不应该直接更改master分支,我们应该在自己的分支上做提交。这个时候先新建一个分支git checkout -b branch3 1a222c3,注意这里的最后一个参数是新分支的起点,也就是说,新的分支branch3是从“commit 8,9”开始的,现在我们需要把刚才的两次提交移动到新的分支上。运行git cherry-pick 0bda20e 1a04d5f,命令行会给出提示两个commit被复制到了当前分支上,此时SourceTree的状态如下图:

确定这两个commit被复制到指定分支以后,在master分支上将这两个commit删除。先切回master分支:git checkout master,运行git reset --hard 1a222c3,此时SourceTree的状态图为:

两个commit被成功的从master分支移动到了branch3分支。

merge - 求合体

merge命令应该也是非常的常用,比如新开了一个分支去完成某个feature,然后完成了以后要merge到master分支来。就拿刚才的例子来讲,开了新分支branch3来存放“commit 10”和“commit 11”,这两个commit可以看成是新的feature,完事以后就要合并到master分支上了。但合并之前,一般要将master分支当前最新的commit合并到branch3上,因为你的branch3的起点此时可能已经不是master分支的最新commit了。切换到branch3分支上运行git merge master,Git提示“Already up-to-date.”,这说明当前所在的分支branch3比master分支还要新,branch3上的commit都是master最新commit点的子commit,故不需要合并。切回master分支git checkout master,将分支branch3合并到master分支上,git merge branch3,结果如下图:

可以看到branch3分支上的更改已经被合并到master上,其中“Fast-forward”是合并的一种类型,当当前分支(master)是目标分支(branch3)的祖先commit时会发生这种“Fast-forward”合并,其实可以理解为HEAD指针指向的快速移动。

前面看到的两种情况都是比较简单的合并,没有遇到任何“冲突”,我们来一次稍微复杂点的合并,比如我们需要将branch2合并到master上。在master分支上git merge branch2,哦NO,命令行提示“Automatic merge failed”,出现冲突了,Git无法判断如何merge,这个时候我们就需要手动解决冲突以后再提交。打开test.txt文件可以看到如下图的内容:

从图28中可以看到<<<<<<<< HEAD========之间的内容是当前分支的内容,而=======>>>>>>>>> branch2之间的内容是branch2分支的内容,由于改动了同一行所以Git无法自动合并了。这个时候你可以决定最后保留哪些内容,我们就简单的将“test aaa”插入到第4行,然后删除多余的标记保存,另外,需要手动做一次提交来解决冲突:git add test.txt,然后这次我们不用-m参数直接git commit,可以看到如下图的提示:

Git已经发现我们是在做一次merge的提交,并且是“解决冲突的merge”,可以看到Git默认给出的提交信息非常的友好,包含了合并的分支上的commit,也写明了冲突的文件是什么,我们就使用Git默认的提交信息,直接:wq保存退出。此时可以直观的从SourceTree里看到branch2分支的线已经合并到master上了,如下图所示:

总结一下merge的集中情况:

  1. git merge 目标分支

    • 如果目标分支是当前分支的祖先commit节点,则merge什么也不会发生,因为当前分支已经是最新的了
    • 如果当前分支是目标分支的祖先commit节点,这时会发生Fast-forward的merge,merge的结果是简单的移动HEAD指针
  2. 如果以上两种情况都不是的话,则其实是做的三方合并,除了这两个分支的最新commit以外,另外一个是这两个分支的共同祖先commit点。这种情况下如果没有冲突的话会自动生成一个merge的commit,如果有冲突则手动解决后还是会有一个merge的commit。

rebase - 我是直男,不喜欢弯的

从图31可以看出,branch2分支(紫色的线)最终交汇到master分支上(蓝色的线),这还只是合并了一次,并且我们当前的分支才几个,如果分支很多并且频繁合并的话,这样弯弯曲曲的线会非常多,搞得你眼花缭乱,根本搞不清楚走向,显然,直男一向是不喜欢弯的,那能把它掰直吗?答案是肯定的,rebase就是干这个事情的!为了看清楚merge和rebase的区别,我们先将刚才branch2的合并取消,使master回滚到“commit 11”的状态:git reset --hard dda0f7d。这时我们位于master分支上,运行git rebase branch2,Git同样提示我们有冲突,只是这次提示非常长,如下图:

根据提示我们就可以发现rebase的流程,从“Applying: commit 3”这句就可以看出来,其实rebase的原理是先找到两个分支的共同祖先commit节点“commit 2,2.5”,然后把master分支上这个节点的儿子节点全部“应用”到branch2分支上。从图31中可以看到第一个儿子节点是“commit 3”,所以先apply这个,而“commit 3”和“commit aaa”编辑的都是第4行,所以立即出现了冲突!照例我们需要手动解决冲突。这次如果我们还是把“test aaa”放第4行,然后“test 3”放在第5行,那很明显后面的“commit 4”在apply时仍然会有冲突,所以为了方便,我们直接把“test 3”和“test aaa”都放在第4行,如下图:

然后保存,注意这时需要先把改动add以后再操作:git add test.txt。按照图32的提示运行git rebase --continue,结果怎么样呢?哦NO,又尼玛冲突了!!!为嘛啊!“commit 4”的第4行还是“test 3”,而我们现在的第4行是“test 3 test aaa”,所以还是冲突!看来rebase在apply每一个commit时并不只是apply这个commit上的变化(即“test 4”这一行),而是apply整个文件!可以想象这样走下去每一步都会有冲突,唯一的办法就是放弃“test aaa”这个更改。真的是这样吗?其实不然,先运行git rebase --abort放弃这次rebase。其实这种场景下并不适合rebase,一般我们把别的分支合并到master时用merge,而把master合并到别的分支时会用到rebase,那我们换个思路,切换到branch2分支上git checkout branch2,然后运行rebase命令git rebase master,显然,还是会有冲突的,这次我们直接把“commit aaa”加到最后一行保存。运行git add test.txt,然后继续进行git rebase --continue,可以看到结果成功了“Applying: commit aaa”。这时的SourceTree如下图:

可是这样与merge的结果恰恰相反,我们是把master分支merge到branch2上了,而我们初衷是将branch2分支merge到master上。简单!先切回master分支git checkout master然后运行git merge branch2即可,因为这时master分支是branch2分支的祖先commit节点,所以直接Fast-forward了!最终的状态图如下图所示:

从图35中可以看出,达到了和图31同样的效果,不同的是:首先,没有了“弯弯”的线;其次,多余的merge那一条commit没有啦!这才是直男喜欢的!

总结一下rebase:

  1. git rebase 目标分支原理其实是先将HEAD指向目标分支和当前分支的共同祖先commit节点,然后将当前分支上的commit一个一个的apply到目标分支上,apply完以后再将HEAD指向当前分支。
  2. rebase与merge的区别:
    • 把master分支合并到别的分支用rebase,把别的分支合并到master分支上用merge
    • rebase不会产生多余的commit,并且保持直线

关于rebase其他要补充的

当然rebase还有其他很多很牛逼的功能,其“交互模式”可以让你干很多事情,比如调整commit的顺序啊,合并一些commit啊,删除一些commit啊等等,通过-i参数可以实现,当然这个命令有些复杂,我们可以使用SourceTree的图形化界面更直观的使用它。比如“commit 10”和“commit 11”太不和谐了,早就看你们不爽了,人家前面的“6,7”和“8,9”都成双成对,就你俩不和谐,我要“整顿”一下!在SourceTree中的“commit 8,9”上右击,点击子菜单中的“Rebase children of 1a222c3 interactively…”:

然后出现了图37中的对话框,我们想整理的2个commit显示在其中,“commit aaa”也是儿子节点,所以也显示在这里,我们可以通过红色方框中的按钮来进行操作。比如,我们想合并一下“commit 10”和“commit 11”,两个commit合并为“commit 10,11”。在这个对话框中可以非常直观的进行上面的操作,先选中“commit 11”这一行,选择红框中的“Squash with previous”按钮,可以看到出现了一条新的commit——“[2 commits]”,如图38所示:

选中这条commit,点击红框中的“Edit message”,出现了更改commit信息的对话框,如下图:

输入“commit 10,11”即可,点击OK保存,再次点击OK完成此次rebase。此时SourceTree的状态如图40所示:

可以看到,目的达到了,commit hash也跟原来的任何两个都不一样了。除了合并commit,利用图37的红色方框里的按钮,还可以实现删除commit,调整commit的顺序等功能,大家自己尝试吧,小心产生“冲突”哦!

好啦,到这里,感觉比较重要的git命令都介绍完了!!!其实这三篇都是小实践,要想融会贯通,还需要在真实项目中的大实践!

from: http://pinkyjie.com/2014/08/10/git-notes-part-3/

Git笔记(三)——[cherry-pick, merge, rebase]相关推荐

  1. idea cherry pick 功能 git log 窗口 冲突conflict

    git log 窗口 参考 source tree cherry pick, merge conflict merge conflict 冲突 <<<<<<< ...

  2. git merge的三种操作merge, squash merge, 和rebase merge

    原链接:https://www.jianshu.com/p/ff1877c5864e git merge的三种操作merge, squash merge, 和rebase merge 举例来说: 假设 ...

  3. git cherry pick

    直接将选定的其他分支的commit,提交到该分支上 不建议使用 git rebase --onto 使用cherry pick代替 http://weblog.avp-ptr.de/20120928/ ...

  4. Git 2.9增加了Merge、Rebase、Commit等新特性

    Git 2.9版本已于近期发布.它给merge.rebase和commit工作流带来了新的特性,以及许多其他方面的改进和缺陷修复. \\ Git merge和pull的命令将不允许两个不相关历史的分支 ...

  5. Git笔记(三)git commit撤销

    Git笔记(三)git commit撤销 1.git commit撤销 1.git commit撤销 写完代码后,我们一般这样 git add . //添加所有文件 git commit -m &qu ...

  6. IDEA git cherry pick 简单使用

    cherry pick的作用: 参考了一些博客, eg: 参考博客1 参考博客2 再做了个小案例后,我目前的理解是,cherry pick的作用是将一个分支的部分提交/历史提交,可以合并到另外一个分支 ...

  7. gerrit cherry pick to merge code

    开发中经常遇到,不同branch代码需要同步修改的问题, 通过gerrit cherry pick to功能可以方便的将已提交A Branch 的修改同步到B Branch上,提升工作效率

  8. Git笔记(25) 选择修订版本

    Git笔记(25) 选择修订版本 1. 单个修订版本 1.1. 简短的 SHA-1 1.2. 分支引用 1.3. 引用日志 1.4. 祖先引用 2. 提交区间 2.1. 双点 2.2. 多点 2.3. ...

  9. Git笔记(23) 不同角色的贡献

    Git笔记(23) 不同角色的贡献 1. 私有小型团队 2. 私有管理团队 3. 派生的公开项目 4. 通过邮件的公开项目 1. 私有小型团队 可能会遇到的最简单的配置是有一两个开发者的私有(闭源)项 ...

最新文章

  1. 2017-2018中国机器人创新Top100榜单深度分析
  2. android 双 webview,Android webview加载页面
  3. 判断图有无环_判断无向图/有向图中是否存在环
  4. Linux 文件系统基础
  5. 动物行为检测计算机视觉_基于红外热成像和计算机视觉的动物行为研究系统便是其中一例...
  6. php sphinx 查询,php-Sphinx RT索引和SphinxQL查询
  7. 笔记-JavaWeb学习之旅4
  8. ASP.NET MVC - 用户验证和权限验证
  9. 系统学习深度学习(四十三)--GAN简单了解
  10. 窗口拖动后,还原窗口位置
  11. SpreadJS 14.2.5 中文版
  12. 回归方程的拟合优度检验_回归分析的“拟合优度”是什么?
  13. TCP——TCP报文分析及TCP状态机、非法TCP报文标志组合
  14. 专业卸载工具Your Uninstaller! Pro
  15. 【工具分享】推荐一款超级好用的截图工具
  16. webstorm 2018 激活破解方法大全
  17. Oracle定时任务DBMS_JOB
  18. python openpyxl冻结首行单元格
  19. Kotlin入门-带着问题,理解 对象表达式和对象声明
  20. 解决:Error during artifact deployment. See server log for details.问题

热门文章

  1. 通过扩展RandomAccessFile类使之具备Buffer改善I/O性能--转载
  2. 【风控模型】融合模型Bagging构建信用评分卡模型
  3. jQuery快速学习
  4. 房价波动5%很正常 房地产市场绝不会崩盘
  5. 催收成本在单体经济中的分析
  6. Java Review - 并发编程_伪共享
  7. 实战SSM_O2O商铺_15【商铺注册】View层+Controller层之图片上传
  8. Java多线程:Semaphore
  9. 爬虫学习笔记(十三)—— scrapy-redis(二):存储到MySQL、Scrapy项目部署
  10. 复习笔记(四)——C++继承