缘起

最近一次新疆采编发版时,发现代码中有一处配置的一个变量没有了,经过查询Git的提交历史发现这次改动涉及的提交bbb的作者是开发人员A,但A君表示从来没有动过这块代码。

这就很奇怪了,明明Git上显示的作者是A君,但A又表示不是自己改的,那到底是Git在说谎还是A君在说谎?

经过线下询问其他采编开发人员,并对比Git的分支图谱,多方查证,终于弄清楚了原因:

  1. 开发人员B君要开发的一个功能正好在产品分支上已经有了,所以采用了cherry-pick的方式从产品分支将这个功能的那次提交000(作者是D,提交者是A)从产品分支复制到了新疆开发分支1上面。复制时产生了冲突,B君解决了冲突,进行了提交aaa
  2. 在解决冲突的过程中,由于那个丢失的变量在产品分支上没有,而在新疆分支上有,但是那个变量上面便是要从产品分支上复制过来的代码,所以B君直接通过工具采用了产品分支的代码,导致新疆分支上有的那个变量被产品分支代码所替换而丢失。
  3. B君继续在开发分支1上进行了其它功能的开发,进行了两次提交,然后提了MR给C君,请求将开发分支1合并到主开发分支0上面。
  4. 这时D君说,不用合并了,他要直接rebase,所以C君关闭了MR,而D君使用rebase命令直接将开发分支1上的这几次提交复制到了主开发分支0上,复制后提交aaa变为了提交bbb

然后就是后来,我们开头说的,发版时发现了变量丢失的问题。

这个过程中,我们产生过两个疑问:

  1. 我们通过历史提交查询的时候为什么没有查询到提交aaa
  2. 为什么提交bbb的作者不是B君而是A君。

破案

解决这两个问题,我们先要弄清楚:

当我们查看提交历史的时候,所显示的Author(作者)真的就是这次提交中那些文件的真正改动者吗?

$ git log
commit af7af21595aba7d6ac02b34c3a852ed267a395b7 (HEAD -> master, origin/master, origin/HEAD)
Author: chen.chen <chenchen@trs.com.cn>
Date:   Thu Aug 5 17:55:12 2021 +0800修复全部栏目检索问题

首先,我们应该知道,Git中所谓的【提交】在底层实现上就是一个二进制对象,它存储在.git/objects目录下。

就比如上例中af7af21这次提交,其实指向的是.git/objects/af/7af21595aba7d6ac02b34c3a852ed267a395b7这个二进制对象,我们可以通过Git的底层命令来查看一下这个二进制对象的内容:

$ git cat-file -p af7af21
tree 3ab963b8fca3658404126787e075b4d4dbdfc697
parent ab8c90a1ca8544802c3e00b2ea5ccaf01d20976b
author chen.chen <chenchen@trs.com.cn> 1628157312 +0800
committer chen.chen <chenchen@trs.com.cn> 1628157312 +0800修复全部栏目检索问题

可以看到,这个提交对象了有两个和人员有关的属性:

  • author:代表这次提交所涉及的更改真正的作者
  • committer: 创建这个提交的人。

从这一点来看,一般情况下,提交都是由作者进行的,那作者和提交者应该是同一个人。

但是,总有不一般的情况,就比如:

  1. cherry-pick操作:A将另一个分支上的提交a复制到自己的分支时,会在当前分支上重新产生一个新的提交b,这个提交b的内容和提交a的内容一模一样,但是提交a的提交者将变成提交b的作者,而A将成为提交a的提交者。
  2. rebase操作: 当A将另一个分支上的提交通过rebase复制到自己分支时,那个提交的作者不变,但提交者将由原来的提交者变为A。
  3. MR 操作:A在一个分支上进行了提交若干次提交后,发送了一个MR请求给B,B在合并时勾选了合并提交选项,这时A做的若干次提交将被合并为一个新的提交(相当于rebase -i操作),此时,这个新的提交的作者是A,提交者是B。

而在本文开头所述那次事故,正好就是踩了这几个坑,我们来梳理一下整个过程:

  1. C君在产品分支1上开发了若干功能(其中就包含B君要的那个),进行了提交,发送了一个MR请求给A君,A君勾选了【合并提交】选项后将产品分支1合并入了产品分支。此时D君做的所有提交被合并后生成了一个新的提交000,这个提交的作者是C,提交者是A。
  2. B君在新疆开发分支1上进行了cherry-pick,将000分支复制到了开发分支1,解决冲突后提交,生成了提交aaa,此时aaa提交的作者是A,提交者是B。
  3. D君使用了rebase操作将aaa从开发分支1复制到了开发分支0上,此时开发分支0上产生了提交bbb,这个提交的作者还是A,但提交者变成了D。

