git merge操作永远作用于当前所在分支,必须先checkout目标分支(如main)再执行merge,否则会反向合并、污染历史;正确流程为:git checkout main → git pull origin main → git merge feature/login。

合并前不切对分支,90% 的“合错了”都是因为这一步出错。 Git 的 git merge 操作永远作用于当前所在分支——它不是“把 A 合进 B”,而是“把目标分支的变更,合进你现在所在的这个分支”。一旦误操作(比如在 feature 分支上执行 git merge main),就等于把 main 的历史反向合进了 feature,后续再推送到远程会污染协作流。
必须先 checkout 主干分支再 merge
这是最常被跳过的硬性前提。想把 feature/login 合入 main,流程只能是:
-
git checkout main(切到你想保留历史、作为主干的那个分支) -
git pull origin main(拉最新,避免本地落后导致三方合并或覆盖) -
git merge feature/login(这时才是“把 login 的改动合进 main”)
如果反过来,在 feature/login 上执行 git merge main,结果是 feature 分支多了一个指向 main 的父提交,历史结构被破坏,CI/CD 可能误判构建来源,代码审查也失去上下文。
merge 与 squash merge 的实际影响差异
默认 git merge 会保留全部提交历史,而 git merge --squash 会把目标分支所有变更打包成一个暂存状态,需手动 git commit。区别不止在“看起来干净”:
- 保留历史:适合多人协作的 feature 分支,方便追溯某次修改由谁、何时、为何引入
- squash 合并:适合单人快速交付、或 PR 中含大量调试/重命名等中间提交,避免污染主干历史;但会丢失原始 author 信息(新 commit 的 author 是当前用户)
- 注意:
--squash后必须git commit,否则什么都不会提交;且该操作不可逆——没有生成真正的合并提交,git log --first-parent看不到来源分支线索
冲突解决后,别急着 push
冲突标记( / <code>======= / >>>>>> feature-x)删完不等于合并完成。常见疏漏:
- 只改了冲突文件,但没
git add标记为已解决 →git status仍显示 unmerged paths - 忘记编译或跑单元测试 → 合并后代码语法合法但逻辑崩坏
- 未检查双亲提交:
git show --stat HEAD看是否混入了不该有的文件;git log --oneline --graph --all确认分支指针位置和合并线是否符合预期 - 本地 commit 成功但未
git push→ 远程主干仍是旧状态,别人基于旧版继续开发,下次合并冲突更剧烈
合并失败后 reset 的安全边界
只要还没 git push,就能用 git reset --hard HEAD~1 撤回合并提交。但有三个关键限制:
- 仅适用于普通合并(非
--squash);squash 合并本质是普通 commit,reset 会连带丢掉你手工写的 commit message - 如果合并过程中已
git add了部分文件,reset 前建议先git stash保存工作区,避免误丢未提交修改 - 一旦
git push到远程,就不能用 reset,必须用git revert -m 1 HEAD反转合并提交,否则会强制改写他人已 fetch 的历史
真正容易被忽略的是:很多人以为 “merge 失败 = 什么都没发生”,其实 Git 已经修改了 index 和 HEAD,直接重试前必须确认工作区干净,否则下一次 merge 会叠加残留状态。











