ワークフロー&基本ツール · daymade/claude-code-skills

git-safety-net

ローカルのGit状態(未プッシュや別ブランチへのコミット、ダーティまたはdetachedなworktree、放置された同一リポジトリの複製クローン、bundleでバックアップできない未追跡の変更、孤立したstash、danglingコミット、古いブランチ、squash/rebaseマージの成否など)を監査、保全、復旧し、安全に退役させます。作業内容が失われた恐れがある場合、コミットやブランチを復旧したい場合、worktree・クローン・作業ディレクトリを削除しても問題ないか確認したい場合、1つのmainブランチにすべて統合したい場合、クリーンアップによって成果物が失われない証拠が必要な場合に使用します。リポジトリ内の監査でクリーンと判定された後でも利用を推奨します(通常、同一マシン上の別クローンは見落とされがちです)。トリガー:「did I lose work」「is everything merged」「is anything else lost」「safe to delete this clone」「clean up old branches/stashes」「only keep one main branch」「git reflog」「dangling commits」「分支灾难」「误删分支/commit」「worktree 能删吗」「还有没有丢的东西」「只保留一个主分支」。ローカルGitのフォレンジックを対象とし、GitHub PR/API操作や日常的な同期は対象外です。

L4 高権限 · 段階的認可と監査V1 コミット固定コマンド実行依存関係インストールネットワーク通信ファイル書き込みDual-pass Audit
Author daymadeGitHub daymade/claude-code-skills ↗Stars 1385License MIT(仓库根 LICENSE 文件;GitHub API spdx MIT;Copyright (c) 2025 daymade)Commit d5c4678cb5
管理レベルは Skill の能力と推奨統制措置を示すものであり、品質や安全性の認証、利用可否の判定ではありません。使用の可否はユーザーおよび管理者が決定します。Agent 環境によって制約が異なるため、自動保護を仮定しないでください。第三者製 Skill の著作権は原著作者に帰属し、利用リスクは利用者が負います。

1仕組みと動作原理

全体構成は「オーケストレーション層 SKILL.md + 6つの付属Bashフォレンジック用スクリプト」であり、すべてのスクリプトは破壊的操作の前に完全に非破壊的・増分実行されます(復旧処理自体が損失を拡大させることはありません)。

git-safety-net/SKILL.md
until a step is explicitly labeled destructive — recovery must never make the loss worse.
ここでの処理内容:「調査・保全」と「破棄」を2つのフェーズに分離。スクリプトは読み取り専用の列挙、ref追加、リポジトリ外バックアップファイルの書き込みのみを実行し、実際の削除(stash drop / branch -d / worktree remove / クローンの退役)は、ユーザーが証拠を確認し承認した後にのみ手動で実行させます。

「何を失う可能性があるか」の確定診断は `git_loss_audit.sh` が担当:最初に `fetch` を実行してリモート追跡refを最新化し、リンクされた各worktreeのHEADとstatus、ローカルブランチ/タグ、stash、danglingコミットを列挙。ローカル固有のコミットやダーティ/読み取り不可なworktreeが存在すればexit 1を返します。

git-safety-net/scripts/git_loss_audit.sh
# It refreshes remote-tracking refs with `fetch`, then only inspects repository/worktree state. It
ここでの処理内容:`git log HEAD --branches --tags --not --remotes` では見落とされる「別worktree内のdetached HEAD」や「未コミットの変更」を明示的に対象に含めます(スクリプトは `git worktree list --porcelain` で全HEADを収集)。終了コードの仕様は意図的であり、ダーティまたは読み取り不可なworktreeは「安全にクリーンアップ可能」の判定をブロックしますが、stashやdanglingコミットはレポートのみ行いスクリプト自体を異常終了させません。

「監査結果はクリーンだが、実は別クローンに残っていた」事態の防止:`git_find_all_checkouts.sh` がマシン単位でチェックアウトを探索。リモートURLの正規化(SSH/HTTPSの等価判定)または「共通コミット履歴の共有」に基づいて同一リポジトリの他チェックアウトを特定し、ディレクトリ名での単純一致は行いません。

