git-conflict-resolve について
git-conflict-resolveは、片側を機械的に選ばず、Gitのマージやリベースの競合を意味に基づいて解決するスキルです。ファイルごとに変更を分析し、確信度に応じて処理した後、解決内容を検証して手動レビュー用チェックリストを作成します。
主な機能
- 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)
概要
盲目的な -X ours/-X theirs 戦略に代わる、セマンティクスに基づいた Git コンフリクト解決プロトコルです。
コンフリクトが発生したファイルごとに、まずセマンティック分析を実行して両方の変更の意図を把握し、次に確信度付きの解決ルールを導き出します。確信度が高いコンフリクトは自動的に解決されます。確信度が中程度の場合は推奨内容を提示して確認を待ち、確信度が低い場合は三者比較ビューを表示して手動での判断を待ちます。解決後は各ファイルを1つずつ論理的に検証し、最後に手動レビュー用のチェックリストを作成します。
関連スキル:git-release-finish のステージ6から呼び出されます。マージ/リベースのコンフリクトを処理するため、単独で呼び出すこともできます。
入力パラメーター
| パラメーター | 説明 | 例 |
|---|---|---|
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
⚠️ リベースの結果をプッシュする際、対象が保護ブランチ(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 に戻り、リベースが完了した場合は Y.5 に進みます |
→ リストが空でない場合は、ビルド成果物を確認する Y.1.5 に進んでから、Y.2 のセマンティック分析を行うかどうかを判断します。
サブステージ Y.1.5 — ビルド成果物のショートサーキット(コンパイル済み/バンドル済みファイル)
⚠️ このステージは Y.2 のセマンティック分析より前に実行されます — トークンを節約し、誤った解決を避けるための重要な事前ゲートです。
ビルド成果物(コンパイルまたはバンドルによって生成されたファイル)は機械生成されます。内容が非常に大きく(1 行に圧縮されたファイルでも数十万文字に達することがあります)、読み込むと大量のトークンを浪費します。圧縮されたコードには分析すべき「どちら側の意図」もなく、無理にマージすると競合マーカーが残ったり、古いバージョンが維持されたりしやすくなります。常にリリースブランチを正とするため、正しい対応は読み込まず、分析せず、リリース側を直接採用することです。
累積リスト内の各ファイルについて、reference.md の「Build Artifact Identification Checklist」(ビルド出力ディレクトリの接頭辞 ∪ ファイルのシグネチャ ∪ プロジェクト固有の追加項目)を使って分類します。
-
ビルド成果物に該当する → 3 者間の内容を読み込まず、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 に進めてください。ソースコードをビルド成果物と誤分類するとターゲット側の変更が失われます。その損失はファイルを 1 つ余分に読むコストを大きく上回ります。判断に迷ったら、誤判定するより読み込んでください。
📖 識別チェックリスト、競合の種類ごとの詳細なコマンド、リネーム+ハッシュのフォールバックとその根拠については、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. シンボル存在チェック(ソースファイル) — 相手側のトップレベルシンボル(関数/クラス/エクスポート)がこちら側に存在することを確認します。こちら側のメソッドシグネチャが相手側の必須パラメーターをすでに満たしている場合、こちら側は機能的な上位集合です。三者比較(base/ours/theirs)で、両側が同じ機能の別実装であること、つまり内容の喪失ではなく設計の相違であることが示された場合は、その所見を記録し、信頼度レベルに従って解決します。
3. 見出しキーによる重複排除付きユニオンマージ(仕様書/ドキュメント) — 見出し構造を持つファイル(例:## → ### Requirement: → #### Scenario:)では、こちら側の内容をすべて保持し、見出しがこちら側に存在しない相手側のブロックを追加します。同じ見出しの項目は一度だけマージし、重複させません。
diff3 の解析時の落とし穴 — ファイルの内容から競合ブロックを解析する前に、diff3 形式を検出します(ブロック内に ^\|{7,} の base セクションがあるか、git config merge.conflictStyle を読み取ります)。diff3 では、競合ブロックは4つの部分で構成されます。<<<<<<< HEAD はこちら側、||||||| base は base、======= は区切り、そして theirs は相手側です。3つの部分からなる形式しか認識しないパーサーは、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 のセマンティック分析の結論に基づき、ファイルごとに解決ルールと信頼度を導き出します。
3段階の信頼度
| 信頼度 | 基準 | 次のアクション |
|---|---|---|
| 🟢 高 | 意図が明確で、一方の側に絶対的な優先権があり、ロジックを失うリスクがない | 自動で解決し、実行したアクションを出力します |
| 🟡 中 | ほぼ明確ですが、局所的に曖昧な点がある、または部分的なマージが必要です | 推奨案を提示し、ユーザーが A/B/C を選択するまで待ちます |
| 🔴 低 | 優先すべき側を判断できない、または保持すべき重要なロジックが両側にあります | 三者の内容を表示し、ユーザーに全面的な判断を委ねます |
コンフリクトの種類の特定(導出の前提条件)
ルールを導出する前に、まずコンフリクトの構造的な種類を特定します。種類によって解決方法はまったく異なり、誤って分類すると、コンフリクトマーカーが残ったり変更が失われたりします。
2 段階で特定します:
ステップ 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 フィールド:リリース側で更新されている | リリース側を採用する(リリース側を正とする) |
| 内容の競合 | リリース側で関数/モジュールが削除され、main側ではそのコードに変更がない(BASEと同一) | リリース側の削除意図に従う(リリース側を採用する) |
| 内容の競合 | ビルド成果物のパス(dist/、resources/dist/)でハッシュが異なる | ディレクトリ全体についてリリース側を採用する |
| 内容の競合 | リリース側で全面的なリファクタリングが行われた(ロジックは同じで構造が異なる)が、main側ではその領域に変更がない | リリース側を採用する |
| 名前変更+ビルド成果物のハッシュ | diff3のラベルが異なるハッシュ付きファイル名を参照し、ファイル名が [0-9a-f]{8,}\.(js|css|map) に一致する | 古いハッシュのファイルを削除し、リリース側から新しいファイルを取得する(専用のY.4セクションを参照) |
| 追加/追加 | 同じ名前のビルド成果物が両側で追加された | リリース側を採用する |
⚠️ 名前変更+ビルド成果物のハッシュは、エラーが起きやすいシナリオです:名前変更後にファイル名が変わっているため、単純な
git checkout --theirsでは機能しません。古いハッシュのファイルを明示的に削除し、新しいファイルをリリース側から明示的に取得する必要があります。詳しい手順はY.4を参照してください。
🟡 確信度が中程度のシナリオ:
| 競合の種類 | シナリオ | 導出されるルール |
|---|---|---|
| 内容の競合 | リリース側で関数/モジュールが削除されたが、main側ではそのコードに独立した変更(ホットフィックス)が加えられている | main側の変更が今も必要か手動で確認する |
| 内容の競合 | リリース側でリファクタリングが行われ、main側には独立したホットフィックスがある(両側が異なる方向に変更している) | リリース側を優先するが、main側のホットフィックスがすでに不要になっているか手動で確認する |
| 内容の競合 | 両側でインポート文が変更されている | 両側のインポートを統合し、重複がないことを手動で確認する |
| 内容の競合 | 複数フィールドを持つ設定ファイルで、各側が異なるフィールドを変更している | フィールドごとに一覧表示し、ユーザーに選択してもらう |
| 名前変更+ソースコード | ソースファイルの名前が変更された(ビルド成果物ではない) | 名前変更の意図を手動で確認する |
🔴 確信度が低いシナリオ:
| 競合の種類 | シナリオ | 導出されるルール |
|---|---|---|
| 内容の競合 | 両側でビジネスロジックに実質的な変更が加えられている(補完的、または関連する方向) | 三者比較を表示する — 自動解決は推奨しない |
| 追加/追加 | 同じ名前で追加されたファイルがビルド成果物ではない | 三者比較を表示し、手動で統合する |
| 削除/変更 | 一方が削除し、もう一方が変更した | 三者比較を表示し、引き続き残す必要があるか手動で確認する |
| 該当なし | 上記のどのカテゴリにも該当しないファイル | デフォルトで確信度を低とし、三者比較を表示する |
サブステージ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のファイルパスが作業ツリー内の現在のパスと異なる場合があります。古いファイルを削除しないと、機能的に同一の断片(古いハッシュと新しいハッシュ)がリポジトリ内に2つ残り、ビルドで誤った方が参照される可能性があります。
出力ログ:
✅ [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
🔴 低い確信度 — 3 つの案を提示し、ユーザーの判断を待ちます
【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、手動編集、rename+hash 戦略など)を終えた直後に、次を実行します。
# 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 文字と、その後にスペース 1 つ)を使うことで、Git の競合マーカー形式に限定され、CSS コメント内の === 区切り線や ASCII アートなどを除外できます。^={7,}$ は、行末までが純粋な等号である行だけに一致するため、/* ====== */ のような CSS コメントには一致しません(等号の後に */ があるためです)。ペアの扱いは、git-release-finish Phase 0 の権威あるペア優先ルールに従います。
grep -r ではなく git grep を使う理由:git grep は自動的に .gitignore を尊重し、追跡対象のファイルだけをスキャンするため、追跡対象外のビルド成果物は自然に除外されます。これに正確な正規表現を組み合わせることで、二重のフィルターになります。
複数ラウンドのリベースを続行する
現在のラウンドですべてのファイルを処理したら:
git rebase --continue
新たな競合が発生した場合 → Y.1 に戻り、累積リストに追加して、Y.2~Y.4 を続行します。 リベースが完了した場合 → Y.5 に進みます。
サブステージ Y.5 — ロジックの検証
現在のラウンドだけでなく、累積リスト内のすべてのファイルを 1 つずつ検証します。
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)がリリース側と一致しない
- リリース側でロジックをリファクタリングしたにもかかわらず、解決結果が古い実装に戻っている
❌ 失敗の基準(次のいずれかに当てはまる場合は ❌ を付けます):
- ファイルに残存する競合マーカー(
<<<<<<<、=======、>>>>>>>)がある - 解決結果内に同じ関数/変数が 2 回現れている(マージの重複)
- 明らかな構文エラーがある(余分な
}や、閉じられていない括弧など)
検証結果:
✅ <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 の事前ショートサーキットを適用します。一致する場合は、読み取りや分析を行わず、リリース側を直接採用してください(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