目录

18-Git

发表于
2 36.0~46.3 分钟 16209

Git rebase和merge的区别是什么?

原始问法:

  • Git rebase和merge的区别是什么?

来源题目:SRC-18-156-522

面试先答

Git merge 和 rebase 都是将两个分支的提交历史合并为一个的操作,但核心区别在于是否保留合并点(Merge Commit)。Merge 会创建一个新的合并提交,保留完整的分支历史,形成"分叉-汇合"的结构;Rebase 则将当前分支的提交"摘下来",重新应用到目标分支之上,形成线性的提交历史,看起来像是在目标分支上直接开发。选择原则是:公共分支(如 main/develop)用 merge 保留完整历史,个人特性分支在合入前用 rebase 整理为线性历史。Rebase 前必须确认分支未推送到远程,避免 force push 破坏他人历史。

核心结论
  • Merge 保留完整分支历史,产生合并提交;Rebase 产生线性历史,无合并提交
  • Merge 安全可追溯,适合公共分支;Rebase 整洁但改写历史,仅用于本地或未共享的分支
  • 已推送到远程的分支禁止 rebase,必须使用 merge 或 revert
1. 是什么

Merge(合并):将两个分支的"当前状态"合并在一起,创建一个新的合并提交(Merge Commit),这个提交同时指向两个分支的末端,形成"Y"形结构。

Rebase(变基):将当前分支的所有提交"移动"到目标分支的最新提交之后,通过创建新的提交(内容相同但哈希不同)来实现,形成一条直线的提交历史。

图示对比

Merge 结果:
main:    A — B — C — D
               \
feature:        E — F — M   (M 是合并提交)

Rebase 结果:
main:    A — B — C — D — E' — F'
feature:               /
        (E' 和 F' 是新提交,哈希值与 E、F 不同)
2. 为什么需要它

Merge 解决的问题

  • 保留完整的开发历史,可追溯每个分支的完整演化过程
  • 标记明确的合并点,便于回溯和审计
  • 操作安全,不会修改已有提交

Rebase 解决的问题

  • 保持提交历史整洁线性,便于 git log 查看
  • 避免在查看历史时出现大量分叉和合并点
  • 便于使用 git bisect 等工具进行问题定位
3. 底层原理与完整流程

Merge 流程

1. 切换到目标分支(如 main):git checkout main
2. 执行合并:git merge feature
3. Git 找到两个分支的最近公共祖先(Merge Base)
4. 进行三方合并:
   a. 找到公共祖先提交
   b. 比较两个分支相对于公共祖先的差异
   c. 将两个差异合并到公共祖先基础上
5. 如果没有冲突,创建合并提交(有两个父提交)
6. 如果有冲突,标记冲突文件,等待手动解决

Rebase 流程

1. 切换到特性分支:git checkout feature
2. 执行变基:git rebase main
3. Git 执行以下操作:
   a. 找到 feature 分支相对于 main 的 Merge Base
   b. 将 feature 分支上从 Merge Base 之后的每个提交"摘下来"
   c. 在 main 的最新提交之上,逐个重新应用这些提交
   d. 每个重新应用的提交会产生新的 commit(新的哈希值)
4. 如果有冲突:
   a. 暂停 rebase 过程
   b. 标记冲突文件
   c. 手动解决冲突
   d. 执行 git add <file>
   e. 执行 git rebase --continue 继续
   f. 或 git rebase --abort 放弃 rebase

核心差异

维度 Merge Rebase
提交历史 保留分叉结构 线性结构
提交哈希 保持不变 产生新哈希
合并提交 有(Merge Commit)
历史可追溯 高(完整历史) 低(改写历史)
操作安全性 安全,不改历史 改写历史,需谨慎
冲突处理 一次解决 可能多次解决(每个提交一次)
适用分支 公共分支 个人/未共享分支
4. 怎么使用

Merge 使用场景

# 标准合并流程
git checkout main
git pull origin main          # 拉取最新 main
git merge feature/login       # 合并特性分支
# 如果有冲突,解决后:
# git add .
# git commit -m "解决合并冲突"
git push origin main

# 压缩合并(Squash Merge):将特性分支所有提交压缩为一个
git checkout main
git merge --squash feature/login
git commit -m "feat: 实现登录功能"

Rebase 使用场景

# 在特性分支上整理提交历史
git checkout feature/login
git fetch origin
git rebase origin/main        # 将特性分支变基到最新 main

# 如果有冲突:
# 解决冲突
# git add .
# git rebase --continue

