兰 亭 墨 苑
期货 · 量化 · AI · 终身学习
首页
归档
编辑文章
标题 *
URL 别名 *
内容 *
(支持 Markdown 格式)
这是一个非常好的问题,因为它触及了Git中两个核心但常常令人困惑的概念:merge(合并)和 rebase(变基)。 我还是用我们熟悉的“合作写书”的比喻来解释,这会让 Rebase and Merge 的意思变得非常直观。 比喻:整理你的草稿,让历史更整洁 我们回到之前的场景: 中央档案馆 (main 分支): 存放着书的最终定稿。 你 (feature 分支): 你在自己的书桌上,基于档案馆周一的定稿版本,开始撰写一个新的章节。 现在,时间来到了周三,你终于完成了你的章节,并提交了审阅请求 (Pull Request)。 但是,在这期间(周二),你的同事小明也完成了一个小章节的修订,并且他的修改已经被管理员合并到了档案馆的main分支里。 所以,现在的情况是: 档案馆的 main 分支,已经是周二的最新版本(包含了小明的修改)。 你的修改稿 (feature 分支),是基于周一的旧版本进行的。 这时,管理员审阅你的稿件时,就有三种方式把它合并到最终定稿中: 方式一:Merge Commit (最常见) 操作: 管理员直接把你的修改稿(基于周一版本的)和档案馆的最新稿(周二版本的)捆绑在一起,然后盖上一个大大的“合并章”,写上“这是将XXX的修改合并进来的记录”,然后放回档案馆。 效果: 档案馆的历史记录会变成这样: Generated code * (周三) 合并了你的修改 <-- 一个新的合并记录 |\ | * (周二) 你完成的修改3 | * (周二) 你完成的修改2 * | (周二) 小明完成的修改 <-- main分支的历史 |/ * (周一) 你们开始时的共同版本 Use code with caution. 历史记录是分叉的,能清晰地看到你是在一个旧版本上独立工作的。 方式二:Squash and Merge (追求简洁) 操作: 管理员对你的修改稿说:“你的修改过程太啰嗦了(提交了3次),我不在乎你怎么改的,我只关心最终结果。” 于是,他把你所有的修改内容(从修改1到3)揉成一团,形成一个全新的、单独的修改记录,然后把它贴在档案馆最新稿(周二版本)的后面。 效果: 档案馆的历史记录会变成这样: Generated code * (周三) 增加了WebRTC功能 (你所有的修改被压缩成一个) <-- 一个干净的提交 * (周二) 小明完成的修改 * (周一) 你们开始时的共同版本 Use code with caution. 历史记录是线性的、干净的,但你详细的修改过程丢失了。 方式三:Rebase and Merge (您问题的核心,追求“完美”历史) 操作: 这位管理员是个“历史洁癖”。他说:“你虽然是基于周一的版本开始写的,但这会让历史看起来不连贯。我们来施展一点‘时间魔法’,假装你是在周二、在小明完成修改之后,才开始写的。” 这个“时间魔法”就是 Rebase (变基)。 “时光倒流”: 系统会暂时把你所有的修改(修改1, 2, 3)拿出来,放在一边。 “跳跃到未来”: 把你的起点(基底),从周一的版本,移动到档案馆最新的周二版本(小明修改后的版本)。 “重新播放”: 然后,系统再把你的那三个修改,一个一个地、按顺序地,重新应用在新的起点上。就好像你是在周二的基础上,完成了修改1,然后是修改2,然后是修改3。 效果: 你的修改稿现在看起来就像是紧接着小明的修改进行的。然后管理员再把这些修改稿直接放到档案馆的定稿后面。最终,档案馆的历史记录会变成这样: Generated code * (周三) 你完成的修改3 (就像是紧接着修改2做的) * (周三) 你完成的修改2 (就像是紧接着修改1做的) * (周三) 你完成的修改1 (就像是紧接着小明的工作做的) * (周二) 小明完成的修改 * (周一) 你们开始时的共同版本 Use code with caution. 历史记录是完全线性的,就像所有工作都是按顺序、一个接一个完成的,非常整洁,没有分叉。 Rebase and Merge 的技术解释 “将你分支的提交记录,‘变基’到main分支的最新点上,然后逐一添加到main分支,形成一个线性的历史记录。” 这句话的准确意思是: “变基”到main分支的最新点上: 找到你的feature分支和main分支的共同祖先提交点。 将feature分支从这个祖先点之后的所有提交,都“摘下来”。 将feature分支的起点(“基底”)移动到main分支当前最新的那个提交上。 然后逐一添加到main分支: 把刚才“摘下来”的那些提交,按照原来的顺序,一个一个地应用在新的基底上。 这个过程完成后,你的feature分支看起来就像是直接从最新的main分支拉出来的。 最后,执行一个**“快进合并”(Fast-forward Merge)**,就是直接把main分支的指针指向你的feature分支的最新提交,因为它们现在是一条直线了,没有任何需要“合并”的分叉。 优缺点 优点: 历史记录非常干净: 形成一条单一、线性的提交历史,没有杂乱的合并提交记录,非常容易阅读和追溯。 回溯问题方便: 如果需要用 git bisect 等工具来查找引入bug的提交,线性历史会简单得多。 缺点: 修改了历史: Rebase会重写你分支的提交历史(因为每个提交的父节点都变了,所以提交的ID也会变)。如果你已经将这个分支分享给其他人,绝对不能使用Rebase,否则会造成他们的仓库混乱。 丢失了分支的上下文: 你无法从历史记录中看出这些提交是来自哪个功能分支、是在哪个时间点并行开发的。所有的开发看起来都是串行的。 总结: Rebase and Merge 是一种为了追求一个“完美”的、线性的提交历史而使用的合并策略。它通过“变基”操作,巧妙地重写了你的提交历史,让它们看起来像是紧跟在主分支的最新进展之后完成的。
配图 (可多选)
选择新图片文件或拖拽到此处
标签
更新文章
删除文章