CLAUDE LABEN
WWDC — WWDC 2026でSiriはGoogle Geminiベースと確定。ChatGPT等への外部ハンドオフは廃止され、サードパーティAI選択はEU(DMA)で当面非対応にBILLING — 6/15の課金変更まで残り6日。Agent SDK・headless Claude Code・GitHub Actions・他社エージェントがAPIレート準拠の月次クレジットへ移行OUTAGE — claude.ai・Claude Code・Coworkで障害が報告(6月)。スケジュール実行はfallbackModelとリトライ前提の設計が安全ですDYNAMIC-WORKFLOWS — Max・TeamプランとAPIでdynamic workflowsがデフォルトON。コードベース横断のバグ探索や独立検証に活用ULTRACODE — Claude Codeの新設定ultracodeがeffortメニューに追加。xhigh固定でワークフロー判断はClaudeに委ねますOPUS4.8 — Claude Opus 4.8が主要プランのデフォルトとして定着。コーディング・エージェント・推論を強化WWDC — WWDC 2026でSiriはGoogle Geminiベースと確定。ChatGPT等への外部ハンドオフは廃止され、サードパーティAI選択はEU(DMA)で当面非対応にBILLING — 6/15の課金変更まで残り6日。Agent SDK・headless Claude Code・GitHub Actions・他社エージェントがAPIレート準拠の月次クレジットへ移行OUTAGE — claude.ai・Claude Code・Coworkで障害が報告(6月)。スケジュール実行はfallbackModelとリトライ前提の設計が安全ですDYNAMIC-WORKFLOWS — Max・TeamプランとAPIでdynamic workflowsがデフォルトON。コードベース横断のバグ探索や独立検証に活用ULTRACODE — Claude Codeの新設定ultracodeがeffortメニューに追加。xhigh固定でワークフロー判断はClaudeに委ねますOPUS4.8 — Claude Opus 4.8が主要プランのデフォルトとして定着。コーディング・エージェント・推論を強化
記事一覧/Claude Code
Claude Code/2026-05-03中級

git pushが詰まるVM環境でGitHub REST APIを使ってcommit/pushする方法

index.lockや所有権エラーでgit CLIが動かないVM・サンドボックス環境で、GitHub REST API(blobs→trees→commits→refs)を使ってファイルをpushする実践ガイドです。

GitHub REST APIClaude Code219git15VM3サンドボックス6push3

Claude Code のスケジュールタスクやサンドボックス環境で作業していると、ある日突然こんなエラーに遭遇することがあります。

fatal: detected dubious ownership in repository at '/tmp/repos/mysite'
error: could not lock config file .git/config: Permission denied
Another git process seems to be running in this repository

index.lock が残っている、リポジトリの所有者が nobody になっている、/tmp への書き込み権限がない——こういったケースはVMやコンテナ環境では珍しくありません。私自身、Claude Code のエージェント実行中に何度もこの問題で作業が止まりました。

そこで行き着いたのが、git CLIを一切使わず、GitHub REST APIだけでcommit/pushする方法です。

なぜGitHub REST APIなのか

git CLIは「Gitリポジトリへの直接アクセス」を前提にしています。ファイルシステムの権限、プロセスロック、所有者チェック——これらすべてが正常でないと動きません。

一方、GitHub REST APIはHTTPリクエストです。リポジトリのローカルコピーが壊れていても、権限が変になっていても、GitHubサーバー上のデータに直接操作できます

git CLI → ローカル.git → GitHub(権限エラーで詰まる)
REST API → GitHub(ローカル状態に関係なく動く)

基本的な仕組み:4ステップのフロー

GitHub REST APIでコミットを作るには、以下の順番で操作します。

1. blob作成  → ファイルの内容をGitHubに登録
2. tree作成  → blobを束ねてディレクトリ構造を作る
3. commit作成 → treeにメッセージを付けてコミットを作る
4. ref更新   → HEADが指すブランチを新コミットに進める