# 交互式 rebase:合并/重排/修改提交
git rebase -i HEAD~3          # 变基最近 3 个提交
# 在编辑器中修改:
# pick abc1234 feat: 添加登录接口
# squash def5678 fix: 修复密码校验
# reword ghi9012 feat: 重写提交信息

# 推送变基后的分支(需要 force push)
git push --force-with-lease origin feature/login

典型工作流

# 推荐工作流:特性分支开发 → 变基整理 → 合并到 main

# 1. 创建特性分支
git checkout -b feature/payment main

# 2. 开发过程中,定期同步 main 的最新进度
git fetch origin
git rebase origin/main

# 3. 开发完成后,整理提交历史
git rebase -i origin/main
# 将多个提交压缩为 2-3 个有意义的提交

# 4. 推送到远程
git push origin feature/payment

# 5. 创建 Pull Request(代码审查)
# 在 GitLab/GitHub 上创建 PR

# 6. 审查通过后,使用 Squash Merge 或 Merge Commit 合入
# Squash Merge: 将 PR 所有提交压缩为一个
# Merge Commit: 保留完整分支历史
5. 适用场景

适用 Merge 的场景

  • 公共分支(main、develop、release)的合并
  • 需要保留完整开发历史和审计追踪
  • 多人协作的长期分支
  • 合并已推送到远程的分支

适用 Rebase 的场景

  • 个人特性分支在合入 main 前整理历史
  • 将长期分支的提交压缩为少量有意义的提交
  • 在特性分支中同步 main 的最新进度(避免分叉过远)
  • 创建干净的提交历史用于演示或 Code Review
6. 不适用场景与替代方案

不适用 Rebase 的场景

  • 已推送到远程且多人协作的分支(会破坏他人的历史)
  • 需要保留完整分支历史的审计场景
  • 不熟悉 Git 的开发者可能误操作

替代方案

  • git merge --no-ff:创建合并提交但保持线性(如果无分叉)
  • git merge --squash:压缩合并,保留工作区变更但不记录历史
  • git reflog:误操作后可通过 reflog 找回丢失的提交
7. 优缺点与技术取舍
维度 Merge 优点 Merge 缺点 Rebase 优点 Rebase 缺点
历史可读性 完整历史可追溯 历史可能混乱 线性整洁 改写历史
安全性 安全不改历史 有风险
协作友好 多人协作友好 需 force push 可能影响他人
冲突处理 一次处理 可能多次处理
审计追踪 完整审计链 历史被改写

决策原则

是否需要保留完整历史?
  ├── 是 → 使用 Merge
  └── 否 → 分支是否已推送到远程?
              ├── 是 → 使用 Merge(已共享的分支)
              └── 否 → 使用 Rebase 整理后合并
8. 常见问题及解决方案

Q1:Rebase 后无法 push 怎么办?

需要 force push:

git push --force-with-lease origin feature/branch
# --force-with-lease 比 --force 更安全,会检查远程分支是否有他人的新提交

Q2:Rebase 过程中想放弃怎么办?

git rebase --abort    # 放弃 rebase,回到 rebase 前的状态
git rebase --skip     # 跳过当前有冲突的提交

Q3:Rebase 后如何找回被丢弃的提交?

git reflog                      # 查看 HEAD 的移动历史
git checkout <old-commit-hash>  # 检出旧提交
git branch recovery-branch <hash>  # 从旧提交创建恢复分支

Q4:Merge 产生的冲突如何高效解决?

1. 使用 IDE 的 Git 冲突解决工具(IntelliJ IDEA、VS Code 都有可视化工具)
2. 理解冲突标记:
   <<<<<<< HEAD          ← 当前分支内容
   当前分支的代码
   =======               ← 分隔线
   待合并分支的代码
   >>>>>>> feature       ← 目标分支内容
3. 手动编辑文件解决冲突
4. git add <resolved-file>
5. git commit 完成合并
9. 版本差异与实现边界
  • Git 2.0+:默认 git config pull.rebase false(pull 时用 merge)
  • Git 2.27+:新增 git merge --no-verify 选项
  • Git 2.32+:git rebase 支持 --rebase-merges 选项
  • GitHub/GitLab:支持在 PR 中选择 merge commitsquash and mergerebase and merge 三种合并方式
  • 注意:不同 Git 客户端(如 GitKraken、SourceTree)对 rebase 的交互支持不同