git-safety-net/scripts/git_find_all_checkouts.sh
# not `git worktree list`, not `git branch -a`, not `git fsck`, not `git stash list`,
ここでの処理内容:独立したクローンは完全な `.git` を持ち逆方向のポインタを持たないため、リポジトリ内コマンドからは不可視です。そのためスクリプト自身がディスク全体の `.git`(ディレクトリ=clone、ファイル=worktree/submoduleのgitlink)を検索し、`node_modules`、`.venv`、`vendor`、`.terraform` を除外した上で候補に対して `status` / `rev-list` を実行します。これが本スキルの最大の中核的強みです。

マージ判定はコミット数ではなくコンテンツレベルの試験的マージを実施:`git merge-tree --write-tree <base> <branch>` を用いてメモリ上でブランチをbaseに統合し、生成ツリー == baseツリーであれば MERGED(内容包含)と判定し、それ以外は NEEDS REVIEW とします。

git-safety-net/scripts/git_verify_branch_merged.sh
# 2. Else do a trial 3-way merge of the branch INTO the base (git merge-tree, in memory, no
ここでの処理内容:squash/rebaseマージはSHAを書き換えるため、`main..branch` は100以上の未マージな「幽霊コミット」を表示します。試験的マージはGit独自のマージ機構で内容の包含を判定するため、スクリプトの注釈やリファレンスでもヒューリスティックではなく堅牢(sound)であると明記されています。Git 2.38未満で `--write-tree` が非対応の場合は「マージ済み」と推測せず、保守的に NEEDS REVIEW へフォールバックします(スクリプト内の `MT_RC>=128` 分岐)。

GC実行前の保全:各danglingコミットを隠しref名前空間 `refs/dangling-backup/<sha>` に固定。refが存在するオブジェクトはGC回収の対象外となり、`git branch` や `git stash list` を汚染することもありません。

git-safety-net/scripts/git_preserve_danglers.sh
git update-ref "refs/dangling-backup/$sha" "$sha"
ここでの処理内容:スクリプトは読み取り専用Gitコマンドと `git update-ref` によるref新規追加のみを行い、refの削除、checkout、reset、gcは絶対に実行しません。オプション `--patch-dir` でマージ以外の各コミットを `.patch` として出力可能。親コミット数(`rev-list --parents` の単語数 > 2)でマージ/stashを判定します。これは `git format-patch -1` がマージコミットに対して別のコミットのパッチを無言で生成しexit 0を返してしまう「バックアップ誤出力」を防ぐための設計です。

破棄前のエクスポート:stashを完全なバイナリパッチとしてエクスポートし、さらに `git archive "$ref^3"` を使ってstashの第3親コミット(`git stash -u/-a` が保持する未追跡ファイル)をtar化。`git stash show -p` ではこれらが出力されず、パッチのみの保存では不可視のまま消失するためです。

git-safety-net/scripts/git_export_before_drop.sh
# -> stashN-untracked.tar the often-forgotten THIRD parent:
ここでの処理内容:「どのバックアップツールがどの作業成果物をカバーできないか」を厳密な制約として設計。ブランチや全refは `git bundle create`(および検証)で扱い、danglingオブジェクトは固定(pin)した上で `--all-refs` bundleに含めます。スクリプトは `--out` へのファイル書き込みのみを行い、自身の権限でdropや削除を実行することはありません。

削除直前のCompare-and-Swapゲート:`--verify-current BUNDLE` でbundle内に記録されたrefとリポジトリの現在の値を1件ずつ突合し、refの移動や消失があれば即座にexit 1で終了します。

git-safety-net/scripts/git_export_before_drop.sh
echo "REFSET_CHANGED checked=$CHECKED changed=$MOVED — rebuild and re-verify the bundle before deletion" >&2
ここでの処理内容:「refの集合自体が変動し得る」問題に対処。ブランチ一覧やbundleはある一瞬の状態を証明するに過ぎないため、削除処理は再列挙と照合の直後に実行しなければならず、差分があればbundleを再作成する必要があります。

