| name | git-merge |
| description | 把指定源分支 merge 进当前分支。merge 前 fetch 确保用源分支的远端最新版,冲突半自动解决(当前分支有实质改动的以当前为准、否则以源分支为准),拿不准时停下用 AskUserQuestion 问用户、绝不自主决定。保留合并提交历史(不改写历史,故不需备份分支)。触发词:「merge 分支 X」「合并 X 进来」「把 X 并入当前分支」。 |
| argument-hint | <源分支> [--no-ff] |
git-merge — 半自动合并
铁律:拉源分支最新 → 半自动解冲突 → 拿不准必停问。可回退(git merge --abort / git reset),故不强制备份分支。
🔴 硬规
- 必用源分支远端最新版。merge 前
git fetch,合 origin/<源分支>,禁用本地陈旧副本。
- 冲突拿不准必停问。两边都实质改同一逻辑 → 🔴 STOP + AskUserQuestion,禁自主猜选一边。
- 不自动 push。merge 完成留在本地,推送归用户指令。
工作流
1. 取参数 + 前置检查
SRC=<源分支>
CUR=$(git branch --show-current)
git status --porcelain
✅ 完成判据:SRC 非空且 git status --porcelain 无输出(或脏改动已 commit/stash 掉)。
2. 拉源分支远端最新 + 执行
git fetch origin "$SRC"
git merge "origin/$SRC"
✅ 完成判据:git fetch 退出码 0;git merge 已跑完 —— 无冲突则直接进第 4 步,有冲突转第 3 步。
3. 冲突循环(半自动)
每个冲突文件按下表判定。反转 (inversion):merge 与 rebase 下 --ours/--theirs 指向相反的分支,是两个 skill 间最易错的判定,查表别凭记忆。merge 里 --ours=当前分支、--theirs=源分支;rebase 方向相反,见 git-rebase 详表。
| 情形 | 语义 | 命令(merge 语境) |
|---|
| 该文件只有当前分支动过 | 以当前分支为准 | git checkout --ours <file> ← ours=当前分支 |
| 该文件只有源分支动过 | 以源分支为准 | git checkout --theirs <file> ← theirs=源分支 |
| 两边都实质改同一逻辑 | 拿不准 | 🔴 STOP,AskUserQuestion 列冲突 hunk 让用户裁,禁自主 |
判定「有实质改动」:git log origin/$SRC..HEAD -- <file> 看当前分支侧是否有针对该文件的提交(空=只源分支动过)。方向无关的判据骨架(前置检查/实质改动判据/冲突循环步骤)+ -s ours 剧毒警告 + -X 用法 单一真值源见 references/conflict-resolution.md §core。
🔴 用户说「都以当前为准」≠ 全盘 --ours / -X ours:仍须逐文件判定。两边都实质改同一文件时,盲选当前会静默丢弃源分支改动;这类文件照样 STOP 问用户,别被一句「以当前为准」诱导跳过判定。更禁 git merge -s ours(丢弃源分支全部改动,只留假合并记录)。
解完一个文件:
git add <file>
git commit --no-edit
git add 前用 git diff --check 确认文件内无残留 <<<<<<< / ======= / >>>>>>> 标记。
✅ 完成判据:全部冲突文件均已判定并 add,无残留冲突标记,git commit --no-edit 已生成合并提交(或本就 fast-forward 无需提交)。
4. 完成
git log --oneline --graph -5
回显:merge 完成 + 合并提交 hash。回退手段见 references/recovery.md。
✅ 完成判据:git log --oneline --graph -5 显示预期的合并提交(或 ff 后的最新 commit),工作区 git status --porcelain 干净。
失败处理(触发条件 → 一线修复 → 仍失败兜底)
| 触发条件 | 一线修复 | 仍失败兜底 |
|---|
| merge 冲突拿不准 | 🔴 STOP + AskUserQuestion 列 hunk | 用户也不确定 → git merge --abort 回原状,报「需人工介入」 |
| 中途想放弃 | git merge --abort(回到 merge 前) | 已 commit → git reset --hard HEAD~1(确认后) |
| fast-forward 非预期 | 想留合并记录 → git merge --no-ff 重来 | 用户要 ff → 保持默认 |
| fetch 失败(网络/权限) | 重试 fetch;确认 remote 名正确 | 拉不到 → STOP,不拿本地陈旧分支 merge(违硬规 1) |
| 源分支不存在 | 列远端分支让用户确认名 | 名确实错 → STOP 待正确分支名 |
add 后仍见冲突标记 | 重新编辑去掉 <<<</====/>>>> 再 add | 拿不准该留哪边 → STOP 问用户 |
诚实边界
- 半自动非全自动:只有「单边改动」能机器判定并 checkout;两边都改的语义冲突必须人工。
- merge 可回退(
--abort/reset),故不像 git-rebase 强制建备份分支;但已 push 的合并 reset 仍影响协作者。
- 不处理 octopus merge(多分支一次并)、不处理 subtree/submodule merge。
- 「实质改动」判定基于提交历史,极端场景可能误判 → 落到「拿不准」分支停问。