10. 常见追问
  • 追问1:为什么 rebase 会改变提交的哈希值?——因为 rebase 实质上是创建了新的提交对象(内容相同但父提交不同),Git 中提交的哈希值由内容、父提交、时间戳等共同决定,任何变化都会产生新哈希。
  • 追问2git pull 内部做了什么?——git pull = git fetch + git merge。如果配置了 pull.rebase=true,则是 git fetch + git rebase
  • 追问3:Rebase 和 Cherry-pick 有什么区别?——Cherry-pick 是将单个或多个指定提交应用到当前分支;Rebase 是将整个分支的所有提交移动到新的基点。Cherry-pick 更灵活,Rebase 更高效。
  • 追问4:Squash Merge 和 Rebase 有什么关系?——Squash Merge 是在合并时将多个提交压缩为一个,效果类似先 rebase 压缩再 merge。区别在于 Squash Merge 在合并点产生压缩后的提交,而 Rebase 是在分支内部压缩。
11. 易错点
  • ❌ 错误:Rebase 比 Merge 更先进,应该优先使用

  • ✅ 正确:两者各有适用场景。公共分支用 Merge 保留历史,个人分支用 Rebase 整理。没有谁更先进,只有谁更合适。

  • ❌ 错误:Rebase 不会改变任何东西,只是视角不同

  • ✅ 正确:Rebase 会创建全新的提交对象(新哈希值),原始提交被丢弃。这不是"视角不同",而是真正的历史改写。

  • ❌ 错误:对已推送到远程的分支进行 rebase 没问题

  • ✅ 正确:如果分支已被他人拉取和基于其开发,rebase 会导致他人的提交历史被破坏。此时应使用 merge。

一句话总结

Merge 保留完整分支历史产生合并提交,适合公共协作;Rebase 产生线性整洁的历史但改写提交,适合个人分支整理后合入——选择的核心标准是"分支是否已共享"和"是否需要完整审计链"。


Git冲突如何解决?

原始问法:

  • Git冲突如何解决?

来源题目:SRC-18-156-523

面试先答

Git 冲突是指两个分支对同一文件的同一部分做出不同修改,Git 无法自动决定保留哪个版本时产生的状态。解决冲突的标准流程是:1. 识别冲突文件(git status 查看标记为 both modified 的文件);2. 打开文件理解冲突标记(<<<<<<<=======>>>>>>>);3. 手动编辑保留正确代码或合并两边的修改;4. git add 标记已解决;5. git commit 完成合并。高效解决冲突的关键是理解冲突根因(同一代码区域的并发修改)、使用 IDE 可视化工具、遵循团队约定的代码风格。对于重复性冲突,可通过 .gitattributes 设置自定义合并策略。

核心结论
  • Git 冲突的本质是两个分支对同一文件区域的并发修改
  • 解决流程:识别 → 理解 → 编辑 → 标记 → 提交
  • 预防冲突的关键是频繁同步、保持分支生命周期短、明确团队代码规范
1. 是什么

Git 冲突:当两个分支对同一个文件的同一位置进行了不同修改,且这些修改无法通过简单的"快进"或"三方合并"自动解决时,Git 会标记冲突,等待人工判断。

冲突类型

类型 描述 典型场景
修改冲突 同一行被不同方式修改 两个开发者修改同一功能
删除冲突 一方删除文件,另一方修改文件 重构中删除 vs 修改
新增冲突 两个分支新增同名文件 两个开发者创建同名类
目录冲突 文件变为目录或目录变为文件 大规模重构

冲突标记

<<<<<<< HEAD
当前分支的修改内容(当前分支 = main)
=======
待合并分支的修改内容(待合并分支 = feature)
>>>>>>> feature
2. 为什么需要它

Git 的自动合并依赖于三方合并算法(Three-Way Merge):

  • 找到两个分支的公共祖先(Merge Base)
  • 如果修改的是不同行 → 自动合并成功
  • 如果修改的是同一行 → 产生冲突

冲突的存在是 Git 保护代码完整性的机制——它不会盲目地用一方覆盖另一方,而是要求人工确认。

冲突的价值

  • 防止无意中覆盖他人的修改
  • 强制开发者理解合并的影响
  • 作为团队协作的"检查点"
3. 底层原理与完整流程

三方合并算法

Merge Base(公共祖先): A
Branch 1(当前):       A → B(修改了第 5-8 行)
Branch 2(待合并):     A → C(修改了第 5-8 行)

三方合并尝试:
  对 Branch 1:Base → B 的差异是修改第 5-8 行
  对 Branch 2:Base → C 的差异是修改第 5-8 行
  两个差异作用于同一区域 → 冲突!