独立クローンの退役準備:スクリプトは詳細な拒否リスト(ダーティ/未追跡/ignoredバイト、stash、reflog限定コミット、クローン固有の到達不能オブジェクト、リンクされたworktree、ローカルsubmodule、partial/promisorクローン、Git LFS/annexオブジェクトストア、追跡コンテンツフィルタ、`include.path`/`hooksPath` の間接参照、浅いクローン)を検証し、全通過時のみ証拠を固定します。

git-safety-net/scripts/git_prepare_clone_retirement.sh
# It refuses to certify a clone that still has working-tree bytes, ignored files,
ここでの処理内容:bundleは「Gitが把握しているオブジェクト」しか証明できません。そのため、refスナップショット、symbolic-refトポロジ、reflog OID、config/hooks/infoのタイプ・パーミッション・ハッシュ、reflogテキスト、リポジトリメタデータのtar、all-refs bundleとsha256を新規作成した外部ディレクトリに書き出し受領証(receipt)を生成。`umask 077`、`GIT_NO_LAZY_FETCH=1`、fsmonitor無効化(リポジトリ側フックの実行防止)を適用します。

書き込み権限範囲の厳格な制限:バックアップディレクトリは絶対パスかつ未存在(上書き拒否)であり、対象クローンおよび存続リポジトリの双方の外側になければなりません。スクリプト自体がチェックアウトを移動・削除したりrefを変更することはありません。

git-safety-net/scripts/git_prepare_clone_retirement.sh
"$CLONE/"*|"$SURVIVOR/"*) die "backup directory must be outside both repositories" ;;
ここでの処理内容:「バックアップはリポジトリ外に配置する」という運用ルールをコード上の検証として強制し、退役ディレクトリの削除にバックアップが巻き込まれる事故を防ぎます。

ワークフロー規律を「成果契約(Outcome contract)+ 権限境界」としてプロンプトに定義:証拠の範囲 ≠ アクションの範囲、権限付与はリポジトリ単位ではなくオブジェクト単位、保全フェーズと退役フェーズの分離、完了基準はbundle数やチェックサムではなくユーザー側で観測可能な事実(コミットがリモートに存在、ブランチ/worktreeの状態が適正など)に準拠します。

git-safety-net/SKILL.md
- **Evidence scope is not action scope.** A read-only audit may discover another clone, ref,
ここでの処理内容:SKILL.mdのエントリルーター(Mode A 復旧 / B 監査・保全 / C マージ検証 / D 予防 / E 安全な退役)と連携したプロンプト層のゲート。ユーザーの明示的な許可がない限り、新たに発見されたクローン/ブランチ/worktreeはすべてレポートのみ(report-only)にとどめます。

スクリプト一覧表で「変更の有無」(読み取り専用 / リモート追跡refのみ更新 / ref追加のみ / バックアップファイル書き出しのみ)を明記し、全ヘルパーにおいてcheckout、reset、push、stash drop、branch -d、gcの実行権限を不許可と宣言します。

git-safety-net/SKILL.md
the helpers authorizes `checkout`, `reset`, `push`, `stash drop`, `branch -d`, or `gc`.
ここでの処理内容:各スクリプトの影響範囲を表形式でホスト環境およびユーザーに開示。fetch、バックアップ生成、ref追加を伴うスクリプトは、事前にリポジトリの排他書き込み権限を取得することを要求します。

2コア機能

