首页 > 其他分享 >图解Git——变基《Pro Git》

图解Git——变基《Pro Git》

时间:2025-01-21 18:47:56浏览次数:1  
标签:git Pro 变基 Git master 提交 rebase 分支

变基

1. 变基的由来

  1. 回顾之前分支合并
    1. 分叉的提交历史

      编辑

    2. 通过合并操作来整合分叉的历史

      编辑

  1. 有一种方法:你可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次。 在 Git 中,这种操作就叫做 变基(rebase)。 你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。

2. 变基的基本操作

  1. 切换到想要变基的分支:git checkout experiment
  2. 变基:git rebase master

3. 变基的原理

编辑

  1. 确定共同祖先:Git 首先寻找 experiment 分支和 master 分支的共同祖先提交,此例中为 C2,因为 experiment 分支从 C2 处分叉。
  2. 保存提交序列:Git 把 experiment 分支上从共同祖先 C2 之后的提交(即 C4)保存成一个序列。这些提交记录了 experiment 分支相对共同祖先的变化。
  3. 调整分支基础:Git 将 experiment 分支的指针移开,把它的基础设置为 master 分支的最新提交 C3。这一步为后续重新应用提交做准备,让 experiment 分支基于 master 分支的最新状态。
  4. 生成新提交:Git 依照保存的提交序列,将 C4 重新应用到新基础 C3 上。通过模拟 C4C3 基础上的变更效果,Git 创建一个新的提交对象 C4'。由于 C4' 的父提交是 C3(而原 C4 的父提交是 C2),尽管功能效果与 C4 相同,但它是一个全新的提交,拥有不同的哈希值。
  5. 过程图:
    1. 变基后:

      编辑

    2. 回到 master 分支,并进行一次快进合并后:

      编辑


