Git Cherry-pick/Git Merge/Git Rebase

2023-05-16

原文出处:http://pinkyjie.com/2014/08/10/git-notes-part-3

Git笔记(三)——[cherry-pick, merge, rebase]

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

现在的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命令都介绍完了!!!其实这三篇都是小实践,要想融会贯通,还需要在真实项目中的大实践!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Git Cherry-pick/Git Merge/Git Rebase 的相关文章

  • 编辑 git patch 给出“您编辑的块不适用”

    我正在交互地添加一个文件 git add template panels panel reports php p diff git a template panels panel reports php b template panels
  • 在 Windows 上为 Bitbucket 设置 SSH 密钥

    首先 我对 git repos 和命令行绝对是菜鸟 我在 Bitbucket 上有仓库 我基本上希望能够通过 gitbash 推送到存储库 而无需每次输入密码 我拥有的 Bitbucket 上的存储库已设置好代码 克隆存储库的本地目录 通过
  • git 别名:多个命令、可变参数

    我经常发现自己输入以下内容 git push remote1 branch1 branch2 tag1 tag2 tag3 git push remote2 branch1 branch2 tag1 tag2 tag3 我更喜欢一个别名 我
  • 如何在 Mac OS X 10.9 上安装和使用最新的 Git?

    我从 sourceforge 下载了 Git 2 4 3http git scm com download mac http git scm com download mac对于我的 Macbook Pro OS X 10 9 5 然后安装
  • 如何为Git存储库组织和设置镜像备份服务器?

    我正在将一些 svn 存储库移至 Git 所以 我基本上尝试做的是 设置一台带有裸 Git 存储库的服务器 我将从中拉取和推送到该存储库 为第一台服务器上的所有存储库设置一些备份服务器 所以 假设我的服务器上有一个目录 例如 HOME gi
  • git jenkins 中未找到存储库

    我正在使用 jenkins 2 64 并安装了最新的插件 我试图在 jenkins 中设置 git 存储库并给出凭据 但给出错误无法连接存储库 状态代码为 128 Cloning repository https github com so
  • 特定远程分支名称的 Git 列表

    如何获取某些远程源分支的所有名称 我从 remote list选项 但变得多余origin HEAD gt origin master来自另一个源的消息和分支 gt git branch remote list origin HEAD gt
  • git分支没有显示所有分支

    opt lampp htdocs drupal 8 4 0 git branch 我已经在我的系统中安装了drupal 我想切换到其他分支 但是当使用git分支时不显示其他分支 Execute git branch av显示所有远程和本地分
  • 如何合并具有相同列名的数据框

    我有一个数据框 如下所示 structure list Variables structure list ADA ADA LEAD LEAD BIG4 BIG4 LOGMKT LOGMKT LEV LEV ROA ROA ROAL ROAL
  • 当 TLSv1 因“忽略未知记录”而失败时,使 git 恢复为 SSLv3

    无法使用git git clone https github com foo bar fails fatal unable to access https github com foo bar Unknown SSL protocol er
  • 你遇到过哪些 git 陷阱?

    我遇到的最糟糕的情况是 git 子模块 我在 github 上有一个项目的子模块 该项目无人维护 我想提交补丁 但无法提交 所以我分叉了 现在子模块指向原始库 而我需要它指向 fork 因此 我删除了旧的子模块 并将其替换为同一提交中新项目
  • Github 操作 - 错误:进程已完成,退出代码为 1

    我正在尝试设置 github 操作来部署我的应用程序 My bash 启动部署过程的脚本如下所示 bin sh set e vendor bin phpunit git push true git checkout production g
  • GIT:查找包括子模块的文件列表(例如使用 git ls-files)

    我一直在试图弄清楚如何获取 git 存储库中所有文件的列表 包括子模块中包含的文件 现在 git ls files将提供顶级子模块目录 但不提供子模块中包含的文件 经过进一步调查 我发现使用git submodule 你可以递归地找到所有的
  • 如何设置 Corkscrew 通过 Draconian 代理连接到 Github

    我的公司有一个严酷的代理服务器 它阻止我通过 SSH 删除服务器 从而阻止我使用 github 我花了最后一天的时间在网上查看示例 例如 如何通过严格的代理使用 GitHub https stackoverflow com question
  • git commit 保存 vim 文件时出错

    我正在遵循简单的 git 指南nettuts 简易 git 指南 http net tutsplus com tutorials other easy version control with git 我在我的中初始化了一个空的 git 实
  • git Push heroku master 因“HTTP 400curl 22 请求的 URL 返回错误”而失败

    我正在尝试推送仅显示 你好 世界 的 Rails 应用程序 然后我遇到了如下错误 我想知道如何解决这个问题 git推送heroku大师枚举对象 88 完成 计数对象 100 88 88 完成 增量压缩最多使用 4 个线程 压缩对象 100
  • 对于 Web 应用程序来说,您理想的 git 分支架构是什么?

    我们是一个由开发人员组成的小团队 正在构建 Web 应用程序 我们目前拥有一个实时 测试和多个开发环境 您会建议什么分支架构 以便理想情况下每个开发人员都可以处理他的功能 这些功能可以在不影响其他开发人员 功能的情况下进行测试和部署 目前
  • 如何使用 git-svn 切换 svn 存储库?

    我有许多使用 git svn 创建为 SVN 存储库克隆的 git 项目 我们已将 SVN 存储库迁移到新的提供商 因此 URL 现在已更改 如何更新 git 克隆的远程 SVN URL 一种可能性是我从新的 SVN 存储库重新克隆 但我不
  • 如何克隆 bitbucket 存储库?

    一段时间后重新开始工作 我似乎不知道如何克隆 bitbucket 存储库 知道为什么我收到 未找到 错误吗 git clone verbose https bitbucket org helllamer mod openid Cloning
  • 如何删除所有意外添加到git系统的本地文件

    我是 git 系统的新手 我可能犯了一个错误 将我所有的本地文件集成到 git 系统中 当我说出现以下错误时 我使用 vs代码编辑器 并放弃所有更改 Git fatal You are on a branch yet to be born