01マシンレベルのチェックアウト探索:すべての独立クローンを検出(SSH/HTTPS等価URLの正規化、共通コミットによる浅いクローンの識別、alternates共有の追跡)
02リポジトリ内の損失監査:ローカル固有のコミット、各worktreeのダーティ状態、stash、danglingコミットを一括列挙し、exit 1で「安全にクリーンアップ可能」の誤判定を阻止
03コンテンツレベルのマージ検証:先祖チェックまたは `merge-tree` 試験マージにより、MERGED または UNMERGED-NEEDS REVIEW を安全側に倒して出力
04GC耐性のある保全:認可範囲内のdanglingコミットを `refs/dangling-backup/*` にピン留めし、コミットごとに `.patch` のエクスポートも可能
05破棄前エクスポート:対象ブランチを検証済みbundleに、stashをバイナリパッチ+第3親コミットのtarに、全refトポロジをall-refs bundleに出力
06削除前のCompare-and-Swapゲート(`--verify-current`):refの移動や消失を検知して異常終了し、bundleの再作成を要求
07独立クローンの損失ゼロ退役準備:拒否リストの検証 + ref/symref/reflog/メタデータの固定 + bundleダイジェスト受領証 + `READY_TO_QUARANTINE` による最終チェック
08段階的復旧アプローチ:reflog → 破棄されたstash(第3親を含む)→ detached HEAD → `fsck`、および共有チェックアウト環境での競合事故(他者コミットのブランチ混入、一時インデックスによるステージング削除トラップ)の解決
09「不適切な調査手法」の防止:`ls-remote` のファイルサイズ判定の誤り、`--is-ancestor` の3値の終了コード、stash listが空でもstashが存在し得るケース(autostash)などのアンチパターンをSKILL.mdとevalsに網羅

3外部依存関係

KindDependency / Endpoint
cligit(含 worktree/fsck/reflog/bundle/merge-tree/update-ref/for-each-ref 等)
cligit ≥ 2.38(merge-tree --write-tree 是内容级判定的前提)
cliuv(仅维护者跑回归测试时用到)
clisha256sum / shasum(bundle 指纹;缺失即报错)
clitar(打包 config/hooks/info 元数据)
clistat(跨 BSD/GNU 的 mtime 与文件模式读取)
clilsof(macOS 上探测 clone 是否仍被进程占用;仅文档步骤,不在脚本内)
networkgit fetch(由脚本执行;对远端主机发起出站连接,可能触发宿主 git 凭证助手)
networkgit fetch --all --prune(合并判定脚本执行,同一出站面)
networkgit push(仅文本指导:把 backup 分支推到 origin 做三重备份;无脚本执行)
package无第三方包(Git + 标准 Bash 即可;测试仅用 Python 标准库 unittest/tempfile/subprocess)

4推奨統制措置と判定根拠

安全運用のための推奨統制措置
Agent 向け
段階的・都度認可、サンドボックス推奨
管理者向け
承認フロー、ロールバック可能、全履歴監査
判定根拠(ファイルパスと抜粋)
  • scripts/: ローカルスクリプトまたはコマンドの実行: `git-safety-net/scripts/git_find_all_checkouts.sh` —— 読み取り専用: `find` + 読み取り専用Gitクエリ(`status`、`rev-list`)
  • scripts/ 或 SKILL.md: 外部言語パッケージ依存関係の動的インストールを宣言
  • 网络端点: 外部ネットワークアクセスの宣言: インバウンド/アウトバウンド: `git fetch "$REMOTE" --prune`(`git-safety-net/scripts/git_loss_audit.sh`)
  • 本地工作目录: ファイル読み書きとアーティファクト出力: リポジトリ外バックアップ: `git_export_before_drop.sh` デフォルト `$HOME/.git-backups/<YYYY-MM-DD>-<repo>/`