解决流程

1. 执行合并操作:git merge feature
2. Git 检测冲突,输出:
   Auto-merging src/main.java
   CONFLICT (content): Merge conflict in src/main.java
   Automatic merge failed; fix conflicts and then commit the result.
3. git status 查看冲突文件列表
4. 打开每个冲突文件,理解修改意图
5. 手动编辑,保留正确代码
6. git add <resolved-file>
7. 所有文件解决后,git commit 完成合并
8. git push 推送到远程

Rebase 冲突解决流程

1. git rebase main
2. Git 应用每个提交时检测冲突
3. 解决冲突(同上)
4. git add <resolved-file>
5. git rebase --continue 继续下一个提交
6. 重复直到所有提交应用完成
7. 如果想放弃:git rebase --abort
4. 怎么使用

手动解决冲突

# 1. 查看冲突
git status
# Unmerged paths:
#   (use "git add/..." to mark resolution)
#        both modified:   src/main/java/com/example/UserService.java

# 2. 打开文件,看到冲突标记
cat src/main/java/com/example/UserService.java
# <<<<<<< HEAD
# public User getUser(Long id) {
#     return userRepository.findById(id);
# }
# =======
# public User getUser(Long id) {
#     User user = userRepository.findById(id);
#     if (user == null) {
#         throw new UserNotFoundException(id);
#     }
#     return user;
# }
# >>>>>>> feature

# 3. 理解:当前分支做了简化,特性分支增加了空值检查
# 决定保留特性分支的版本(更完善),删除冲突标记

# 4. 编辑后的文件:
# public User getUser(Long id) {
#     User user = userRepository.findById(id);
#     if (user == null) {
#         throw new UserNotFoundException(id);
#     }
#     return user;
# }

# 5. 标记解决
git add src/main/java/com/example/UserService.java

# 6. 完成合并
git commit -m "解决合并冲突,保留空值检查逻辑"

使用 Git 工具解决

# 使用 merge 工具(需要配置)
git mergetool

# 配置默认 merge 工具
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd "code --wait $MERGED"

# 或使用图形化工具
git gui              # Git 自带 GUI
git mergetool --tool=meld  # 使用 Meld

预防冲突的技巧

# 1. 频繁同步 main 分支
git checkout feature
git fetch origin
git merge origin/main    # 或 git rebase origin/main

# 2. 使用 .gitattributes 设置合并策略
# 在项目根目录创建 .gitattributes 文件
# 指定某些文件的合并策略
*.java merge=java        # 使用 Java 感知的合并
*.xml merge=xml          # 使用 XML 感知的合并
*.json merge=json        # 使用 JSON 感知的合并

# 3. 使用 Git Hooks 进行预提交检查
# 在 .git/hooks/pre-commit 中添加检查

IntelliJ IDEA 解决冲突示例

1. 打开冲突文件,IDEA 自动高亮冲突区域
2. 点击冲突标记上方的按钮:
   - Accept Current:  接受当前分支版本
   - Accept Incoming: 接受待合并分支版本
   - Accept Both:     接受两个版本
3. 或直接手动编辑
4. Ctrl+Alt+M(或 VCS → Git → Resolve Conflicts)
5. 选择 "Merge" 完成冲突解决
5. 适用场景
  • 日常分支合并:特性分支合入 main,需要解决冲突
  • 多人协作:两个开发者修改了同一文件
  • 长期分支维护:release 分支与 develop 分支的周期性合并
  • 版本升级:大版本升级时大量文件变更导致的冲突
6. 不适用场景与替代方案
  • 完全无关的文件修改:不会产生冲突,Git 自动合并
  • 空文件冲突:新增空文件不会冲突
  • 二进制文件:图片、视频等二进制文件 Git 无法自动合并,需手动选择版本

替代方案

  • git merge -X theirs:冲突时自动采用对方版本
  • git merge -X ours:冲突时自动采用当前版本
  • git checkout --theirs <file>:手动选择对方版本
  • git checkout --ours <file>:手动选择当前版本
# 整个合并过程中冲突都采用对方版本
git merge -X theirs feature

# 单个文件采用对方版本
git checkout --theirs src/main.java
git add src/main.java
7. 优缺点与技术取舍
维度 手动解决 自动策略 合并工具
准确性 高(人工判断) 中(可能丢代码) 高(可视化辅助)
效率 低(需人工介入) 高(自动处理) 中(图形辅助)
适用场景 逻辑冲突 文本冲突 复杂冲突
学习成本