一見面倒ですが、各ステップは独立したAPIコールなので、エラーが起きても再試行しやすいのが利点です。

実装例:シェルスクリプト版

以下は、bashとcurlだけで実装したサンプルです。Claude Code のスケジュールタスクやCI環境でそのまま使えます。

#!/bin/bash
set -e
 
GITHUB_TOKEN="YOUR_GITHUB_TOKEN"
OWNER="your-username"
REPO="your-repo"
BRANCH="main"
COMMIT_MSG="Add: new article (JA+EN)"
 
# ── Step 1: 最新のHEAD SHAを取得 ──────────────────
HEAD_SHA=$(curl -sf \
  -H "Authorization: token ${GITHUB_TOKEN}" \
  "https://api.github.com/repos/${OWNER}/${REPO}/git/refs/heads/${BRANCH}" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['object']['sha'])")
 
BASE_TREE=$(curl -sf \
  -H "Authorization: token ${GITHUB_TOKEN}" \
  "https://api.github.com/repos/${OWNER}/${REPO}/git/commits/${HEAD_SHA}" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['tree']['sha'])")
 
echo "HEAD: ${HEAD_SHA}"
echo "BASE_TREE: ${BASE_TREE}"
 
# ── Step 2: blobを作成(変更ファイルごとに実行) ──
FILE_PATH="content/articles/ja/claude-code/my-article.mdx"
FILE_CONTENT=$(cat "${FILE_PATH}")
 
BLOB_SHA=$(curl -sf \
  -X POST \
  -H "Authorization: token ${GITHUB_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://api.github.com/repos/${OWNER}/${REPO}/git/blobs" \
  -d "$(python3 -c "
import sys, json
content = open('${FILE_PATH}', 'r').read()
print(json.dumps({'content': content, 'encoding': 'utf-8'}))
")" | python3 -c "import sys,json; print(json.load(sys.stdin)['sha'])")
 
echo "BLOB: ${BLOB_SHA}"
 
# ── Step 3: treeを作成 ──────────────────────────────
TREE_SHA=$(curl -sf \
  -X POST \
  -H "Authorization: token ${GITHUB_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://api.github.com/repos/${OWNER}/${REPO}/git/trees" \
  -d "$(python3 -c "
import json
tree = {
    'base_tree': '${BASE_TREE}',
    'tree': [{
        'path': '${FILE_PATH}',
        'mode': '100644',
        'type': 'blob',
        'sha': '${BLOB_SHA}'
    }]
}
print(json.dumps(tree))
")" | python3 -c "import sys,json; print(json.load(sys.stdin)['sha'])")
 
echo "TREE: ${TREE_SHA}"
 
# ── Step 4: commitを作成 ───────────────────────────
COMMIT_SHA=$(curl -sf \
  -X POST \
  -H "Authorization: token ${GITHUB_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://api.github.com/repos/${OWNER}/${REPO}/git/commits" \
  -d "$(python3 -c "
import json
commit = {
    'message': '${COMMIT_MSG}',
    'tree': '${TREE_SHA}',
    'parents': ['${HEAD_SHA}']
}
print(json.dumps(commit))
")" | python3 -c "import sys,json; print(json.load(sys.stdin)['sha'])")
 
echo "COMMIT: ${COMMIT_SHA}"
 
# ── Step 5: refを更新(ブランチを進める) ─────────
curl -sf \
  -X PATCH \
  -H "Authorization: token ${GITHUB_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://api.github.com/repos/${OWNER}/${REPO}/git/refs/heads/${BRANCH}" \
  -d "{\"sha\": \"${COMMIT_SHA}\"}" > /dev/null
 
echo "✅ Push完了: ${COMMIT_SHA}"

複数ファイルを1コミットにまとめる

日英セットの記事を1コミットにまとめたい場合は、Step 3のtree作成時に複数ファイルを配列に入れます。