監査ノート: リスク評価:青(通常使用可能)。コード実行およびファイル書き込みが存在します。6本のBashスクリプトがGitコマンドの実行、リポジトリ外へのバックアップ書き込み、隠しrefの追加を行い、3箇所で `git fetch`(リモートへのアウトバウンド、ホストの認証情報ヘルパーが起動する可能性あり)を実行します。しかし、破壊的な操作は構造的に排除されています。スクリプト自体には `rm -rf`、`branch -D`、`reset --hard`、`stash drop`、`gc`、`worktree remove` は含まれておらず、削除操作はすべて明示的な認可後にユーザー自身の手で実行されるよう設計されています。ファイル書き込みはリポジトリ外のディレクトリに厳格に制限されており(既存ディレクトリの上書き拒否、クローン/存続リポジトリの外部必須、`umask 077`)、認証情報の読み取りやサードパーティAPI、ハードコードされたドメインも存在しません。またSKILL.mdには成果契約、オブジェクト単位の認可、単一ライター制、verify-currentなどのゲートが組み込まれています。真の残留リスクは「読み取ったリポジトリ内容がエージェントのコンテキストに入ること(プロンプトインジェクション)」および「スキルの指示に従ってプッシュ/退役を行う際、操作者が真に正当な権限を有しているか」という運用上の判断事項であり、スクリプト自体の権限逸脱ではありません。

5二重目の独立検証

  • [ok] external_deps 逐条反查调用点:git 系列命令 — 在 6 个脚本里逐条确认 git 子命令的真实执行点(fetch/worktree list/fsck --dangling/stash list/bundle create+verify/list-heads/reflog/for-each-ref/update-ref/check-attr/submodule status/cat-file/rev-list)。全部为执行路径上的真实调用,非注释。
  • [ok] external_deps:uv 与 lsof 是否真在脚本里 — 两者都不在脚本中执行:`uv run python -m unittest discover -s tests -p 'test_*.py'` 只出现在 SKILL.md § Maintainer verification(维护者本地跑测试);lsof 只出现在 references/merge_verification.md 的退役 READ-DO 序列(macOS 探测进程占用)。已按『文档层工具』而非『运行时依赖』归类。
  • [ok] 网络调用面是否存在遗漏(隐藏脚本/混淆内容) — glob 全量(hidden=true, gitignore=false)显示该 skill 目录仅 17 个文件:SKILL.md、3 个 references、6 个 scripts、6 个 tests、evals/evals.json、agents/openai.yaml,无可执行二进制、无压缩/混淆内容。全目录 grep curl/wget/gh/nc/python -c 零命中;唯一 https:// 出现在 find_all_checkouts 的 URL 归一化注释示例里。
  • [ok] 反例排查:git_find_all_checkouts.sh 号称不联网,但脚本里有 `git fetch --all --prune` — 该行(第 317 行)位于 `cat <<'FRESHNESS'` heredoc 内,是打印给用户看的建议,不在执行路径上;脚本头部 `# NON-DESTRUCTIVE: runs only \`find\` plus read-only Git queries` 与代码一致(唯一外部命令是 find 与只读 git 查询)。不构成 discrepancy,因此改为标注为『文本指导』。
  • [ok] 反查『脚本非破坏性』是否属实(是否有删除/改写仓库对象) — 对 rm -rf / branch -D / reset --hard / stash drop / worktree remove / update-ref -d / gc 全目录扫描:脚本内仅两处相关文本——preserve_danglers 的 `rm -f "$OUT"`(删除自己刚写失败的 patch 文件)与 loss_audit 的提示字符串 `never use 'git worktree remove --force'`。所有真正的破坏性命令(`git update-ref -d`、`git worktree remove`、`--force-with-lease` 等)只出现在 SKILL.md/references 供人执行的步骤中。
  • [ok] 『写操作面』核对:备份到底写到哪里、是否会覆盖既有数据 — export 脚本默认写 $HOME/.git-backups/<date>-<repo> 并可 --out 覆盖;preserve_danglers 的 --patch-dir 先绝对化再 mkdir -p;prepare_clone_retirement 强制 `[ ! -e "$OUT" ]`(拒绝已存在目录)、要求绝对路径、并 `case "$OUT/" in "$CLONE/"*|"$SURVIVOR/"*) die ...` 拒绝把备份放进被退役/保留的仓库内。三处均与 SKILL.md『备份放仓库外』一致。
  • [ok] 凭证/全局配置读取面反查 — 全目录 grep --global / .gitconfig / credential / HOME 的结果:脚本内只有 export 的 `$HOME/.git-backups/...` 默认输出路径;`git config --global` 只出现在两处 references 中作为给用户的建议命令。prepare_clone_retirement 读取仓库私有配置时显式用 `git config --file <config> --no-includes`(不吞并用户全局配置)。无 token/env 读取。
  • [ok] 实现原理是否夸大:『内容级判定是 sound 而非启发式』 — 与脚本逐行比对成立:脚本先 `git merge-base --is-ancestor` 判 ancestor,再 `git merge-tree --write-tree <base> <branch>` 比较结果树与 base 树;MT_RC>=128(git<2.38)时明确退回 NEEDS REVIEW 而非猜 MERGED。声明与实现一致,未夸大。

