1仕組みと動作原理
全体構成は「オーケストレーション層 SKILL.md + 6つの付属Bashフォレンジック用スクリプト」であり、すべてのスクリプトは破壊的操作の前に完全に非破壊的・増分実行されます(復旧処理自体が損失を拡大させることはありません)。
until a step is explicitly labeled destructive — recovery must never make the loss worse.
「何を失う可能性があるか」の確定診断は `git_loss_audit.sh` が担当:最初に `fetch` を実行してリモート追跡refを最新化し、リンクされた各worktreeのHEADとstatus、ローカルブランチ/タグ、stash、danglingコミットを列挙。ローカル固有のコミットやダーティ/読み取り不可なworktreeが存在すればexit 1を返します。
# It refreshes remote-tracking refs with `fetch`, then only inspects repository/worktree state. It
「監査結果はクリーンだが、実は別クローンに残っていた」事態の防止:`git_find_all_checkouts.sh` がマシン単位でチェックアウトを探索。リモートURLの正規化(SSH/HTTPSの等価判定)または「共通コミット履歴の共有」に基づいて同一リポジトリの他チェックアウトを特定し、ディレクトリ名での単純一致は行いません。
# not `git worktree list`, not `git branch -a`, not `git fsck`, not `git stash list`,
マージ判定はコミット数ではなくコンテンツレベルの試験的マージを実施:`git merge-tree --write-tree <base> <branch>` を用いてメモリ上でブランチをbaseに統合し、生成ツリー == baseツリーであれば MERGED(内容包含)と判定し、それ以外は NEEDS REVIEW とします。
# 2. Else do a trial 3-way merge of the branch INTO the base (git merge-tree, in memory, no
GC実行前の保全:各danglingコミットを隠しref名前空間 `refs/dangling-backup/<sha>` に固定。refが存在するオブジェクトはGC回収の対象外となり、`git branch` や `git stash list` を汚染することもありません。
git update-ref "refs/dangling-backup/$sha" "$sha"
破棄前のエクスポート:stashを完全なバイナリパッチとしてエクスポートし、さらに `git archive "$ref^3"` を使ってstashの第3親コミット(`git stash -u/-a` が保持する未追跡ファイル)をtar化。`git stash show -p` ではこれらが出力されず、パッチのみの保存では不可視のまま消失するためです。
# -> stashN-untracked.tar the often-forgotten THIRD parent:
削除直前のCompare-and-Swapゲート:`--verify-current BUNDLE` でbundle内に記録されたrefとリポジトリの現在の値を1件ずつ突合し、refの移動や消失があれば即座にexit 1で終了します。
echo "REFSET_CHANGED checked=$CHECKED changed=$MOVED — rebuild and re-verify the bundle before deletion" >&2
独立クローンの退役準備:スクリプトは詳細な拒否リスト(ダーティ/未追跡/ignoredバイト、stash、reflog限定コミット、クローン固有の到達不能オブジェクト、リンクされたworktree、ローカルsubmodule、partial/promisorクローン、Git LFS/annexオブジェクトストア、追跡コンテンツフィルタ、`include.path`/`hooksPath` の間接参照、浅いクローン)を検証し、全通過時のみ証拠を固定します。
# It refuses to certify a clone that still has working-tree bytes, ignored files,
書き込み権限範囲の厳格な制限:バックアップディレクトリは絶対パスかつ未存在(上書き拒否)であり、対象クローンおよび存続リポジトリの双方の外側になければなりません。スクリプト自体がチェックアウトを移動・削除したりrefを変更することはありません。
"$CLONE/"*|"$SURVIVOR/"*) die "backup directory must be outside both repositories" ;;
ワークフロー規律を「成果契約(Outcome contract)+ 権限境界」としてプロンプトに定義:証拠の範囲 ≠ アクションの範囲、権限付与はリポジトリ単位ではなくオブジェクト単位、保全フェーズと退役フェーズの分離、完了基準はbundle数やチェックサムではなくユーザー側で観測可能な事実(コミットがリモートに存在、ブランチ/worktreeの状態が適正など)に準拠します。
- **Evidence scope is not action scope.** A read-only audit may discover another clone, ref,
スクリプト一覧表で「変更の有無」(読み取り専用 / リモート追跡refのみ更新 / ref追加のみ / バックアップファイル書き出しのみ)を明記し、全ヘルパーにおいてcheckout、reset、push、stash drop、branch -d、gcの実行権限を不許可と宣言します。
the helpers authorizes `checkout`, `reset`, `push`, `stash drop`, `branch -d`, or `gc`.
2コア機能
3外部依存関係
| Kind | Dependency / Endpoint |
|---|---|
| cli | git(含 worktree/fsck/reflog/bundle/merge-tree/update-ref/for-each-ref 等) |
| cli | git ≥ 2.38(merge-tree --write-tree 是内容级判定的前提) |
| cli | uv(仅维护者跑回归测试时用到) |
| cli | sha256sum / shasum(bundle 指纹;缺失即报错) |
| cli | tar(打包 config/hooks/info 元数据) |
| cli | stat(跨 BSD/GNU 的 mtime 与文件模式读取) |
| cli | lsof(macOS 上探测 clone 是否仍被进程占用;仅文档步骤,不在脚本内) |
| network | git fetch(由脚本执行;对远端主机发起出站连接,可能触发宿主 git 凭证助手) |
| network | git fetch --all --prune(合并判定脚本执行,同一出站面) |
| network | git push(仅文本指导:把 backup 分支推到 origin 做三重备份;无脚本执行) |
| package | 无第三方包(Git + 标准 Bash 即可;测试仅用 Python 标准库 unittest/tempfile/subprocess) |
4推奨統制措置と判定根拠
- 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>/`
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結論
b2b944f8a078459b…