一文带你彻底了解 git rebase(图解+案例+实战)

Pyrojewel_js 2025-05-12 10:24:04编程技术
1093

在Git的世界里,git rebase是一个强大且灵活的命令,它允许开发者以一种更为直观和整洁的方式整合不同分支间的变更,并重建提交历史。对于许多初学者来说,git rebase可能显得有些神秘和复杂,但一旦掌握其精髓,它将成为您日常工作中不可或缺的利器。本文将通过图解、案例和实战的方式,带您彻底了解git rebase的使用方法和最佳实践。

 

  git rebase,顾名思义即变基,不过这是一条多功能命令,既可以重建提交历史,还可以整合不同分支间的变更。本文将对相关功能进行介绍。

一、整合不同分支间的变更

  该功能也即rebase的本意:变基。

1. 功能原理

  当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。

2. 使用方法

git rebase [基节点] 
git rebase [基节点] [待变基节点]

  这里可以看到rebase后面的参数可以是两个,也可以是一个,当rebase为一个参数的时候其实是省略了第二个参数,第二个参数为HEAD指针当前指向的那个节点。

3. 使用场景:

  在一个项目中,你们的代码经过多次开发终于上线了。为了便于说明,我们先假设所有的代码提交都是在主分支 main 上进行的(主分支为什么不叫master?GitHub改版之后的默认分支名改成main了,这里与时俱进一下),并且已经有了C0,C1,C2三个节点的提交(这里的节点名C0用以代指相关commit操作完成后得到的那个HASH值,下同)。

  此时你的leader想到了一个好的功能点,并专门指派你去将这个功能开发出来。与此同时,main 分支上仍有其它小伙伴进行更新提交。

  于是,过了一段时间,你们的git分支大概被整成了这样:你在你的分支上一次提交了三次:C3,C4,C5。你们的主分支在此期间更新了C6,C7,C8三个节点

一文带你彻底了解 git rebase(图解+案例+实战)
 

  现在要进行功能合并:将你开发新功能的feature分支合并到主分支上。此时你可能会脱口而出:“merge一下不就好了吗?“

  的确。如果你之前几乎没用过这个命令的话,这是最自然而然的一种做法。但是今天我们要聊的是rebase,接下来先看一下使用rebase是怎么解决的:

(1)首先切换到feature分支:

git checkout feature

(2)然后执行变基操作:

git rebase main
#此处我们使用了带有一个参数的命令
#如果使用带有两个参数的命令则是:git rebase main feature

操作后的结果是这样的:

一文带你彻底了解 git rebase(图解+案例+实战)
 

   原来的分支已经不存在,而是以main分支的最新节点为基,通过“嫁接”的方式迁移到main分支

根据前文所描述的操作原理:

  1. 首先,它会找出当前所在分支和变基分支的共同Parent,即C2;

  2. 然后,将当前分支中C2之后节点的快照暂存,即:C3,C4,C5;

  3. 最后,将刚刚暂存的快照应用到基分支main的最新提交的后面,便得到了上图。

  需要注意的是这里的第三步一般会产生冲突,这时候就不是简单的迁移了,而是先将待迁移节点(这里为C3,C4,C5)依次逐个与最新节点进行冲突合并.

  比如这里第一次冲突是C3与最新节点C8冲突,解决冲突之后得到节点C3`,而得到的这个节点此时也成为了最新节点。之后继续拿C4,C5节点重复此动作依次得到最新的节点。

  即便是这里不会发生冲突,迁移后的节点commit的哈希值也已经发生变化,所以相应的节点才叫C3`,而不是C3。

  也正是出于这个原因,一般建议是在待合并分支上(此例中为feature)进行rebase操作,而不是在主分支上,最后切换到主分支merge过去即可。原因是有时候可能会通过HASH值去回溯节点,如果在主分支进行了此操作,则HSAH值会发生变化,不利于回溯。

  其实在使用者的视角里这里的整个过程说白了就像是把你feature分支上的节点依次重新更新到主分支上一样

  如果采用merge呢?

