ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-06-12中級

AIエージェントの git push が成功表示なのにリモートへ反映されないときの原因と対処

エージェントに任せた git push が「Everything up-to-date」のまま空振りし、リモートに何も反映されない症状について、再現条件と原因、identity 明示・SHA 照合・GitHub REST API という3つの対処をまとめました。

ai-agent13git7automation23ci-cd6troubleshooting84

朝、夜間に走らせていた定期実行のログを確認すると、エージェントは「コミットして push しました」と報告していました。終了コードも 0。それなのに GitHub のリポジトリを開くと、最新コミットは前日のまま。エラーは一行も出ていません。

個人開発のいくつかのプロジェクトで、リポジトリへの定期的なデータ更新を AI エージェントに任せています。その運用を始めてから私自身が最初に深くハマったのが、この「無言の失敗」でした。エラーで止まってくれる障害よりも、成功した顔をして何もしていない障害のほうがずっと厄介です。気づくまでに丸一日かかりました。

原因をたどると、git のごく基本的な仕様に行き着きます。ただ、自動化環境特有の条件が重なると、その仕様が人間の目から完全に隠れてしまうのです。

症状 — ログは正常、リモートは無変化

観測できた事実は次の3点です。

  • エージェントの実行ログは正常終了(exit code 0)
  • git push origin main の出力は Everything up-to-date
  • リモートの main ブランチに新しいコミットが存在しない

Everything up-to-date は一見すると成功のメッセージに見えます。実際には「push すべきコミットが何もなかった」という意味で、ここが見落としの入り口になります。

なお、認証情報の問題で Permission denied が返るケースは別系統です。そちらの切り分けは Antigravity の Agent から git push したら permission denied になるときの切り分けと恒久対策 にまとめています。今回扱うのは、エラーが一切出ないまま空振りするケースです。

再現条件 — 使い捨て環境とエラーの握りつぶし

この問題は、次の3条件が揃うと再現します。

  1. 使い捨ての VM やコンテナで git clone 直後に作業している(グローバルの .gitconfig が存在しない)
  2. スクリプトが set -e なしで動いている、またはコミット行が || true などで保護されている
  3. 実行ログを人間がリアルタイムで見ていない

clone したばかりの環境には user.nameuser.email もありません。この状態で git commit を実行すると、git は「Please tell me who you are」というメッセージとともにコミットを拒否します。

対話的なターミナルならすぐ気づきます。しかし自動実行では、このメッセージはログの中ほどに埋もれ、スクリプトはそのまま次の行へ進みます。コミットされていないので push 対象はゼロ。git push は「送るものがない」状態を正常として終了コード 0 で終わります。

GitHub Actions などの CI では、テンプレートや既製のアクションが identity を設定してくれることが多く、この躓きを経験しないまま自動化を組んでいる方も多いはずです。素のコンテナでエージェントを動かす場合、その便利な層は存在しません。

原因 — commit の無言失敗と push の仕様の組み合わせ

整理すると、原因は2つの仕様の重なりです。

ひとつは、git が identity(user.name / user.email)未設定のコミットを拒否すること。これ自体は正しい挙動です。

もうひとつは、git push が「push すべきものがない」場合をエラーにしないこと。Everything up-to-date は失敗ではなく「仕事がなかった」という報告であり、終了コードは 0 です。

つまり「commit が静かに失敗 → push が空振りで成功 → エージェントは成功と報告」という連鎖です。どのコマンドも仕様どおりに動いていて、壊れている箇所はどこにもありません。だからこそ気づきにくいのだと思います。エージェントの判断基準が「コマンドの終了コードが 0 だったか」だけだと、この連鎖は完全な成功に見えてしまいます。

対処1 — identity の明示と「SHA 照合」での成功判定

まず identity の明示です。クローン直後に、リポジトリローカルで必ず設定します。

cd /path/to/repo
git config user.email "bot@example.com"
git config user.name "Update Bot"

ワンショットで済ませたい場合は -c オプションで都度渡す方法もあります。

git -c user.email="bot@example.com" -c user.name="Update Bot" \
  commit -m "Update data files"

そして、より本質的な対処が成功判定の変更です。私はこの一件以来、push の成否を終了コードではなく「ローカルとリモートの先端 SHA が一致したか」で判定するようにしました。

#!/bin/bash
set -euo pipefail
 
cd /path/to/repo
git config user.email "bot@example.com"
git config user.name "Update Bot"
 
git add data/
git commit -m "Update data files"
git push origin main
 
# push 後にローカルとリモートの先端を照合する
LOCAL_SHA=$(git rev-parse HEAD)
REMOTE_SHA=$(git ls-remote origin refs/heads/main | cut -f1)
 
if [ "$LOCAL_SHA" != "$REMOTE_SHA" ]; then
  echo "ERROR: local=$LOCAL_SHA remote=$REMOTE_SHA 反映されていません" >&2
  exit 1
fi
echo "OK: $LOCAL_SHA がリモートに反映されました"

set -euo pipefail を冒頭に置けば、commit が失敗した時点でスクリプト全体が止まります。さらに SHA 照合があれば、想定外の経路で push が空振りしても必ず検出できます。

