rebase 把当前分支的提交逐个重放到目标分支上,每重放一个提交都可能撞上冲突。遇到冲突不是环境坏了,而是 Git 需要你替它决定保留哪边。先按下面的方法判断范围,再动手改。
冲突出现后,先别急着改,看两个位置
Git 提示 CONFLICT 时,工作区里一般会留下未合并的文件。用 git status 查看,文件会出现在 Unmerged paths 下面,状态通常是 both modified。打开这些文件,能看到 <<<<<<< HEAD、=======、>>>>>>> 这样的冲突标记。上段是当前分支的内容,下段是正在变基的提交引入的内容。只要文件里还有这些标记,就说明这个文件还没有完成合并,必须逐段处理。
如果 git status 显示的是 deleted by us 或 deleted by them,说明冲突类型是删除,和 both modified 的处理方式不同。这时要么用 git add 接受删除,要么用 git restore --source= 指定提交把文件找回来。
手动改文件的时候,记住一个原则
手动解决冲突没有捷径,核心是逐段决定保留哪边内容,或者把两边内容按业务逻辑拼接起来。编辑完文件后,记得把所有冲突标记连同多余的空行删除干净。然后执行git add把该文件标记为已解决。注意在这个阶段千万不要运行git commit,因为rebase会自己帮你提交,你只需要继续流程。确认所有冲突文件都add之后,执行git rebase --continue,Git会打开编辑器让你确认提交信息,保存后即完成当前提交的变基。
这个流程可以写成固定套路:
# 1. 查看冲突文件列表
git status
# 2. 打开文件逐个编辑,删掉冲突标记
vi src/example.py
# 3. 标记为已解决
git add src/example.py
# 4. 继续 rebase,Git 会重新打开编辑器确认提交信息
git rebase --continue
如果 rebase 停下来是因为一个提交里有多个文件冲突,每个文件都要分别编辑并 add,最后一起 continue。不要只处理完一个文件就急着 continue。
continue 之前,花十几秒检查暂存内容
在git rebase --continue之前值得花几秒钟做双重检查:一是用git diff查看已暂存的改动是否符合预期,重点留意有没有漏掉某个冲突标记;二是运行git diff --check,它能发现空白字符错误,比如行尾多余空格或冲突残留符。如果git status显示没有未合并文件,且工作区干净,再继续操作会更稳妥。若rebase命令因为某个提交有未暂存改动而拒绝继续,通常说明还有文件没add,补上即可。
注意,文件已经 git add 之后,git diff 默认不看暂存区。想看已暂存内容和上一个提交的差异,用 git diff --cached。如果你刚修改完还没 add,git diff 是有意义的。建议先看未暂存,再看 --cached。
rebase 里的 ours/theirs 和 merge 含义相反
很多人听说rebase冲突可以用git checkout --ours或--theirs快速解决,但这里有个容易踩的坑:在rebase过程中,ours指的是变基前所在的分支(即你原来的提交),theirs指的是正在重放的提交。这和merge里的含义恰好相反。如果一时搞混,有可能把错误版本保留下来,甚至丢失重要代码。所以我建议只在小规模、明确理解上下文的零散冲突里用这个命令,常规情况还是逐行手动解决更安全。解决后若发现方向不对,可以git rebase --abort一键回到rebase前的干净状态。
这里可以补充一个判断方法:执行 git rebase --abort 前,先确认自己的分支有没有未提交的改动。如果有,最好先用 git stash 暂存,因为 abort 会把工作区恢复到 rebase 开始时的状态,未提交的改动可能被覆盖。
改乱了还可以用 rebase --abort 撤回
如果你在 rebase 过程中多次冲突,或者已经无法判断哪个版本才是该保留的,最直接的办法是 git rebase --abort。它会终止整个变基,回到执行 rebase 之前的分支位置。这个操作不会影响你原本的提交,已经在仓库里的历史不会被删掉。
另一个容易遇到的错误是:解决冲突后习惯性执行了 git commit,这会在 rebase 过程中的临时分支上多出一个提交。之后 git rebase --continue 可能会报错,或者历史里出现重复的提交。这种时候可以用 git reset --soft HEAD~1 撤销这个多余提交,然后再继续。但更稳妥的办法是从一开始就不要 commit,只做 add。
rebase 冲突本质上是在问你:这两段历史里,哪些内容才是要继续保留的。把冲突标记清干净,走到 continue 结束,整个流程就算完成。如果还不熟悉,建议先在备份分支上试一次,避免在唯一的分支上反复折腾。