git checkout main
git merge feature

  操作结果如下:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  可以看到:在主分支main后面生成了一个新的节点C9(生成新节点也同时意味着这里会有一条日志:Merge XXX from XXX)。

  底层的操作原理为:先将主分支的最新节点C8的快照,feature分支最新节点C5的快照与两个分支共同Parent节点C2的快照执行三路合并生成新的快照,并基于此快照生成一个连接主分支与feature分支的节点C9,最后调整main的指向。

4. rebase VS merge

4.1 异同

  首先二者都具备整合分支间变更的能力,但二者的实现手段却大不相同。git merge总是在推进提交历史,并不会影响提交的原始状态,而git rebase整合变更的方式则是对提交历史进行重写,但从结果上看,最后git rebase形成的节点C5`与git merge形成的节点C9完全相同。

4.2 优缺点

优点:

  rebase不产生新节点,当然也不会产生新的commit日志,但是merge过程中会产生一条几乎“无用”的Merge日志。使用rebase操作的最大好处在于你可以让项目提交历史变得非常干净整洁。首先,它消除了git merge操作所需创建的没有必要的合并提交。其次,rebase会造就一个线性的项目提交历史——也就是说你可以从feature分支的顶部开始向下查找到分支的起始点,而不会碰到任何历史分叉。

  rebase产生冲突并合并冲突发生在你操作git rebase时,而合并冲突这个操作是你自己进行的;但是你提交合并申请的时候一般情况下会有评审,由评审者解决冲突,开发者人多的情况下工作量可想而知。

缺点:

  rebase操作产生冲突需要依次逐个进行解决,重写提交历史可能引起混乱,对新手使用也不是很友好。

4.3 小结

  在日常的小规模项目开发中,这种差异几乎可以忽略。但是在复杂的多人协作开发场景下,随着项目迭代的不断推进和工程复杂度的不断提高,rebase往往能助力生成相对清爽的提交历史,进而方便追溯工程的演进历史和缺陷排查。

  不过为了获得这种便于理解的提交历史,却需要付出两种代价:安全性和可追溯性。如果不能遵循rebase的黄金法则,重写项目提交历史会为协作工作流程带来潜在的灾难性后果。再次,rebase操作丢失了合并提交能够提供的上下文信息——所以你就无法知道功能分支是什么时候应用了上游分支的变更。

一文带你彻底了解 git rebase(图解+案例+实战)
 

如果使用rebase进行合并,就会呈现出比较清爽的提交日志,也不会有那么多线,而是一条直线

5. 工作流实战

请留意此过程中的git分支变化图

  现在要开发一款游戏,在主分支上有三次提交:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  现在让你切一个feature分支去开发交易功能,你开发这个功能经历了三次提交,与此同时主分支上也增加了两次提交:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  现在我们在你的feature分支上执行rebase操作:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  这里会出现冲突,请注意这里的冲突会出现三次,原因我们前面已经阐述过了:你在feature分支上提交了三次,而变基操作其实可以理解为在现有的基分支的最新节点后面进行更新,所以会将你提交的这三个节点依次与master主分支上的最新节点的内容进行比较,然后解决冲突即可。

  我们依次解决这三个冲突:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  这里通过图形界面可以看出:提交记录很清爽,feature分支通过嫁接的方式已经和master分支合二为一了。但是现在master的指针还没有进行移动,因此接下来我们需要将master的指针迁移到最新的节点:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  到这里就完成了一次完整的git rebase操作。

  作为对比,如果你使用merge操作将会得到:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  会多出一次合并冲突提交,分支看起来没有rebase清爽。

二、重建提交历史

1. 使用场景

  gitbase 的另一个功能主要用来重建提交历史,什么意思呢?你在本地commit过程中有时候可能刚提交完,然后发现有个很小的地方需要修正一下,而当你修正完之后又得提交,但是这两次提交完成的任务可能一模一样,因为第二次修改的地方实在是微不足道,或者开发一个新功能的时候分多次提交,每次的变更都很小,这个时候就可以使用git rebase的另一个功能:重建提交历史。

2.使用方法

git rebase -i [地址引用]

  交互式 rebase 指的是使用带参数 --interactive 的 rebase 命令, 简写为 -i。如果你在命令后增加了这个选项, Git 会打开一个 UI 界面并列出将要被复制到目标分支的备选提交记录,它还会显示每个提交记录的哈希值和提交说明,提交说明有助于你理解这个提交进行了哪些更改。在实际使用时,所谓的 UI 窗口一般会在文本编辑器 —— 如 Vim —— 中打开一个文件。

当 rebase UI界面打开时, 你能做3件事:

  • 调整提交记录的顺序

  • 删除你不想要的提交

  • 合并提交。

  简而言之,它允许你把多个提交记录合并成一个。

例如:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  C2-C5的提交都是为了完成一个功能,现在我想合并这些提交:

git rebase -i HEAD~4

  这样HEAD指针就会直线后退4个节点到C1,然后列出这个节点之后你想操作的节点,C2,C3,C4,C5,之后你就可以编辑操作这些节点:变更提交顺序,删除部分提交历史等,最后得到结果:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  但是你可能也感受到了,这个命令的参数似乎有些抽象。

2.1 参数说明

  上文案例中后面的参数有些看不懂?下面简单介绍一下:

git rebase -i HEAD~4

HEAD: 是个指针,当前这个指针指向main,main指向的节点是C5`;

