mcpField
N
non-interactive-git-rebase

non-interactive-git-rebase

github.com/facebook開発11.4k48 回インストール今日更新
リポジトリ

non-interactive-git-rebase について

GIT_SEQUENCE_EDITOR を使って Git の対話型 rebase をスクリプト化する開発者向けガイドです。コミットの並べ替え、削除、統合、分割、メッセージ変更を扱い、事前バックアップと結果検証を求めます。

主な機能

  1. 01準備済み todo ファイルによる対話型 rebase
  2. 02コミットの並べ替え、削除、統合、分割
  3. 03edit と amend による非対話的なメッセージ変更
  4. 04--exec による一括編集
  5. 05バックアップブランチと結果検証の必須化

活用シーン

  1. 01コミットの並べ替えや削除をスクリプト化
  2. 02作者やメッセージを一括変更
  3. 031つのコミットを複数に分割
  4. 04履歴変更の前後でリポジトリ内容を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/facebook/hermes --skill non-interactive-git-rebase

インストール後、Claude Code で/non-interactive-git-rebaseを入力して読み込まれたか確認します。

詳細

非対話型 Git リベース

概要

通常、git rebase -i を実行すると、ToDo リストを編集するためのエディターが開きます。GIT_SEQUENCE_EDITOR に、あらかじめ用意したファイルで ToDo ファイルを置き換えるコマンドを設定すると、並べ替え、削除、スカッシュ、編集、修正など、あらゆる対話型リベース操作をスクリプトだけで実行できます。

重要:必ずバックアップブランチを作成する

リベースの前に、必ずバックアップブランチを作成してください:

git branch backup-before-rebase HEAD

リベースが成功し、検証に合格した後も、バックアップブランチを自動で削除しないでください。 ユーザーが自動クリーンアップを明示的に要求した場合を除き、削除する前に必ずユーザーに確認してください。バックアップを残しておくコストは低く、後から問題に気づく可能性もあります。

基本的な手法

GIT_SEQUENCE_EDITOR の仕組み

エディターには ToDo ファイルのパスが $1 として渡されます。このファイルを上書きするコマンドであれば、どれでも機能します:

# Replace the todo with our prepared version
GIT_SEQUENCE_EDITOR="cp /tmp/prepared-todo" git rebase -i <base>

Git はデフォルトの ToDo(すべて pick の行)を生成してから、cp /tmp/prepared-todo <todo-file> を呼び出し、ファイルを用意した内容に置き換えます。その後、Git は書き換えられた ToDo を実行します。

ToDo ファイルの準備

実際にはリベースせずにデフォルトの ToDo を取り出すには、ファイルにコピーした後、エディターを失敗させて Git を中断します:

GIT_SEQUENCE_EDITOR='cp $1 /tmp/default-todo && false' git rebase -i <base>

false はゼロ以外のステータスで終了するため、Git はリベースを中断します。ToDo ファイルは手元に残り、リベースは実行されていません。

または、git log から直接作成できます:

git rev-list --reverse <base>..HEAD | while read hash; do
  echo "pick $hash $(git log --oneline -1 $hash | cut -d' ' -f2-)"
done > /tmp/prepared-todo

その後、ファイルを編集します。行を並べ替えたり、pick を drop/squash/edit などに変更したりします。

一括修正に --exec を使う

--exec <cmd> フラグを指定すると、ToDo 内の各 pick の後に exec <cmd> の行が挿入されます。GIT_SEQUENCE_EDITOR=:(何もせず成功し、デフォルトの ToDo を変更しないコマンド)と組み合わせると、各コミットの再適用後にコマンドを実行できます。エディターは不要です。

範囲内のすべてのコミットの作成者メールアドレスを変更する:

GIT_SEQUENCE_EDITOR=: git rebase -i <base> --exec \
  'if [ "$(git log -1 --format=%ae)" != "[email protected]" ]; then git commit --amend --no-edit --author="Name <[email protected]>"; fi'

コミットメッセージのパターンを変更する:

GIT_SEQUENCE_EDITOR=: git rebase -i <base> --exec \
  'git commit --amend -m "$(git log -1 --format=%B | sed s/old/new/)"'

操作

コミットの並べ替え

ToDo ファイル内の行を並べ替えます。例 — コミット abc123 を先頭に移動する:

# Build todo with abc123 first, then everything else in original order
{
  echo "pick abc123 The commit to move first"
  git rev-list --reverse <base>..HEAD | while read hash; do
    full=$(git rev-parse abc123)
    [ "$hash" != "$full" ] && echo "pick $hash $(git log --oneline -1 $hash | cut -d' ' -f2-)"
  done
} > /tmp/prepared-todo