最佳实践

  1. 频繁合并,减少每次冲突量
  2. 使用 IDE 可视化工具
  3. 理解两边代码的修改意图再选择
  4. 合并后运行完整测试
  5. 团队约定代码风格,减少格式类冲突
8. 常见问题及解决方案

Q1:Rebase 过程中产生多个提交的冲突,如何高效处理?

# 方案一:逐个解决(推荐,保证正确性)
git rebase main
# 解决第一个提交的冲突
git add .
git rebase --continue
# 解决第二个提交的冲突
# ... 重复

# 方案二:跳过有问题的提交
git rebase main
git rebase --skip     # 跳过当前提交

# 方案三:中止 rebase,改用 merge
git rebase --abort
git checkout main
git merge feature

Q2:如何处理二进制文件冲突?

# 选择保留当前版本
git checkout --ours path/to/binary-file
git add path/to/binary-file
git commit

# 或保留对方版本
git checkout --theirs path/to/binary-file
git add path/to/binary-file
git commit

# 使用 git 命令逐个处理二进制文件冲突
git diff --name-only --diff-filter=U  # 列出所有冲突文件

Q3:格式类冲突(如空格、换行符)如何解决?

# 配置 .gitattributes 统一行尾
* text=auto eol=lf    # 所有文件使用 LF 行尾

# 使用 merge driver 处理格式
git config --global merge.ignorcr.driver \
    "true"  # 忽略 CRLF 冲突

Q4:如何撤销已解决的冲突?

# 重新合并
git merge --abort     # 放弃当前合并,回到合并前状态
git rebase --abort     # 放弃当前 rebase

# 手动重置文件
git checkout --conflict=merge <file>  # 恢复冲突标记
9. 版本差异与实现边界
  • Git 2.0+:默认使用三方合并算法
  • Git 2.18+:git merge 支持 --autostash 选项,自动保存工作区修改
  • Git 2.34+:git rebase 支持 --merge 选项,更好地处理合并提交
  • VS Code / IntelliJ IDEA:内置 Git 冲突解决可视化工具持续改进
  • 注意:不同操作系统的行尾符差异(Windows CRLF vs Unix LF)可能导致无意义的冲突
10. 常见追问
  • 追问1:为什么会冲突?我以为 Git 能自动合并一切?——Git 的自动合并基于"三方合并算法",它假设不同开发者修改的是不同行。当修改的是同一行时,Git 无法判断哪个版本正确,必须人工介入。这是 Git 的设计哲学:不做假设,只呈现事实。
  • 追问2:如果我和同事同时改了不同文件,会冲突吗?——不会。Git 会自动合并不同文件的修改。只有同一文件的同一位置被修改才会冲突。
  • 追问3:如何减少冲突?——1. 保持分支生命周期短(1-2 天内完成一个特性);2. 频繁同步 main 分支;3. 团队约定代码分区(不同模块/包由不同人负责);4. 明确代码风格(避免格式化冲突)。
  • 追问4git merge --abortgit reset --hard HEAD 有什么区别?——git merge --abort 专门用于中止合并,会恢复到合并前的状态(包括工作区和暂存区)。git reset --hard HEAD 是通用的重置命令,效果类似但语义不同,且不检查是否处于合并状态。
11. 易错点
  • ❌ 错误:冲突意味着代码有问题,必须立即解决

  • ✅ 正确:冲突是正常的协作现象,只表示"两个分支对同一位置有修改,需要人工判断"。解决冲突是日常开发的一部分。

  • ❌ 错误:解决冲突时应该盲目选择"当前"或"对方"版本

  • ✅ 正确:应该理解两边代码的修改意图,合并两边的有效修改。大多数情况下需要手动融合,而非简单二选一。

  • ❌ 错误:合并完成后不测试直接推送

  • ✅ 正确:合并后必须运行完整的测试套件,确保合并没有引入回归问题。特别是在解决了复杂冲突后,手动测试尤为重要。

一句话总结

Git 冲突的本质是两个分支对同一代码区域的并发修改,解决核心是"理解修改意图、融合有效代码、测试验证正确性"——通过频繁同步和明确协作规范可以有效预防冲突。


常见的Git工作流有哪些?

原始问法:

  • 常见的Git工作流有哪些?

来源题目:SRC-18-156-524

面试先答