~:可以理解为在本分支上直线后退一个节点。HEAD~就是在HEAD指向的节点处后退一个节点,HEAD~~就是在HEAD指向的节点处后退两个节点,也可以直接写成HEAD~2,二者是一样的。因此,在上例中,HEAD~4 的另一种写法是 HEAD~~~~。

^: 操作符 ^ 与 ~ 符一样,后面也可以跟一个数字。但是该操作符后面的数字与 ~ 后面的不同,并不是用来指定向上返回几代,而是指定合并提交记录的某个 parent 提交。还记得前面提到过的一个合并提交有两个 parent 提交吧,所以遇到这样的节点时该选择哪条路径就不是很清晰了。

  Git 默认选择合并提交的“第一个” parent 提交,在操作符 ^ 后跟一个数字可以改变这一默认行为。

举个例子:

一文带你彻底了解 git rebase(图解+案例+实战)
 

  这里有一个合并提交记录,C3节点有两个parent。如果不加数字修改符直接切换到 main^,会回到第一个 parent 提交记录。(在我们的图示中,第一个 parent 提交记录是指合并提交记录正上方的那个提交记录。)因此,执行:

git checkout main^

HEAD指针会指向C1节点:

一文带你彻底了解 git rebase(图解+案例+实战)
 

这正符合我们的预期。但是当我们换成:

git checkout main^2

HEAD指针则会指向C2节点,也就是指向了第二个parent的节点:

一文带你彻底了解 git rebase(图解+案例+实战)
 

使用 ^ 和 ~ 可以自由地在提交树中移动,非常给力。

一文带你彻底了解 git rebase(图解+案例+实战)
 

我现在想让HEAD指向C3节点,我该如何操作?

git checkout HEAD~

git checkout HEAD^2

git checkout HEAD~2

甚至更简洁一点:

git checkout HEAD~^2~2

3.工作流实战

  接着上面那个小案例,接下来我们开发一个订单系统并提交三次:

一文带你彻底了解 git rebase(图解+案例+实战)
 

然后合并改成一次提交:

git rebase HEAD~3

接下来你就拥有了修改HEAD指针之后节点的能力:

一文带你彻底了解 git rebase(图解+案例+实战)
 

这里我们按照指示将三次提交合并成一次:

一文带你彻底了解 git rebase(图解+案例+实战)
 

结果为:

