关于 git-conflict-resolve
git-conflict-resolve 是用于处理 Git 合并与变基冲突的语义分析 Skill,避免盲目选择一方。它逐文件分析变更并按置信度决定处理方式,随后验证文件并生成手动审查清单。
主要功能
- 01处理合并与变基冲突
- 02分析冲突双方的变更
- 03分类冲突与构建产物
- 04按置信度分级处理
- 05验证文件并生成审查清单
适用场景
- 01处理发布分支合并冲突
- 02处理变基过程中的多轮冲突
- 03确认有歧义的变更后再处理
- 04检查已解决文件中的残留标记
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ fudesign2008/ open-skills --skill git-conflict-resolve安装后在 Claude Code 中输入/git-conflict-resolve确认已加载。
附带文件reference.md
详细介绍
Git 冲突解决工作流(git-conflict-resolve)
概述
一种由语义驱动的 Git 冲突解决协议,用于替代盲目使用 -X ours/-X theirs 策略。
对于每个冲突文件:首先运行语义分析,了解双方的意图,然后推导出一条解决规则(并给出置信度)。高置信度的冲突会自动解决;中置信度的冲突会显示建议并等待确认;低置信度的冲突会显示三方视图并等待人工决策。解决冲突后,会逐个对每个文件进行逻辑验证,并生成最终的人工审核清单。
配套技能:由 git-release-finish 阶段 6 调用;也可以单独调用以处理任何合并/rebase 冲突。
输入参数
| 参数 | 描述 | 示例 |
|---|---|---|
source | 正在合入的分支(通常是发布分支) | release/8.2.60 |
target | 合并目标分支(通常是 main/master) | master |
version | 版本号(用于命名合并分支) | 8.2.60 |
mode | 冲突场景:merge 或 rebase | merge |
单独调用示例:
运行
git-conflict-resolve技能,参数为 source=release/8.2.60、target=master、version=8.2.60、mode=merge
子阶段 Y.0 — 模式检测与初始化
- 读取输入参数并确认
mode(merge或rebase) - 初始化累计冲突文件列表(一个会在所有轮次中持续保留的全局变量——绝不能在任何时候清空)
- 根据模式进行初始化:
merge 模式(默认):
# Create the merge branch from the target branch (no -X auto strategy, so conflicts surface naturally)
git checkout origin/<TARGET> -b merge-release/<VERSION>
git merge origin/<SOURCE> --no-commit --no-edit
⚠️ 不要使用
-X ours或-X theirs——盲目选择一方可能会悄无声息地丢弃逻辑。冲突应通过下方的语义分析逐个文件决定。
rebase 模式:
# Create a local working branch from the remote source (avoids polluting the original remote branch)
git checkout origin/<SOURCE> -b rebase-release/<VERSION>
# Replay source's commits one by one onto target
git rebase origin/<TARGET>
# Stops on conflict → proceed to Y.1
# If rebase completes with no conflicts → skip Y.1–Y.4, go straight to Y.5
⚠️ 推送 rebase 结果时,如果目标是受保护分支(release/*、main、master),远程服务可能会拒绝强制推送(
remote: rejected)。推送前请检查分支保护;如有必要,应推送到新分支(例如rebase-release/<VERSION>)并新建 MR,而不是强制推送到原分支。
子阶段 Y.1 — 冲突清单(跨轮次汇总)
⚠️ 在 rebase 模式下,每次执行
git rebase --continue后出现新冲突时,都必须重新运行 Y.1,并将新文件追加到累计列表中——绝不能替换该列表。
# Get the conflicted files for the current round
git diff --name-only --diff-filter=U
追加规则:
cumulative list = cumulative list ∪ current round's conflicted files
(set union — no duplicates, but the round in which each file first appeared is retained)
输出格式:
【Conflict inventory — round N】
New conflicted files this round (M):
- path/to/file-a.ts (new)
- path/to/file-b.ts (new)
Cumulative conflict file list (K total, across all rounds):
- path/to/file-a.ts (round 1)
- path/to/file-b.ts (round 2)
...
如果当前轮次的冲突列表为空:
| 模式 | 含义 | 后续操作 |
|---|---|---|
| merge 模式 | git 已自动合并所有内容冲突(但仍可能存在语义问题) | 跳过 Y.2–Y.4,直接进入 Y.5;重点验证版本字段和构建产物路径 |
| rebase 模式 | 当前提交没有冲突 | 运行 git rebase --continue;如果出现新冲突,返回 Y.1;如果 rebase 完成,则进入 Y.5 |
→ 如果列表不为空,则进入 Y.1.5 检查构建产物,然后再决定是否进入 Y.2 进行语义分析。
子阶段 Y.1.5 — 构建产物短路处理(编译/打包文件)
⚠️ 此阶段在 Y.2 的语义分析之前运行——这是节省 token、避免误判的关键前置关卡。
构建产物(编译/打包生成的派生文件)由机器生成:其内容非常庞大(单行压缩代码可能长达数十万字符),因此读取会浪费大量 token;压缩代码没有可供分析的“双方意图”;而强行合并很容易留下冲突标记,或保留过时版本。这类文件始终以发布分支为准——正确做法是不读取、不分析,直接采用发布分支一侧。
对于累积列表中的每个文件,请使用 reference.md 中的“构建产物识别清单”进行分类(构建输出目录前缀 ∪ 文件特征 ∪ 项目特定补充项):
-
匹配构建产物 → 不读取三方内容,也不进入 Y.2 的语义分析;直接使用下方的短路处理表解决:
冲突类型 解决方法 内容冲突(UU)/ 双方新增 git checkout --theirs <FILE> && git add <FILE>(采用发布分支一侧)整个目录均为构建产物 git rm -rfq <DIR> && git checkout origin/<SOURCE> -- <DIR> && git add <DIR>重命名 + 哈希冲突 使用 git 的重命名元数据获取文件名(不要读取文件内容);删除旧的哈希文件,并从发布分支获取新文件——详情参见 Y.4 解决后,仍须运行 Y.4.5 的即时验证(扫描残留冲突标记),确认没有遗漏。
-
不匹配(源代码/配置) → 继续进行 Y.2 的常规语义分析。
⚠️ 默认谨慎处理:边界模糊的文件(既不在已知的构建输出目录中,也不匹配明确的产物特征)绝不能短路处理——应交由 Y.2 处理。若将源代码误判为构建产物,就会丢失目标侧的更改,而这远比多读取一个文件代价更高——有疑问时,宁可读取,也不要误判。
📖 识别清单、各类冲突的详细命令,以及重命名 + 哈希冲突的备用处理方法和理由,请参见 reference.md。
子阶段 Y.1.6 — 机械分流快速路径(语义分析前)
⚠️ 在 Y.1.5 的构建产物短路之后、Y.2 的语义分析之前运行。默认情况下,机械标准只提供证据,不直接得出结论:“采用我方版本”只有在子集检查证明后才有效。如果机械标准无法作出判断,则进入 Y.2 的常规语义分析和 Y.3 的置信度分级。
对于每个剩余的冲突块(已通过 Y.1.5 的源代码 / 配置 / 文档):
1. 子集差异检查(首选) — 对方的内容是否是我方内容的子集?
diff <(ours_block) <(theirs_block) | grep -c '^>'
# 0 → theirs ⊆ ours → take ours (🟢 high confidence), record the criterion in the log
# >0 → escalate: union merge or take-theirs analysis below
2. 符号存在性检查(源文件) — 验证对方的顶层符号(函数 / 类 / 导出项)是否存在于我方内容中;如果我方的方法签名已涵盖对方所需的参数,则我方在功能上是超集。如果三方比较(基础版本 / 我方版本 / 对方版本)显示双方是同一功能的替代实现——属于设计分歧,而非内容丢失——则记录该发现,并通过置信度分级解决。
3. 按标题键去重的合并(规范 / 文档) — 对于具有标题结构的文件(例如 ## → ### Requirement: → #### Scenario:),保留我方的全部内容,并追加我方中不存在其标题的对方内容块;标题相同的条目合并一次,绝不重复。
diff3 解析陷阱 — 从文件内容解析冲突块之前,先检测 diff3 样式(块内的 ^\|{7,} 基础版本部分,或读取 git config merge.conflictStyle)。使用 diff3 时,冲突块包含四个部分:<<<<<<< HEAD 我方版本、||||||| base 基础版本、======= 分隔符、对方版本。只了解三段式格式的解析器会误将基础版本部分当作我方版本,并得出“我方是超集”的结论——这是错误判断。
子阶段 Y.2 — 语义分析
⚠️ 此阶段为只读阶段——不要修改任何文件。
对于每个冲突文件,按顺序执行以下操作:
1. 阅读三方内容
git show :1:<FILE> # BASE: the common ancestor version
git show :2:<FILE> # main side (ours): the target branch's version
git show :3:<FILE> # release side (theirs): the source branch's version
注意:在合并和变基模式下,
:2:都表示主分支一侧,:3:都表示发布分支一侧,含义相同。
2. 分析变更差异
# Compute the common ancestor
MERGE_BASE=$(git merge-base origin/<SOURCE> origin/<TARGET>)
# What changed on the main side relative to BASE
git diff $MERGE_BASE origin/<TARGET> -- <FILE>
# What changed on the release side relative to BASE
git diff $MERGE_BASE origin/<SOURCE> -- <FILE>
3. 输出语义描述
【Semantic analysis — <FILE>】
main side intent: [unchanged / hotfix / feature development / refactor / deletion / version-field update / other]
Specific changes: ...
release side intent: [unchanged / hotfix / feature development / refactor / deletion / version-field update / other]
Specific changes: ...
Relationship between the two sides: [mutually exclusive (one overrides the other) / complementary (both must be kept) / one-sided change (the other side is identical to BASE)]
子阶段 Y.3 — 规则推导
根据 Y.2 的语义分析结论,为每个文件推导解决规则和置信度。
三个置信度等级
| 置信度 | 标准 | 后续操作 |
|---|---|---|
| 🟢 高 | 意图明确,一方具有绝对权威,且不存在丢失逻辑的风险 | 自动解决,并输出所采取的操作 |
| 🟡 中 | 大体明确,但存在局部歧义或需要部分合并 | 提出建议,并等待用户确认 A/B/C |
| 🔴 低 | 无法确定权威一方,或双方都有必须保留的重要逻辑 | 显示三方视图,由用户自行决定 |
冲突类型识别(推导的前提)
在推导规则之前,先识别冲突的结构类型——不同类型的解决策略完全不同,分类错误会导致残留冲突标记或更改丢失。
两步识别:
步骤 1——根据 git status 确定大类:
git status --porcelain # conflict status codes
git diff --name-status --diff-filter=U # rename info
| git status 代码 | 类别 | 含义 |
|---|---|---|
UU(双方均已修改) | 内容冲突 | 双方修改了同一个文件 |
UU + 冲突标记引用不同的文件名 | 重命名冲突 | diff3 格式的 HEAD/base/theirs 标签使用了不同的文件名 |
AA(双方均已添加) | 添加/添加冲突 | 双方独立添加了一个同名文件 |
DU / UD | 删除/修改冲突 | 一方删除,另一方修改 |
步骤 2——根据文件特征进一步判断:
构建产物的初步识别和短路处理已在 Y.1.5 中完成(匹配时采用发布侧,并且不会进入 Y.3)。此处的特征检查是后备措施:如果 Y.1.5 未识别到,但 Y.3 检测到构建产物特征,则将其视为构建产物(采用发布侧)。
# Build-artifact hash file (webpack/vite/rollup chunk)
echo "$FILE" | grep -qE '[0-9a-f]{8,}\.(js|css|map)$'
# Config file
echo "$FILE" | grep -qE '(^|/)(package\.json|tsconfig\.json|\.config\.(js|ts))$'
规则库
按冲突类型和置信度组织。先匹配结构类型,再根据具体场景推导。
🟢 高置信度场景:
| 冲突类型 | 场景 | 推导出的规则 |
|---|---|---|
| 内容冲突 | version/testVersion 字段:发布侧已更新 | 采用发布侧(发布侧为权威) |
| 内容冲突 | 发布侧删除了某个函数/模块,主线对该代码未做任何更改(与 BASE 相同) | 遵循发布侧的删除意图(采用发布侧) |
| 内容冲突 | 构建产物路径(dist/、resources/dist/)的哈希不同 | 整个目录采用发布侧 |
| 内容冲突 | 发布侧进行了完整重构(逻辑相同、结构不同),主线未触及该区域 | 采用发布侧 |
| 重命名 + 构建产物哈希 | diff3 标签引用了不同哈希文件名,文件名符合 [0-9a-f]{8,}\.(js|css|map) | 删除旧哈希文件 + 从发布侧采用新文件(参见专门的 Y.4 节) |
| 添加/添加 | 双方都添加了同名构建产物 | 采用发布侧 |
⚠️ 重命名 + 构建产物哈希是容易出错的场景:简单地执行
git checkout --theirs不起作用,因为重命名后文件名已改变——必须明确删除旧哈希文件,并从发布侧拉取新文件。详细流程请参见 Y.4。
🟡 中置信度场景:
| 冲突类型 | 场景 | 推导出的规则 |
|---|---|---|
| 内容冲突 | 发布侧删除了某个函数/模块,但主线对该代码做了独立更改(热修复) | 手动确认主线的更改是否仍有必要 |
| 内容冲突 | 发布侧进行了重构 + 主线有独立热修复(双方都做了更改,方向不同) | 优先采用发布侧,但手动确认主线的热修复是否已被取代 |
| 内容冲突 | 双方都更改了导入语句 | 合并双方的导入,手动确认没有重复项 |
| 内容冲突 | 多字段配置文件:双方分别更改了不同字段 | 逐字段列出,让用户选择 |
| 重命名 + 源代码 | 源文件已重命名(非构建产物) | 手动确认重命名的意图 |
🔴 低置信度场景:
| 冲突类型 | 场景 | 推导出的规则 |
|---|---|---|
| 内容冲突 | 双方都对业务逻辑做了实质性更改(方向互补或相关) | 展示三方视图——不建议自动解决 |
| 添加/添加 | 添加了同名文件,且该文件不是构建产物 | 展示三方视图,手动合并 |
| 删除/修改 | 一方删除,另一方修改 | 展示三方视图,手动确认是否仍需保留 |
| 任意 | 文件不属于上述任何类别 | 默认设为低置信度,展示三方视图 |
子阶段 Y.4 — 按类别解决
按 Y.3 中的置信度分类,依次处理每个文件:
🟢 高置信度 — 自动解决
# Take the release side (theirs)
git checkout --theirs <FILE>
git add <FILE>
# Take the main side (ours)
git checkout --ours <FILE>
git add <FILE>
# Take the release side for a whole directory (build artifacts, etc.)
git rm -rfq <DIR>
git checkout origin/<SOURCE> -- <DIR>
git add <DIR>
重命名 + 构建产物哈希策略(绝不读取文件内容)
此场景通常已由 Y.1.5 的前置短路处理(匹配到构建产物时直接采用发布侧)。如果 Y.1.5 未能捕获(回退情况),请使用此策略处理,并且优先使用 git 的重命名元数据确定文件名——绝不读取文件内容。
重命名后文件名会改变,因此 git checkout --theirs 可能指向一个已不存在的路径;必须明确处理旧文件名和新文件名:
# 1. Preferred: get both sides' filenames from git's rename metadata (never reads file content)
git diff --name-status --diff-filter=U
# Output looks like: R100 old-abc.js new-def.js → gives OLD_FILE / NEW_FILE
# 1b. Fallback: if rename metadata is missing, extract filenames only from the conflict-marker lines (do not read the full file)
OLD_FILE=$(git show :2:<FILE> | grep "^<<<<<<<" | sed 's/^.*HEAD://')
NEW_FILE=$(git show :3:<FILE> | grep "^>>>>>>>" | sed 's/^.*://' | tail -1)
# 2. Delete the old hash file (otherwise the repo ends up with two functionally identical chunks)
git rm -f "$OLD_FILE" 2>/dev/null
# 3. Take the new hash file from the release branch
git checkout origin/<SOURCE> -- "$NEW_FILE"
git add "$NEW_FILE"
⚠️ 为什么直接执行
git checkout --theirs不起作用:在重命名冲突中,--theirs的文件路径可能与工作树中的当前路径不同。若未删除旧文件,仓库中会留下两个功能相同的代码块(旧哈希 + 新哈希),构建可能会引用错误的文件。
输出日志:
✅ [High confidence] <FILE>
Rule: release refactored, main unchanged → take the release side
Action: git checkout --theirs <FILE> && git add <FILE>
🟡 中等置信度 — 给出建议,等待用户确认
【Conflicted file】<FILE>
【main-side change】...
【release-side change】...
【AI recommendation】Favor release; main's hotfix has already been superseded by xxx in release
【Please choose】
A = Accept the AI's recommendation (take the release side)
B = Keep the main side
C = I'll edit it manually — let me know when it's done
🔴 低置信度 — 展示三方视图,等待用户决定
【Conflicted file】<FILE>
【BASE (common ancestor), lines X–Y】
...(code)
【main side (ours), lines X–Y】
...(code)
【release side (theirs), lines X–Y】
...(code)
【AI analysis】Both sides made substantive logic changes — cannot determine an authoritative side
【Please choose】
A = Take the release side
B = Take the main side
C = I'll merge it manually — let me know when it's done
Y.4.5 — 即时验证(解决每个文件后必须执行)
⚠️ 快速失败原则:每解决一个文件后立即扫描,而不是等到 Y.5 批量验证。这样能立刻发现单个文件中的错误,回滚成本也很低(只需重新处理这一个文件)。等到 Y.5 再验证,可能会忘记当时是如何解决该文件的。
在 Y.4 中每个文件的解决操作完成后(git checkout --theirs/--ours、手动编辑、重命名 + 哈希策略等),立即运行:
# Pair-first verdict (authoritative rule in git-release-finish Phase 0; same semantics here):
# a match counts as residue only when <, >, or | markers are present; pure '=' lines
# (license underlines, Markdown separators) are false positives.
if git grep -qE '^<{7,} |^>{7,} |^\|{7,} ' -- "$FILE" 2>/dev/null; then
echo "❌ $FILE resolution failed: conflict markers remain"
# Roll back to the conflicted state and re-enter Y.2 for analysis
git checkout MERGE_HEAD -- "$FILE" 2>/dev/null
return 1
elif git grep -qE '^={7,}$' -- "$FILE" 2>/dev/null; then
echo "ℹ️ $FILE has pure '=' lines (no markers) — pair-first false positive, clean"
else
echo "✅ $FILE is clean"
fi
为什么使用精确正则,而不是宽泛匹配:<<<<<<<(7 个 < 字符后跟一个空格)会锁定 git 的冲突标记格式,排除 CSS 注释或 ASCII 艺术字中的 === 分隔线。^={7,}$ 要求整行只有等号,因此像 /* ====== */ 这样的 CSS 注释不会匹配(等号后面还有 */)。配对语义遵循 git-release-finish Phase 0 中权威的先配对规则。
为什么使用 git grep 而不是 grep -r:git grep 会自动遵循 .gitignore,且只扫描已跟踪文件,因此自然会排除未跟踪的构建产物;与精确正则结合后,形成双重过滤。
继续多轮 rebase
处理完当前轮次中的所有文件后:
git rebase --continue
如果出现新的冲突 → 返回 Y.1,追加到累计列表中,并继续执行 Y.2–Y.4。 如果 rebase 完成 → 继续执行 Y.5。
子阶段 Y.5 — 逻辑验证
逐个验证累计列表中的每个文件(不只是当前轮次中的文件)。
1. 验证完整保留发布意图
# Compare the resolution result against the original release-side version
git show origin/<SOURCE> -- <FILE>
检查:发布分支中的关键更改(函数、导入、逻辑块)是否已在解决结果中完整保留?
2. 验证 main 上必要的更改
# Compare the resolution result against the original main-side version
git show origin/<TARGET> -- <FILE>
检查:main 上是否有独立且必要的更改(例如热修复)被错误地丢弃?
3. 检查残留冲突标记(仅限累计列表中的文件)
不要扫描整个仓库。只扫描 Y.1 累计列表中的文件——这些是本次冲突解决涉及的唯一文件,因此也是唯一可能残留冲突标记的位置。扫描整个仓库会被构建产物中的 CSS 注释等内容产生的大量误报淹没。
# Scan only the cumulative-list files; the verdict is pair-first (pure '=' lines without
# <, >, or | markers are false positives — authoritative rule in git-release-finish Phase 0)
for FILE in $CONFLICT_FILES_CUMULATIVE; do
git grep -qE '^<{7,} |^>{7,} |^\|{7,} ' -- "$FILE" 2>/dev/null \
&& echo "❌ $FILE has residual markers"
done
⚠️ 警告标准(符合任一项即标记为 ⚠️):
- 发布分支中存在的函数 / 类 / 方法在解决结果中消失
- 发布分支删除的代码在解决结果中重新出现(即被“还原”)
- 发布分支中的某条导入语句在解决结果中缺失
- 版本字段(version/testVersion)与发布分支不匹配
- 发布分支重构了某些逻辑,但解决结果退回到旧实现
❌ 失败标准(符合任一项即标记为 ❌):
- 文件中仍有残留冲突标记(
<<<<<<<、=======、>>>>>>>) - 同一个函数 / 变量在解决结果中出现两次(重复合并)
- 存在明显的语法错误(例如多余的
}、未闭合的括号)
验证输出:
✅ <FILE> — logically consistent (release intent fully preserved, main's necessary changes handled)
⚠️ <FILE> — possibly lost a release change: function/logic xxx does not appear in the resolution result
❌ <FILE> — logic conflict: residual <<<<< markers or an obvious semantic contradiction
⚠️/❌ 文件:不得提交——必须先重新处理,然后才能继续执行 Y.6。
子阶段 Y.6 — 全局审查清单 + 提交
输出摘要表(涵盖累计列表中的所有文件):
⚠️ The following files were changed during this conflict resolution — please review them carefully:
| File | Round appeared | Resolution | Confidence | Logic verification | Needs extra review |
|------|---------|---------|--------|---------|----------|
| src/effects/database/search-database.ts | round 1 | AI automatic (took release side) | 🟢 High | ✅ | — |
| package.json | round 1 | AI automatic (took release's version field) | 🟢 High | ✅ | — |
| src/components/editor.tsx | round 2 | User chose A (release side) | 🟡 Medium | ✅ | — |
| src/utils/helper.ts | round 1 | User merged manually | 🔴 Low | ⚠️ | ⚠️ Needs review |
Files that need extra review (⚠️/❌ verification, or 🔴 low confidence):
- src/utils/helper.ts: verification result ⚠️, possibly lost a release change
After confirming the files above are logically correct, reply "continue" to complete the commit.
用户确认后(按模式执行):
合并模式:
git add -A
⚠️ 提交前门禁(L2 防御):在执行
git commit之前,扫描所有已暂存文件,检查是否残留冲突标记。这是提交前的最后一道防线——即使跳过了 Y.4.5 即时验证或验证出错,它仍能发现问题。
# Scan all staged files; the verdict is pair-first (pure '=' lines are false positives,
# authoritative rule in git-release-finish Phase 0)
git diff --cached --name-only | while read f; do
git grep -qE '^<{7,} |^>{7,} |^\|{7,} ' -- "$f" 2>/dev/null \
&& { echo "❌ Commit blocked: $f still contains conflict markers"; exit 1; }
done
# exit 1 → blocks the commit, go back to Y.4 to reprocess that file
门禁通过后:
git commit --no-verify -m "Merge release/<VERSION> into <TARGET>"
⚠️ 仅当提交前钩子因格式警告等原因阻止合并提交时,才使用
--no-verify;如果钩子运行了类型检查,请修复错误,而不是绕过检查。
变基模式:
# Each rebased commit has already been applied individually — no extra merge commit is needed
# Notify the caller (git-release-finish) to perform the final force-push
git rebase --continue # if commits remain to finish from the last round
# Once the rebase completes, exit and let git-release-finish stage 6 take over the force-push
禁止行为(危险信号)
以下行为违反本协议。如果 AI 注意到自己即将执行其中任何一项,必须立即停止并返回正确步骤。
| 违规行为 | 正确做法 |
|---|---|
| 新一轮变基产生冲突时,清空累计列表并从头开始 | 必须追加——累计列表需始终保留,绝不能清空 |
| 在 Y.4 中解决某个文件后跳过 Y.4.5 即时验证,直接处理下一个文件 | 每个文件都必须执行 Y.4.5——遵循快速失败原则 |
| 以“高置信度文件应该没问题”为由,跳过 Y.5 的逻辑验证 | 累计列表中的每个文件都必须执行 Y.5,不得例外 |
| 生成 Y.6 审查清单后,未等待用户确认就自动提交 | 执行 git commit 前必须等待用户回复“继续” |
| Y.6 提交前门禁检测到冲突标记后,以“影响很小”为由强行提交 | 门禁是硬性拦截——必须返回 Y.4 修复,然后重新运行门禁 |
未实际运行 git show :1:/:2:/:3:,仅凭记忆在 Y.2 语义分析中描述双方内容 | 必须先运行命令读取三方内容,再基于实际内容进行分析 |
对重命名 + 构建产物哈希冲突使用 git checkout --theirs(不删除旧文件) | 必须使用 Y.4 专用的重命名 + 哈希处理策略:删除旧文件,取用新文件 |
| 对双方都有复杂改动的文件套用高置信度规则,跳过中/低置信度的人工确认 | 置信度必须依据 Y.3 的标准判定——绝不可主观拔高 |
| 逻辑验证结果为 ⚠️/❌ 后,以“影响很小”为由继续提交 | 不得提交 ⚠️/❌ 文件——必须重新处理 |
| 对构建产物(已编译/打包的文件)运行 Y.2 语义分析,或读取其三方内容 | 应采用 Y.1.5 的前置快速处理:匹配时直接采用 release 侧内容,不读取或分析(参见 reference.md) |
使用 grep 读取文件内容,以提取重命名 + 构建产物哈希冲突的文件名 | 优先使用 git diff --name-status --diff-filter=U 中的重命名元数据获取文件名;备用方案只读取冲突标记所在行,绝不读取整个文件 |
错误处理
| 场景 | 处理方法 |
|---|---|
git show :1:/:2:/:3: 没有输出 | 该文件没有对应的暂存阶段——使用 git status 检查其状态(可能已自动解决,也可能是新文件) |
git merge-base 出错 | 使用 git log --oneline --graph -10 检查分支拓扑,并手动指定基准提交 |
git rebase --continue 再次产生冲突 | 正常情况——返回 Y.1,追加到累计列表,并继续循环 |
| 逻辑验证结果为 ❌,且没有明确的正确修复方案 | 暂停,向用户展示 ❌ 文件的三方视图,并等待人工决定 |
git checkout --theirs/--ours 报错“pathspec not found” | 先运行 git add -A,然后重试 |
快速参考命令
# ── Conflict-marker detection (precise regex + pair-first verdict, shared by every defense layer) ──
# Matcher: git's conflict-marker format, 7+ characters at line start + space/end-of-line
# Verdict: a match is residue only when the marker regex matches too; pure '=' lines are false positives
RE='^<{7,} |^={7,}$|^>{7,} |^\|{7,} '
RE_MARKER='^<{7,} |^>{7,} |^\|{7,} '
# Y.4.5 single-file instant verification
git grep -qE "$RE_MARKER" -- "$FILE" 2>/dev/null && git grep -nE "$RE" -- "$FILE" 2>/dev/null
# Y.5 cumulative-list scan
for f in $CONFLICT_FILES; do git grep -qE "$RE_MARKER" -- "$f" 2>/dev/null && git grep -lE "$RE" -- "$f" 2>/dev/null; done
# Y.6 pre-commit gate (staged files)
git diff --cached --name-only | while read f; do
git grep -qE "$RE_MARKER" -- "$f" 2>/dev/null && git grep -lE "$RE" -- "$f" 2>/dev/null && echo "❌ $f"
done
# ── Three-way version content ──
git show :1:<file> # BASE
git show :2:<file> # main side (ours)
git show :3:<file> # release side (theirs)
# Each side's delta (compute MERGE_BASE first)
MERGE_BASE=$(git merge-base origin/$SRC origin/$TGT)
git diff $MERGE_BASE origin/$TGT -- <file> # main's delta
git diff $MERGE_BASE origin/$SRC -- <file> # release's delta
# ── Conflict-type identification ──
git status --porcelain # conflict status codes (UU/AA/DU/UD)
git diff --name-status --diff-filter=U # rename info
# ── Resolve by confidence ──
git checkout --theirs <file> && git add <file> # take the release side
git checkout --ours <file> && git add <file> # take the main side
# Y.1.5 build-artifact short-circuit (match → take release side, no content read)
git checkout --theirs <file> && git add <file> # content conflict / Add-Add
git rm -rfq <dir> && git checkout origin/<SOURCE> -- <dir> && git add <dir> # whole-directory artifact
# rename + build-artifact hash (prefer rename metadata, never read file content)
git diff --name-status --diff-filter=U # get OLD/NEW filenames
git rm -f "$OLD" 2>/dev/null && git checkout origin/<SOURCE> -- "$NEW" && git add "$NEW"
# continue the rebase
git rebase --continue