深入Git-变基

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 前言在Git中整合不同分支的修改主要有两种方法:merge和rebase。其中merge在一般的团队中使用的比较多,而rebase则使用的比较少。本篇文章将主要介绍变基(rebase)的概念以及探讨我们应该在什么时候使用它。

前言

在Git中整合不同分支的修改主要有两种方法:merge和rebase。其中merge在一般的团队中使用的比较多,而rebase则使用的比较少。本篇文章将主要介绍变基(rebase)的概念以及探讨我们应该在什么时候使用它。


什么是变基


变基就是提取当前分支的commit一步步应用到基底分支形成新的commit。15.png

git rebase master


16.png

变基的原理如下


  1. 寻找变基分支与基底分支的最近公共祖先节点

  2. 提取当前分支相对于该祖先的历次commit修改

  3. 将历次修改应用到基底分支(新的commit 原先的commit-msg)

  4. 如果基底分支和当前分支相对于祖先节点同时修改某处将产生冲突,需要手动解决冲突执行continue

对于变基实质也是对提取的commit基底分支的最新commit最近祖先commit进行Three Way Merge,这点和merge过程的三方合并是一致的。大家可参考上篇文章进行阅读深入Git-分支及合并


为什么使用变基


在大家已经理解变基的基础上,我们再来分析下为什么使用变基?


通常在我们使用merge的时候,经过不断的分支创建合并将自动生成很多merge相关的commit,同时分支图谱也会变的非常错综复杂。17.png

那么有什么办法在合并的时候可以不用生成新的commit并且让分支图谱看起来简洁呢?那答案就是变基。


场景1


团队中多人在同一功能分支开发,当远程分支有更新的时候我们一般需要先执行pull命令拉取最新提交,而pull命令实际由两个命令组成

git fetch # 获取远程所有分支更新
git merge origin/feature-xxx # 合并远程分支
复制代码


我们常常会忽略拉取代码时候的合并,直到我们遇到冲突才会留意。实际每次我们去拉代码都有可能因为合并而产生新的merge commit。这时候我们可以通过变基来消除本次多余的commit。


git fetch
git rebase origin/feature-xxx
复制代码


由前所述,此时将当前分支的所有提交提取应用于远程分支。变基之后,我们再去push就可以直接推送成功,也不会产生多余的合并commit


场景2


在开发中,我们可能在不同的功能分支进行开发,但是最终需要合并到master分支进行部署。



我们此时直接执行merge操作,将很有可能产生合并commit

git mrge feature-xxx
复制代码


但如果我们先执行变基再去merge

git rebase master # feature-xxx分支
git merge feature-xxx # master分支
复制代码


此时再进行merge就会应用默认策略fast-foward,不会产生多余的合并记录。

在这里我的理解是应当将变基应用于合并到master分支这步,保证master主线的简洁而非每次合并到dev或者test分支都进行变基。


什么时候不应该使用变基


实际上进行rebase是一种修改操作记录的行为,为了使提交记录变的简洁,我们修改了实际操作记录。


  • 原先是在commit1节点切出的新分支,我们将其变基,会让其看起来是从commit2切出的节点。

  • 原先是先进行开发再进行合并,变基后让人看起来像是一切就绪后才进行的开发,而且相关的记录顺序也会有所修改。


所以一直有两种不同的声音


  1. 应该使用rebase来使提交日志变的简洁

  2. 不应该使用rebase,因为rebase会修改提交日志,而我们应该使用日志记录我们每一步操作。并且rebase使用不像merge那么简单,有可能造成不可逆的结果。


当然,我们在这不去讨论两种声音应该支持哪种,而是指出在什么时候我们的确不应该再去进行rebase

当我们将当前提交推送到远程的时候,此时不应该对当前提交再进行rebase


为什么呢?我们通过案例来理解


假定有A和B两个开发者,A在feature进行了提交D并且推送到了远程,B也拉取了最新代码


18.png

这是A对feature进行以dev为基底的变基,此时提交D变修改为提交D219.png

此时用户B再去拉去远程分支,就会出现merge,并且提交记录将包括A提交的两次D(D和D2),尽管D和D2实际是同一份修改。以后在执行log命令查看日志的时候就会出现两个D提交,让人看起来有点莫名其妙20.png

rebase参数

onto

在前面分析rebase的时候,我们说过会提取commit的差异进行重新生成commit。

所以假定我们在A分支切出B分支,在B分支再切出C分支。此时我们在C分支执行rebase的时候会将B分支的内容一起提交到A分支。那么如何通过变基将C分支的提交内容(EF)单独变基到A分支呢?

21.png



git rebase --onto A B C
复制代码


通过onto命令就可以摘出(B, C]的提交单独变基到A分支。

实际上上面的BC不一定是分支,也可以是个commitID,即我们可以通过onto命令将区间(B, C]的提交变基到A分支,注意区间开闭性。

i


我们再来了解一个有趣且强大的rebase参数i。

git rebase -i commitxxx
复制代码


他将允许我们对commitxxx后(不包含ommitxxx)的所有提交进行修改

pick 76e0513 master2
pick 3f7e15b master3
pick 77737ed dev1
pick a2d0cc4 dev2
pick 258ce19 dev3
# Rebase 7ab7f31..258ce19 onto 7ab7f31 (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
复制代码


我们可以将上面的pick修改成其它,上面的注释实际已经说明可选的选项。我们介绍下常用的几种


  • pick 不作任何修改

  • reword 修改commitMsg

  • edit 修改commit内容

  • squash 将commit合并到上次commit

  • fixup 和squash类似,但是不会保留commitMsg

  • drop 移除commit

结语


rebase是个强大的命令,它能够帮助我们保持分支的简洁以及整合或修改历史提交。但是在我们将提交已经推送远程的时候,还是尽量别去使用以免导致和其他同事出现协同问题。


参考

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6月前
|
开发工具 git
git问题
git问题
36 0
|
29天前
|
缓存 数据可视化 算法
GIt详解
GIt详解
|
6月前
|
开发工具 git
git blame
git blame 是一个 Git 命令,用于显示某个文件中每一行代码的修改历史。它会显示每行代码的最后一次修改者、修改日期和修改内容。通过 git blame 命令,你可以轻松追踪代码的修改记录,了解团队成员在开发过程中的协作情况。
181 10
|
存储 Linux 开发工具
git相关总结大全
git相关总结大全
|
开发工具 git
git:.gitkeep
git:.gitkeep
204 0
|
关系型数据库 MySQL 应用服务中间件
Git相关知识
Git相关知识
193 0
|
Shell Linux 网络安全
git详解
git详解
241 0
git详解
|
Shell 开发工具 git
|
开发工具 git
|
开发工具 git