(三)分支与合并 - git rebase 命令的使用
文章目录
- 1. 命令概述
- 2. 命令格式
- 3. 基本用法
- 3.1 整理本地分支的提交历史
- 3.2 交互式变基
- 4. 高级用法
- 4.1 使用 --onto 进行精确变基
- 4.2 从变基中排除提交
- 5. 注意事项(非常重要!)
- 5.1 黄金法则
- 5.2 处理冲突
- 5.3 理解“重写历史”
- 6. 补充信息
1. 命令概述
git rebase(变基)的核心思想是 “重新定位”一个分支的基准。它将一个分支上的一系列提交“移动”到另一个新的基础提交之上,从而创造出更线性的项目历史。
与 git merge 的区别:
- Merge(合并):创建一个新的“合并提交”,将两个分支的历史联系在一起。历史记录会忠实地反映出所有的开发过程,但可能会显得复杂(尤其是存在大量分支时)。
- Rebase(变基):通过重新播放提交来整合变化,使得历史记录看起来像在一条直线上进行的。它重写了提交历史。
一个简单的比喻:
想象你在玩一个用积木(提交)搭的塔(分支)。merge 是把另一个塔整个搬过来,在底部放一个平台(合并提交)连接起来。而 rebase 则是把你这个塔从原来的地基上拿起来,放到另一个更新、更高的塔顶上。
2. 命令格式
基本的命令格式有两种:
# 格式一:将当前分支变基到 <base_branch>
git rebase <base_branch># 格式二:更复杂的变基,将 <branch> 变基到 <new_base>(可以是提交ID、分支或标签)
git rebase --onto <new_base> <old_base> <branch>
3. 基本用法
3.1 整理本地分支的提交历史
这是 rebase 最常用也是最安全的场景。假设你的 feature 分支是从 main 分支切出来的,现在 main 分支有了一些新的提交。
你想让 feature 分支基于最新的 main 分支:
# 1. 切换到 feature 分支
git checkout feature# 2. 执行变基,将 feature 的提交“重新播放”到 main 之上
git rebase main
执行过程:
- Git 会找到当前分支 (
feature) 和目标分支 (main) 的最近共同祖先。 - 提取当前分支在共同祖先之后的所有提交,并将这些提交临时保存为补丁。
- 将当前分支指针重置到目标分支 (
main) 的最新提交(即新的“基”)。 - 将之前保存的补丁(你的提交)按顺序重新应用到当前分支上。
如果重新应用提交的过程中没有冲突,变基就成功了。如果有冲突,需要解决(见注意事项)。
3.2 交互式变基
这是一个极其强大的功能,允许你在重新应用提交之前,修改、整理、合并这些提交。这在将本地分支推送到远程之前,整理凌乱的提交历史时非常有用。
使用 -i 或 --interactive 选项:
# 对当前分支最新的 n 个提交进行交互式变基
git rebase -i HEAD~n# 或者变基到某个提交ID(不包括该提交)
git rebase -i <commit_hash>
执行命令后,会打开一个编辑器,列出你选定的提交列表,并允许你为每个提交选择一个命令。
常用的交互式命令:
pick (p): 使用该提交(不做修改)。reword (r): 使用该提交,但修改其提交信息。edit (e): 使用该提交,但在重新应用时暂停,允许你修改提交内容(例如添加漏掉的文件)。squash (s): 将该提交压缩到前一个提交中。提交内容将被合并,并且你可以重新编辑提交信息。fixup (f): 与squash类似,但会丢弃当前提交的提交信息,直接使用前一个提交的信息。drop (d): 丢弃该提交。
示例: 将最近3个提交合并为1个。
git rebase -i HEAD~3
在编辑器中,将第一行保留为 pick,将后两行改为 squash 或 fixup。
pick a1b2c3d 提交1
squash e4f5g6h 提交2
squash i7j8k9l 提交3
保存退出后,Git 会让你为这个新的合并提交编辑一条提交信息。
4. 高级用法
4.1 使用 --onto 进行精确变基
这个选项用于更复杂的场景,比如你想把一个分支的一部分提交移动到另一个完全不同的基础上。
场景:你从 main 分支创建了 feature 分支,然后从 feature 分支又创建了 feature-sub 分支。现在你想把 feature-sub 分支的修改直接应用到 main 分支,而忽略feature 分支的修改。
# 将 feature-sub 分支(从 feature 分叉出来的部分)变基到 main 分支
git rebase --onto main feature feature-sub
4.2 从变基中排除提交
在交互式变基中,直接 drop 一个提交即可。在非交互模式下,这通常需要与 --onto 结合使用,或者通过创建不含特定提交的新分支来实现。
5. 注意事项(非常重要!)
5.1 黄金法则
不要对已推送到公共仓库的分支进行变基!这是使用 rebase 最最重要的一条规则。如果你重写了已经公开的提交历史(即其他人可能已经基于这些提交进行工作了),会给他们带来极大的混乱。他们需要手动修复他们的本地分支,这是一个非常痛苦的过程。只对本地、未推送的提交使用 rebase。
5.2 处理冲突
变基过程中,在重新应用每一个提交时都可能产生冲突。这与合并冲突类似。
- 当冲突发生时,Git 会暂停变基过程。
- 你需要手动解决这些冲突(编辑文件)。
- 使用
git add <file>标记冲突已解决。 - 然后使用
git rebase --continue继续变基过程。 - 如果想放弃整个变基操作,回到开始前的状态,使用
git rebase --abort。
5.3 理解“重写历史”
变基会创建新的提交(即使修改内容相同,提交的哈希值也会改变)。这意味着你原来的提交链被一个新的、看起来类似的提交链替代了。
6. 补充信息
何时使用 Rebase,何时使用 Merge?
- 使用 Rebase:
- 整理本地分支历史:在将功能分支合并回主分支之前,使用交互式变基使其历史清晰、有意义。
- 更新功能分支:定期将主分支的最新更新整合到你的功能分支中,保持线性历史。
- 个人项目或私有分支:在这些场景下,重写历史是安全的。
- 使用 Merge:
- 保留完整的历史记录:当你想明确记录下分支的合并点和时间时。
- 合并公共分支:当你需要将更改整合到主分支(如
main,develop)时,通常使用合并(尤其是创建合并请求/拉取请求时),因为它更安全,不会重写公共历史。 - 团队协作:在团队环境中,对共享的、已推送的分支坚持使用
merge可以避免混乱。
与 git pull 的结合
你可以配置 git pull 时默认使用 rebase 而不是 merge,这样可以避免不必要的合并提交,保持历史线性。
# 为当前分支设置
git config branch.<branch_name>.rebase true# 为所有分支全局设置
git config --global pull.rebase true
设置后,直接执行 git pull 就相当于 git pull --rebase。