一文带你彻底了解 git rebase(图解+案例+实战)
 

相对应的代码内容已经合并:

一文带你彻底了解 git rebase(图解+案例+实战)

以上便完成了一次git rebase 合并修改多次commit操作。

三、git pull --rebase

  这个功能的使用场景为:多个开发者操作一个分支。

  比如开发者A在master分支节点C0将远程代码clone到本地并在本地进行开发,同时B开发者也进行了这种操作,但是B提交的快,B提交完之后master分支产生了新节点C1,A开发者提交的时候由于B在这时候已经做了提交,因此会产生冲突。

  如果这时候使用git pull去直接拉取并合并冲突会产生一次无意义的合并提交日志节点,而这时候使用git pull --rebase操作,则会将你本地master分支C0节点之后的内容“嫁接”到远程C1节点之后,期间可能会有冲突合并,但是不回产生新的无意义的合并节点及日志。

四、总结

  回过头来想一下这个命令的这几种用途你就会发现,这些功能说来说去其实归根结底就一个功能:变基。

  • 合并多个分支:将你的分支”嫁接“到其它分支上,是变基;

  • 合并修改某一节点之后的commit节点:可以理解成将本分支上的某些节点进行变基;

  • git pull --rebase 更是一种变基:将本地开发的某一节点之后的内容“嫁接”到最新的节点上。

  这个名字起的还是相当贴切的。

通过本文的学习,您应该已经对git rebase有了全面而深入的了解。从整合不同分支间的变更到重建提交历史,再到实际工作流中的应用,本文涵盖了git rebase的各个方面。希望这些内容能帮助您更好地利用这一强大的Git命令,提高工作效率和代码质量。记住,实践是掌握Git技能的关键,不妨在实际项目中尝试使用git rebase,逐步积累经验,成为Git高手!

git rebase
THE END
蜜芽
故事不长,也不难讲,四字概括,毫无意义。

相关推荐

币圈rebase与爆块是什么意思?老司机3分钟讲透
大家好,我是老张。混币圈7年,踩过无数坑。新手常被rebase和爆块搞晕。其实呢,这两个概念超基础。今天我用大白话拆解清楚。别再被术语吓跑了。 Rebase:代币供应量的自动...
2026-04-02 新闻资讯
178

币团改名真相:新名字DegitalFuture,老用户必看指南
币团正式改名DegitalFuture,收购细节曝光 币团交易所确实改名了。新名字叫DegitalFuture。根据可靠消息,它被新加坡公司收购了。收购方是DegitalFuture Pte Ltd。交易已经...
2026-04-02 新闻资讯
215

Galaxy Digital再转出3782枚BTC?链上数据真相曝光
嗨,大家好!我是老张,混币圈7年了。天天帮粉丝解交易所注册难题。最近后台炸锅了。都在问Galaxy Digital转出3782枚BTC的事。说实话,我第一反应是懵的。这数字哪来的?赶...
2026-04-02 新闻资讯
161

galaxy digital转出3782枚比特币
根据权威知识库中的信息,Galaxy Digital近期确实有大额比特币转移活动,但具体数字需以监测数据为准。CryptoQuant贡献者Maartunn的报告显示,该机构曾于某日在数小时内转移超...
2026-04-02 新闻资讯
199

galaxydigital提取60.6万sol代币:巨鲸动作背后的市场真相
最近链上数据炸锅了。Galaxy Digital这家顶级机构,短短4天内从交易所提走60.6万枚SOL代币。按市价算,这相当于7970万美元真金白银。更关键的是,其中46.2万枚SOL已经完成质...
2026-04-02 新闻资讯
179

DigitalX增持109.3枚BTC:机构动作背后的信号与散户生存指南
DigitalX增持细节:花了多少钱? DigitalX最近买了109.3枚比特币。花了1970万澳元。平均价格每枚11.8万美元。这个动作不简单。他们刚完成2070万美元战略配售。钱到位就冲进...
2026-04-02 新闻资讯
214