常见 Git 工作流有五种:Git Flow(分支模型最完整,适合发布周期固定的项目)、GitHub Flow(简洁的主干开发+PR,适合持续交付)、Trunk-Based Development(主干开发,适合 CI/CD 成熟的团队)、Forking Flow( fork+PR,适合开源项目)、集中式工作流(Centralized,类似 SVN 的单人/小团队模式)。选择依据是团队规模、发布频率、协作模式。国内互联网公司常用的是"简化版 Git Flow"或"GitHub Flow"变种:main 分支保持稳定,特性分支开发后通过 MR/PR 合入,配合 Code Review 和自动化流水线。

核心结论
  • 五种主流工作流各有适用场景,没有"最好"只有"最合适"
  • 企业级常用 GitHub Flow + Code Review + CI/CD 的组合
  • Git Flow 分支多但管理清晰,适合版本驱动的项目
1. 是什么

Git 工作流:团队在使用 Git 进行协作开发时遵循的分支模型、合并策略和发布规范。它定义了:

  • 使用哪些分支(main、develop、feature、release、hotfix)
  • 分支的生命周期(何时创建、何时合并、何时删除)
  • 合并的规则(谁可以合并、合并方式、是否需要审查)
  • 发布的流程(如何从代码变更到生产发布)
2. 为什么需要它

没有统一工作流的团队常遇到:

  • 分支混乱:每个开发者都有自己的命名和管理方式
  • 发布困难:不知道哪个分支可以发布、哪个分支包含什么功能
  • 回溯困难:无法追溯某个 bug 修复或功能是在哪个版本引入的
  • 协作低效:合并时频繁冲突,不知道谁该找谁同步

规范的工作流带来:

  • 明确的责任边界和操作规范
  • 可预测的发布节奏
  • 清晰的变更追溯链路
  • 降低协作成本
3. 底层原理与完整流程

工作流一:集中式工作流(Centralized)

模式:所有开发者在一个中央仓库的 main 分支上直接提交
分支模型:只有 main 分支
适用场景:单人开发、小团队、从 SVN 迁移的项目

流程:
  开发者 A ──push──→ main ←──push── 开发者 B
                ↓
             中央仓库
# 基本操作
git clone <repo-url>        # 克隆仓库
git checkout main
git pull origin main        # 拉取最新
# ... 开发 ...
git add .
git commit -m "feat: xxx"
git pull --rebase origin main  # 拉取并变基
git push origin main          # 推送

工作流二:特性分支工作流(Feature Branch)

