Skip to content
cccskills
FreePublished on GitHub

gh-push

非対話セッション(claude-code の remote-control / CI など TTY が無く SSH 鍵パスフレーズを入力できない状況)で git push を通すスキル。

remote が SSH URL で `ssh -o BatchMode=yes` による非対話 SSH 認証が実際に通る(agent の鍵・パスフレーズ無しのディスク鍵・macOS キーチェーン鍵のいずれでも可)なら素の SSH push を実行し、非対話 SSH 認証が通らず `git push` が `Permission denied (publickey)` で失敗する場合は、push を HTTPS + gh トークン(credential.helper='!gh auth git-credential')経由へ自動フォールバックして標準入力なしで実行する。

「push して」「リモートに反映して」と頼まれたが SSH 認証が使えない、push が publickey で弾かれた、remote-control から push したい、といった場面で使う。`/gh-push` で明示起動も可。GitHub(gh) 前提。

The English summary is being prepared. Showing the original description.

Works withGitHub

Run score Not tested

See how to install

Files included (4)

  • SKILL.md12.4 KB
  • scripts/gh-push.sh22.7 KB
  • scripts/push-arm.sh1.4 KB
  • scripts/tests/gh-push.test.sh11.8 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

gh-push — 非対話 push(SSH 優先・gh フォールバック)

このスキルの目的

非対話セッション(TTY 無し)で git push を通す。経路は 決定論的に 選ぶ:

  1. SSH 優先 — remote が SSH URL で、かつ ssh -o BatchMode=yes による非対話 SSH 認証が実際に通るなら、素の git push を SSH で実行する。判定は agent の鍵有無ではなく BatchMode=yes での ls-remote が成功するかで直接テストする(agent の鍵・パスフレーズ無しのディスク鍵・macOS キーチェーン鍵を区別せず「非対話で通るか」を確かめられる)。GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new' を強制し、パスフレーズ入力プロンプトや接続ハングに落ちず即失敗させる。

  2. gh(HTTPS) フォールバック — SSH push が失敗した場合、または SSH が使えない(remote が HTTPS / 非対話 SSH 認証テストが失敗)場合は、push 認証を gh の credential helper に肩代わりさせて HTTPS で送る:

    git -c credential.helper= -c credential.helper='!gh auth git-credential' push <https-url> <branch>
    

    credential.helper=(空)で既存ヘルパー一覧をリセットし gh ヘルパーだけを使う(cache/oauth 等の介入を避ける)。remote が SSH URL でも URL を HTTPS に変換して push 先に使うので origin の設定は変更しない。

なぜ SSH を先に試すか: 「SSH で push できるか」は ssh -o BatchMode=yes の ls-remote を1回打って直接テストすれば決定論的に判定できる。非対話 SSH が通る環境(Linux で ssh-agent 常駐、macOS のキーチェーン連携、パスフレーズ無しのディスク鍵など)では素の push がそのまま通るため、余計なトークン経由を挟まない。判定の ls-remote は push 範囲算出に使うリモート tip 取得と兼ねるので、往復コストは増えない。ssh-add -l(agent の鍵一覧)では、agent が空でもディスク鍵やキーチェーン鍵で非対話認証できるケースを取りこぼすため使わない。

