经验笔记:Git Merge 和 Git Rebase 的作用、区别和联系

ops/2024/11/20 16:41:12/

Git Merge 和 Git Rebase 的作用、区别和联系

1. Git Merge

作用:

  • git merge 用于将一个分支的更改合并到另一个分支中。
  • 它通过创建一个新的合并提交来记录两个分支的差异,并将这些差异应用到目标分支上。

实现过程:

  1. Git 找到两个分支的最近公共提交。
  2. Git 创建一个新的提交,这个提交包含了两个分支之间的所有差异。
  3. 如果有冲突,Git 会让用户手动解决这些冲突。
  4. 合并完成后,目标分支的HEAD会被移动到合并后的提交上。

特点:

  • 保留历史git merge 保留了分支的历史,创建了一个新的合并提交,显示了合并的过程。
  • 顺序重要:合并提交的顺序是由分支的发展历史决定的。
  • 冲突处理:可能会产生更多的冲突,因为所有差异都在一个提交中解决。
  • 使用场景:适用于快速解决小冲突或将特性分支合并到主分支。

图形展示:
先执行 git checkout main,切换当前分支
初始状态:

A -> B -> C (main)\D -> E (feature)

执行 git merge feature 后(默认快进模式):

A -> B -> C  \     D -> E (main, feature)

执行 git merge --no-ff feature 后(非快进模式):

A -> B -> C ----> F (main)\     /D -> E (feature)
2. Git Rebase

作用:

  • git rebase 用于将一个分支上的所有更改重新应用到另一个分支上。
  • 它通过将源分支的提交逐个应用到目标分支的最新状态上来实现这一点,使得源分支看起来像是直接从目标分支发展出来的。

实现过程:

  1. Git 将源分支的第一个提交应用到目标分支的最新状态上。
  2. 接着应用第二个提交,以此类推,直到所有提交都被重新应用。
  3. 如果在这个过程中有任何冲突,Git 会让用户解决这些冲突。
  4. 解决冲突后,用户可以继续 rebase 过程。

特点:

  • 修改历史git rebase 修改了历史,将源分支的提交重新应用到目标分支上,可能会改变提交的顺序或创建新的提交。
  • 提交顺序:允许你调整提交的顺序,甚至可以通过交互式 rebase 来选择性地包含、忽略或重新排序提交。
  • 冲突处理:可能会产生冲突,但在每次提交被重新应用时都需要单独解决冲突,这可能会让冲突更易于管理。
  • 使用场景:适用于重构代码或希望保持一个线性的提交历史,以及避免不必要的提交。

图形展示:
先执行 git checkout feature,切换当前分支
初始状态:

A -> B -> C (main)\D -> E (feature)

执行 git rebase main 后:

A -> B -> C (main)\D' -> E' (feature)

倘若rebase指定的base(在这里是main)相比当前所在的分支(在这里是feature)没有改进,
rebase执行后,当前分支(在这里是feature)的内容不变;
否则,则相当于对指定的base(在这里是main)的最新节点重新进行修改。

3. 区别
  • 历史保留 vs 修改

    • git merge 保留了分支的历史,创建了一个新的合并提交。
    • git rebase 修改了历史,将源分支的提交重新应用到目标分支上。
  • 提交顺序

    • git merge 的提交顺序是由分支的发展历史决定的。
    • git rebase 允许你调整提交的顺序,甚至可以通过交互式 rebase 来选择性地包含、忽略或重新排序提交。
  • 冲突处理

    • git merge 可能会产生更多的冲突,因为所有差异都在一个提交中解决。
    • git rebase 可能会产生冲突,但在每次提交被重新应用时都需要单独解决冲突,这可能会让冲突更易于管理。
  • 使用场景

    • git merge 适用于快速解决小冲突或将特性分支合并到主分支。
    • git rebase 适用于重构代码或希望保持一个线性的提交历史,以及避免不必要的提交。
4. 联系
  • 目的相同git mergegit rebase 都是为了将一个分支的更改合并到另一个分支中。
  • 冲突处理:两者在遇到冲突时都需要用户手动解决。
  • 使用技巧
    • git merge 时,可以使用 --no-ff 标志来始终创建一个合并提交,保留分支历史。
    • git rebase 时,可以使用 --interactive 标志来进行交互式变基,手动选择要应用的更改。

为什么使用 --no-ff

  1. 保留分支历史

    • 使用 --no-ff 可以清楚地看到分支的合并点,保留了分支的历史信息。这对于代码审查和追踪代码的演变过程非常有用。
    • 例如,如果你有一个特性分支 feature-branch,使用 --no-ff 合并到 main 分支后,你可以清晰地看到 feature-branch 的所有提交和合并点。
  2. 便于回滚

    • 如果合并后发现有问题,可以更容易地回滚到合并前的状态,因为有一个明确的合并提交。
  3. 文档化工作流程

    • 合并提交可以作为代码审查的一部分,记录了哪些分支被合并,何时合并,以及谁进行了合并。

不使用 --no-ff 的优点

  1. 简洁的提交历史

    • 如果不使用 --no-ff,合并时会使用快进模式,不会创建额外的合并提交。这使得提交历史更加简洁,特别是对于频繁的小特性分支。
  2. 减少提交数量

    • 快进模式不会增加额外的提交,这有助于减少提交的数量,使提交历史更加干净。

