git-rebase
git rebase を自然言語指示から非対話で実行する。commit 整理(squash / fixup / reword / drop / split / 順序入替)、upstream 取り込み、branch 載せ替え(`--onto`)、conflict 解消、stacked rebase(`--update-refs`)を扱う。「rebase して」「squash」「fixup」「reword」「split」「main 取り込んで」「載せ替えて」「base 付け替え」「conflict 解消」などのリクエストで使用。
Works with
---
name: git-rebase
description: git rebase を自然言語指示から非対話で実行する。commit 整理(squash / fixup / reword / drop / split / 順序入替)、upstream 取り込み、branch 載せ替え(`--onto`)、conflict 解消、stacked rebase(`--update-refs`)を扱う。「rebase して」「squash」「fixup」「reword」「split」「main 取り込んで」「載せ替えて」「base 付け替え」「conflict 解消」などのリクエストで使用。
license: MIT
---
# git-rebase
git rebase を自然言語の指示から非対話で実行する skill。commit 整理・fixup workflow・upstream 取込・conflict 解消支援を扱う。`rebase -i` の todo / commit message を Claude が事前生成して `GIT_SEQUENCE_EDITOR` / `GIT_EDITOR` を差し替える方式で完遂する。
対象は**ローカル branch の rebase**。push・コード修正・レビュー対応との chain は本 skill の責務外。
以下の特殊ケースでは、該当する references を読んでから手順を進める:
- **stacked branch 構成(ユーザー指示または会話文脈で stacked と分かっている時のみ)**:`references/stacked-update-refs.md`(`--update-refs` の付与・各 ref の push 判定・サマリー追記)
## 共通の動作フロー
1. **モード判定**:自然言語指示を解釈してモードを決定する(commit 整理 / fixup / upstream / reword / split / conflict 解消)。
2. **事前チェック**:以下を順に実施する。
1. **進行中 rebase の検知**:`.git/rebase-merge` または `.git/rebase-apply` が存在すれば前回の rebase が中断したまま。ユーザーに `--continue / --abort / --skip` のどれにするか確認する。
2. **detached HEAD の検知**:`git branch --show-current` で branch 名取得。出力が空なら detached HEAD と判定し、警告して続行確認。続行する場合は最終出力に `git branch <name>` のコマンドを添える。
3. **dirty 判定**:`git status --porcelain` の出力で判定する。**ただしモード別に許容範囲が違う**:
- commit 整理 / upstream 取込 / branch 載せ替え / reword / split(過去 commit 対象):dirty なら commit/stash を促して中止
- fixup workflow / amend 系 / 最新 commit の split:差分そのものが入力なので dirty を許容(rebase 開始前に staging 状況を確認)
4. **rebase 前 HEAD sha の保持**:`git rev-parse HEAD` で現在 sha を取得し、skill 内で保持する。ユーザーが「戻して」等を要求した時に `git reset --hard <sha>` で戻すために使う(ユーザーには表示しない)。
3. **対象 sha の特定**:`git log` を見て対象 sha を確定する。曖昧なら「候補 sha が一意に決まらない時」へ。
4. **base の解決**:rebase 範囲の base を決める(モード別。単独 revision として渡す。`<sha>^` が root で死ぬ場合は `--root` に切替、後述)。
5. **merge commit の検知**(base 決定後):`git log --merges <base>..HEAD` で rebase 範囲に merge commit があるかチェック。あれば次の文言(例)でユーザーに確認する:
> merge commit があります。drop されて linear になりますが OK ですか / `--rebase-merges` で構造保持しますか?
`--rebase-merges` を選んだ場合は **git が生成した todo(`label / reset / merge` 行を含む)をそのまま使う**(Claude は編集しない)。
6. **stacked 構成の判定**:以下のいずれかに該当する場合は stacked 構成として扱い、`references/stacked-update-refs.md` を読んで `--update-refs` 付与以降の手順に従う:
- **ユーザーが明示指示した**:「stacked rebase」「下位 branch も追従させて」「`--update-refs` で」等
- **直前の会話文脈で stacked branch 構成が前提と分かっている**:`feature-base → feature-A → feature-B` のような積み上げ運用が会話で言及されている等
いずれにも該当しなければ通常 rebase で進む。
7. **push 済み判定**(後述「push 済みブランチの扱い」)。
8. **todo 案の提示**:rebase で組む todo(または等価な操作プラン)を 1 行ずつユーザーに提示する。
9. **非対話で rebase を実行**:走った git コマンドは隠さずユーザーに見える形で実行する。
10. **結果サマリーの出力**(後述「最終サマリーの形式」)。
Y/N 確認を取るのは以下の時のみ:
- push 済みブランチへの rebase
- 候補 sha が一意に決まらない時
- merge commit が rebase 範囲に含まれる時
- conflict 発生時
- その他 destructive な分岐があると skill が判断した時
todo 案の表示は確認なしで提示してそのまま実行する。
## 単純ケースの最適化(rebase -i を使わない)
「最新 commit の HEAD 操作」で済むケースは `rebase -i` を回さずショートカットを使う。常に `rebase -i` を通すよりも速く・安全。
| ケース | コマンド |
|---|---|
| 最新 commit の reword | `git commit --amend -m "<新メッセージ>"` |
| 最新 commit に修正を追記(message 維持) | `git add ... && git commit --amend --no-edit` |
| 最新 commit の drop | `git reset --soft HEAD^`(内容を残す)or `git reset --hard HEAD^`(破棄) |
| 最新 commit を split | `git reset HEAD^` で unstaged に戻し、分割して再 commit |
これらでも事前チェック(進行中 rebase / detached HEAD / rebase 前 HEAD sha)は実施する。amend は HEAD の sha を変えるため、push 済み判定も別途実施。
## 非対話化の基本パターン
git は `GIT_SEQUENCE_EDITOR` / `GIT_EDITOR` の値を `/bin/sh -c "<EDITOR>" <EDITOR> <todofile>` の形でシェル経由起動し、編集対象ファイルパスを末尾引数として渡す。これを利用して事前に書いた一時ファイルで上書きする。
### 一時ファイルの作り方
todo / message 用の一時ファイルを作って対応する。ユーザーの一時ファイル配置方針があればそれに従う。
以降の例では作成済み一時ファイルのパスを `$TODO_FILE`(todo 用) / `$MSG_FILE`(commit message 用)というプレースホルダーで表す。
```bash
cat > "$TODO_FILE" <<'EOF'
pick abc1234 first commit subject
squash def5678 typo fix
squash ghi9012 minor refactor
EOF
GIT_SEQUENCE_EDITOR='sh -c '\''cp "'$TODO_FILE'" "$1"'\'' --' \
git rebase -i <base>
```
- 動詞は `pick / reword / edit / squash / fixup / drop` のみ。**タイポを含む todo は git に拒否されて即 abort になる**ので、todo 生成時は厳密に書く。
- 動作原理:git が編集対象パスを末尾引数として追加し、`cp <一時ファイル> <git の todo パス>` 相当が走る。
### todo 差し替えと commit message 差し替えを併用する(squash で新メッセージを与える例)
```bash
# $TODO_FILE と $MSG_FILE に内容を書いた前提
GIT_SEQUENCE_EDITOR='sh -c '\''cp "'$TODO_FILE'" "$1"'\'' --' \
GIT_EDITOR='sh -c '\''cp "'$MSG_FILE'" "$1"'\'' --' \
git rebase -i <base>
```
**squash 時の COMMIT_EDITMSG**:git は「複数 commit の連結 message」を事前に書く。`cp` で上書きすると **完全に置き換わる**。これを意識して使い分ける:
- 「メッセージは最初のを使って」 → `git log -1 --format=%B <first_sha>` で取得して `MSG_FILE` に書く
- 「git に任せて連結 message のままで」 → `GIT_EDITOR` 自体を渡さないか、`GIT_EDITOR=true` を使う
- 「両方の意図を残してまとめて」 → 各 commit の subject を残し、本文は重複を排して結合してから書く(命令形・体言止めなど元 message のスタイルに合わせる)
### message のみ差し替える(reword 単独で squash しない場合)
todo 側は触らず、message だけ差し替えればよい。
```bash
GIT_SEQUENCE_EDITOR=true \
GIT_EDITOR='sh -c '\''cp "'$MSG_FILE'" "$1"'\'' --' \
git rebase -i <base>
```
ただし todo に対象 commit を `reword` として書きたい場合は todo 側も差し替える必要がある(その場合は前項の併用パターン)。
### autosquash の todo をそのまま採用
```bash
GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash <base>
```
`true` は「何もせず exit 0」なので、git が autosquash で組んだ todo がそのまま使われる。
**注意**:base 直後の commit 以降は対象外でも rebase の対象として再適用される(empty commit drop / hook の発火など副作用が起きうる)。`<target_sha>^` を base にする方針で巻き込み範囲を最小化する。
### `<target_sha>^` が root commit で死ぬ問題
```bash
if git rev-parse --verify "${TARGET_SHA}^" >/dev/null 2>&1; then
BASE_ARG="${TARGET_SHA}^"
else
BASE_ARG="--root"
fi
```
`--root` を base にすると最初の commit から rebase できる。**base が必要な全モード(commit 整理 / fixup / reword / split)でこの判定を必ず挟む**。
### `git rebase --continue` 時の GIT_EDITOR 再付与(最重要落とし穴)
rebase は途中で停止(conflict / `edit` 動詞)すると環境変数が切れる。`--continue` を呼ぶ時は **再度 `GIT_EDITOR` を渡す**こと。
```bash
# 元 message を維持して続行
GIT_EDITOR=true git rebase --continue
# 新 message に書き換えて続行
GIT_EDITOR='sh -c '\''cp "'$MSG_FILE'" "$1"'\'' --' git rebase --continue
```
これを忘れると conflict 解消後にエディタが開いて skill が止まる。
## モード別の手順
### 1. commit 整理(squash / fixup / drop / 順序入替)
- 対象範囲を特定し、base を **単独 revision** として決める(範囲表記 `HEAD~3..HEAD` ではなく `HEAD~3` のような形)。`<最古対象 sha>^` を `BASE_ARG` ロジックに通す。
- todo 案をユーザーに 1 行ずつ提示し、「todo 差し替え」で実行する。
- squash で message 統合が必要なら「todo + message 差し替え併用」を使う。
### 2. fixup workflow
1. 対象 commit sha を特定する(`BASE_ARG` ロジックで `<target_sha>^` か `--root` を決める)。
2. **事前予告**:todo 自体は autosquash が git 内部で動的に組むので事前提示は不要。代わりに「`<target_sha>` (`<subject>`) に `<対象 path 一覧>` の差分を fixup します」を 1 行でユーザーに見せてから次に進む(共通フロー ステップ 7「todo 案の提示」のモード固有版)。
3. fixup 対象の差分を確認し、必要な path を `git add <paths>` で stage する(未 stage のままだと `git commit --fixup` が「nothing added」で失敗するため)。部分 staging を壊さないよう、対象 path をユーザーに確認してから add する。
4. `git commit --fixup=<target_sha>` で fixup commit を作る。
5. **commit 失敗時の挙動**:commit 作成が失敗した場合は **rebase に進まずその時点で停止**し、エラー出力をそのままユーザーに見せる。原因切り分けと対応は「作業の注意点 / commit 失敗の原因切り分け」を参照。
6. 成功したら `GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash <BASE_ARG>` で実行する。
### 3. upstream 取り込み
- `git symbolic-ref --short refs/remotes/origin/HEAD` で base を解決する(`--short` 付きで `origin/main` のような短形を直接得る)。
- 失敗時 fallback:(a) ユーザーに base 名を確認 (b) `git remote set-head origin --auto` を提案して再試行。
- ユーザーが「develop に rebase して」「master 取り込んで」と明示した場合はそれを優先する。
- `git fetch origin` → `git rebase <resolved>`(`<resolved>` は既に `origin/main` のような短形なので、頭に `origin/` を重ねない)。
- conflict が起きたら「conflict 解消」へ。
### 4. branch 載せ替え(--onto)
- 派生元 branch から別 branch に付け替え/間違った base からの修正に使う。`git rebase --onto <newbase> <upstream>` で実行する(**`rebase -i` 不要**。todo / `GIT_SEQUENCE_EDITOR` 差し替えは行わない)。
- `<newbase>` と `<upstream>` の両方を特定する。「A から B に載せ替え」→ `<upstream>=A`, `<newbase>=B`。`<upstream>` が曖昧なら自動推測せず候補提示で確認する(`git merge-base HEAD <newbase>` の自動採用はしない:stacked で `<upstream>` 手前の commit を巻き込む危険があるため)。
- 実行前に `git log --reverse --oneline <upstream>..HEAD` で載せ替え対象 commit を提示し、`<newbase>` と実行コマンドと併せて Y/N 確認する。範囲が空なら no-op で停止。
### 5. reword
- ユーザーが新メッセージを明示指定 → 指定通り採用、確認なし。
- 指定がない(「いい感じに直して」「内容に合わせて」など)→ `git show <sha>` の diff から変更目的を 1 行で要約し、リポジトリの直近 commit message のスタイル(命令形 / 体言止め等)に揃えた案を提案、ユーザー承認後に適用する。
- 最新 commit のみが対象なら「単純ケースの最適化」の `git commit --amend` を使う。
- それ以外は todo で対象 commit を `reword` にし、「todo + message 差し替え併用」で実行する。
### 6. split
最新 commit のみが対象なら「単純ケースの最適化」のショートカット(`git reset HEAD^`)を使う。それ以外は以下の手順を踏む:
1. 対象 commit を `edit` に書いた todo を「todo 差し替え」で適用 → rebase が `edit` 行で停止する。
2. `git reset HEAD^` で対象 commit を unstaged に戻す。
3. **分割方針をユーザーに確認**する(ファイル単位 / hunk 単位 / ロジック vs テスト など)。指示が既にある場合は省略可。
4. 各分割について `git add <files>` → `git commit -m "<message>"` を繰り返す。message が必要で曖昧な場合は reword と同じ提案フローで案を作る。
5. `GIT_EDITOR=true git rebase --continue` で残りを再開する(GIT_EDITOR 再付与を忘れない)。
## conflict 解消
- **デフォルトは 1 ファイルずつ**:「両側の意図要約 → 解決案 diff → 承認 → 適用 → 次のファイル」を繰り返す。
- ユーザーが「まとめて」「一括で」「全部いい感じに」等を指示した時のみ、全 conflict の解決案 diff を一気に提示し 1 度の承認で全適用に切り替える。
- 解消ごとに `git add <file>` → 全部解消したら `GIT_EDITOR=true git rebase --continue`。
- ユーザーが abort を選んだら `git rebase --abort` を実行し、abort した旨を伝える。
## push 済みブランチの扱い
- `git rev-parse @{u}` で upstream sha を取得する(upstream が未設定なら push 済みではないとみなす)。
- **書き換え対象 sha のうち最古のもの**が `@{u}` の祖先かを `git merge-base --is-ancestor <oldest_rewritten_sha> @{u}` でチェックする。0 を返したら祖先(push 済みを書き換える)、1 を返したら祖先ではない(push 済みではない)。
- 「最古の書き換え対象 sha」はモード別に異なる:
- commit 整理 / reword:`<base>..HEAD` の最古 commit
- fixup workflow:`<target_sha>`
- upstream 取込:通常 `<base>..HEAD` 全体(push 済み部分は普通含まれないが、再 push のケースでは含まれうる)
- branch 載せ替え:`<upstream>..HEAD` の最古 commit
- 含まれる → 「push 済みなので force push が必要です。続行しますか?」を Y/N 確認する。
- 続行されたら rebase 実行、最終出力に `git push --force-with-lease` を添えて終了する。
- **skill 自身は push しない**。
- stacked 構成(共通フロー ステップ 6 で検知)の場合、各下位 ref ごとの push 判定が必要。`references/stacked-update-refs.md` の「push 済み判定(stacked 拡張)」を参照する。
## 候補 sha が一意に決まらない時
- 「auth まわり」「最近の」など曖昧な指示で候補が複数ある時、候補一覧(sha + subject)を提示してユーザーに選択を求める。
- 暗黙の決定(最も新しい候補を選ぶ等)はしない。
## 復旧(rebase 失敗・中断時)
ユーザーが「戻して」等を要求した時の対応方針:
- rebase 進行中なら `git rebase --abort`。
- 着手前の状態に戻したい場合は、事前チェックで保持した「rebase 前 HEAD sha」を使って `git reset --hard <sha>`。
- 保持した sha が無い/さらに前に戻りたい場合は `git reflog` で過去の HEAD を辿る。
## 作業の注意点
- **destructive 操作はユーザー確認**:rebase は破壊的操作なので、Y/N 確認を取るタイミングは「共通の動作フロー」末尾のリストに集約。失敗時の `git rebase --abort` も自動実行せずユーザーに確認する(自動 abort で意図せず作業を破棄しない)。
- **commit 失敗の原因切り分け**:rebase 中・fixup workflow 中・amend 中の commit 作成失敗には複数の原因がある。skill は **どの原因でも勝手に回避せず、エラー出力と原因の見立てをユーザーに伝えて指示を仰ぐ**。
- **pre-commit / commit-msg hook 失敗**:hook 起因。`--no-verify` を skill が勝手に付けない。「hook を直してリトライ」「`--no-verify` で進めて」のいずれかをユーザーが選ぶまで skill は何もしない。
- **index / working tree 不整合**:未解決 conflict や index lock 等。状況を提示して、`git status` の確認をユーザーに促す。
- rebase 前 HEAD sha は事前チェックで保持済みなので、いずれの場合も追加の `git reset` は不要(rebase 中なら `git rebase --abort` で着手前に戻せる)。
- **rebase 中の hook 挙動の注意**:git バージョン・バックエンド(apply / merge)によって hook の発火タイミングが違う。途中で hook が発火して止まった場合の continue/abort はユーザー判断。
- **empty commit**:`rebase -i` のデフォルトでは保持される(`pick` のまま)。drop したい場合はユーザーが明示する。
- **実行コマンドの可視化**:走った git コマンドは隠さずユーザーに見える形で実行する。
## 最終サマリーの形式
「結果」セクションは 2 形式を使い分ける。境界は **変わるのが 1 commit に閉じるか否か**:
- **形式 A(範囲全体型)**:commit 整理(squash / 順序入替 / drop)、upstream 取込、split、stacked など、複数 commit が変わるケース
- **形式 B(1 commit ピンポイント型)**:fixup workflow、reword(1 commit)、単純ケースの amend 系(最新 commit の amend / drop / reword)など、変わるのが 1 commit に閉じるケース
### 形式 A(範囲全体型)
```markdown
## git-rebase 実行サマリー
### 結果(rebase 後の commit log)
<git log --oneline <base>..HEAD の出力をそのまま貼る>
### 変更内容
- <モードに応じた要約を 1〜数行で>
- 例: 「def5678 と xyz9876 を fixup として abc1234 に統合」
- 例: 「順序を A → B に入れ替え」
- 例: 「origin/main を取り込み(N commit が再適用)」
### 次のアクション(あれば)
- push 済みなので force push が必要: `git push --force-with-lease`
```
### 形式 B(1 commit ピンポイント型)
```markdown
## git-rebase 実行サマリー
### 結果(変わった commit の before / after)
<旧 sha> <旧 subject>
→ <新 sha> <新 subject>
### 変更内容
- <何をしたかの 1 行要約>
### 次のアクション(あれば)
- push 済みなので force push が必要: `git push --force-with-lease`
```
失敗・中断時は形式 A をベースに使い、該当しないセクションは省略する。
stacked 構成(共通フロー ステップ 6 で検知)の場合は形式 A を使い、「更新された下位 branch」「下位 ref ごとの force push」を追記する。詳細は `references/stacked-update-refs.md` の「最終サマリーへの追加項目」を参照。More Git Workflows skills
git-commit
github/awesome-copilot
Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions "/commit". Supports: (1) Auto-detecting type and scope from changes, (2) Generating conventional commit messages from diff, (3) Interactive commit with optional type/scope/description overrides, (4) Intelligent file staging for logical grouping
git-workflow-and-versioning
addyosmani/agent-skills
Structures git workflow practices. Use when making any code change. Use when committing, branching, resolving conflicts, or when you need to organize work across multiple parallel streams. Use when cutting a release, choosing a semantic version bump, tagging, or writing a changelog.
resolve-merge-conflicts
warpdotdev/common-skills
Resolve Git merge conflicts by extracting only unresolved paths, conflict hunks, and compact diffs instead of loading whole files into context. Use when a merge, rebase, cherry-pick, or stash pop stops on conflicts, when `git status` shows unmerged paths, or when files contain conflict markers.

