ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-07-15中級

エージェントのコミットに .bak が混じる — 自動修正ツールの副産物がリポジトリに入る原因と対処

エージェントに --fix 系ツールを走らせた後のコミットに .bak や .orig が紛れ込む症状について、再現条件と原因、ステージ範囲の限定・副産物の即時掃除・pre-commit での拡張子ゲートという3つの対処をまとめました。

Antigravity332エージェント60Git7自動化29troubleshooting88

デプロイ後の差分を眺めていて、見覚えのないファイル名が目に入りました。

next.config.ts.bak

エージェントに設定ファイルの自動修正を任せ、ゲートが通ったので push した直後のことです。本番は何事もなく動いていました。だからこそ気づくのが遅れました。

個人開発でリポジトリを触るのは私一人ですので、レビュアーもいません。混入に気づいたのは、翌週に別の作業で ls を叩いたときでした。

症状 — 直したはずの差分に、直していないものが並ぶ

エージェントに --fix オプション付きの整形ツールや検査スクリプトを走らせ、その流れでコミットさせると、次のようなファイルがリポジトリに入ります。

混入するもの生成元厄介な点
*.bak自作の in-place 修正スクリプト元ファイルの旧版がそのまま残り、秘密情報を含む場合がある
*.orig / *.rejpatch・マージ衝突の残骸次回のマージで混乱の元になる
*.tmp / *.swpエディタ・一時書き出し数が増えると差分レビューが機能しなくなる
__pycache__/検査スクリプトの実行環境依存のバイナリがリポジトリに乗る

私の場合は .bak が1つでした。ビルドは通ります。テストも通ります。CI も緑のままです。

何も壊れないというのが、この症状のいちばん質の悪いところでした。

再現条件 — 「直す」と「集める」が別々の道具である

再現には3つの条件が揃う必要があります。

  1. 自動修正ツールが、書き換えの前にバックアップを作る
  2. そのツールが、修正後にバックアップを消さない
  3. コミット直前のステージング操作が、ワークツリー全体を対象にしている

3番目が引き金です。エージェントに「修正して、コミットして」と頼むと、多くの場合 git add -Agit add . が選ばれます。エージェントは差分の内容を理解していますが、「その差分を作った副産物」までは意図の対象として区別しません。

再現手順は次の通りです。

# 1. バックアップを残す典型的な in-place 修正(GNU sed / BSD sed 両対応の書き方)
sed -i.bak 's/foo/bar/g' next.config.ts
ls next.config.ts*
# => next.config.ts  next.config.ts.bak
 
# 2. エージェントが選びがちな広いステージング
git add -A
 
# 3. 何が入ったかを確認せずにコミット
git commit -m "Fix: config"
 
# 4. 事後に気づく
git show --stat HEAD
#  next.config.ts     | 2 +-
#  next.config.ts.bak | 47 ++++++++++++++   ← 意図していない

sed -i.bak は macOS の BSD sed でも動く互換的な書き方として広く使われています。互換性を優先した結果として副産物が残る、という順序でした。

原因 — .gitignore は「後から」効かない

最初に疑ったのは .gitignore の不備でした。実際 *.bak の記述はありませんでしたので、そこに1行足せば済むと考えました。

これは半分だけ正解でした。

.gitignore が働くのは、未追跡ファイルに対してだけです。一度コミットされて追跡対象になったファイルは、後から .gitignore に書いても無視されません。すでに入ってしまった .bakgit rm --cached で外す必要があります。

そしてもう半分。.gitignore は拡張子を列挙する防御ですので、列挙していない拡張子は素通りします。.bak を塞いだ翌月に .rej で同じことが起きるだけでした。

根本原因は拡張子の側ではなく、ステージング範囲の側にあります。

git add -A は「ワークツリーで変わったものを全部」という意味です。エージェントの作業では、変わったものの中に「成果物」と「作業の残りかす」が必ず混在します。全部を対象にする限り、区別は .gitignore の網の目に委ねられ続けます。

対処1 — ステージ対象をパスで限定する

いちばん効いたのはこれでした。エージェントへの指示から git add -A を排し、変更してよいディレクトリだけを明示します。

# ✗ 何が入るか事前に決まらない
git add -A
 
# ✓ 入りうるものが事前に決まる
git add content/ src/config/

add の引数がホワイトリストになりますので、.bak がどこに落ちても、対象ディレクトリの外にあれば入りません。対象ディレクトリの中に落ちた場合は次の対処で塞ぎます。

私はエージェントの運用規約に「add はパス限定。-A. は使わない」の1行を足しました。これだけで、その後の8週間で .bak 系の混入はゼロになっています。

対処2 — 修正ツールを、掃除まで含めてラップする

--fix を素で呼ばず、副産物の後始末までを1つのコマンドにまとめます。

#!/usr/bin/env bash
# scripts/safe-fix.sh — in-place 修正と後始末を分離させない
set -euo pipefail
 
TARGET="${1:?usage: safe-fix.sh <file>}"
BACKUP="${TARGET}.bak"
 
# 修正前の状態を退避(リポジトリ外へ)
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
 
sed -i.bak 's/foo/bar/g' "$TARGET"
 
if [ -f "$BACKUP" ]; then
  # ロールバック用に退避してから、リポジトリ内からは消す
  mv "$BACKUP" "$TMPDIR/$(basename "$BACKUP")"
  echo "backup moved out of repo: $TMPDIR"