6結論

  • 「監査の死角」を根本問題として解決:独立したクローンはリポジトリ内ツールから不可視であるため、マシン全体の探索スクリプトを内蔵し、ディレクトリ名ではなくリモートURLの正規化や共通コミット履歴で同一性を判定します。
  • 推測ではなくGit本来の試験的マージを採用し「安全バイアス」を適用:内容の包含が立証された場合のみ MERGED とし、それ以外はすべて人間の確認に委ねます。
  • 破壊と保全のアーキテクチャ的分離:スクリプトの動作は読み取り、ref追加、リポジトリ外書き込みに限定。stashの第3親コミットのような「通常のパッチで見落とされる変更」にも専用のエクスポート経路を設け、未追跡ファイルは「ディスク上の現物のみ」と明確に扱います。
  • 実効性のある削除ゲートの確立:Compare-and-Swap(`--verify-current` / `REFSET_CHANGED`)と退役最終検証(`READY_TO_QUARANTINE` + sha256受領証)により、「ref集合の動的変化」を機械的な検証ステップに変換。
  • 高いエンジニアリング完成度:6つのスクリプトに1,730行のビヘイビア回帰テストを付属、8件のevalsで規律を担保し、84KBのリファレンスは§セクション指定により必要な箇所のみロードします。
  • 並行性および認可モデルの明示化:単一ライター(one writer)、オブジェクト単位の認可、調査専用と変更認可の明確な切り分けを徹底し、共有チェックアウト環境で発生する2つの実事故(他者のコミット混入、一時インデックスに起因するステージング削除)の検知ロジックを備えています。
  • 最適な用途: 対象:ローカルGitでトラブルを経験した方、または不安を抱えている方(「コミットを消失したかもしれない」「worktree/stash/ブランチを削除しても大丈夫か」「本当にmainにマージ済みか」「このマシン上に同じリポジトリのコピーがいくつあるか」)。マルチエージェントや複数セッションで同一チェックアウトを共有する環境において、書き込み権限と証拠管理の規律を確立したいチーム。ならびに「非破壊フォレンジックスクリプト + 認可ゲート」の設計パターンを参考にしたいスキル開発者。削除処理とはフェーズを完全に分け、クリーンアップ前の事前監査・保全として実行する運用に最適です。
    不向きな用途: 非推奨:GitHubのPRやAPI操作を伴うワークフロー(SKILL.md上でも他スキルへ明確に委譲されており、日常のコミット/プッシュは `/auto-repo-setup` を利用すべきです)。「検証してから削除する」という慎重なプロセスを受け入れられず、ワンコマンドで即座に一括削除したいユーザー。promisor/partialクローン、Git LFS/annexへの依存、または追跡コンテンツフィルタが設定されたリポジトリでのクローン退役(スクリプト側で実行を拒否します)。スキル側が自動で破壊的削除を行ったり、Gitのグローバル設定を無断変更することを期待するユースケース。
    Install Agent-Ready
    ① Verified Mirror 2026-09-15
    Option A · Direct DownloadDownload git-safety-net.tar.gz
    sha256: b2b944f8a078459b…
    Option B · Copy Guide for Agent
    install.json
    Agent はこの JSON ガイドから自動的にダウンロードして検証します。
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit d5c4678cb5.