「コマンドが通ったか」ではなく「観測できる状態が変わったか」を見る。エージェントに作業を任せるうえで、この発想の転換がいちばん効きました。

対処2 — index.lock に阻まれる環境では REST API という選択肢

identity を設定しても、サンドボックス環境によっては .git/index.lock が残留し、git commit 自体が詰まることがあります。私の環境では並行して動く別プロセスとロックが衝突し、リトライしても解消しないケースがありました。

ロックファイルは「他に git プロセスが動いていないこと」を確認したうえで削除すれば復旧できます。

# 他に git プロセスがいないことを確認してから削除する
ps aux | grep -v grep | grep "git " || rm -f .git/index.lock

ただ、詰まるたびに手当てするのも不毛です。最終的に私は、この種のジョブを GitHub REST API で直接コミットを作る方式に切り替えました。ローカルの index を一切使わないため、identity 問題とロック問題の両方を構造的に回避できます。単一ファイルの更新なら次の流れで完結します。

#!/bin/bash
set -euo pipefail
 
OWNER="your-name"; REPO="your-repo"; BRANCH="main"
TOKEN="YOUR_GITHUB_TOKEN"
API="https://api.github.com/repos/$OWNER/$REPO"
AUTH="Authorization: Bearer $TOKEN"
 
# 1) 現在の先端コミットと、そのツリーを取得
HEAD_SHA=$(curl -s -H "$AUTH" "$API/git/ref/heads/$BRANCH" | jq -r '.object.sha')
TREE_SHA=$(curl -s -H "$AUTH" "$API/git/commits/$HEAD_SHA" | jq -r '.tree.sha')
 
# 2) 新しい内容で blob → tree → commit を作成
BLOB_SHA=$(jq -n --rawfile c data.json '{content:$c, encoding:"utf-8"}' \
  | curl -s -X POST -H "$AUTH" -d @- "$API/git/blobs" | jq -r '.sha')
 
NEW_TREE=$(jq -n --arg base "$TREE_SHA" --arg b "$BLOB_SHA" \
  '{base_tree:$base, tree:[{path:"data.json", mode:"100644", type:"blob", sha:$b}]}' \
  | curl -s -X POST -H "$AUTH" -d @- "$API/git/trees" | jq -r '.sha')
 
NEW_COMMIT=$(jq -n --arg t "$NEW_TREE" --arg p "$HEAD_SHA" --arg m "Update data.json" \
  '{message:$m, tree:$t, parents:[$p]}' \
  | curl -s -X POST -H "$AUTH" -d @- "$API/git/commits" | jq -r '.sha')
 
# 3) ブランチの先端を新しいコミットへ進める
curl -s -X PATCH -H "$AUTH" -d "{\"sha\":\"$NEW_COMMIT\"}" \
  "$API/git/refs/heads/$BRANCH" | jq -r '.object.sha'

コミットの author はトークンの持ち主として記録されるため、user.name の設定は不要です。push に相当する処理は最後の refs 更新だけなので、失敗したときの原因の切り分けも簡単になりました。

予防策 — エージェントの「成功」を疑う仕組みを先に作る

同じ転び方をしないために、いまは次の3点を運用に組み込んでいます。

  1. クローン直後の identity 設定を手順書に固定で入れる。 エージェントへ渡す指示の最初に、毎回必ず置いています。
  2. 成功判定を SHA 照合に一本化する。 終了コードや「push しました」という自己申告は、判定材料に使いません。
  3. set -euo pipefail を全スクリプトの1行目に置く。 静かに先へ進んでしまう失敗を、その場で止まる失敗に変えます。

エージェントの報告は、検証可能な事実と突き合わせてはじめて信頼できるものになります。自動化の便利さを保ったまま「疑う仕組み」を一枚足しておくことが、結局いちばんの近道でした。

挙動の裏付けを確認したいときは、git commit 公式ドキュメントgit push 公式ドキュメントGitHub REST API — Git database が参考になります。

まずは手元の自動化スクリプトに、SHA 照合の数行を足すところから試してみてください。同じ症状に向き合っている方の手がかりになれば幸いです。

シェア

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

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

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

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

関連記事

Agents & Manager2026-03-28
SKILL.md駆動のコードレビューエージェントを設計する方法
AIの実装支援が進むほどレビュー負荷が増大する時代。SKILL.mdを核としたコードレビューエージェントの設計パターンを解説します。9段階のレビューステップ、品質ガイド、カスタム命令の構成方法を紹介。
Agents & Manager2026-03-17
Antigravity Browser Sub-Agent による E2E テスト自動化
Antigravity の Browser Sub-Agent を活用した E2E テスト・ビジュアルリグレッションテスト・CI/CD 統合の完全実践ガイド。Gemini の視覚能力でブラウザ自動化を次のレベルへ引き上げる。
Agents & Manager2026-05-30
Antigravity のエージェントが node や python を『command not found』にするときの原因と対処
自分のターミナルでは動くのに、Antigravity のエージェントがコマンドを実行すると command not found になる。PATH 継承の仕組みから、nvm・pyenv・Homebrew 環境ごとの具体的な解決手順を解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →