Git 用 squash + rebase -i 合并提交(简化Graph)

一、核心说明(纠正操作逻辑)

正确操作顺序:先使用 git squash 合并目标提交 → 再用 git rebase -i 整理删除冗余提交记录,最终实现提交历史简化,避免混淆操作流程,确保代码合并与历史清理分步有序。

核心作用:

  • git squash:核心合并指令,可一次性指定多个提交哈希值,将其合并为一个提交,保留所有代码修改,暂不删除任何原始提交记录,仅整合代码变更。
  • git rebase -i:交互式变基,用于编辑、删除squash合并后产生的冗余提交记录,最终简化Git Graph

适用场景:合并本地未推送的零散提交(如fix、debug、update类),简化Git提交历史和Graph图,避免杂乱。

⚠️ 禁忌:不要合并已推送到远程的公共分支(如main/master),会导致团队代码冲突。


二、操作步骤(正确流程)

步骤1:查看提交历史,确定合并范围

先执行命令,查看当前提交记录,明确需要合并的目标提交(本次目标:合并自己的3条B类提交):

1
git log --oneline

示例输出(共6条提交,分3类,仅合并B类自己的提交):

1
2
3
4
5
6
f6g7h8i (HEAD -> main) 第6次提交:C提交(无需合并,公共基础提交)
e5d6c7b 第5次提交:B提交(需合并,自己的提交)
d4c5b6a 第4次提交:B提交(需合并,自己的提交)
c3b4a59 第3次提交:B提交(需合并,自己的提交)
b2a3z4y 第2次提交:A提交(无需合并,他人/公共提交)
a1z2y3x (origin/main) 第1次提交:A提交(无需合并,他人/公共提交)

说明:A提交(第1、2次):他人或公共提交,不合并;B提交(第3、4、5次):自己的零散提交,需合并;C提交(第6次):公共基础提交,不合并。

步骤2:使用 squash 合并目标提交

squash 核心用法:可一次性指定多个提交哈希值,将其合并为一个提交,语法格式:git squash <提交哈希值1> <提交哈希值2> ... <提交哈希值n>

我们仅合并自己的B类提交(第3、4、5次,共3条),执行一条squash命令即可一次性完成合并,无需多次操作:

  1. 执行一条squash命令,一次性合并3条B类提交(第3、4、5次),直接指定3条B类提交的哈希值,语法格式如下: git squash e5d6c7b d4c5b6a c3b4a59 说明:该命令会将指定的3条B类提交(e5d6c7b、d4c5b6a、c3b4a59)一次性合并为一个提交,默认合并到指定哈希值中最靠前的提交(c3b4a59),无需多次执行命令,直接完成3条B类提交的squash合并,A、C类提交不受影响。

⚠️ 说明:squash 仅合并代码修改,不会删除任何原始提交记录,此时提交历史中仍会显示6条原始提交,只是3条B类提交的代码已整合为一个版本,后续需通过rebase -i删除冗余提交。

步骤3:用 rebase -i 删除冗余提交

经过squash合并后,代码已整合,但提交历史中仍有冗余的零散提交记录,需用rebase -i编辑删除:

  1. 执行交互式变基命令,指定编辑范围(仅编辑自己的3条B类提交,即第3、4、5次提交,避开A、C类提交),命令如下: git rebase -i HEAD~3 说明:HEAD~3 表示选取最近3次提交,正好对应3条B类提交,不会影响A、C类提交。
  2. 编辑变基指令:仅保留1个合并后的B类核心提交,删除其余2条冗余的B类提交(A、C类提交不涉及): 打开文本编辑器后,内容如下(修改前,仅显示3条B类提交): pick e5d6c7b 第5次提交:B提交(需合并,自己的提交) pick d4c5b6a 第4次提交:B提交(需合并,自己的提交) pick c3b4a59 第3次提交:B提交(需合并,自己的提交) 修改后(核心:保留1个B类合并后提交,其余2条B类提交改为drop删除,不影响A、C类): pick e5d6c7b 第5次提交:B提交(自己的核心提交,合并后) drop d4c5b6a 第4次提交:B提交(冗余,已squash合并) drop c3b4a59 第3次提交:B提交(冗余,已squash合并) 说明:drop 指令仅删除冗余的B类提交,A类(第1、2次)、C类(第6次)提交保持不变,精准实现“仅合并自己提交”的需求。
  3. 保存文件并退出,rebase -i 操作完成,冗余提交已删除。

步骤4:编辑合并后的提交信息(可选)

若需统一提交信息,可在rebase -i编辑时,将保留的提交改为reword(简写r),编辑简洁规范的提交信息:

1
reword e5d6c7b 第5次提交:B提交(自己的核心提交,合并后)

保存退出后,提交信息更新完成。

步骤5:验证最终结果

执行命令,查看合并+删除后的提交历史,确认Git Graph简洁:

1
git log --oneline

成功示例(仅3条B类自己的提交合并为1条,A、C类提交不变):

1
2
3
4
f6g7h8i (HEAD -> main) 第6次提交:C提交(无需合并,公共基础提交)
e5d6c7b 第5次提交:B提交(自己的核心提交,合并后)
b2a3z4y 第2次提交:A提交(无需合并,他人/公共提交)
a1z2y3x (origin/main) 第1次提交:A提交(无需合并,他人/公共提交)

三、特殊情况与常用技巧

1. 合并后推送到远程(个人分支)

仅个人分支可强制推送,覆盖远程历史(公共分支严禁操作,避免影响团队协作):

1
2
3
4
5
# 安全强制推送(推荐)
git push --force-with-lease

# 不推荐:普通强制推送(风险高)
# git push -f

2. 常用快捷命令

  • 撤销squash合并:git reset --hard HEAD^(仅squash合并后未执行其他操作、未提交结果时可用)
  • 撤销rebase -i操作:git rebase --abort
  • rebase冲突解决后继续:git rebase --continue
  • 快速squash合并最近2次提交:git squash HEAD^

四、避坑总结

  1. 操作顺序不可颠倒:必须先squash合并代码,再用rebase -i删除冗余提交,颠倒顺序会导致代码丢失或提交历史混乱。
  2. 仅合并「本地未推送」的提交,公共分支严禁执行squash和rebase操作。
  3. squash仅负责合并代码修改,不删除任何提交记录;rebase -i的drop指令才是删除冗余提交、简化Git Graph的关键,二者配合完成“代码合并+历史清理”。
  4. 强制推送优先用 --force-with-lease,比 -f 更安全,避免误覆盖他人代码。