smooth-rebase について
smooth-rebaseは、ブランチの更新や競合したリベースの再開に使うスキルです。既定ブランチを検出して競合を慎重に処理し、コードから解決方法を判断できない場合はユーザーに確認します。
主な機能
- 01進行中のリベースの検出と再開
- 02リポジトリの既定ブランチの特定
- 03リモートブランチの取得とリベース
- 04コードの文脈に基づく競合解決
- 05判断が難しい場合のユーザー確認
活用シーン
- 01現在のブランチを既定ブランチにリベース
- 02中断したリベースの続行
- 03プルリクエストの競合解消
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bonkey/ skills --skill smooth-rebaseインストール後、Claude Code で/smooth-rebaseを入力して読み込まれたか確認します。
詳細
スムーズなリベース
現在のブランチをリポジトリのデフォルトブランチにリベースし、発生した競合を解決します。意図を保ち、根拠のない判断を避け、コードや周辺のコンテキストから正しい解決方法が明らかでない場合は、必ずユーザーに確認してください。
動作
このスキルでは、次のシンプルなルールに従います。
- すでにリベース中の場合(競合中または一時停止中)は、新しい処理を開始しません。現在の競合を解決してリベースを続行し、完了するまで繰り返します。
- それ以外の場合は、リポジトリのデフォルトブランチ(
main、master、またはリモートが指定するブランチ)を検出してフェッチし、現在のブランチをそのブランチにリベースします。発生した競合を解決し、リベースが完了するまで続けます。
対象範囲
ブランチを最新の状態にしたい場合や、競合中のリベースを完了したい場合に、このスキルを使用します。たとえば、次のような依頼が該当します。
- 「このブランチをリベースして」
- 「main にリベースして」
- 「PR の競合を修正して」
- 「リベースを続行して競合を修正して」
ユーザーが別のベースブランチを明示した場合は、デフォルトブランチではなく、そのブランチにリベースします。
ルール
- 慎重に対応してください。根拠なく片方を選ばないでください。
- 競合の解決は、テキスト編集ではなく意味上のマージ作業として扱ってください。
- 両方の変更が互いに補完し合う場合は、両方を残すことを優先してください。
- 適切な解決方法が、プロダクトの意図、アーキテクチャの方針、所有権、命名規則や構成規則に左右される場合は、必ずユーザーに確認してください。
- ベースブランチで構成が変更され、機能ブランチで内容が変更されている場合、どちらを優先するか決めつけないでください。両方を調べ、答えが明らかでなければ確認してください。
- 古い、または不適切であると説明できないコードを削除しないでください。
- 最終的なファイルが一貫性を保ち、コンパイル可能で、周囲のコードのスタイルに沿うようにしてください。
- デフォルトブランチをそれ自身にリベースしないでください。現在のブランチがデフォルトブランチの場合は、停止してユーザーに伝えてください。
- リベース開始前に未コミットの変更が作業ツリーにある場合は、停止して対処方法をユーザーに確認してください。
git stashは使用しないでください。 - リベースによって履歴が書き換えられるため、その後プッシュが必要な場合は、通常の
--forceではなくgit push --force-with-leaseを使用してください。
ユーザーへの確認が必要な場合
次のような不確実性を伴う競合がある場合は、停止してユーザーに確認してください。
- ベースブランチで新しい構成、抽象化、またはファイル配置が導入されている
- 機能ブランチに、変更後の構成にうまく適合しなくなったビジネスロジックが含まれている
- 両方のブランチで同じロジックが異なる形に変更されている
- 一方でコードの名前変更や移動が行われ、もう一方で動作が編集されている
- どちらか一方が、より新しいプロダクト上の決定や API 契約を反映している可能性がある
- チームの方針によって対応が異なる可能性のある、生成ファイル、ロックファイル、マイグレーション、大規模なリファクタリングが競合に関係している
確認時の質問例:
- 「
mainの構成を維持して、このブランチの動作をそこに移植しますか?」 - 「一方で名前の変更、もう一方でロジックの変更が行われているようです。両方を組み合わせますか?」
- 「ベースブランチではこのコードが削除されていますが、このブランチでは拡張されています。削除は意図的なものですか?」
ワークフロー
1. 現在の状態を確認する
リベース(または別の競合中の操作)がすでに進行しているか確認します。
git status
ls .git/rebase-merge .git/rebase-apply 2>/dev/null
- リベース中 → 手順 3 に進み、リベースを再開します。
- マージまたは cherry-pick 中 → 以下に説明する同じ注意を払って競合を解決し、
git rebase --continueではなく、操作に対応する続行コマンド(git merge --continueまたはgit cherry-pick --continue)で完了します。 - クリーンな状態 → 手順 2 に進みます。
作業ツリーに変更があり、リベース中でない場合は、停止して進め方をユーザーに確認してください。stash は使用しないでください。
2. デフォルトブランチを検出してリベースを開始する
名前を決めつけず、Git からデフォルトブランチを検出します。
git symbolic-ref --short refs/remotes/origin/HEAD
この参照先が設定されていない場合は、まず解決します。
git remote set-head origin --auto
または、代替手段としてリモートから直接確認します。
git ls-remote --symref origin HEAD
その後、フェッチしてリベースします。
git fetch origin
git rebase origin/<default-branch>
競合なくリベースが完了した場合は、成功を報告して終了します。それ以上の作業はありません。
3. 競合を一度に一つずつ解決する
リベース中に競合で停止するたびに、競合しているファイルを特定します。
git status --short
git diff --name-only --diff-filter=U
競合している各ファイルについて、次のことを行います。
- 作業ツリー内の競合マーカーを確認する
- ファイルの周辺を調べ、構成と意図を把握する
- 必要に応じて、base、ours、theirs の各バージョンを調べる
- 競合しているシンボルを参照する近くのコードを確認する
git show :1:path/to/file
git show :2:path/to/file
git show :3:path/to/file
リベース中は、ステージ 2(ours)がリベース先のベースブランチ、つまり現在のブランチがリベースされる先のブランチであり、ステージ 3(theirs)が再適用中の現在のブランチのコミットであることを覚えておいてください。これは、マージ時の直感とは逆です。このスキルがリベースを開始した場合、ベースはデフォルトブランチです。すでに進行中のリベースを再開する場合は、デフォルトブランチだと決めつけず、git status の出力(「rebasing onto ...」)または .git/rebase-merge/onto からベースを特定してください。
4. 各競合を分類する
各ファイルまたはハンクについて、競合の種類を判断します。
- 構造と内容 — 一方がコードを再構成し、もう一方がロジックを変更した
- 並行したロジックの編集 — 両方が重複する行で動作を変更した
- 名前変更/移動と編集 — 一方がコードを移動し、もう一方が変更した
- 削除と変更 — 一方がコードを削除し、もう一方が更新した
- 機械的な競合 — インポート、書式設定、生成されたセクション、ロックファイル
機械的な競合は、多くの場合そのまま解決できます。 意味上の競合では、より確かな根拠が必要であり、ユーザーへの質問が必要になることもよくあります。
5. 明確なものだけを解決する
次のように、正しい結果が文脈から強く裏付けられている場合に限り、質問せずに解決します。
- インポートの重複や、単純な順序の競合
- 両方の変更を安全に組み合わせられる
- 一方が明らかに古い、または機械的に置き換えられている
- 移動/名前変更が明白で、動作の変更をきれいに移植できる
解決する際は、次の点に従います。
- 必要な動作をすべて維持する
- 競合している変更が明らかに置き換えている場合を除き、現在のアーキテクチャを維持する
- 競合マーカーを一行ずつつなぎ合わせるのではなく、マージ後の結果をきれいに書き直す
不明瞭なハンクが一つでもある場合は、作業を中断して次の内容を提示します。
- 競合しているファイル
- 両方の変更内容の簡潔な説明
- それぞれの変更が何を意図していると考えるか
- ユーザーに判断してほしい具体的な事項
質問は具体的で、判断しやすいものにします。
6. リベースが完了するまで続ける
現在のラウンドですべての競合を解決したら、次のことを行います。
- 競合マーカーが残っていないことを確認する
git addで解決済みファイルをステージする- 続行する
git rebase --continue
リベースが完了するまで、競合が発生するラウンドごとに手順 3~6 を繰り返します。ユーザーから指示がない限り、リベースを中止しないでください。
7. 完了する
リベースが完了したら、次のことを行います。
- ブランチの履歴が妥当であることを確認する(
git log --oneline <base>..HEAD。ここで<base>はリベース先のブランチです) - ユーザーからリモートブランチの更新を依頼された場合は、リースの安全性を確保してプッシュする
git push --force-with-lease
ユーザーから依頼された場合、またはタスク上明らかに必要な場合(PR の競合を解消するなど)を除き、プッシュしないでください。
解決のヒューリスティック
次の場合は、両方の変更を組み合わせることを優先します。
- 一方が API の形を変更し、もう一方が同じ概念を使って動作を変更している
- 両方の変更に含まれるインポート、依存関係、登録が必要である
- ベースブランチから導入された新しいラッパーや抽象化に、ブランチ固有のロジックをきれいに組み込める
次の場合は、ベースブランチの構造を優先します。
- ベースブランチで導入された広範なリファクタリングが、近くのファイルにも適用されている
- 機能ブランチのコードを新しい構造に曖昧さなく移植できる
- 古い構造を維持すると、廃止されたパターンが再び持ち込まれる
次の場合は、機能ブランチの内容を優先します。
- レビュー対象の機能や修正が含まれている
- ベース側の変更が主に機械的なもので、機能ブランチの内容に組み込める
- その変更を取り除くと、ブランチが意図した動作が気付かれないまま失われる
これらはヒューリスティックであり、自動的に適用する規則ではありません。迷った場合は質問してください。
出力形式
競合しているファイルごとに、次の項目をまとめます。
fileconflict typedecisionreasonneeds user input(yesまたはno)
ユーザーに質問する場合は、必要な判断事項を短い番号付きリストにして末尾に記載します。
トラブルシューティング
- 競合マーカーが残っている場合は、続行する前に
<<<<<<<、=======、>>>>>>>を検索します。 - リベース中にステージの意味が分かりにくい場合は、思い込みに頼らず、ファイルの内容とコミット履歴を確認します。
refs/remotes/origin/HEADがない場合は、デフォルトブランチを検出する前にgit remote set-head origin --autoを実行します。- 競合を解決した結果コミットが空になった場合は、その変更がすでにベースブランチに存在するため、そのコミットに対して
git rebase --skipを使用します。 - ロックファイルまたは生成ファイルで競合が発生した場合は、明確な標準ワークフローがプロジェクトにあり、結果が決定論的である場合に限り、再生成を優先します。
- 一方の側でファイルが削除され、もう一方の側で変更されている場合は、削除が意図的だったかを推測せず、周辺のコードを確認し、不明な場合は質問します。
- リベース全体を取り消す必要がある場合、
git rebase --abortを実行するとブランチの元の状態に戻ります。ただし、ユーザーから依頼された場合に限って実行します。