fi
 
# 差分が空なら修正不要だったということ
if git diff --quiet -- "$TARGET"; then
  echo "no change: $TARGET"
fi

trap ... EXIT を置いていますので、途中で失敗しても退避先は残りません。バックアップを完全に捨てるのではなく、いったんリポジトリ外へ動かしているのが要点です。手元でのロールバック手段は残しつつ、Git の視界からは外れます。

自作スクリプトなら書き換えられますが、サードパーティの codemod ではそうもいきません。その場合は実行後に find . -name '*.bak' -newer <基準ファイル> -delete を足すか、次の対処に頼ります。

対処3 — pre-commit で、ステージ済みの拡張子を検査する

最後の砦です。コミットの瞬間に、ステージされたファイル名だけを見て弾きます。

#!/usr/bin/env bash
# .git/hooks/pre-commit — 副産物の混入を機械的に止める
set -euo pipefail
 
DENY='\.(bak|orig|rej|tmp|swp)$|(^|/)__pycache__/|(^|/)\.DS_Store$'
 
# -z を付けないと、非ASCIIパスが八進エスケープされて検査を素通りする
BAD="$(git diff --cached --name-only -z --diff-filter=ACM \
       | tr '\0' '\n' | grep -E "$DENY" || true)"
 
if [ -n "$BAD" ]; then
  echo "コミット対象に副産物が含まれています:" >&2
  echo "$BAD" | sed 's/^/  - /' >&2
  echo "" >&2
  echo "対処: git restore --staged <file> でステージから外してください" >&2
  exit 1
fi

--diff-filter=ACM で追加・コピー・変更に絞り、削除されたファイルを誤検知しないようにしています。-z を付けている理由は実害があったからです。付けずに書いた最初の版は、日本語を含むパスを八進エスケープした文字列で返してきて、検査対象を取り違えたまま「クリーン」と報告していました。

ゲートが嘘をつくのは、ゲートが無いより悪い状態です。私自身、エージェントが書いたファイルが .gitignore に飲まれる問題を追いかけたときにも同じ落とし穴を踏んでいますので、ファイル名を走査する処理では -z を反射的に付けるようにしています。

なお .git/hooks/ はリポジトリに含まれませんので、新しい環境では設定が必要です。git config core.hooksPath .githooks でリポジトリ管理下のディレクトリを指すようにしておくと、clone した側にも自動で行き渡ります。

予防 — コミット前の1行を、エージェントの手順に埋める

3つの対処のうち、どれか1つだけを選ぶなら対処1です。ステージ範囲が狭ければ、残りは保険になります。

その上で、エージェントの手順に次の確認を入れると効果が上がりました。

# add の後・commit の前に、必ず一度は目に入れる
git diff --cached --name-only

出力を読ませるだけです。エージェントは自分がステージしたファイル一覧を見ると、意図と合わないものに気づきます。私の体感では、add のパス限定と合わせて、意図しない混入の大半はこの段階で止まりました。

push が「成功」と表示されながら実際には何も反映されていないgit identity 未設定による空振りもそうですが、エージェントに Git を任せるときの事故は、たいてい「表示は正常」という顔をしてやってきます。目視ではなく機械的な検査を挟む箇所を決めておくのが、結局いちばん安く済みました。

すでに .bak を入れてしまった場合の後始末は次の通りです。

# 追跡から外す(ローカルのファイルは残る)
git rm --cached next.config.ts.bak
echo '*.bak' >> .gitignore
git add .gitignore
git commit -m "Remove: backup artifact from repository"

履歴からも消したい場合は git filter-repo が必要になりますが、秘密情報を含んでいないのであれば、追跡から外すだけで実務上は足ります。私は .bak の中身を確認した上で、履歴の書き換えまでは行いませんでした。

次の一手

エージェントの直近3コミットに何が入っているかを確認してみてください。

git log -3 --stat --oneline

見覚えのない拡張子が1つでも出てきたら、そのコミットを作った手順のどこかに git add -A があります。そこをパス限定に書き換えるところから始めるのが、いちばん早いはずです。

コミットの内容そのものを検査する仕組みについては、エージェントのコミットを pre-commit で止める仕組みにまとめてあります。合わせて読んでいただければ幸いです。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Agents & Manager2026-07-12
Antigravity のエージェントに任せる作業と任せない作業を2週間の運用で見直す
個人開発の日々のタスクを2週間ほど Antigravity のエージェントに任せてみて、任せて正解だったものと手元に残すべきだったものの線引きを、運用ログを添えて振り返ります。
Agents & Manager2026-07-10
半年前にエージェントが書いた行の意図を追えるようにする — コミット粒度と来歴トレーラの設計
エージェントが 14 ファイル 800 行を 1 コミットに詰め込むと、半年後の git blame は何も語ってくれません。コミットを意図の単位に割り、Git trailer に来歴を機械可読で残し、blame から設計判断まで逆引きする仕組みを、動くコードとともにまとめます。
Agents & Manager2026-07-10
エージェントが書いたファイルが .gitignore に飲まれる — commit 前に気づくための検出ゲート
エージェントが生成したファイルが .gitignore に一致していると、差分レビューでは正常に見えるのに commit には含まれません。ignored な生成物を push 前に検出するゲートスクリプトと、その運用調整をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →