resolve-conflicts について
Git のマージコンフリクトを計画、承認、解決、検証の順に扱うコーディングエージェント向けスキルです。可能な限り両ブランチの変更意図を保ちます。
主な機能
- 01編集前に解決計画を作成
- 02承認を得て不明点を確認
- 03可能な限り双方の変更を統合
- 04生成ファイルをソースから再生成
- 05削除・変更の競合ファイルをバックアップ
- 06競合を検証してテストを実行
活用シーン
- 01複数種類のファイルの競合解決
- 02削除・変更ファイルのバックアップと分析
- 03テスト、インポート、設定の統合
- 04コミット前の解決状況の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tailcallhq/ forgecode --skill resolve-conflictsインストール後、Claude Code で/resolve-conflictsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/patterns.mdsample-plan.mdscripts/handle-deleted-modified.shvalidate-conflicts.sh詳細
Git の競合解決
両方のブランチの変更をインテリジェントに組み合わせ、双方の意図を保ちながら、Git のマージ競合を解決します。このスキルでは、まず計画を立てる方法を採用しています。競合を評価し、詳細な解決計画を作成して承認を得た後、実行します。
基本原則
- 実行前に計画する:変更を加える前に、必ず構造化された解決計画を作成し、ユーザーの承認を得ます
- 両方の変更を優先する:直接矛盾しない限り、デフォルトでは両方の変更を維持します
- 選ぶのではなくマージする:特にインポート、テスト、設定では、両方をマージします
- 生成ファイルは再生成する:生成ファイルを手動でマージしてはいけません。必ずソースから再生成します
- 解決前にバックアップする:削除と変更が競合しているファイルは、まずバックアップを作成します
- テストで検証する:解決後は必ずテストを実行します
- すべての解決方法を説明する:解決した各競合について、解決方針を一文で説明します
- 不明な点は質問する:差分から正しい解決方法が明確でない場合は、選択肢を提示し、ユーザーに選んでもらいます
ワークフロー
ステップ 1:競合状況を評価する
まず、競合の範囲を把握するための確認を実行します。
git status
競合しているすべてのファイルを特定し、分類します。
- 通常のファイル競合(両方で変更)
- 削除と変更の競合(一方で削除、もう一方で変更)
- 生成ファイルの競合(ロックファイル、ビルド成果物、生成コード)
- テストファイルの競合
- インポート/設定の競合
- バイナリファイルの競合
競合している各ファイルについて、次の情報を収集します。
- ファイルの種類と用途
- 競合の内容(内容、削除、種類の変更)
- 変更の範囲(変更された行、影響を受けるセクション)
- ファイルが生成されたものか、手動で作成されたものか
ステップ 2:マージ解決計画を作成する
評価に基づき、競合を解決する前に構造化された計画を作成します。次の Markdown 形式で計画を提示します。
## Merge Resolution Plan
### Conflict Summary
- **Total conflicted files**: [N]
- **Deleted-modified conflicts**: [N]
- **Generated files**: [N]
- **Regular conflicts**: [N]
### Resolution Strategy by File
#### 1. [File Path]
**Conflict Type**: [deleted-modified / generated / imports / tests / code logic / config / struct / binary]
**Strategy**: [Brief description of resolution approach]
**Rationale**: [Why this strategy is appropriate]
**Risk**: [Low/Medium/High] - [Brief risk description]
**Action Items**:
- [ ] [Specific action 1]
- [ ] [Specific action 2]
#### 2. [File Path]
...
### Execution Order
1. **Phase 1: Deleted-Modified Files** - Handle deletions and backups first
2. **Phase 2: Generated Files** - Regenerate from source
3. **Phase 3: Low-Risk Merges** - Imports, tests, documentation
4. **Phase 4: High-Risk Merges** - Code logic, configuration, structs
5. **Phase 5: Validation** - Compile, test, verify
### Questions/Decisions Needed
- [ ] **[File/Decision]**: [Question for user] (Options: 1, 2, 3)
### Validation Steps
- [ ] Run conflict validation script
- [ ] Compile project
- [ ] Run test suite
- [ ] Manual verification of high-risk changes
この計画をユーザーに提示し、解決を進める前に承認を待ちます。ユーザーの入力が必要な不明確な競合がある場合は、「必要な質問/決定事項」セクションに記載します。
完全な計画の例については、references/sample-plan.md を参照してください。
ステップ 3:削除と変更が競合しているファイルに対応する
このフェーズは、計画の承認後にのみ実行します。
削除されたファイルが変更もされている場合(ステータス:DU、UD、DD、UA、AU):
.forge/skills/resolve-conflicts/scripts/handle-deleted-modified.sh
このスクリプトは次の処理を実行します。
- 変更された内容のタイムスタンプ付きバックアップを作成する
- 移動先となり得る場所を分析する
- 各ファイルの分析レポートを生成する
- 削除のステータスを自動的に解決する
バックアップディレクトリと分析ファイルを確認し、変更をどこに適用するべきかを把握します。
ステップ 4:解決計画を実行する
**計画で定義した実行順序に従います。**競合している各ファイルに対し、計画に沿って適切な解決パターンを適用します。解決する競合ごとに、解決方法を一文で説明します。
計画内の各アクションを完了したら、完了としてマークし、進捗をユーザーに報告します。
解決方法が不明確な場合
差分だけでは正しい解決方法を判断できない場合(このような競合は、すでに計画の「必要な質問/決定事項」セクションに記載されているはずです):
- 競合を提示し、両方のブランチの競合するコードを示します
- 番号付きの選択肢(選択肢 1、選択肢 2 など)を提示します
- 各選択肢の内容と、それによって行われる処理を明確に説明します
- 選択肢の番号を選ぶか、追加情報を提供するようユーザーに尋ねます
- ユーザーの選択を記憶し、以降の関連する競合にも同様の判断基準を適用します
やり取りの例:
I found a conflict in src/main.rs where both branches modify the `calculate_price` function:
<<<<<<< HEAD (Current Branch)
fn calculate_price(item: &Item) -> f64 {
item.base_price * (1.0 + item.tax_rate)
}
=======
fn calculate_price(item: &Item) -> f64 {
item.base_price + item.tax_amount
}
>>>>>>> feature-branch (Incoming Branch)
I'm not sure which calculation is correct. Please select an option:
**Option 1**: Keep current branch (multiplies base_price by tax_rate)
**Option 2**: Keep incoming branch (adds tax_amount to base_price)
**Option 3**: Keep both approaches with a new parameter
**Option 4**: Provide more context to help me decide
Please respond with "Option 1", "Option 2", "Option 3", or "Option 4", or provide additional information.
ユーザーの回答を受け取ったら、その決定と同様のロジックを関連する競合にも適用します。
解決パターン
競合している各ファイルに対し、適切な解決パターンを適用します。
インポート/依存関係
目標:両方のブランチから、重複のないすべてのインポートを統合します。
一行での説明:「両方のブランチから重複のないインポートを組み合わせ、重複を削除してモジュールごとにグループ化します。」
詳しい例については、references/patterns.md の「インポートの競合」セクションを参照してください。
簡単な手順:
- 両方からすべてのインポートを抽出します
- 重複を削除します
- モジュール/パッケージごとにグループ化します
- 言語固有のスタイルに従います(アルファベット順、標準/外部/内部でグループ化)
テスト
目標:両方のブランチからすべてのテストケースとテストデータを含めます。
一行での説明:「両方のブランチからすべてのテストケースを含め、フィクスチャを統合し、必要に応じて名前を変更して競合を避けます。」
詳しい例については、references/patterns.md の「テストの競合」セクションを参照してください。
簡単な手順:
- まったく同じ内容をテストする場合を除き、すべてのテスト関数を残します
- テストフィクスチャとセットアップ関数を統合します
- 両方の側のアサーションを組み合わせます
- テスト名が競合していても、異なる動作をテストする場合は、内容が分かるように名前を変更します
生成ファイル
目標:生成ファイルを再生成して、両方のブランチの変更を反映します。
一行での説明:「ソースファイルから再生成し、両方のブランチの変更を反映することで、生成ファイルの競合を解決します。」
判別方法:次のいずれかに該当するファイルは生成ファイルです。
- ビルドツール、コンパイラ、またはコードジェネレーターによって生成される
- そのファイルを定義するソースファイルまたは設定がある
- 自動生成を示すヘッダーやコメントが含まれている
.gitattributesで生成ファイルとして指定されている- 一般的な例:ロックファイル、protobuf の出力、GraphQL スキーマファイル、コンパイル済みアセット、自動生成されたドキュメント
手順:
-
生成元を特定します:ファイルを生成するコマンドまたはツールを判断します
-
どちらかのバージョンを一時的に選びます(どちらでもかまいません):
git checkout --ours <generated-file> # or --theirs -
ソースから再生成します:適切な生成コマンドを実行します:
# Package manager lock files cargo update # for Cargo.lock npm install # for package-lock.json yarn install # for yarn.lock bundle install # for Gemfile.lock poetry lock --no-update # for poetry.lock # Code generation protoc ... # for protobuf files graphql-codegen # for GraphQL generated code make generate # for Makefile-based generation npm run generate # for npm script-based generation # Build artifacts npm run build # for compiled/bundled assets cargo build # for Rust build artifacts -
再生成したファイルをステージします:
git add <generated-file>
ファイルが生成ファイルかどうか不明な場合:ファイルヘッダーに自動生成を示す記載がないか確認するか、再生成するか手動でマージするかをユーザーに尋ねます。
設定ファイル
目標:両方のブランチから設定値を統合します。
一行での説明:「両方のブランチのキーをすべて含め、競合する値には適切なものを選んで設定を統合します。」
詳しい例については、references/patterns.md の「設定ファイルの競合」セクションを参照してください。
簡単な手順:
- 両方の側のキーをすべて含めます
- 値が競合する場合は、次の基準で選びます:
- 新しい値、またはより最近の値
- より安全で保守的な値
- 本番環境の要件
- 選択した理由をコミットメッセージに記載します
判断が難しい場合:どちらの設定値(現在の値と取り込む値)を優先するか、ユーザーに尋ねます
コードロジック
目標:両方の変更の意図を理解し、可能であれば組み合わせます。
一行での説明:「意図を分析してコードロジックの競合を解決します。変更が互いに独立している場合は統合し、競合する場合は一方の方法を選びます。」
詳しい例については、references/patterns.md の「コードロジックの競合」セクションを参照してください。
簡単な手順:
- 各ブランチが何を実現しようとしているか分析します
- 変更が互いに独立した内容であれば、両方を統合します
- 変更が競合する場合(同じ内容に対して異なる方法を採用している場合):
- 背景を把握するために、コミットメッセージや PR を確認します
- 要件に合う方法を選びます
- 判断が難しい場合は、両方の方法をテストします
- 判断した理由を記録します
判断が難しい場合:それぞれの方法で何ができるかを説明し、両方を選択肢としてユーザーに提示します
構造体/型定義
目標:両方のブランチのすべてのフィールドを含めます。
一行での説明:「両方のブランチのすべてのフィールドを含めて構造体をマージし、定義が競合するフィールドには適切な型を選択します。」
簡単な手順:
- すべてのフィールドをマージします
- フィールドの型が競合する場合、どちらが適切かを分析します
- 更新した構造体に起因するコンパイルエラーをすべて修正します
- 新しいフィールドを使うようにテストを更新します
判断が難しい場合:フィールドの型が競合するときは、どの型定義が正しいかユーザーに尋ねます
ステップ 5:解決結果を検証する
計画のすべての解決フェーズを完了したら、競合がすべて解決されていることを検証します。
.forge/skills/resolve-conflicts/scripts/validate-conflicts.sh
このスクリプトでは、次の項目を確認します。
- 残っている競合マーカー(<<<<<<<、=======、>>>>>>>)
git statusに表示される未マージのパス- 削除と変更の競合
- マージ状態ファイル
ステップ 6:コンパイルとテスト
計画の検証手順に従ってビルドとテストを行い、解決が正しいことを確認します。
# For Rust projects
cargo test
# For other projects, use appropriate test command
# npm test
# pytest
# etc.
テストに失敗した場合:
- 失敗の原因を確認します。マージしたコードによるものですか、それとも競合の解決によるものですか?
- 両方のブランチのテストがそれぞれ単独で成功するか確認します
- マージした変更間の統合上の問題を修正します
- すべて成功するまでテストを再実行します
ステップ 7:完了する
すべての競合が解決され、テストが成功したら、完了した計画を確認してコミットします。
# Review the changes
git diff --cached
# Commit with descriptive message that references the plan
git commit -m "Resolve merge conflicts: [describe key decisions]
Executed merge resolution plan:
- [Phase 1 summary]
- [Phase 2 summary]
- [Phase 3+ summaries]
Key decisions:
- Merged imports from both branches
- Combined test cases
- Regenerated lock files
- [other significant decisions from plan]
Co-Authored-By: ForgeCode <[email protected]>"
判断の記録
ユーザーに選択肢を選んでもらう場合は、その判断を記録し、後続の競合にも同様の考え方を適用します。
シナリオの例:
- 最初の競合:ユーザーがオプション 1 を選択(現在のブランチの検証ロジックを優先)
- 2 つ目の類似した競合:同じ考え方を適用(現在のブランチの検証方法を優先)
- 次のように伝えます:「現在のブランチの方法を維持して解決します(先ほどの選択に合わせています)」
主な原則:
- 同じ競合解決セッション内でユーザーの好みを記憶します
- 競合が類似している場合は、一貫したパターンを適用します
- 一貫性について伝えます:「先ほどと同じパターンに従います……」
- 新しい競合が以前のものと大きく異なる場合は、再度尋ねます
よくあるパターンの参考情報
詳しい解決パターンについては、次を参照してください。
references/patterns.md- すべての競合タイプに関する包括的な例
パターンをすばやく確認するには:
- インポート:重複しないインポートをすべてまとめ、モジュールごとにグループ化します
- テスト:同一のものを除き、すべてのテストを残してフィクスチャをマージします
- 生成ファイル:どちらかのバージョンを選び、ソースから再生成します
- 設定:すべてのキーをマージし、競合する値には新しい値またはより安全な値を選びます
- コード:意図を分析し、互いに独立していればマージし、競合する場合はどちらか一方を選びます
- 構造体:両方のブランチのすべてのフィールドを含めます
- ドキュメント:すべてのドキュメントセクションをまとめます
特別なシナリオ
バイナリファイルの競合
バイナリファイルはマージできません。どちらかのバージョンを選択します。
git checkout --ours path/to/binary # keep our version
# or
git checkout --theirs path/to/binary # keep their version
大規模な名前変更/リファクタリングの競合
一方のブランチで多くのファイルの名前変更やリファクタリングを行い、もう一方のブランチでそれらのファイルを変更した場合:
- 名前変更やリファクタリングを受け入れます(構造上の変更です)
- 新しい構造に変更を適用します
- 適用する際の手引きとして、
handle-deleted-modified.shのバックアップを使用します
サブモジュールの競合
# Check submodule status
git submodule status
# Update to the correct commit
cd path/to/submodule
git checkout <desired-commit>
cd ../..
git add path/to/submodule
トラブルシューティング
「両方で追加」の競合(AA)
両方のブランチで同じ名前の新しいファイルが追加され、内容が異なる場合:
- 両方のバージョンを確認します
- 同じ目的で使われる場合は、内容をマージします
- 異なる目的で使われる場合は、どちらかの名前を変更します
空白のみの競合
競合が空白の違いだけの場合:
git merge -Xignore-space-change <branch>
競合マーカーが残っている場合
検証で競合マーカーが見つかったものの、解決済みだと思われる場合:
- マーカーの文字列をそのまま検索します:
git grep -n "<<<<<<< HEAD" - 文字列やコメント内にマーカーがある場合もあります。それらも解決します
- 隠し文字やエンコードの問題がないか確認します
解決後にテストが失敗する場合
- 各ブランチを個別にテストし、成功することを確認します
- 失敗の原因は、マージした変更間の相互作用である可能性が高いです
- 個々の変更ではなく、相互作用の問題をデバッグします
- 両方の変更が共存できるようにコードを更新します
クイックリファレンスカード
| 競合の種類 | 方針 | 1 行の説明テンプレート |
|---|---|---|
| インポート | すべて統合し、重複を削除して、モジュールごとにまとめる | 「両方のブランチから重複しないインポートを統合し、モジュールごとにまとめます」 |
| テスト | すべて残し、フィクスチャを統合する | 「両方のブランチのすべてのテストケースを含め、テストフィクスチャを統合します」 |
| 生成ファイル | ソースから再生成する | 「両方のブランチの変更を含めるため、ソースから [file] を再生成します」 |
| 設定 | キーを統合し、新しい値を選ぶ | 「すべての設定キーを統合し、[key] には [current/incoming] の値を選びます」 |
| コードロジック | 意図を分析し、互いに独立している場合は統合する | 「両方の変更は異なる課題に対応しているため、統合します」または「[reason] のため、[current/incoming] の方針を選びます」 |
| 構造体 | すべてのフィールドを含める | 「両方のブランチのすべてのフィールドを構造体定義に含めます」 |
| ドキュメント | すべてのセクションをまとめる | 「両方のブランチのドキュメントを統合します」 |
| 削除と変更 | バックアップし、分析して、新しい場所に適用する | 「ファイルが移動/名前変更された後、新しい場所に変更を適用します」 |
| バイナリファイル | いずれかのバージョンを選ぶ | 「バイナリファイルの [current/incoming] バージョンを残します」 |
覚えておくこと:
- 競合を解決するたびに、必ず 1 行の説明を付けます
- 判断が難しい場合は、番号付きの選択肢をユーザーに提示します
- ユーザーの決定を記録し、同様の競合にも一貫して適用します
- 目的は、まとまりのある結果を作成しながら、両方のブランチの意図と機能を保つことです