随机推荐

  • 生产者消费者模型

    什么是生产者消费者模型 xff1f span class token variable 生产者和消费是操作系统中一种重要的模型 xff0c 它描述的是一种等待和通知的机制 span 一 概念引入 日常生活中 xff0c 每当我们缺少某些生活
  • Mariadb-Mysql服务器

    1 安装服务 root 64 ftp2 yum install y mariadb 2 启动服务 root 64 ftp2 systemctl start mariadb 3 进入Mysql 因为默认进入Mysql是不需要密码的 xff0c
  • Vmware批量开关机脚本

    运行Windows脚本批量开关Vmware虚拟机 1 vmrun T ws start opt VMware win2k8r2 vmx nogui启动无图形界面虚拟机 xff08 T 是区分宿主机的类型 xff0c ws server se
  • linux下proxy设定的一般方法

    在linux下配置测试环境时 xff0c 经常遇到代理服务器配置的相关问题 xff0c 在这里总结一些 xff0c 为以后节省些时间 也希望对需要的人有所帮助 linux下proxy的常规设置 一般是把如下环境变量的设置放到 etc pro
  • 计算机视觉中的论文常见单词总结

    前言 本文对计算机视觉论文中常出现的单词进行了汇总 xff0c 对于不具备直接阅读英文文献的读者 xff0c 可以考虑把这些单词给背了 之前的文章 计算机视觉中的高效阅读论文的方法总结 中提到了如何掌握阅读英文文献的能力 xff0c 我就是
  • android常见面试题与我自己的回答 (二)

    1 xff0c android process 解决访问SharedPreferences xff0c 不在同一进程 private SharedPreferencesDB Context cxt this context 61 cxt C
  • 解决打开Chrome出现 输入密码以解锁您的登录密钥环

    问题是这样的 xff0c 打开Chrome 后出现如下所示 xff1a xff08 图是网上找的 xff0c 我电脑上解决了这个问题 xff0c 这图就出现不了了 xff09 我的具体情况是 xff0c 输入什么密码都解不开 xff0c 也
  • Spring_ 依赖注入 详细讲解

    文章目录 一 什么是依赖注入 xff1f 1 类的关系1 1 依赖关系 xff08 Dependency xff09 1 2 聚合 xff08 Aggregation xff09 2 关系强度 二 为什么使用依赖注入 xff1f 1 开闭原
  • 向日葵ubuntu19.10安装不上依赖解决办法

    源链接 https blog csdn net zhang24qin article details 103611923 http www luyixian cn news show 267507 aspx 不知道哪个是原作者 都放上面了
  • Linux向日葵重启以后连接不上解决办法

    Linux重启之后向日葵连接不上 xff0c 查看log时候显示和屏幕组件有关 xff0c 获取不到屏幕组件 在 etc profile d 下面创建一个脚本xrk sh vim编辑 bin bash xhost 43 wq 保存一下 ch
  • clickhouse的too many part问题

    clickhouse踩坑记录 Yuque what DB Exception Too many partitions for single INSERT block more than 100 The limit is controlled
  • jumpserver DOCKER脚本报错解决方案

    ERROR for koko Container 34 10761048e0bf 34 is unhealthy ERROR for celery Container 34 10761048e0bf 34 is unhealthy ERRO
  • ESXI 无法打开磁盘“XXX.vmdk”或其所依赖的快照磁盘之一

    如果遇到断电突然VMDK嗝屁了 xff0c 这时候重启没有 lck文件把硬盘锁死还是无法启动可能需要修复硬盘 vmkfstool x check vm 103 disk 0 vmdk vmkfstool x repair vm 103 di
  • linux C++创建多级目录

    static bool check exists const std string amp file path return access file path c str F OK 61 1 static std string get pa
  • [转] Linux 之 /etc/profile、~/.bash_profile 等几个文件的执行过程

    原文链接 在登录Linux时要执行文件的过程如下 xff1a 在刚登录Linux时 xff0c 首先启动 etc profile 文件 xff0c 然后再启动用户目录下的 bash profile bash login或 profile文件
  • clickhouse授权

    create role xxx db readonly grant select on xxx db to xxx db readonly grant xxx db readonly to username show grants for
  • MYSQL docker 和 UBUNTU docker

    MYSQL docker 和 UBUNTU docker sudo docker run p 3306 3306 name mysql restart 61 always privileged 61 true v raid10 mysql
  • pandas datetime64 转string

    https stackoverflow com questions 50449453 pandas datetime64 to string You can just cast the dtype first using astype In
  • clion 头文件和源文件切换

    H 和 CPP切换 在keymap快捷键找到 related symbol
  • Git Cherry-pick/Git Merge/Git Rebase

    原文出处 xff1a http pinkyjie com 2014 08 10 git notes part 3 Git笔记 三 cherry pick merge rebase 书接上回 xff0c 直入主题 xff01 这篇继续实践剩下