最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南

    正文概述 掘金(睿Act)   2021-02-26   1138

    1. rebase原理

    a. 概述

    1. 用处:rebase能合并提交、净化commit历史;它也能移植分支,把一些分支的提交移植到另一个分支
    2. 最大的优势:commits历史干净清爽,git graph中能尽量呈线性延伸、减少了交叉情况,易于代码的维护和管理

    让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南

    b. rebase和merge的区别

    rebase(变基)的作用,就是可以改变一个分支中一串commit的‘基点’、也就是父commit。这样说起来可能并不好理解,所以我们可以将它和开发中常用的merge操作进行类比——它和merge操作的目的是类似的:将对代码的更改,从一个分支集成到另一个分支

    因此,不妨假设:git rebase ≈ git merge,把两种命令代入到例子中——一个简易版的、由Master主分支和Feature开发分支组成的日常开发环境。在示例中,用两种命令实现同一工作流,来比较它们的异同、理解rebase的原理。 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 如上图,假设一个简易的日常工作环境:多人合作开发,在基于commit 2的Feature分支上进行新功能的开发时,Master分支中有一些新的提交,需要在自己的分支上同步Master的更新。

    1. 使用merge操作

    我们常会使用pull来拉取远端的代码,git pull = git fetch + git merge,也就是说,在使用pull时实际上也是在使用merge操作合并修改。通常来说,我们会使用如下的命令操作:

    git checkout feature
    //切换活动分支到feature
    (feature)git merge master
    

    这会在feature分支中创建一个新的“merge commit”(下图中的commit 8),将两个分支的历史联系在一起,产生如下所示的分支结构: 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 merge操作是很常用的,它会保留原有的分支结构、用一个新的commit来实现对两个分支上代码修改的合并。使用merge,可以避免使用rebase时所有可能的问题。

    但另一方面,这意味着每当我们在Feature分支同步Master分支的代码时,都会产生一条实际上没啥意义的、merge操作产生的commit节点(图中的commit 8)。这会产生两个问题:

    1. 如果需要多次拉取Master分支的最新代码,多次合并产生的多次commit节点会污染我们的commit记录,让commit记录变得冗杂、可读性和维护性变差。
    2. merge操作会让两个分支间产生交叉、形成“钻石链”。这会让我们的git graph变得凌乱,不易管理和维护。

    2. 使用rebase操作

    让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 在同样的场景下,可以使用以下命令,将feature分支rebase到master分支上:

    git checkout feature
    git rebase master
    

    让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 在使用rebase前,Feature分支的3个commit(3,4,5)是基于commit 2的。通过执行git rebase命令,Feature分支的的基点变成了commit 7.

    实际上,rebase的所做的就是为Feature分支上的3个提交(commit 3,4,5)创造了一个副本、将这个副本移动到master分支的顶端,从而有效地整合了所有master分支的新提交。具体来说:Git会让我们想要移动的提交序列(commit 3、4、5)在目标分支(Master)上按照一样的顺序再现一遍,相当于一个【副本】——图中的3'、4'、5',与3、4、5拥有一样的修改、一样的作者、日期、注释信息,不同的是rebase这些副本拥有与原本的提交不同的全新commit id。

    与merge操作的效果一样,在完成rebase操作后,Feature分支就成功整合了Master分支的所有更新。

    c. 优缺点总结:

    Git官网文档对rebase操作的优点的阐述如下:

    用大白话来说,使用rebase的好处主要是能获得更清晰的commit历史记录。它消除了不必要的git merge产生的merge commit;同时,如上图所示,rebase操作能够产生线性的git graph结构。我们可以从feature分支的顶端一路向前追溯,没有任何分叉地追踪到项目的开始——这能让我们更好的读懂项目的修改历史。

    但是,rebase操作较merge操作更加复杂、更加危险。它会重写项目的历史记录,这可能对别人的工作造成巨大的影响;同时,merge操作所附加的那一次merge commit能够提示人们何时合并了上游(Master分支)的更改。在使用rebase操作时,我们无法获取这样的提示的。

    2. 工作流中的示例

    a. 合并不同分支的多次提交:避免多余的merge commit

    在与上述类似的工作环境(本地开发后,同步线上master的最新代码,然后并入master)中,分别进行如下操作,在线上观察commit历史日志

    //#左图
    (feature)开发...
    (feature)git pull origin master
    git checkout master
    (master)git merge feature
    
    //#右图
    (feature)开发...
    (feature)git rebase master
    git checkout master
    (master)git merge feature
    

    让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 可以看到,通过rebase操作,我们让commit历史变得更为精简了。同时,在git graph结构中,也保证了直观的线性结构(见后文)

    b. 合并同一分支的多次提交:rebase -i 操作

    在日常工作中,我们在同一开发分支下开发某一功能时,常会随着需求的小改动、测试的推进,对代码进行不断的修改、微调,然后commit提交、push到线上。过多的commit其实没有意义,我们可以通过rebase --interactive这一操作,对同一分支下的多次提交进行重写,将多次commit合并为一个。

    假设我们在分支feature-D上进行了3次提交操作,如下图: 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 我们可以执行git rebase -i HEAD~num命令,对过去的几次提交做修改(num是可指定的提交的次数),操作示例如下:

    //当前所处分支:feature-D
    (feature-D)git rebase -i HEAD~3
    

    git会在终端(命令行)生成如下文本,输入vi进入编辑模式即可编辑 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 在这个列表中需要关注的两个地方:

    • 该列表中最旧的提交在最上面,最新的在最下面,与使用git log查看的顺序是相反的,该顺序是交互式rebase的操作顺序。
    • hash前的单词表示对该提交的操作,该操作有如下几种:
    # Commands:
    # p, pick = use commit 默认
    # r, reword = use commit, but edit the commit message   
      使用该提交,但是可以修改该提交的提交信息,当时用该命令时,接下来就会进入一个页面,
      让我们写新的提交信息。如果我们想修改那个commit的提交信息时,可以使用这个方法
    # e, edit = use commit, but stop for amending   
      使变基中断,这时我们可以修改工作区文件,修改完以后git add . => git commit --amend进行重新提交。  
      提交完后使用git rebase --continue继续变基。如果你想修改某个提交,可以使用该方法
    # s, squash = use commit, but meld into previous commit   
      合并提交,它会合并到前面的提交中,并且允许我们重新编辑提交信息,这也是我们要实现的。
    # f, fixup = like "squash", but discard this commit's log message 
      也是合并提交,但是没有然我们重新编辑提交信息,而是丢弃这些提交的提交信息
    # x, exec = run command (the rest of the line) using shell 
      丢弃该提交,也就是该提交不会复制过去。
    # d, drop = remove commit
    

    如果想将这三次提交都合并到最旧的提交上,需要把后两次提交的操作修改为squash,如下: 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 完成上图的修改后,会进入新的文本编辑页面,允许我们为合并后的新commit写新的注释,如下图 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 由于我们在本地进行了“三合一”操作,也就是用一个全新的commit概括并覆盖掉原有的3个commit,涉及了对commit历史的修改,因此需要使用git push --force 强制推到线上。完成后如下图: 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 点击进入9f830b9这一commit,如下图,详情中保留了进行rebase -i操作前的3次初始commit的注释信息。 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 总而言之,我们通过rebase -i操作,让一个新的commit覆盖了原有的3个commit,编辑了新的概述性注释、同时也保留了原有3次commit的注释。

    这时,假设我们想要同步线上分支的代码然后合并到master分支中,执行如下操作:

    (feature-D)git rebase master
    git checkout master
    (master)git merge feature-D
    

    让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 同样的工作流,使用了rebase系列操作后,commit历史明显变得简洁了非常多。

    c. 复杂项目下简化git graph的效果

    假设有如下图的git结构:基于线上分支(master)进行新功能的开发;完成开发后,我们需要同步master线上分支的最新代码,然后将开发分支的内容同步到测试分支中。 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 分别不使用/使用rebase操作,操作代码、效果如下:

    //左侧
    (dev-B) git pull origin master
    git checkout st
    (st) git merge dev-B
    //右侧
    (dev-B) git rebase master
    git checkout st
    (st) git merge dev-B
    

    让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南 如果在同样的工作流中,更充分的使用rebase命令 比如在合并到st分支前 rebase到st分支后再合并,就能完全避免merge commit信息;再比如,如果在提交前使用rebase -i,就能把多次的commit提交进行归纳、缩减。

    3. 常见问题和解决方案

    a. rebase会消除提交历史、甚至影响别人——黄金法则

    请遵循Git官方文档中提出并强调的黄金法则:永远不要在公用的分支上rebase别的分支。
    先来一个反面典型:下面的操作就是错误的

    //在master这样的公用分支下rebase别的分支
    (master)git rebase feature-xx
    

    那么我们应该怎么做?引用Git官网文档的说法:

    还是用大白话来说,只要把rebase的使用范围限制在自己的开发分支内,就不会出现影响到他人的情况;在遵循“黄金法则”的前提下,rebase才能成为我们对commit历史进行优化、精简commit提交的利器。

    b. rebase会引发更多冲突,怎么避免?

    1. 问题概述:除了可能覆盖commit历史、需要push --force强制覆盖之外,rebase操作还有一个广为流传的“诟病”,即使用rebase时会比常规操作遇到更多的冲突。
    2. 形成原因:在【本地开发分支 feature】进行了多次commit,当rebase到【需要合入的分支master】时,如果feature分支在开发中和master分支有冲突,那么feature的每一个commit都需要手动解决一次冲突。
    3. 问题的图文示例、解决方案:https://blog.csdn.net/weixin_44053668/article/details/110367667;上文中的rebase -i 操作可以有效解决这一问题,详见链接

    4. 在实际工作中应用rebase

    在写这篇文章时,我也刚刚在团队leader指导下完成了对rebase操作的调研和文档输出、正在推进其在团队内的应用,下面的3点是我认为能够较好的使用到rebase操作优点的场景;在我的设想中,如果充分理解了rebase,他们能够较为快速的接入到现有的工作流中。
    当然,可以预见的是,实际的工作过程远比想象的复杂、有更多正在协作开发的仓库和分支,因此在推进rebase操作的过程中也一定会遇到很多问题,我希望能够通过输出这篇文章记录我此时此刻的一些初步粗浅的想法、起到一点点点抛砖引玉的作用,也很希望大佬们指正我的错误、给出一些真正易于应用的范例。

    a. 开发过程中:用rebase减少merge commit

    (本地开发分支) 在每次开始新一天的开发前,通常都会pull远端的代码,这个使用可以使用rebase(或者 pull --rebase)来操作。这样操作的好处是可以让git graph更清晰、同时减少多余的merge commit记录

    b. 合入代码前

    先将本地的开发分支 (如feature)rebase变基到想要合入的分支上 (如master),进行完这一步rebase操作之后,再切换到master分支上进行merge feature的操作。
    Git的官方文档中的示例所表达的就是这个意思,这样做的好处也是精简commits记录和git graph。

    c. 后期持续修改时

    在本地多次修复一些小bug、提交到远程仓库前可以在本地开发分支下,使用rebase -i 来缩减提交记录,避免过于冗余的历史出现:

        1. commit 1:完成'xxx'功能;
        2. commit 2:修复‘xxx’功能中的bug1; 
        3. commit 3:修复‘xxx’功能的bug2; 
        4. commit 4:补充‘xxx’功能中遗漏的'yyy'功能;
    

    这一整串的commit 可以被合并成一个总的commit:完成‘xxx’功能的开发和bug修复,然后再合并到远程线上分支中,避免了多次不必要的commit记录。

    5. 参考

    1. 一些基础操作及团队协作的介绍 juejin.cn/post/684490…
    2. Git官方文档-rebase(变基) git-scm.com/book/zh/v2/…
    3. 比较清晰的叙述,同时介绍了rebase使用铁律: yrq110.me/post/tool/g…
    4. 掘金上对实操讲的比较好的一篇文章 juejin.cn/post/684490…

    起源地下载网 » 让commits历史像Vue一样清爽优雅-Git rebase 原理、工作流介绍+常见问题指南

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元