GIT_SEQUENCE_EDITOR="cp /tmp/prepared-todo" git rebase -i <base>
コミットの削除

ToDo から行を削除するか、pick を drop に変更します。

コミットメッセージの書き換え

ToDo では決して reword を使わないでください。 reword コマンドは新しいメッセージを入力する対話型エディターを開くため、GIT_SEQUENCE_EDITOR ではスクリプト化できません。代わりに edit を使い、-m を指定して修正してください:

# Step 1: Prepare todo with 'edit' on commits to reword

# Step 2: At each stop, amend the message non-interactively:
git commit --amend -m "New subject line

New body text."

# Step 3: Continue to the next stop
git rebase --continue
スカッシュ/フィックスアップ

pick を squash または fixup に変更します。スカッシュの場合は、スカッシュ後に開くコミットメッセージ用エディターにも GIT_SEQUENCE_EDITOR が必要です:

# Squash second commit into first, keep first message
# In the todo: pick aaa, fixup bbb
GIT_SEQUENCE_EDITOR="cp /tmp/prepared-todo" git rebase -i <base>
コミットの分割

ToDo で edit が必要です。リベースが停止したら、分割するコマンドを実行してから続行します。

# Step 1: Prepare todo with 'edit' on the target commit
sed 's/^pick TARGET_HASH/edit TARGET_HASH/' /tmp/default-todo > /tmp/prepared-todo
GIT_SEQUENCE_EDITOR="cp /tmp/prepared-todo" git rebase -i <base>

# Step 2: Rebase stops at the target commit. Split it:
git reset HEAD~1

# Step 3: Selectively stage and commit pieces.
# If the commit has N hunks in a file and you want hunk 3:
printf 'n\nn\ny\n' | git add -p path/to/file
git commit -m "First piece: just hunk 3"

# Stage the rest
git add .
git commit -m "Second piece: remaining changes"

# Step 4: Continue the rebase
git rebase --continue

git add -p によるハンク選択の自動化: printf 内の各 y/n は、順番に各ハンクに対応します。ハンクが十分に離れている(ファイル内の異なる領域にある)場合は、安定して動作します。ハンクが隣接していると、Git がそれらを 1 つのハンクとして表示する場合があり、その場合はまず s(分割)を入力する必要があります:

# Split first hunk, then accept/reject sub-hunks
printf 's\ny\nn\ny\n' | git add -p path/to/file

別の方法 — パッチを使った分割(複雑なケースでは、こちらのほうが信頼性が高いです):

git reset HEAD~1
git diff path/to/file > /tmp/full.patch
git checkout -- path/to/file

# Apply only the lines you want for commit 1
# (manually prepare /tmp/part1.patch from full.patch)
git apply /tmp/part1.patch
git add path/to/file
git commit -m "First piece"

git apply /tmp/full.patch  # won't re-apply already-applied hunks
# Or: git checkout <original-hash> -- path/to/file
git add .
git commit -m "Second piece"

検証

リベース後は、(意図的にコミットを削除した場合を除き)ツリーの内容がリベース前と同一であることを検証します:

git diff backup-before-rebase HEAD --stat
# Empty output = content preserved correctly

よくある間違い

間違い修正方法
ToDo で reword を使うreword は対話型エディターを開きます。代わりに edit と git commit --amend -m を使います
以前のリベース後に ToDo ファイル内のハッシュが間違っているgit log から再生成します。ハッシュはリベースのたびに変わります
git add -p で予期しないハンクが選択されるコンテキストが重なるとハンクが結合する場合があります。代わりにパッチを使って分割します
バックアップブランチを早まって削除する削除する前に必ずユーザーに確認してください。後から問題に気づく可能性があります

クイックリファレンス

操作コマンド
todo を抽出GIT_SEQUENCE_EDITOR='cp $1 /tmp/default-todo && false' git rebase -i <base>
並べ替え/削除GIT_SEQUENCE_EDITOR="cp /tmp/prepared-todo" git rebase -i <base>
メッセージを書き換え上記と同様に、todo で edit を指定し、git commit --amend -m "..." と --continue を実行します
スカッシュ(メッセージを保持)上記と同様に、todo で fixup を指定します
スカッシュ(メッセージを編集)上記と同様に、squash を指定してからメッセージエディターで編集します
分割上記と同様に、edit を指定してから手動で分割し、--continue を実行します
一括 amendGIT_SEQUENCE_EDITOR=: git rebase -i <base> --exec '<cmd>'

コメント