判定の ls-remote は refs/heads/<branch> に限定する(refs/heads/* で全ブランチを引かない)。全一覧は使い道が無く、ブランチ数の多いリポジトリでは出力が数百KB に達して抽出処理を壊すため(後述の「異常終了の切り分け」参照)。

SSH 認証テストのメモ化: 非対話 SSH 認証の成否は host 単位で決まりリポジトリ/ブランチに依存しないため、セッション内で一度成功したら結果を /tmp/gh-ssh-authcache.<session_id>.<host> に記録し、以降の preflight / push では実 ls-remote を省いて即 SSH 経路を採る(TTL 30 分・成功のみキャッシュ・セッション毎に独立)。キャッシュヒット時は tip を SSH で 1 ブランチ分だけ引く。実 push が成功すれば TTL を延長し、SSH が失敗(鍵失効等)すればキャッシュを破棄して gh 経路へ降格する。$CLAUDE_SESSION_ID が無い環境ではメモ化せず従来どおり毎回テストする。gh-fetch とキャッシュを共有する。

前提

  • SSH 経路の条件: remote が SSH URL(ssh://git@… または git@host:owner/repo)で、ssh -o BatchMode=yes の非対話 SSH 認証が実際に通ること(agent 鍵・パスフレーズ無しのディスク鍵・キーチェーン鍵のいずれでも可)。この2条件が揃わなければ自動的に gh 経路になる。
  • gh 経路(フォールバック)の条件: gh auth status でログイン済みで、トークンに repo(write)scope があること。無ければ push は権限エラーで落ちる(gh auth refresh -s repo で付与)。
  • SSH と gh のどちらも使えない(非対話 SSH 認証が通らず かつ gh 未認証/未導入)ときは preflight/push が ERROR: で停止する。SSH 鍵を非対話で使える状態にするか gh auth login を促す。
  • GitHub(github.com / GitHub Enterprise)が対象。GitLab 等 gh が扱わないホストは gh 経路が使えない — SSH が通らなければこのスキルの対象外(SSH 鍵や glab を案内する)。

ワークフロー

判定・URL 変換・push 範囲算出・push 実行はすべて決定論的なので、git コマンドを手で並べ直さず scripts/gh-push.sh を使う。

1. preflight(push 対象を収集して提示)

bash <skill-dir>/scripts/gh-push.sh preflight [branch]

=== SECTION === 区切りの出力を読み、push 経路(SSH / gh)・push 先 URL・ブランチ・送るコミットをユーザーに提示する。TARGET の route 行で、SSH 経路か gh 経路かとその理由が分かる。TARGET の protected 行は push 先が保護ブランチ(静的リスト main / master / develop / development / trunk / release / release/* / releases/*、origin/HEAD、GitHub 上の既定ブランチ)かどうか。AUTH セクションで非対話 SSH 認証テストの成否と gh 認証を確認する。STATE の意味:

  • up-to-date … 差分なし。push 不要。
  • new … リモートに無い新規ブランチ。直近コミットを提示。
  • fast-forward … 通常 push 可。送るコミット一覧が出る。
  • diverged … 履歴分岐。通常 push は弾かれる。WARNING を読み、ここで停止してユーザーに確認(fetch して rebase/merge で整合させるのが既定。意図的な上書きのときだけ force)。
  • unknown … リモート tip がローカルに無く厳密判定不能。非 FF ならサーバが安全に拒否するのでそのまま push 試行してよい。

preflight が ERROR: を出したら、その内容(非対話 SSH 認証不可 かつ gh 未認証・未対応 URL・detached HEAD 等)を解決してから進む。

2. push 実行

起動=push 意図とみなし、preflight 提示後そのまま実行する(毎回の yes/no は取らない)。ただし上記 diverged(force が要る状況)と、protected: yes(保護ブランチへの push)だけは必ず停止して確認する。

bash <skill-dir>/scripts/gh-push.sh push [branch]

保護ブランチへの push は --allow-protected が無ければスクリプトが拒否する。このスクリプトの内部 push は Bash ツールの git push ではないので、ask ルールにも permission-gate にもかからない。ここで止めないと確認なしに通るため、ユーザーがそのブランチへの push を明示承認したときだけ付ける:

bash <skill-dir>/scripts/gh-push.sh push <branch> --allow-protected

意図的な上書きをユーザーが承認した場合のみ force を付ける(保護ブランチへの force は --allow-protected があっても拒否される):

bash <skill-dir>/scripts/gh-push.sh push [branch] --force [--expect=<sha>]

force は両経路とも --force-with-lease=<branch>:<現リモート tip> の明示 lease で実行される(gh 経路の URL 直 push では引数なし --force-with-lease の比較対象となる remote-tracking ref が参照されず常に stale info で拒否されるため、明示 lease に統一している)。呼び出し元が「安全と確認済みのリモート tip」を持っている場合 — rebase-flow スキルからの委譲等 — は --expect=<sha> で渡す。確認時点以降に他者の push が挟まると実 tip と不一致になり、push 前に確実に停止する。

push は実際の git push の直前に scripts/push-arm.sh <branch> で arm する(git rev-parse --git-path push-flow.armed に 1 行 <epoch> <ttl秒> <branch>、TTL 既定 1800 秒)。承認済みの push を permission-gate hook に通させる marker で、スキル外で承認済みの push を流すときも bash <skill-dir>/scripts/push-arm.sh <branch> [--ttl <秒>] を push の直前に実行する。permission-gate は push の実行前に判定するので、その場合は arm と push を別々の Bash 呼び出しにし、push は git push [-u] origin <branch> か cd <リテラルのパス> && git push … の形だけで書く(;・パイプ・リダイレクト・置換・引用符を含むと規則に該当せずダイアログが出る)。

gh 経路で push した場合、スクリプトは refs/remotes/<remote>/<branch> を手で進めて git status の ahead 表示を整合させる(URL 直 push では remote-tracking ref が自動更新されないため)。SSH 経路では git が更新するのでこの補正は行われない。実行結果の OK: [ssh] / OK: [gh] でどちらの経路を使ったか分かる。

異常終了の切り分け

スクリプトが ERROR: 以外の形で落ちたとき(出力ゼロ + exit code が 0/1 以外)は、 サンドボックスや環境の制約と決めつけず、次の順で切り分ける。素の git push へ 逃げてはいけない(force-with-lease の明示 lease・保護ブランチ判定を全て失う)。

  1. exit code と stdout/stderr を分けて取る。パイプ越しでは $? がスクリプトの 終了コードにならない。

    bash <skill-dir>/scripts/gh-push.sh preflight >/tmp/out 2>/tmp/err; echo "EXIT=$?"
    
  2. bash -x で最後に実行された行を見る。出力は大きいのでファイルへ落とし末尾だけ読む。

    bash -x <skill-dir>/scripts/gh-push.sh preflight >/dev/null 2>/tmp/trace; tail -5 /tmp/trace
    
  3. exit 141 は SIGPIPE(128+13)。set -o pipefail + set -e と組み合わさると、 パイプ上流が SIGPIPE を受けた時点でスクリプト全体が出力ゼロのまま即死する。 スクリプト冒頭を読んでも原因は見えないので、bash -x の最後の行を必ず見る。 スクリプト側の対処は「大きな出力を早期 exit するフィルタへパイプしない」 (scripts/gh-push.sh の first_sha はこのためにパイプを使わない)。

  4. 引数形式の疑いは --help では確かめられない(未知オプションとして ERROR: になる)。 本ファイルの「ワークフロー」節が唯一の仕様。

ERROR: で止まった場合は環境要因ではなくスクリプトの意図的な停止なので、 メッセージの指示(gh auth login / lease 不一致 / 保護ブランチ 等)に従う。

制約

  • force はユーザーの明示承認が無い限り付けない。diverged 検出時は停止が既定。
  • 保護ブランチへの force は script が拒否する(静的リスト main/master/develop/trunk/release 等 + origin/HEAD + GitHub 既定ブランチ)。force が許されるのは作業ブランチのみ。
  • このスキルは push そのものが目的なので、起動された時点では実行してよい(pr-create の「自動 push 禁止」とは役割が別)。ただし push 先が main/master など保護ブランチのときは、送るコミットを提示した上で一言断ってから実行する。
  • remote URL や push 先ブランチが曖昧・複数候補ありうるときは、憶測で push せずユーザーに確認する。

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Claude Code の並列エージェント(agent teams・teammate)の後始末と無応答時の打ち切りルール。`name` を付けて Agent を起動するとき、TeamCreate でチームを組むとき、teammate から `idle_notification` が届いたとき、評価ループ等で次のイテレーションのエージェントを起動する前、エージェントの返信が届かないときに参照する。`name` を付けない通常のサブエージェント起動だけなら対象外。

The English summary is being prepared. Showing the original description.

yasunori0418/skills9Updated Oct 23, 2026

spec.md の REQ-# を入力に、機能一覧・モジュール構成・インターフェース・データフローを持つ docs/dev/<対象>/basic-design.md を作成・改訂するスキル。/basic-design <対象名> で明示的に呼び出されたときのみ使用する。

The English summary is being prepared. Showing the original description.

yasunori0418/skills9Updated Oct 23, 2026

技術的な内容を、技術用語を排したビジネス職向けの平易な説明文に翻訳する。`/biz-translate` と明示的に呼ばれたときのみ実行する。

The English summary is being prepared. Showing the original description.

yasunori0418/skills9Updated Oct 23, 2026

`git commit` / `git commit --amend` を実行する前、または「commit」「amend」「コミット」「コミットして」の一語・短文だけを渡された時点で必ず発火する git コミット実施ルール。理由や差分の説明が一切無くても、ファイル全文を読んでメッセージを組み立てる前に先に参照する。主目的は論理的に独立した修正を都度・適切な粒度でコミットすること。メッセージは Conventional Commits 形式、素材は同梱の決定論スクリプト commit-context.sh が出す staged diff のみ。「コミット分けて」と依頼される、独立した複数修正をまとめるか分けるか判断する、レビューコメント対応をコミットする、rebase / squash / cherry-pick 後のメッセージを整える、`gh pr create` の PR タイトルをコミット流儀へ揃える場面でも参照する。plan モードでのコミット計画の立案は commit-plan スキルの領分。

The English summary is being prepared. Showing the original description.

yasunori0418/skills9Updated Oct 23, 2026

実装計画・リファクタリング計画・レビュー対応計画・並列作業のタスク分解など、計画を成果物として書き出すときに必ず参照するコミット計画ルール。plan モードでは ExitPlanMode で plan を提示する前に必須、計画ドキュメントや job-graph のタスク分解・エージェントへの指示文でも同様に適用する。計画成果物にコミット計画セクション(論理的に独立した修正単位での分割と Conventional Commits 形式のメッセージ)が無ければ実装に入らない。「実装計画を立てて」「planを立てて」「実行計画を作って」「リファクタリング計画を立てて」「コミット計画を立てて」「タスクを分解して」と依頼される、複数の独立した修正をまとめるか分けるか計画段階で判断する等の場面では、ユーザーが「コミット」に一切言及していなくても必ず発火する。コミットの実施(素材収集・メッセージ確定・git commit 実行)は commit-flow スキルが担う。

The English summary is being prepared. Showing the original description.

yasunori0418/skills9Updated Oct 23, 2026

プロジェクトに 1 つの「完成の定義」docs/dev/definition-of-done.md を対話で構築・改訂し、機械判定節と人判定節の二部構成で書き出すスキル。/def-done で明示的に呼び出されたときのみ使用する。

The English summary is being prepared. Showing the original description.

yasunori0418/skills9Updated Oct 23, 2026

See all skills by yasunori0418

Report a problem with this skill