git rebase --onto 三个参数顺序为 ,即“把 分支中从 之后的提交搬到 后面”,顺序颠倒会导致丢 commit 或分支错乱。

git rebase --onto 三个参数顺序不能错
很多人执行 git rebase --onto 后发现分支没动、提交乱了,甚至丢 commit——根本不是命令不灵,而是把 <newbase></newbase>、<oldbase></oldbase>、<top></top> 的位置搞反了。
它不是“把 A 改成基于 B”,而是“把 <top></top> 分支中、从 <oldbase></oldbase> 之后开始的那些提交,搬到 <newbase></newbase> 后面去”。
-
<newbase></newbase>:新落点,比如main或HEAD~2,必须存在且可到达 -
<oldbase></oldbase>:旧分界点,是你要“切下来”的那段提交的**前一个**提交(不是起点本身) -
<top></top>:终点,通常是当前分支名,比如bugfix,Git 会提取<oldbase></oldbase>到<top></top>的所有非共同祖先提交
典型错误写法:git rebase --onto main bugfix feature(误以为是“把 feature 嫁接到 main”)
正确写法:git rebase --onto main feature bugfix(把 bugfix 中从 feature 分出之后的提交,重放到 main 顶端)
怎么选对 <oldbase></oldbase>?别全靠分支名
用分支名当 <oldbase></oldbase> 看似方便,但一旦分支有 merge、rebase 或快进历史,git merge-base feature bugfix 就可能算不准共同祖先,导致漏提或重复提。
更稳妥的做法是直接用那个“分叉点 commit hash”:
- 用
git log --oneline feature...bugfix查看 bugfix 独有提交,再往上翻一行就是分叉点 - 或者用
git merge-base --fork-point feature bugfix(需开启 reflog,更准) - 如果 bugfix 是从 feature 的某个特定 commit
abc123分出的,就直接写abc123,别写feature
常见现象:执行后少了几个 fix 提交——大概率是 <oldbase></oldbase> 设得太靠前,把本该保留在原分支上的共同祖先也排除进去了。
冲突时别 git rebase --skip,那是删 commit
git rebase --onto 必然重放每个被搬运的 commit。只要目标分支(<newbase></newbase>)上已有同文件修改,就会停在冲突处。
这不是 bug,是设计使然。解决方式很明确:
- 手动编辑冲突文件,
git add <file></file>标记已解决 - 必须
git rebase --continue,否则下一个 commit 还会卡住 - 绝对不要
git rebase --skip—— 它会跳过当前 commit,相当于丢掉整个修改 - 中途想放弃?用
git rebase --abort,它会干净回退到 rebase 前状态(前提是没push --force过)
注意:git status 在 rebase 过程中显示的是 “REBASING”,不是 “ON BRANCH”,别误以为还在原分支上操作。
push 前必须确认协作约束
git rebase --onto 改写了本地 commit hash,要同步到远程必须 git push --force-with-lease。
但强制推送不是技术问题,是协作问题:
- 如果别人已经基于你旧的
bugfix提交做过开发,--force-with-lease会失败(保护机制),这时得先沟通 - 团队若禁用 force push,就得改用
merge+--no-ff来保留意图,哪怕历史多一个合并节点 - CI/CD 流水线若依赖旧 commit hash(比如某些部署脚本硬编码 SHA),重写后可能中断
真正容易被忽略的,是 <oldbase></oldbase> 和 <newbase></newbase> 的语义差异:前者定义“切口”,后者定义“着陆区”,两者不在同一逻辑层级,混用分支名最容易掩盖这个区别。