模式:每个新功能在独立分支上开发,完成后合并到 main
分支模型:main(主干)+ feature/*(特性分支)
适用场景:小型团队,快速迭代

流程:
  main: ──A──B──C──D──E
                \
  feature/login:  F──G──H
                    \
                  merge → main
git checkout main
git pull origin main
git checkout -b feature/login        # 创建特性分支
# ... 开发 ...
git add .
git commit -m "feat: 添加登录接口"
git push -u origin feature/login     # 推送到远程
# 创建 Pull Request → Code Review → 合并
git checkout main
git pull origin main
git branch -d feature/login          # 删除已合并的分支

工作流三:Git Flow

模式:最完整的分支模型,包含 5 类分支
分支模型:
  - main:       生产环境代码
  - develop:    开发集成分支
  - feature/*:  特性分支(从 develop 创建)
  - release/*:  发布分支(从 develop 创建)
  - hotfix/*:   紧急修复(从 main 创建)

适用场景:版本驱动的项目(如 App、库、中间件)
                    ┌── feature/A ──┐
                    │               │
  develop: ─────────┤               ├───────
                    │               │
                    └── feature/B ──┘
                            │
                    ┌── release/1.0 ──┐
                    │                 │
  main: ────────────┤                 ├───
                    │                 │
                    └── hotfix/1.0.1 ──┘
# 创建特性分支
git checkout develop
git checkout -b feature/user-auth

# 创建发布分支
git checkout develop
git checkout -b release/1.0.0
# 在发布分支上进行测试和 bugfix
# 合并到 main(发布)和 develop(同步)
git checkout main
git merge release/1.0.0
git checkout develop
git merge release/1.0.0
git branch -d release/1.0.0

# 创建紧急修复
git checkout main
git checkout -b hotfix/1.0.1
# 修复 bug 并测试
git checkout main
git merge hotfix/1.0.1
git checkout develop
git merge hotfix/1.0.1

工作流四:GitHub Flow

模式:简化版,基于主干开发 + Pull Request
分支模型:main(主干)+ feature/*(特性分支)
核心规则:
  1. main 分支始终可部署
  2. 所有开发在特性分支上进行
  3. 特性分支通过 Pull Request 合并
  4. Code Review 通过后才能合并
  5. 合并后立即部署

适用场景:持续交付的互联网产品
main: ──A──B──C──D──E──F──G
                  \
  feature/payment:  H──I──J
                    ↓
              Pull Request
                    ↓
              Code Review
                    ↓
              Merge → main → 部署
# 开发流程
git checkout main
git pull origin main
git checkout -b feature/payment-api

# 开发过程中同步 main
git fetch origin
git rebase origin/main

# 提交并推送
git add .
git commit -m "feat: 添加支付接口"
git push -u origin feature/payment-api

# 在 GitHub/GitLab 上创建 PR
# 指定 Reviewer 进行 Code Review
# CI/CD 自动运行测试
# 审查通过后合并到 main
# 自动部署到生产环境

工作流五:Forking Flow

模式:每个开发者 fork 中央仓库,在自己的 fork 中开发,通过 PR 贡献代码
分支模型:中央仓库(upstream)+ 个人 fork(origin)
适用场景:开源项目、多团队协作、不信任的贡献者
中央仓库(upstream): main
    ↑
    │ Pull Request
    │
个人 fork(origin): feature/*
# 1. Fork 中央仓库(通过 GitHub/GitLab 网页操作)
# 2. 克隆个人 fork
git clone <personal-fork-url>
cd project
git remote add upstream <central-repo-url>

# 3. 同步中央仓库
git fetch upstream
git checkout main
git merge upstream/main

# 4. 创建特性分支
git checkout -b feature/new-feature

# 5. 推送到个人 fork
git push origin feature/new-feature

# 6. 创建 Pull Request 到中央仓库
# 在 GitHub/GitLab 上操作
4. 怎么使用

企业级推荐方案(国内互联网常见)

命名规范:
  - main:           生产环境
  - develop:        开发环境(可选,小团队可省略)
  - feature/xxx:    特性分支(从 main 创建)
  - hotfix/xxx:     紧急修复(从 main 创建)

合并策略:
  - 一律通过 Merge Request / Pull Request
  - 必须至少 1 人 Code Review
  - CI/CD 必须通过
  - 使用 Squash Merge 保持提交整洁

发布流程:
  1. 开发者创建 feature 分支
  2. 开发完成后提 MR
  3. Reviewer 审查并通过
  4. CI 自动运行测试
  5. 合并到 main
  6. 自动部署到预发/生产

分支命名约定

feature/       # 新功能:feature/payment-integration
bugfix/        # Bug 修复:bugfix/login-timeout
hotfix/        # 紧急修复:hotfix/payment-crash
release/       # 发布版本:release/v2.1.0
docs/          # 文档:docs/api-reference
refactor/      # 重构:refactor/user-service

.github/PULL_REQUEST_TEMPLATE.md

## 变更描述
<!-- 简要描述本次变更的目的和内容 -->

## 变更类型
- [ ] 新功能
- [ ] Bug 修复
- [ ] 重构
- [ ] 文档

## 关联 Issue
<!-- 关联的 Issue 编号 -->

## 测试验证
<!-- 描述如何测试和验证本次变更 -->

## 截图(如果适用)
5. 适用场景
工作流 适用场景
集中式 单人开发、小团队、原型验证
特性分支 小团队快速迭代、简单项目
Git Flow 版本驱动产品(App、中间件、库)、发布周期固定
GitHub Flow 互联网产品、持续交付、云原生应用
Forking Flow 开源项目、跨团队协作、外部贡献者
6. 不适用场景与替代方案

不适用 Git Flow 的场景

  • 持续交付的互联网产品(分支过多,管理复杂)
  • 小团队(流程过重)

不适用集中式的场景

  • 多人协作(冲突频繁、互相阻塞)
  • 需要分支隔离的场景

替代方案

  • Trunk-Based Development:所有开发者在短生命周期分支上开发,合入主干后立即部署。需要强大的 CI/CD 支撑。
  • 环境分支工作流mainstagingproduction,每个环境一个分支。
7. 优缺点与技术取舍
工作流 优点 缺点
集中式 简单直观 无隔离、冲突频繁
特性分支 隔离清晰、简单 分支管理松散
Git Flow 分支明确、版本清晰 分支多、管理复杂
GitHub Flow 简洁、持续交付友好 无 release 分支、版本标识弱
Forking Flow 贡献者隔离、开源友好 流程较重、延迟高

选择决策树

团队规模?
  ├── 1 人 → 集中式
  ├── 2-10 人 → 是否需要版本管理?
  │   ├── 是 → Git Flow
  │   └── 否 → GitHub Flow
  └── 10+ 人 → 是否持续交付?
      ├── 是 → GitHub Flow + 特性分支
      └── 否 → Git Flow
8. 常见问题及解决方案

Q1:特性分支应该从哪个分支创建?

  • main 创建(GitHub Flow 风格)
  • develop 创建(Git Flow 风格)
  • 原则:从包含最新稳定代码的分支创建

Q2:特性分支的生命周期多长?

  • 建议 1-3 天完成一个小特性
  • 大特性可拆分为多个小 PR
  • 分支存活时间越长,合并冲突概率越高

Q3:如何处理多个特性分支同时开发?

# 方案:定期同步 main
git checkout feature/a
git fetch origin
git rebase origin/main

# 如果特性 A 和 B 有依赖关系:
# 先开发 A,合并到 main,再让 B 基于最新 main 开发
# 或 B 从 A 分支创建(基于 A 的提交继续开发)
git checkout feature/a
git checkout -b feature/b

Q4:如何确保 main 分支始终可部署?

  1. 所有代码通过 CI/CD 才能合并到 main
  2. 使用 Feature Flag 控制新功能开关
  3. 灰度发布 / 蓝绿部署
  4. 回滚机制:git revert <commit> 或快速切换到上一版本
9. 版本差异与实现边界
  • GitHub / GitLab:对不同工作流的支持程度
    • GitHub:默认 GitHub Flow,PR + Review + Actions
    • GitLab:支持 Git Flow 模式,内置 Issue 分支
  • Git 本身不限制工作流,工作流是团队约定
  • 云原生时代的趋势:从 Git Flow 向 GitHub Flow / Trunk-Based 简化
  • 关键因素:团队规模、CI/CD 能力、发布频率
10. 常见追问
  • 追问1:为什么国内大厂常用 Git Flow 或其变种?——国内大厂(阿里、腾讯、美团等)的产品发布通常有固定周期(双周/月度),需要明确的版本管理和发布分支。Git Flow 的 release 分支能很好地支持版本冻结、预发布测试、多版本并行维护。但近年来也在向 GitHub Flow + Feature Flag 模式演进。
  • 追问2:Trunk-Based Development 和 GitHub Flow 有什么区别?——GitHub Flow 有特性分支的存在(虽然生命周期短),开发者在分支上开发后合入主干。Trunk-Based Development 更进一步,开发者直接在主干(或从主干创建非常短的分支,几分钟内合入)开发,需要极强的 CI/CD 能力和测试覆盖。
  • 追问3:Git Flow 中的 develop 分支和 GitHub Flow 的 main 分支有什么区别?——功能类似(都是开发集成分支),但 Git Flow 中 develop 是所有特性分支的汇合点,main 只接收 release 分支的合并。GitHub Flow 中 main 是唯一的集成分支,同时承担发布职责。
  • 追问4:如何从集中式工作流迁移到 Git Flow?——分步骤进行:1. 引入特性分支(每个功能独立分支);2. 引入 develop 分支作为开发集成;3. 引入 release 分支管理版本发布;4. 引入 hotfix 分支处理紧急修复;5. 制定分支命名和合并规范。每一步让团队适应后再推进一步。
11. 易错点
  • ❌ 错误:Git Flow 是业界标准,所有团队都应该使用

  • ✅ 正确:没有"最好"的工作流,只有"最合适"的工作流。小团队用 Git Flow 是过度设计,大团队用集中式是混乱之源。

  • ❌ 错误:GitHub Flow 就是不用 develop 分支

  • ✅ 正确:GitHub Flow 的核心是"main 始终可部署 + 短生命周期分支 + PR 审查 + 持续交付"。是否有 develop 分支不是本质区别。

  • ❌ 错误:工作流定好了就能自动执行

  • ✅ 正确:工作流是约定,执行靠团队纪律和工具支撑。需要通过 Git Hooks、CI/CD、代码审查制度来保障执行。

一句话总结

Git 工作流是团队协作的"交通规则"——集中式简单但易拥堵,Git Flow 完整但管理复杂,GitHub Flow 简洁且持续交付友好,选择的核心是匹配团队规模、发布频率和 CI/CD 能力。


推荐文章

07-计算机网络
06-Redis
上一篇 17-安全
下一篇 19-HR与软技能