Appearance
Git 合并策略
合并是Git中将不同分支的更改整合到一起的重要操作。本章详细介绍各种合并策略、应用场景和最佳实践。
合并基础
什么是合并
合并是将一个分支的更改集成到另一个分支的过程。Git提供了多种合并策略来处理不同的场景。
合并类型
Git支持多种合并方式,每种都有不同的用途和效果:
- 快进合并(Fast-forward):当目标分支没有新提交时
- 三方合并(Three-way merge):当两个分支都有新提交时
- Squash合并:将多个提交压缩为一个
- Rebase合并:重新应用提交到新基底
快进合并
快进合并原理
当要合并的分支是目标分支的直接上游时,Git会执行快进合并,只是简单地移动分支指针。
bash
# 演示快进合并
# 当前在main分支,feature分支是main的直接上游
git checkout main
git merge feature-branch
# 结果:main分支指针直接移动到feature-branch的最新提交
# 查看合并结果
git log --oneline --graph
强制非快进合并
bash
# 即使可以快进也创建合并提交
git merge --no-ff feature-branch
# 配置默认行为
git config --global merge.ff false # 总是非快进
git config --global merge.ff only # 只允许快进
三方合并
三方合并原理
三方合并使用三个提交:两个分支的最新提交和它们的共同祖先。
bash
# 当两个分支都有独立的提交时,Git执行三方合并
git checkout main
git merge feature-branch
# Git会:
# 1. 找到共同祖先提交
# 2. 比较两个分支的更改
# 3. 自动合并更改(如果无冲突)
# 4. 创建合并提交
合并冲突
当两个分支修改了同一文件的同一部分时,会产生合并冲突。
bash
# 执行合并
git merge feature-branch
# 如果有冲突,Git会报告:
# CONFLICT (content): Merge conflict in filename.txt
# Automatic merge failed; fix conflicts and then commit the result.
# 查看冲突状态
git status
# 冲突文件会包含冲突标记:
# <<<<<<< HEAD
# 当前分支的内容
# =======
# 要合并分支的内容
# >>>>>>> feature-branch
合并策略详解
Recursive策略(默认)
bash
# 默认的合并策略,适用于两个头的合并
git merge -s recursive feature-branch
# Recursive策略的选项:
# -X ours:冲突时选择当前分支的版本
git merge -s recursive -X ours feature-branch
# -X theirs:冲突时选择要合并分支的版本
git merge -s recursive -X theirs feature-branch
# -X patience:使用耐心差异算法
git merge -s recursive -X patience feature-branch
# -X ignore-space-change:忽略空白字符差异
git merge -s recursive -X ignore-space-change feature-branch
Octopus策略
bash
# 用于合并多个分支(两个以上)
git merge -s octopus branch1 branch2 branch3
# 通常用于合并多个主题分支
Ours策略
bash
# 合并时保留当前分支内容,忽略被合并分支的更改
git merge -s ours feature-branch
# 这种合并不会产生实际更改,但会创建合并提交
高级合并技巧
Squash合并
bash
# 将feature分支的所有提交压缩为一个提交合并到main
git checkout main
git merge --squash feature-branch
# 提交squash后的更改
git commit -m "Add feature from feature-branch"
# 删除功能分支
git branch -d feature-branch
合并特定提交
bash
# 樱桃拣选(选择性合并特定提交)
git checkout main
git cherry-pick commit-hash
# 樱桃拣选多个提交
git cherry-pick commit1 commit2 commit3
# 樱桃拣选提交范围
git cherry-pick start-commit^..end-commit
# 樱桃拣选时禁用提交信息编辑
git cherry-pick -n commit-hash
合并预览
bash
# 预览合并结果而不实际执行合并
git merge --no-commit --no-ff feature-branch
# 检查合并结果
git diff --cached
# 如果不满意,可以重置
git reset --hard
# 或者完成合并
git commit -m "Merge feature-branch"
变基(Rebase)合并
基本变基
bash
# 将当前分支的提交重新应用到目标分支上
git checkout feature-branch
git rebase main
# 然后切换到main并快进合并
git checkout main
git merge feature-branch
交互式变基
bash
# 交互式变基,可以修改、重排、删除提交
git rebase -i HEAD~3
# 这会打开编辑器,显示最近3个提交:
# pick abc1234 First commit
# pick def5678 Second commit
# pick ghi9012 Third commit
# 可以修改操作:
# pick:保留提交
# reword:修改提交信息
# edit:修改提交内容
# squash:合并到前一个提交
# fixup:合并到前一个提交(丢弃提交信息)
# drop:删除提交
变基冲突处理
bash
# 变基过程中遇到冲突
git rebase --continue # 解决冲突后继续
git rebase --abort # 放弃变基
git rebase --skip # 跳过当前提交
合并最佳实践
合并前的准备
bash
# 合并前确保主分支是最新的
git checkout main
git pull origin main
# 确保功能分支基于最新主分支
git checkout feature-branch
git rebase main
# 解决可能的冲突
# 测试代码确保功能正常
npm test # 或其他测试命令
合并提交信息
bash
# 编写好的合并提交信息
git merge -m "Merge pull request #123 from user/feature-branch
Feature: Add user authentication
- Implement login functionality
- Add password validation
- Fix security vulnerabilities" feature-branch
合并后清理
bash
# 合并完成后删除功能分支
git branch -d feature-branch # 本地删除
git push origin --delete feature-branch # 远程删除
# 推送合并结果
git push origin main
合并工具和配置
配置合并工具
bash
# 配置外部合并工具
git config --global merge.tool vimdiff
git config --global merge.tool meld
git config --global merge.tool bc3 # Beyond Compare
# 查看配置
git config --get merge.tool
合并策略配置
bash
# 设置默认合并策略
git config --global pull.rebase false # 使用merge
git config --global pull.rebase true # 使用rebase
# 设置合并时的默认选项
git config --global merge.conflictstyle diff3
合并钩子
bash
# .git/hooks/post-merge
#!/bin/sh
# 合并后执行的脚本
# 更新子模块
git submodule update --init --recursive
# 安装依赖
npm install
# 运行测试
npm test
合并冲突解决
手动解决冲突
bash
# 1. 找到冲突文件
git status
# 2. 编辑冲突文件,移除冲突标记
# 3. 选择要保留的内容
# 4. 标记冲突已解决
git add conflicted-file.txt
# 5. 完成合并
git commit
使用工具解决冲突
bash
# 使用配置的合并工具
git mergetool
# 使用特定工具
git mergetool --tool=vimdiff
冲突解决策略
bash
# 查看冲突的详细信息
git diff
# 查看双方的更改
git diff --ours
git diff --theirs
# 查看共同祖先的版本
git diff --base
特殊合并场景
合并大项目
bash
# 为大项目配置更大的缓冲区
git config --global http.postBuffer 524288000 # 500MB
# 使用稀疏检出合并特定目录
git config core.sparseCheckout true
echo "specific/directory/" > .git/info/sparse-checkout
合并二进制文件
bash
# 配置二进制文件的合并策略
git config merge.binary.driver "cp %B %A" # 保留目标分支版本
git config merge.binary.driver "cp %T %A" # 保留合并结果
通过掌握这些合并策略和技巧,你可以在不同场景下选择最适合的合并方式,确保代码质量和开发效率。