私が4つの技術ブログを毎日自動更新している仕組みで、いちばん怖かったのは「赤いエラー」ではなく「緑のログ」でした。スケジュール実行のログには git push 成功と出ているのに、記事がサイトに一向に増えない。手元では確かに push が走っているのに、リモートには何も届いていない——この無音の失敗を突き止めるまで、原因を勘違いして数日を溶かしました。
git push は、実は「何もしていなくても成功する」コマンドです。Claude Code やサンドボックス環境で自動化を組んでいると、この性質が思わぬ落とし穴になります。エラーが出ないからこそ気づきにくい、commit の無音失敗について整理します。
症状 — エラーは一切出ないのに変更が消える
典型的なログはこうなります。
$ git add content/
$ git commit -m "Add: new article (JA+EN)"
$ git push origin main
Everything up-to-date
git push が Everything up-to-date を返し、終了コードも 0。スクリプトは何事もなく次の処理へ進みます。ところが GitHub を見ると、新しいコミットは存在しません。CI も走らず、デプロイも起きない。エラーハンドリングを if [ $? -ne 0 ] で書いていても、push 自体は成功扱いなので決して引っかかりません。
問題は push ではなく、その手前の commit が無音で失敗していることにあります。
なぜ起きるのか — commit が静かにスキップされる2パターン
パターン1: clone 直後で git identity が未設定
これがいちばん多い原因です。CI コンテナやサンドボックスで git clone した直後は、user.name と user.email が設定されていません。この状態で git commit を実行すると、環境によっては以下のように コミットを作らずに終了 します。
Author identity unknown
*** Please tell me who you are.
厄介なのは、出力をパイプで握りつぶしていたり、commit の終了コードを確認していないと、この警告が見えないまま次の git push に進んでしまう点です。commit が作られていないのでローカルの HEAD はリモートと同じまま。だから push は当然 Everything up-to-date を返します。
私のスケジュールタスクでは、git clone --depth 1 の直後に毎回 identity を設定する処理を入れていなかった時期があり、これに長く気づけませんでした。
パターン2: ステージした変更が実質ゼロ
git add したつもりでも、対象パスがずれていて何もステージされていない、あるいは生成物が .gitignore で除外されていると、git commit は次のように何もせず終わります。
On branch main
nothing to commit, working tree clean
このときも commit は作られず、終了コードは 1(または環境により 0)。続く push はやはり Everything up-to-date です。自動生成したファイルが意図したディレクトリに書き込めていなかったケースが、これに当てはまります。
パターン3: コミット先と push 先のブランチがずれている
意外に見落としがちなのが、commit は成功しているのに push 先のブランチが別物 というケースです。--depth 1 の浅いクローンで特定コミットを取得すると detached HEAD になることがあり、その状態で commit すると名前のないブランチに積まれます。あるいはリポジトリの既定ブランチが master なのに git push origin main と書いていれば、main には何も載っていないので当然 Everything up-to-date が返ります。
# 自分がどのブランチに commit したかを確認する
git rev-parse --abbrev-ref HEAD # "HEAD" と出たら detached
git branch --show-current # 空なら detached HEADclone のオプションに --branch main を明示し、push の直前に現在ブランチを確認しておくと、この取り違えは防げます。
再現してみる
挙動を手元で確かめると、対策の勘所が掴めます。identity を消した状態で commit を試すと、push が空振りする流れを再現できます。
# 検証用の使い捨てクローン
git clone --depth 1 https://github.com/you/your-repo.git /tmp/verify
cd /tmp/verify
# identity をあえて未設定にする
git config --unset user.name 2>/dev/null
git config --unset user.email 2>/dev/null
echo "test" >> README.md
git add README.md
git commit -m "test commit" # ← ここで identity unknown により失敗する
echo "commit exit code: $?" # 128 などゼロ以外が返る
git push origin main # ← それでも Everything up-to-datecommit exit code がゼロ以外であること、にもかかわらず push が成功扱いになることが確認できます。
確実な対処 — 「設定」と「検証」を分けて入れる
対処は2段構えにします。発生を防ぐ「設定」と、起きても気づける「検証」です。
1. clone 直後に必ず identity を設定する
自動化スクリプトでは、clone のたびに無条件で identity を設定するのが安全です。一度設定すればそのリポジトリでは保持されますが、再 clone のたびに消えるため、毎回入れておきます。
git clone --depth 1 --branch main "https://${TOKEN}@github.com/you/your-repo.git" "$WORK"
cd "$WORK"
# clone 直後は identity が空。無条件で設定する
git config user.email "you@example.com"
git config user.name "your-name"2. push の成否を「SHA 照合」で判定する
ここがいちばん大切です。git push の終了コードは信用できないので、ローカルの HEAD とリモートの HEAD が一致したか で成功を判定します。これなら commit の無音失敗も、push の取りこぼしも、まとめて検出できます。
# commit は終了コードも見る
git add content/
if ! git commit -m "Add: new article (JA+EN)"; then
echo "❌ commit に失敗しました(変更なし、または identity 未設定)"
exit 1
fi
# push 後にローカルとリモートの SHA を突き合わせる
git push origin main
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git ls-remote origin -h refs/heads/main | cut -f1)
if [ "$LOCAL" = "$REMOTE" ]; then
echo "✅ push 確認: $LOCAL がリモートに反映されました"
else
echo "❌ 不一致 — local=$LOCAL remote=$REMOTE。push は反映されていません"
exit 1
figit ls-remote はリモートの最新 SHA を直接問い合わせるので、ローカルのキャッシュに惑わされません。この照合を通ってはじめて「push 成功」とみなす——という原則にしてから、私の自動更新では「成功ログなのに記事が増えない」現象が起きなくなりました。
自動化パイプラインでは「終了コードを信じない」を既定にする
この一件で学んだのは、自動化において終了コードは出発点でしかない、ということです。git push のように「何もしなくても成功するコマンド」は珍しくありません。成果物が本当に存在するか(コミットが積まれたか、ファイルが届いたか)を、コマンドの戻り値ではなく 状態そのもの で確認する。これは Git に限らず、API 呼び出しでもファイル生成でも同じ姿勢で臨むべきだと感じています。
無音の失敗が厄介なのは、ログを何度見返しても「正常」としか書かれていない点にあります。エラーであれば文面を手がかりに検索できますが、何も起きていない成功はそもそも調べる糸口がありません。個人開発で自動化を一人で回していると、声を上げてくれる人もいません。私自身、原因をログの読み違いだと思い込んだまま、関係のない場所を何日も探ってしまいました。だからこそ、成果物が本当に積まれたかを毎回機械的に問い合わせる一手間を、パイプラインの既定動作にしてしまうのが結局いちばん早道だと考えています。
Git 操作で別の壁にぶつかったときは、サンドボックス特有の問題をまとめたClaude Code の git index.lock がVM・CIで詰まるときの対処や、git の dubious ownership を safe.directory で解決する方法も合わせて確認してみてください。どうしても git コマンドが安定しない環境では、GitHub REST API で commit と push を行う方法に切り替えるのも現実的な選択肢です。
まずは、自動化スクリプトの git push の直後に、上記の SHA 照合を3行足してみてください。次に「成功ログ」が出たとき、それが本物かどうかを初めて自信を持って言えるようになります。
最後までお読みいただき、ありがとうございました。同じ無音の失敗で時間を溶かす方が一人でも減れば嬉しいです。