Git

AIの大きな差分をコミットへ分ける|git add -p・stage解除・rebaseの手順

AIの修正・整形・文書変更が混ざった差分を意図ごとに分割。git add -p、restore --staged -p、未共有commitのrebase分割と、各commitを別worktreeでテストする手順を紹介します。

この記事の目次
  1. ファイル名より、変更の目的と依存関係で分ける
  2. git add -pで、修正する塊だけをstageする
  3. 選びすぎたときは、作業内容を消さずにstageだけ外す
  4. 分けたcommitだけを、別のworktreeでテストする
  5. 未共有のcommitを分割するときは、editで止める

AIに不具合修正を頼んだら、同じファイルの整形とREADMEの書き換えまで入っていた。ファイル単位でcommitすると、修正理由が一つにまとまらないことがあります。

まだcommitしていない変更なら、git add -pで変更の塊を選び、関連するテストと一緒にcommitします。すでに一つのcommitへ入れた場合は、自分だけが使う未共有の履歴に限り、rebaseのeditで止めて分割できます。

このページでは、変更内容を残したままstageを選び直す手順と、分割したcommit単体を確認する方法を扱います。Git 2.55.0・Node.js 24.13.0の独立した検証リポジトリで操作を確認しました。コマンド中のパスとテストは例なので、自分の対象へ置き換えてください。

ファイル名より、変更の目的と依存関係で分ける

最初に、AIの差分へ入ったものを見ます。もともと自分やほかの人が編集していた変更があるなら、それも含めた全体をAIの成果として扱いません。

git status --short
git diff --stat
git diff -- src/pricing.mjs
git diff --staged

今回の例は、数量が負の場合を拒否する修正、同じファイル内の引用符の整形、READMEへのテスト実行方法の追記です。次のように目的を分けます。

commit 含める変更 一緒に確かめること
負の数量を拒否する 条件判定と、その挙動を確かめるテスト 通常の計算と負の数量の両方
表記を整える 同じファイルの引用符の変更 前のcommitと挙動が同じか
テスト手順を記す READMEの追記 記載したコマンドが実行できるか

整形・移動・挙動変更は分ける候補になりますが、機械的に3分類へ押し込む必要はありません。関数を移すならimport先の変更も必要です。不具合修正に必須のテストや設定を別commitへ追い出すと、途中のcommitが壊れます。「一つずつ読める」ことと「一つずつ動く」ことを両方満たす単位を選びます。

スポンサーリンク

git add -pで、修正する塊だけをstageする

hunkは、diffに表示される変更の塊です。同じファイルでもhunkを選べるため、ファイル全体をaddする前に次を実行します。

git add -p -- src/pricing.mjs

たとえば次の差分では、負の数量を拒否する行だけを最初のcommitへ入れ、引用符の変更は後へ残したい状態です。

export function total(price, quantity) {
+  if (quantity < 0) throw new RangeError('negative quantity');
   return price * quantity;
 }
 
 export function currency() {
-  return 'JPY';
+  return "JPY";
 }

二つが一つのhunkで出たらsで分けます。修正の塊でy、引用符の塊でnを選びます。表示順や分割可能な箇所は実際の差分によるので、キーの並びを見ずに流し込まないでください。

キー 操作
y いまのhunkをstageする
n いまのhunkを今回はstageしない
s 分割できるhunkを、さらに小さく分ける
e エディターでstageするpatchを編集する
q 残りを選ばず終了する。すでに選んだ分まで全取消する操作ではない
? 操作の説明を表示する

sで分けられない場合は、eでpatchを編集できます。stageしない追加行はpatchから削り、stageしない削除行は先頭の「-」を空白へ戻します。置換を外すなら、削除側と追加側の両方を調整します。これは作業ファイルの編集ではなく、indexへ適用するpatchの編集です。

手動編集では、indexだけが作業ファイルとも元のcommitとも違う中間状態になり得ます。適用できない場合や内容を判断できない場合は、無理に確定せず選び直します。操作後は、次の二つを必ず読みます。

git diff --staged -- src/pricing.mjs
git diff -- src/pricing.mjs

上が次のcommitへ入る差分、下がまだ入らない差分です。さらに、実装と対応するテストをstageします。テストファイルにも別目的の変更が混じっているなら、そちらも-pで選びます。

git add -- tests/pricing.test.mjs
git diff --staged
git diff --staged --check
git commit -m "Reject negative quantity"

この手順では、commitに-aやファイル名を追加しません。選んだindexの内容をcommitしたい場面で別のstage方法を混ぜると、残すつもりだった変更まで含める原因になります。未追跡の新規ファイルを部分stageしたい場合は、git add -N -- path/to/new-fileで存在をindexへ知らせてから、git add -p -- path/to/new-fileを使えます。

選びすぎたときは、作業内容を消さずにstageだけ外す

整形のhunkまでyにしてしまった場合、commit前ならstageを選び直せます。部分的に外すコマンドは次です。

git restore --staged -p -- src/pricing.mjs
git diff --staged -- src/pricing.mjs
git diff -- src/pricing.mjs

今回は外したいhunkを選びます。通常のHEADがあるリポジトリでは、–stagedによってindexをHEAD側へ戻し、作業ファイルの編集は残します。そのファイルのstageを全部外すなら、git restore --staged -- src/pricing.mjsです。

–stagedを付けないgit restore -pは、作業ファイルの変更を戻す操作です。分割のためのstage解除と混同しないでください。最初からstage済みだった他の人の変更がある場合も、ファイル全体をまとめて外さず、対象を確認して部分的に扱います。

分けたcommitだけを、別のworktreeでテストする

手元の作業ファイルには、まだcommitしていない整形や追加処理が残っています。その状態でテストが通っても、直前に作ったcommit単体が通るとは限りません。必要な関数をstageし忘れた場合でも、作業ファイルには関数があるため見逃せます。

一つ目をcommitした後、未使用のパスへそのcommitだけのworktreeを作ります。下の例はNode標準のテストを使うため、追加の依存インストールは不要です。

git worktree add --detach ../review-fix HEAD
node --test ../review-fix/tests/pricing.test.mjs
git -C ../review-fix status --short
git worktree remove ../review-fix

自分のプロジェクトでは、そのworktreeに入って規定の依存準備・テスト・ビルドを行います。元の作業フォルダーのnode_modulesへ無理に依存させず、検証条件をそろえてください。worktreeの削除を拒否されたら、残った変更を確認し、forceで捨てないようにします。

検証で失敗したら、必要な変更を最初のcommitへ含め直すなど、分け方を修正します。通過したら、残った整形、READMEを順にcommitし、それぞれ確認します。

git add -- src/pricing.mjs
git diff --staged
git commit -m "Format currency literal"

# このcommit単体を確認してから、次へ進む
git add -- README.md
git diff --staged
git commit -m "Document test command"

検証例では、修正・整形・文書の各commitを別worktreeでテストし、すべて通ることを確認しました。実案件でgit addをファイル全体に使うのは、その時点の残りが当該目的だけだと確認できた場合です。

未共有のcommitを分割するときは、editで止める

次は、すでに「修正+整形+文書」を一つのcommitへまとめ、その後に別のcommitも作ったケースです。自分だけの未共有ブランチで、マージを含まない直線の履歴を前提にします。共有済みの履歴や、誰の変更か分からない作業へこの手順をそのまま使いません。

最初に未commit変更と未追跡ファイルがないことを確認します。ある場合は、先に自分の作業を保存・整理します。backupブランチが保存するのはcommit済みの履歴であり、未commitの編集ではありません。

git status --short
git log --oneline -n 5
git branch backup/ai-split-before
git rebase -i HEAD~2

HEAD~2は、今回の「大きいcommit+その後のcommit」の2本を対象にする指定です。自分の履歴に合わせて範囲を選びます。開いた一覧では、分割するcommitの先頭のpickをeditへ替え、後続のcommitはpickのまま保存します。

対象commitで停止したら、次を実行します。–mixedはHEADとindexを一つ前へ戻し、作業ファイルには対象commitの内容を残します。–hardへ替えないでください。

git reset --mixed HEAD^
git add -p -- src/pricing.mjs
git add -- tests/pricing.test.mjs
git diff --staged
git commit -m "Reject negative quantity"

# 残りも、差分と単体動作を確認してcommitする
git add -- src/pricing.mjs
git commit -m "Format currency literal"
git add -- README.md
git commit -m "Document test command"

git status --short
git rebase --continue

続行前には、分ける対象の変更がすべてcommitされ、作業フォルダーが整理できていることを確認します。rebase –continueで後続のcommitが再適用されます。競合したら、何を残すかを確かめて解消し、解消したファイルをaddして続行します。

途中で元へ戻すならgit rebase –abortを使えます。ただし、中断中に加えた編集もそのまま残るとは考えず、必要な新しい作業があれば別途保全してから中止します。commitを分ける以外の編集を同時に始めないと、戻す対象を把握しやすくなります。

最後に、分割前の先端とファイル内容を比較します。

git diff --exit-code backup/ai-split-before HEAD
git log --oneline -n 6
git status --short

内容を変えず分割できたなら、最初のdiffは空になり終了コードは0です。検証例でも、後続commitを再適用した後の最終内容が一致しました。これは途中のcommitが動くことまで保証しないため、先ほどの単体テストと併せて確認します。

次回AIへ依頼するときは、「今回は不具合修正と対応テストだけ。整形・ファイル移動・文書改善の提案は、変更せず別に列挙してください」と範囲を先に伝えられます。それでも実際のdiffを確認し、既存の編集と混ざっていないかを見ます。分割後の文面を整える段階は、AIでコミットメッセージを作る方法を参照してください。

公式の操作説明:git addの対話操作、git restoreの対象領域、git rebaseのコミット分割(2026年9月12日確認)。

スポンサーリンク