git rebase -i 是合并本地未推送提交的唯一合理方式,它可控、可逆且符合git设计哲学;应避免用merge或commit --amend,正确使用squash/fixup、--force-with-lease及注意时间戳变化。

git rebase -i 是合并本地 commit 的唯一合理选择
别用 git merge 或 git commit --amend 来合并多个已有提交——它们要么引入无意义的合并节点,要么只能改最后一个。真正可控、可逆、符合 Git 设计哲学的方式只有 git rebase -i。
它不是“重写历史”的危险操作,而是对尚未共享的本地提交做逻辑归并。只要没 git push 过,或者你有权限强制推送且已和协作者同步过意图,就放心用。
- 必须在目标分支上操作(比如你在
feature/login分支开发,就切到该分支再执行) - 不能对已推送到远程且被他人拉取的提交随意变基,否则会引发指针错乱
-
HEAD~N和commit-hash^两种起始写法效果一致,但后者更精准,尤其当分支有分叉时
怎么选 squash 还是 fixup?关键看要不要保留原提交信息
在 git rebase -i 编辑器里,你会看到多行 pick <hash><message></message></hash>。把某行改成 squash(或简写 s)表示:合并进前一个 commit,并进入二次编辑界面,让你手动整合提交信息;改成 fixup(或 f)则直接丢弃该提交的 message,只保留代码变更,不弹出编辑器。
- 用
squash:当你想把 “修复按钮样式” + “调整 API 参数” + “补充单元测试” 合成一条 “feat: implement login flow with validation” - 用
fixup:当你有一堆fix typo、add console.log、revert debug change,只想清理掉,不关心它们原来写了啥 - 注意顺序:被
squash或fixup的提交必须排在目标 commit 的后面,Git 不支持向前合并
强制推送前务必确认 remote 分支状态
执行完 git rebase -i 后,本地提交哈希全变了,git push 会拒绝,报错 ![rejected] branch -> branch (non-fast-forward)。这时你需要 git push --force-with-lease,而不是裸 --force。
-
--force-with-lease会检查远程分支自你上次git fetch后是否被别人更新过,如果被更新了就中止推送,避免覆盖他人工作 - 如果你已经
git fetch过,且确定没人动过这个分支,那--force-with-lease是安全的 - 如果分支是团队共用的(比如
develop),哪怕只是临时整理,也建议先建新分支(如feature/login-clean)再操作,避免影响他人
IDE 里点几下就能完成,但得知道它背后在调什么命令
Goland、VS Code 的 Git 图形界面确实能点选多个提交 → 右键 → “Squash into previous commit”,看起来很省事。但它底层仍是调用 git rebase -i,只是帮你生成了指令文件并自动保存退出。
- 图形界面不会告诉你哪些提交被跳过(比如已被合并进其他分支的),容易误操作
- 一旦出现冲突,IDE 通常只给合并工具,但你仍需理解
git add+git rebase --continue的流程 - 建议新手先在终端跑一遍
git rebase -i HEAD~3,观察编辑器内容和后续交互,再用 IDE 加速重复操作
最常被忽略的一点:squash 后的提交时间戳是最新那个 commit 的时间,不是第一个。如果你依赖 git log --since 做自动化筛选,这点会影响结果。别假设“合并后的时间 = 第一个提交时间”。