4. 更复杂的变基应用——对两个分支进行变基(git rebase --onto <newbase> <upstream> [branch]

  1. git rebase --onto <newbase> <upstream> [branch]命令格式:
    1. <newbase>:新的基底
      1. 意义: 指定你希望“重放的提交”应用到的目标分支或提交。
      2. 作用: 这些提交会被重放到 <newbase> 指定的位置。
      3. 类型:
        1. 可以是分支名(如 master)。
        2. 可以是提交哈希(如 abc123)。
        3. 可以是一个引用(如 HEAD~2)。
    1. <upstream>:基准分支
      1. 意义: 确定从哪里开始选取要重放的提交。
      2. 作用: Git 会找到 <upstream>[branch] 的共同祖先,并选取从这个分叉点到 [branch] 之间的提交进行“重放”。
      3. 类型:
        1. 分支名(如 dev)。
        2. 提交哈希。
        3. 可以省略,默认使用 [branch] 的上游分支(即用 git branch --set-upstream-to 设置的分支)。
    1. [branch]:当前分支 :
      1. 意义: 指定操作的分支,默认为当前分支。
      2. 作用: 表示重放哪个分支的提交。
      3. 类型:
        1. 分支名(如 feature)。
        2. 如果省略,则默认使用当前所在的分支。
  1. 模拟你创建了一个主题分支 server,为服务端添加了一些功能,提交了 C3C4。 然后从 C3 上创建了主题分支 client,为客户端添加了一些功能,提交了 C8C9。 最后,你回到 server 分支,又提交了 C10

    编辑

  2. 截取主题分支上的另一个主题分支,然后变基到其他分支:

    1. 假设你希望将 client 中的修改合并到主分支并发布,但暂时并不想合并 server 中的修改。

    2. 这时使用 git rebas 命令的 --onto选项,选中在 client 分支里但不在 server 分支里的修改(即 C8C9),将它们在 master 分支重放:git rebase --onto master server client

    3. 翻译一下这个命令: “取出 client 分支,找出它从 server 分支分歧之后的补丁, 然后把这些补丁在 master 分支上重放一遍,让 client 看起来像直接基于 master 修改一样”。这理解起来有一点复杂,不过效果非常酷。

    4. 编辑

    5. 快进合并 master,使之包含来自 client 分支的修改

      1. git checkout master + git merge client

      2. 快进合并后:

        编辑

  1. server 中的修改变基到 master 上—— $ git rebase master server
    1. git rebase <basebranch> <topicbranch>简化了先切换到 server分支,再对其执行变基。

    2. server 变基后:

      编辑

  1. 最终的历史提交并删除 clientserver 分支
    1. 快进合并主分支 mastergit checkout master + git merge server

    2. 删除 clientserver 分支:git branch -d client + git branch -d server

    3. 最终的提交历史:

      编辑


5. 变基的风险

奇妙的变基也并非完美无缺,要用它得遵守一条准则:

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。(

  • 如果你的提交已经被其他开发者获取并使用,避免用 rebase 改变历史。
  • 使用 rebase 的原则是: 只能在自己控制的范围内操作 ,避免影响其他人。)

如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。

变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。

5.1. 变基问题示例

让我们来看一个在公开的仓库上执行变基操作所带来的问题。 假设你从一个中央服务器克隆然后在它的基础上进行了一些开发。 你的提交历史如图所示:

编辑

Figure 44. 克隆一个仓库,然后在它的基础上进行了一些开发

然后,某人又向中央服务器提交了一些修改,其中还包括一次合并。 你抓取了这些在远程分支上的修改,并将其合并到你本地的开发分支,然后你的提交历史就会变成这样:

编辑

Figure 45. 抓取别人的提交,合并到自己的开发分支

接下来,这个人又决定把合并操作回滚,改用变基;继而又用 git push --force 命令覆盖了服务器上的提交历史。 之后你从服务器抓取更新,会发现多出来一些新的提交。

编辑

Figure 46. 有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交

结果就是你们两人的处境都十分尴尬。 如果你执行 git pull 命令,你将合并来自两条提交历史的内容,生成一个新的合并提交,最终仓库会如图所示:

编辑

Figure 47. 你将相同的内容又合并了一次,生成了一个新的提交

此时如果你执行 git log 命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。 此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被变基抛弃的提交又找了回来,这会令人感到更加混乱。 很明显对方并不想在提交历史中看到 C4C6,因为之前就是他把这两个提交通过变基丢弃的。

5.2. 用变基解决变基

如果你 真的 遭遇了类似的处境,Git 还有一些高级魔法可以帮到你。 如果团队中的某人强制推送并覆盖了一些你所基于的提交,你需要做的就是检查你做了哪些修改,以及他们覆盖了哪些修改。

实际上,Git 除了对整个提交计算 SHA-1 校验和以外,也对本次提交所引入的修改计算了校验和——即 “patch-id”。

如果你拉取被覆盖过的更新并将你手头的工作基于此进行变基的话,一般情况下 Git 都能成功分辨出哪些是你的修改,并把它们应用到新分支上。

举个例子,如果遇到前面提到的 有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交 那种情境,如果我们不是执行合并,而是执行 git rebase teamone/master, Git 将会:

  • 检查哪些提交是我们的分支上独有的(C2,C3,C4,C6,C7)
  • 检查其中哪些提交不是合并操作的结果(C2,C3,C4)
  • 检查哪些提交在对方覆盖更新时并没有被纳入目标分支(只有 C2 和 C3,因为 C4 其实就是 C4')
  • 把查到的这些提交应用在 teamone/master 上面

从而我们将得到与 你将相同的内容又合并了一次,生成了一个新的提交 中不同的结果,如图 在一个被变基然后强制推送的分支上再次执行变基 所示。

编辑

Figure 48. 在一个被变基然后强制推送的分支上再次执行变基

要想上述方案有效,还需要对方在变基时确保 C4'C4 是几乎一样的。 否则变基操作将无法识别,并新建另一个类似 C4 的补丁(而这个补丁很可能无法整洁的整合入历史,因为补丁中的修改已经存在于某个地方了)。

在本例中另一种简单的方法是使用 git pull --rebase 命令而不是直接 git pull。 又或者你可以自己手动完成这个过程,先 git fetch,再 git rebase teamone/master

如果你习惯使用 git pull ,同时又希望默认使用选项 --rebase,你可以执行这条语句 git config --global pull.rebase true 来更改 pull.rebase 的默认配置。

如果你只对不会离开你电脑的提交执行变基,那就不会有事。 如果你对已经推送过的提交执行变基,但别人没有基于它的提交,那么也不会有事。 如果你对已经推送至共用仓库的提交上执行变基命令,并因此丢失了一些别人的开发所基于的提交, 那你就有大麻烦了,你的同事也会因此鄙视你。

如果你或你的同事在某些情形下决意要这么做,请一定要通知每个人执行 git pull --rebase 命令,这样尽管不能避免伤痛,但能有所缓解。

6. ⭐变基总结

  1. 什么是变基:
    • 将一系列提交“重新播放”到另一个分支上,改变提交历史,使其更线性。
  1. 基本操作:
    • git rebase <目标分支>:将当前分支的修改基于目标分支重新应用。
    • git rebase --onto <新基底> <旧基底> <分支>:将特定提交从旧基底移动到新基底。
  1. 优点:
    • 提交历史更加整洁、直线化。
    • 避免了不必要的合并提交,便于代码审查。
  1. 风险:
    • 如果变基已推送的提交,可能破坏其他开发者的工作(引发冲突和混乱)。
  1. 使用建议:
    • 可以使用: 对未推送的本地分支清理历史,或整理提交后再推送。
    • 避免使用: 对已共享的公共分支执行变基。
  1. 常用配置:
    • 默认拉取使用变基:git config --global pull.rebase true
  1. 注意事项:
    • 若必须在公共分支变基,请通知团队使用 git pull --rebase
    • rebase 是一种改写历史的操作,改写的历史如果已经被其他人使用,会造成混乱。

标签:git,Pro,变基,Git,master,提交,rebase,分支
From: https://www.cnblogs.com/cikiss/p/18684140

相关文章

  • 图解Git——服务器上的Git《Pro Git》
    ​协议1.Git远程仓库及通信协议概述1.1.远程仓库的重要性作用:提供协作平台,支持团队共享代码,即使主机离线,其他人仍可访问。常见形式:裸仓库(不含工作目录,仅保存Git元数据)。2.Git支持的协议类型1.本地协议适用场景:在同一台主机或共享文件系统(如NFS)上使用。......
  • 图解Git——分布式Git《Pro Git》
    ​分布式工作流程CentralizedWorkflow(集中式工作流)​编辑所有开发者都与同一个中央仓库同步代码,每个人通过拉取、提交来合作。如果两个开发者同时修改了相同的文件,后一个开发者必须在推送之前合并其他人的更改。Integration-ManagerWorkflow(集成管理者工作流)​编辑......
  • 图解Git——分支简介《Pro Git》
    ​分支简介1.分支的重要性作用:分支允许将工作从主开发线上分离,避免影响主线开发。传统版本控制的劣势:创建分支通常需要复制整个项目文件,效率低下。Git的优势:分支是Git的“必杀技特性”,创建和切换分支都非常轻量和高效,几乎瞬间完成。2.Git分支的核心概念2.1.数据......
  • 图解Git——分支的新建与合并《Pro Git》
    ​⭐分支的新建与合并先引入一个实际开发的工作流:开发某个网站。为实现某个新的需求,创建一个分支。在这个分支上开展工作。正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。你将按照如下方式来处理:切换到你的线上分支(productionbranch)。为这个紧急任务新......
  • Company Azul Product Zulu OpenJDK vs. Oracle JDK
    TechnologiesOverviewCassandraKafkaSolrElasticsearchHadoop&HBaseSparkIgniteHazelcastTomcatJBoss -[DifferencesBetweenOpenJDKvsOracleJDK|Azul](https://www.azul.com/products/core/jdk-comparison-matrix/)Product&FeaturesProd......
  • git 使用总结
    https://gitee.com/****************.gitgitconfig--globaluser.name'***'gitconfig--globaluser.email'f******@gmail.com'git--version查看版本originhttps://gitee.com/f*****************.git(fetch)originhttps://gitee.com/********......
  • The directory <Project>\aaa is registered as a Git root, but no Git repositorie
    aaa是一个单独被git管理的项目,把删除其中的.git,后把它移动到一个bbb项目跟目录下(其也已经被git管理),然后报错:Thedirectory<Project>\aaaisregisteredasaGitroot,butnoGitrepositorieswerefoundthere. 根据你的描述,出现这个错误的原因是因为开发工具仍然......
  • ProtChat:融合大语言模型与蛋白质语言模型的自动化蛋白质分析工具
    近年来,大语言模型(LLMs)在自然语言处理领域取得了巨大进展,极大地提升了人机交互的效率和精准度。而在计算生物学中,蛋白质序列被类比为自然语言,基于此的蛋白质大语言模型(PLLMs)也应运而生。然而,PLLMs的应用往往需要复杂的预处理和脚本开发,这使得非计算背景的研究人员难以充分利用其潜......
  • Vue3 在defineProps中某个属性的默认值使用多语言i18n 异常defineProps()` in <script
    原代码<scriptsetuplang="ts">constprops=defineProps({modelValue:{type:Array,default:[]},typeName:{type:String,default:t('TypeName')},disabled:{type:Boolean,default:false......
  • 20 GitHub 仓库帮助你成为 React专家
    原文:https://dev.to/martinadamsdev/20-github-repositories-to-become-a-react-master-opl#how-to-become-a-react-master-1 推荐的GitHub仓库列表:reactjs/reactjs.org:官方React文档,提供了详细的学习指南和示例代码。facebook/react:React的官方仓库,包含了核心代码......