使用场景

  • 使用 --no-ff

    • 代码审查:当你需要保留分支的历史信息,以便进行详细的代码审查。
    • 大型特性分支:对于涉及多个提交的大型特性分支,使用 --no-ff 可以更好地记录合并过程。
    • 团队协作:在多人协作的项目中,使用 --no-ff 可以帮助团队成员更好地理解代码的演变过程。
  • 不使用 --no-ff

    • 小型特性分支:对于涉及少量提交的小型特性分支,使用快进模式可以使提交历史更加简洁。
    • 个人项目:在个人项目中,如果你不需要保留详细的分支历史,可以使用快进模式。
    • 频繁的合并:如果你经常需要合并多个小特性分支,使用快进模式可以减少提交的数量,使提交历史更加干净。

示例

假设你有一个特性分支 feature-branch,包含以下提交:

A -> B -> C \D -> E (feature-branch)

main 分支的提交历史如下:

A -> B -> C (main)
  1. 使用 --no-ff

    git checkout main
    git merge --no-ff feature-branch
    

    结果:

     A -> B -> C ----> F (main)\     /D -> E (feature-branch)
    
  2. 不使用 --no-ff

    git checkout main
    git merge feature-branch
    

    结果:

     A -> B -> C  \     D -> E (main, feature-branch)
    

git_rebase_174">为什么使用 git rebase

  1. 线性提交历史git rebase 可以创建一个线性的提交历史,使得提交历史更加清晰和易于阅读。
  2. 减少合并提交git rebase 不会创建额外的合并提交,这有助于减少提交的数量,使提交历史更加简洁。
  3. 重构代码git rebase 可以用于重构代码,例如重新排序提交、合并提交(squash)、删除提交等。

交互式变基 --interactive

git rebase 还支持交互式变基,允许你在变基过程中手动选择和修改提交。使用 --interactive 标志可以启动交互式变基:

git rebase --interactive HEAD~3

这将打开一个文本编辑器,列出最近的三个提交,允许你进行以下操作:

  • pick:保留该提交。
  • reword:修改提交信息。
  • edit:停止变基过程,允许你修改该提交。
  • squash:将该提交与前一个提交合并。
  • fixup:将该提交与前一个提交合并,但不保留提交信息。
  • exec:执行一个 shell 命令。
  • drop:删除该提交。

总结

  • git mergegit rebase 都是 Git 中用于合并分支的命令,但它们的工作方式和效果不同。
  • git merge 保留了分支的历史,适合快速解决小冲突和常规的代码合并。
  • git rebase 修改了历史,适合重构代码和保持线性的提交历史。
  • 选择哪种方式取决于你的具体需求和团队的工作流程。

希望这篇总结对你有所帮助!


http://www.ppmy.cn/ops/135280.html

相关文章

16.100ASK_T113-PRO 配置QT运行环境(二)

前言 1.在Ubuntu中安装QT Creator 文件名: qt-creator-opensource-linux-x86_64-4.8.0.run 2.配置 2.1 打开选项界面: 在 QtCreator 界面中,依次点击 tools -> options 2.2 选择编译器: 在出现的选项对话框中,在左边点击 Ki…

LeetCode 热题 100 回顾

目录 一、哈希部分 1.两数之和 (简单) 2.字母异位词分组 (中等) 3.最长连续序列 (中等) 二、双指针部分 4.移动零 (简单) 5.盛最多水的容器 (中等) 6…

uniApp项目运行到鸿蒙手机,应用图标一直是H,应用名一直是HBuilder问题

项目运行到鸿蒙手机,应用图标一直是H,应用名一直是HBuilder问题 应用运行到鸿蒙手机和鸿蒙模拟器,应用图标一直是H,应用名一直是HBuilder,在自动生成的harmony-configs文件夹下也没有配置的文件, 这时候需要你将DevEco Studio 下…

android 使用SQLiteOpenHelper 如何优化数据库的性能

一、数据库设计优化 (Schema Design): 这是性能优化的基础。一个精心设计的数据库结构可以显著提高查询速度和减少存储空间。 范式化 (Normalization): 遵循数据库范式,特别是第一范式、第二范式和第三范式,可以消除数据冗余。冗余数据不仅浪费存储空间…

hhdb数据库介绍(9-24)

计算节点参数说明 failoverAutoresetslave 参数说明&#xff1a; PropertyValue参数值failoverAutoresetslave是否可见是参数说明故障切换时&#xff0c;是否自动重置主从复制关系默认值falseReload是否生效否 参数设置&#xff1a; <property name"failoverAutor…

正则表达式常用字符

基础正则 ^:开头字符 $:结尾字符 ^$:空行 .:任意一个字符 *:前一个字符连续出现0次或以上 .*:所有 []&#xff1a;括号中的任意一个字符 [a-z] [a-zA-Z0-9] [a-zA-Z0-9] [^]:除括号内以外的字符 扩展正则 |:或 ssh|telnet|http ():表示整体 ^(ssh|telnet|http)^ssh|^telnet|^ht…

(33)iptables设置防火墙策略常用命令(docker环境、非docker环境)

#普通环境&#xff08;非docker&#xff09; # 拒绝所有对端口 31001 的访问 iptables -A INPUT -p tcp --dport 31001 -j DROP # 允许 IP 地址 20.59.30.77 访问端口 31001 (此处用的是虚拟机 所以要使用nat地址的网关) iptables -I INPUT 1 -p tcp -s 20.59.30.77 --dpor…

第一章 Spring Boot快速⼊⻔ —— 构建Spring Boot项目

概览&#xff1a; SpringBoot设计目的是用来简化Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置&#xff0c;可以更加快速便捷地开发Spring项目&#xff0c;在开发过程当中可以专注于应用程序本身的功…