当发现代码问题时,我们顺着开发分支0的提交历史去看,自然看到的作者是A。

所以,Git没有说谎,A也没有说谎,这是一场由A、B、C、D共同参与的【无心的共谋】。

教训

这次事故的原因找到后,我们从中应该学到一些东西。

  1. rebase合并提交操作会重写提交历史。(MR时的合并提交其实就是rebase -i
  2. rebase复制提交操作后,提交历史无法反映提交来源自哪个分支以及被复制提交的原始信息
  3. cherry-pick复制提交操作后,提交历史无法反映提交来源自哪个分支以及被复制提交的原始信息,并且无法真实反映被复制提交原来的作者信息。(当被复制提交作者与提交者不同时)

这些特性的存在,会严重影响代码出问题时的溯源工作。

所以,这里做出如下建议,供大家讨论决定:

  1. rebase操作不允许应用在共享分支上。(可以在自己的私有分支间随便折腾)
  2. cherry-pick操作必须记录到单独日志文件里,注明原始分支和提交的相关信息。

·

关于Git的rebase操作与cherry-pick操作的建议相关推荐

  1. git cherry pick

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

  2. git 交互式rebase

    交互式的rebase的场景在分支开发时特别有用, 可以减少没有必要的提交 git rebase -i -i 参数表示互动 interactive,这时 git 会使用你设定的编辑器,让你对 git 历 ...

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

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

  4. IDEA git cherry pick 简单使用

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

  5. [gitsourcetree]cherry pick和遴选的使用

    前言 cherry pick. 拷贝其中的某一次提交记录. 本文就介绍一种更加快捷的方式 cherry pick. 介绍 此方法主要用于2分支分别独立维护的情况, 即某一分支已经上线了spring-2 ...

  6. Git 分支 - rebase 变基

    变基 在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase. 在本节中我们将学习什么是"变基",怎样使用"变基",并将展示该操作的 ...

  7. Git使用技巧(3)-- 远程操作

    Git远程操作详解 作者: 阮一峰 编辑更新:shifu204 日期: 2016年9月1日 Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操 ...

  8. git使用—rebase还是merge

    转载自:https://segmentfault.com/q/1010000007704573/ 我猜现实中的情况是这样的: 使用 git 的人群中,不会用 rebase(哪怕是基础功能的)的至少一半 ...

  9. 为什么要使用git pull --rebase?

    1.git pull git pull = git fetch + git merge FETCH_HEAD git pull --rebase = git fetch + git rebase FE ...

  10. git pull origin master与git pull --rebase origin master的区别

    建议:最好看一遍廖雪峰的git教程,看完时间差不多就两个小时,git相关的知识写的很清楚,看完整个人都豁然开朗,很多git的问题都想通了. 区别: git pull=git fetch + git m ...

最新文章

  1. 无法升级_Windows 10出现升级BUG:无法保留用户个人数据
  2. 关于我对c#的一些看法
  3. C语言打印链表的中间节点的算法(附完整源码)
  4. Java环境变量CLASSPATH详解
  5. java 安卓 html文件怎么打开方式_android 浏览器 打开本地html文件的方法
  6. 如何提升你的javascript代码逼格之简写篇
  7. CMU Bomblab 答案
  8. 人力资源管理学习网站推荐
  9. 复变函数在计算机科学中的应用,051复变函数与实变函数
  10. C语言 输出正三角形图形
  11. 无线通信设备安装工程概预算编制_如何编制膜结构工程安装方案?
  12. 怎么写化学反应方程式?
  13. r语言平均值显著性检验_R语言与显著性检验学习笔记
  14. java 0-999 阿拉伯数字转英文
  15. [转帖] 雀巢公司物流项目管理
  16. 【jzoj5335】早苗
  17. 概率论_证明_辛钦大数定律
  18. 电脑黑屏却开着机是怎么回事?解决黑屏的快捷方法
  19. 《数据结构(C语言版)》严巍敏课件~第七章:图
  20. 上海一级计算机试卷,上海计算机一级考试试题及答案

热门文章

  1. 09 JAVA如何将字符串反转?
  2. 设置 Docker 开机自启动
  3. 深度学习面试题总结1-20
  4. ListIterator
  5. pandas.Series.plot的简单参数使用说明
  6. vue项目中scrollTop如何使用
  7. 【Linux】安装虚拟机
  8. linux内核是压测,从应用到内核查接口超时(中) -枕边书
  9. ora-12505 监听程序当前无法识别sid
  10. 2021NCTF-RE