# 複数ファイルをまとめてtreeに追加する例
python3 -c "
import json
 
# JA版のblob SHAとEN版のblob SHAを事前に取得しておく
tree_items = [
    {
        'path': 'content/articles/ja/claude-code/my-article.mdx',
        'mode': '100644',
        'type': 'blob',
        'sha': '${BLOB_JA_SHA}'
    },
    {
        'path': 'content/articles/en/claude-code/my-article.mdx',
        'mode': '100644',
        'type': 'blob',
        'sha': '${BLOB_EN_SHA}'
    }
]
 
payload = {
    'base_tree': '${BASE_TREE}',
    'tree': tree_items
}
print(json.dumps(payload))
"

blobは並行して作成できるので、ファイル数が増えても待ち時間は最小限に抑えられます。

エラーハンドリングのポイント

REST APIを使う際に実際に遭遇しやすいエラーと対処法をまとめます。

422 Unprocessable Entity(blob作成時)

バイナリファイルやBase64エンコードが必要な場合に発生します。テキストファイルなら encoding: "utf-8" で問題ありません。

409 Conflict(ref更新時)

別の誰かが先にpushしている場合です。git pull --rebase に相当する処理として、最新のHEAD SHAを再取得してからやり直します。

401 Unauthorized

トークンの権限不足か期限切れです。GitHub Personal Access Tokenに repo スコープが付いているか確認してください。

git CLIと組み合わせるハイブリッド戦略

VM環境でも /tmp 以外の場所($HOME/repos/ など)にリポジトリをcloneできる場合は、まずgit CLIを試みて、失敗したらREST APIにフォールバックするハイブリッド戦略も有効です。

push_article() {
  local repo_path="$1"
  
  # git CLIを試みる
  if cd "$repo_path" && git push origin main 2>/dev/null; then
    echo "✅ git push成功"
    return 0
  fi
  
  echo "⚠️ git push失敗 → REST APIにフォールバック"
  # REST API pushの処理を実行...
}

私はこのパターンをClaudeのスケジュールタスクに組み込んでから、環境依存のpushエラーがほぼゼロになりました。

全体を振り返って

git CLIに依存しないデプロイフローを用意しておくと、環境の差異に振り回されなくなります。特にエージェント型のツールやCI/CDパイプラインでは、「ローカルのgit状態が信頼できない」前提で設計するのが現実的です。

GitHub REST APIは公式のドキュメントが充実していて、RateLimit(認証済みで5,000 req/h)も通常の用途では十分です。まずは小さなスクリプトで試してみると、意外とシンプルに動くことを実感できると思います。

自分の現場で当てはめる3つの質問

  • この機能が止まったとき、ユーザー体験はどの程度劣化するか
  • 失敗を検知する仕組みは備わっているか
  • 戻す手順は手元のドキュメントに書いてあるか
シェア

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

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

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

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

関連記事

Claude Code2026-05-27
Claude Code Bash ツールで /tmp が Permission denied になる時の対処 — $HOME/repos フォールバックパターン
Claude Code のサンドボックス Bash で git clone が `Permission denied` で止まる症状の原因と、$HOME/repos へ自動退避させる実装パターンを、4サイト並行運用での実体験とともに整理します。
Claude Code2026-06-03
Claude Code で git push が「成功」したのに反映されない — commit が無音で失敗する罠
git push がエラーを出さず Everything up-to-date と表示されるのに、変更がリモートに反映されない。clone 直後の identity 未設定で commit が無音失敗する原因と、SHA 照合で確実に検証する方法を解説します。
Claude Code2026-05-30
git の detected dubious ownership が出てコマンドが止まるときの原因と対処
Claude Code やコンテナ・CI でgitを動かすと突然出る「detected dubious ownership in repository」の原因を整理し、safe.directory設定から所有権の根本対処までを実例で解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →