マガジン

Claude Codeの変更が大きくなりすぎたとき:差分を分けてコミットし直す方法

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

散らばった紙片を目的ごとの小さな束に整理する手元
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

Claude Codeに「ここまでやって」と任せ続けた結果、git diff --stat が数十ファイルになってしまうことがあります。この状態でできる安全な対処は、まず今の状態をブランチに退避し、変更を「変更理由」ごとに分けて、小さなコミットに積み直すことです。コードを巻き戻して縮めるのではなく、全体はそのまま残して並べ替えます。 流れは4段階です。 1. 現状を退避ブランチに保存する 2. 変更を理由ごとに分類する(Claudeに案を出させ、人が決める) 3. git add -p などで少しずつステージし、1つずつコミットする 4. 退避ブランチとの差分がゼロであることを確認する この記事のコマンドは説明用の構成例で、手元の環境では実行していません。自分のリポジトリで、まず退避ブランチを作ってから試してください。

この記事の目次
  1. 最初に退避する:`/rewind` で縮めない
  2. 分割の判断基準
  3. 分類案をClaudeに出させる依頼文
  4. 少しずつステージして積み直す
  5. すでに大きなコミットにしてしまった場合
  6. 次から大きくしないための一言

最初に退避する:`/rewind` で縮めない

大きくなった変更を小さくしたくなると、Claude Codeの /rewind で戻したくなります。ただし、これは分割の道具ではありません。公式ドキュメントによれば、チェックポイントはセッション単位の素早い復旧用です。Bashコマンドだけで変更されたファイルは追跡されず、サブエージェントの編集も復元されない場合があります。恒久的な履歴にはGitを使うよう書かれています。

そこで、Gitで確実に残します。未コミットの変更がある場合の例です(feature/x は作業中のブランチ名の例)。

bash
git status --short            # 秘密情報や不要ファイルが混じっていないか先に確認
git add -A
git commit -m "WIP: 分割前の退避"
git branch backup/feature-x   # この時点の全変更を保存
git reset HEAD~1              # コミットだけ取り消し、変更は作業ツリーに残す

git add -A は .env などを巻き込みます。git status で見てから実行し、含めたくないものは .gitignore や個別指定で除いてください。backup/feature-x は、うまくいかなくなったときに全変更へ戻るための保険です。

分割の判断基準

分け方の基本は「1コミット=1文で目的を説明でき、単独でテストが通る」ことです。次の表を目安に分類します(編集上の提案です)。

  • 整形・リネームなど挙動を変えない変更、扱い:最初に単独でコミット、理由:後続の差分からノイズを消せる
  • 挙動を変えないリファクタ、扱い:機能追加と分ける、理由:「見た目は大きいが安全」な差分と混ぜない
  • 機能追加・バグ修正の本体、扱い:目的ごとに1コミット、理由:レビューの中心になる
  • そのコードのテスト、扱い:対応する本体と同じコミット、理由:各コミットで検証できる
  • 依存追加・lockfile・設定変更、扱い:別コミットにして理由を書く、理由:影響範囲が違い、見落としやすい
  • 頼んでいないのに触られたファイル、扱い:戻すか、別ブランチへ、理由:目的外の変更はレビュー対象から外す

最後の行は特に重要です。Claude Codeに広めの依頼をすると、関連しそうな周辺ファイルまで直されることがあります。意図に合わないものは分割以前に外します。

GitHubのドキュメントも、小さく焦点の絞られたPRのほうがレビューしやすく安全にマージできるとしています。コミットに分けても1つのPRが大きすぎるなら、PR自体を分けることも検討してください。

分類案をClaudeに出させる依頼文

分類は、差分を読むだけなのでClaudeに任せやすい作業です。ただしこの段階ではGitを変更させません。そのまま使える依頼文です。

text
git diff --stat と git diff を読んで、コミット分割案を表で出してください。
- 各コミットに「目的を1文」「含めるファイル(同じファイルを複数コミットに
  分ける場合は、どの変更箇所かを特徴で説明)」「実行すべきテスト」を書く
- 順序は、挙動を変えない変更を先に、機能の本体を後に
- 今回の目的は「○○」です。目的に関係なさそうな変更は別枠で列挙する
- この段階では git add / commit / reset / checkout を実行せず、
  ファイルも編集しない

○○ には本来の依頼内容(例:ログイン失敗時のエラー表示を直す)を入れます。

出てきた案は、人が次の点を確認します。

  • 目的外の変更を拾えているか。判断できなければ、その変更だけ個別にClaudeへ理由を聞く
  • 各コミットが単独で成立するか(前のコミットに依存して壊れないか)
  • 秘密情報、生成物、巨大なファイルが入っていないか

案が固まれば、ファイル単位でステージするコミットはClaudeに実行を頼めます。1つのファイルを複数コミットに分けるときは、git add -p の対話操作を自分で行うほうが確実です。

少しずつステージして積み直す

退避と reset が済んだら、作業ツリーに全変更があり、ステージは空の状態です。1コミットごとに次を繰り返します。

bash
git add -p path/to/file     # 変更箇所(ハンク)ごとに y / n / s(さらに分割) を選ぶ
git add path/to/new_file    # 新規ファイルは -p の対象外なので個別に指定
git diff --cached --stat    # 今回コミットに入るものだけか確認
# ここでテストなどを実行
git commit -m "refactor: 認証モジュールの命名を統一"

ポイントは、git diff --cached で確認してからコミットすることです。ここでは「ステージされた内容」だけがレビュー対象になります。ハンクが細かく分かれないときは s で分割し、それでも足りなければ e で手編集できます。

すべて積み終わったら、元の全変更と一致しているか確認します。

bash
git status --short                        # 残りがないこと
git diff backup/feature-x --stat          # 出力が空なら内容は同一
git log --oneline backup/feature-x..HEAD  # 新しい履歴を確認

差分が出た場合は、入れ忘れか、積み直しの途中で変えてしまった箇所です。退避ブランチとの差分が空になるまで直します。

すでに大きなコミットにしてしまった場合

大きな変更を1つ、あるいは雑なコミット数個にしてしまったときも、方法は同じです。退避してから、分岐元まで履歴だけを戻します。

bash
git branch backup/feature-x               # 現在のコミットを保存
git reset $(git merge-base main HEAD)     # main との分岐点へ。変更は作業ツリーに残る

main は自分のベースブランチ名に読み替えてください。これで未コミットのときと同じ状態になります。直前の1コミットだけ分割したいなら、git rebase -i で対象を edit にして止める方法もあります。GitHubのrebaseの解説でも、edit はコミットの分割・修正に使うものとされています。

注意が必要なのは、すでにpush済みの場合です。履歴を書き換えるため、通常の git push は拒否されます。同じ解説では、複数人がアクセスするリポジトリでの書き換えは慎重にすべきとし、強制pushには --force-with-lease を挙げています。自分だけが使っているブランチで、チームの運用ルールにも反しないときに限り、次のようにします。

bash
git push --force-with-lease origin feature/x

共有ブランチや、他の人が上に積んでいるブランチでは使わず、新しいブランチ名で出し直してください。

次から大きくしないための一言

依頼の段階で「この作業の目的は○○だけ。無関係なファイルは変更しない。区切りごとに差分を見せて」と範囲を絞ると、分割の手間は減ります。ただ、すでに大きくなった差分には、上の退避→分類→積み直しがそのまま使えます。

出典・参考資料