Community研究&データ分析github.com

config-file-versioning(設定ファイル自動バージョン管理)

ローカルの設定ファイルを Git + OSファイル監視で自動バージョン管理する、AIコーディングエージェント(Claude Code、Codex、Gemini CLIなど)向けのドロップインスキル。

config-file-versioning(設定ファイル自動バージョン管理) とは?

このスキルは、小規模で重要、かつ「静かに上書きされたくない」ローカル設定ファイル(dotfilesなど)を自動的にバージョン管理するためのものです。指定されたファイルの実際の内容が変更されると、10秒以内に自動でGitコミットが作成され、ローカルの独立したGitリポジトリ(separate-git-dir)に保存されます。ユーザーはいつでも過去の任意のバージョンにワンクリックでロールバックできます。対応プラットフォームはmacOS(launchd WatchPaths)、Linux(systemd path unit)、その他(fswatch、gitwatch、inotifywait)です。設計の特徴は、設定ドメインごとに独立したリポジトリ、ホワイトリスト型.gitignore、イベント駆動監視+スロットル(デフォルト10秒)、commit時の差分チェックによる無駄なコミット防止です。バックアップルートディレクトリは自己完結型で、スクリプト、サービス定義ファイル、READMEをすべて含むため、ディレクトリごとコピーすれば新しいマシンで容易に復元できます。秘密情報を含む設定を誤ってリモートにプッシュしないよう、あえてプッシュ操作は行いません。

対応✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add dragon-fish/config-file-versioning

Installed? Explore more 研究&データ分析 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Skill: Config File Versioning

「小規模+重要+知らないうちに上書きされたくない」ローカル設定ファイルを自動バージョン管理します。

監視対象ファイルの実際の内容が変化するたび、10 秒以内に自動で git commit が作成され、ローカルの独立した git リポジトリ(separate-git-dir)に保存されます。ワンクリックで任意の過去バージョンにロールバックできます。


使用タイミング

ユーザーが以下のトリガーシグナルのいずれかを発した場合に本スキルを使用します:

  • 「<某ファイル> に自動バージョン管理/バックアップ/上書き防止を追加して」
  • 「いつかまた某プログラムが私の <某 dotfile> を上書きしそうで心配」
  • 「<某 config> が変更されたら自動 commit して」
  • 「<既存のバックアップディレクトリ> を参考にして、<他のファイル> もバックアップして」
  • ユーザーが重要な config をツールや手作業で上書き・消失した経験を話し、今後どう防ぐか質問している

適用外のケース:

  • 大規模コードリポジトリ(通常の git workflow で十分)
  • マシン間の同期(本スキルはローカルバージョン履歴のみ。同期が必要な場合は syncthing または手動 git push でプライベートリモートへ)
  • 頻繁かつ高速に変化するファイル(.bash_history、history.jsonl など。大量の commit が発生する)

アーキテクチャ概要

   <保護対象ファイル>           (実際のパス、例 ~/.ssh/config)
        │ 変更
        ▼
   OS レベルファイル監視
   ┌──────────────────────────────┬──────────────────────┬─────────┐
   │ macOS: launchd WatchPaths    │ Linux: systemd .path │ その他  │
   └──────────────────────────────┴──────────────────────┴─────────┘
        │ トリガー(10秒スロットル後)
        ▼
   auto-commit.sh
        │ git add -A → staged diff が空でない場合のみ commit
        ▼
   <BACKUP_ROOT>/<DOMAIN>-config.git/   ← 実際の git repo(separate-git-dir)
        ▲
        │ worktree ルートの ".git"(1行の gitdir: テキスト)で接続

主要な設計ポイント:

設計理由
設定ドメインごとに独立したリポジトリ(1つの大リポジトリにまとめない)履歴がクリーン;独立して有効化/無効化/移行可能
separate-git-dirworktree 全体がプログラムに削除されても、履歴は <BACKUP_ROOT> に残る
ホワイトリスト .gitignore(* + !<保護対象ファイル>)同じディレクトリ内のランタイムデータ/キャッシュ/一時ファイルを誤って取り込まない
イベント駆動監視+スロットル(デフォルト10秒)通常時は常駐プロセスなし;1回の書き込みで複数 commit が発生するのを防ぐ
commit スクリプト内で git diff --cached --quiet チェック内容に実際の変更がない場合(mtime のみ変更)は静かに終了

実装手順

手順 0:ユーザーと 4 つの変数を確認する

変数意味推奨デフォルト値
<DOMAIN>設定ドメインの短縮名(小文字英数字とハイフンのみ;ディレクトリ名/ラベルサフィックスとして使用)ユーザーと相談;例:ssh / zsh / vscode / claude
<WORKTREE>保護対象ファイルが存在するディレクトリの絶対パス(git worktree ルート)通常は監視対象ファイルがあるディレクトリ
<FILES>監視する絶対パスのリスト(1つ以上)ユーザーが指定
<BACKUP_ROOT>リポジトリ+スクリプト+サービス定義テンプレートの格納先ルートディレクトリ必ずユーザーに確認:デフォルト案は ~/.local/share/config-versioning/<DOMAIN>/(XDG データディレクトリ規約);ユーザーがすでに専用のバックアップ/同期ディレクトリ(~/Documents/backups/、~/Sync/...、自分用サンドボックスなど)を持っている場合は、ユーザーに決定してもらう

手順 1:データディレクトリを作成し、git リポジトリを初期化する

mkdir -p "<BACKUP_ROOT>"

mkdir -p "<WORKTREE>"
cd "<WORKTREE>" && git init -q -b main

手順 2:ホワイトリスト .gitignore を作成する

templates/gitignore-whitelist を <WORKTREE>/.gitignore にコピーし、<FILES> の各アイテムについて <WORKTREE> からの相対パスを !<相対パス> の形で 1 行ずつ追加します。

例:worktree=~/.ssh、保護対象が ~/.ssh/config と ~/.ssh/known_hosts の場合:

!config
!known_hosts

手順 3:初期コミットを作成する

cd "<WORKTREE>"
git add -A
git commit -q -m "chore: initial snapshot of <DOMAIN> config"

-c user.name/-c user.email で強制上書きしないこと。ユーザーのグローバル git 設定を使わせる。リポジトリは純粋にローカルで、プッシュもしないため、コミッター情報は重要ではない。

手順 4:.git ディレクトリを <BACKUP_ROOT> に移動し、gitdir ポインタを残す

GITDIR="<BACKUP_ROOT>/<DOMAIN>-config.git"
mv "<WORKTREE>/.git" "$GITDIR"
echo "gitdir: $GITDIR" > "<WORKTREE>/.git"
git -C "$GITDIR" config core.worktree "<WORKTREE>"

手順 5:auto-commit スクリプトをコピーして書き換える

templates/auto-commit.sh を <BACKUP_ROOT>/auto-commit.sh にコピーし、2 つのプレースホルダを置き換えます:

プレースホルダ置き換え先
__WORKTREE__<WORKTREE> の絶対パス
__LOG__ログファイルパス。推奨:macOS は ~/Library/Logs/config-file-versioning.log、Linux は ~/.local/state/config-file-versioning.log

chmod +x を実行します。

手順 6:監視層をインストールする(OS 別)

6a. macOS(launchd LaunchAgent)

templates/launchagent.plist をコピーし、プレースホルダを置き換えます:

プレースホルダ置き換え先
__LABEL__local.<USER>.<DOMAIN>-config-watch(local. プレフィックスで競合防止;<USER> は $USER を使用)
__SCRIPT_PATH__<BACKUP_ROOT>/auto-commit.sh の絶対パス
__WATCH_PATHS__<FILES> の各ファイルを <string>...</string> で囲み、全体を <array> で包む
__LOG__手順 5 と同じ

2 か所に書き込みます(ディレクトリ移行のため):

  1. <BACKUP_ROOT>/<LABEL>.plist(バックアップテンプレート)
  2. ~/Library/LaunchAgents/<LABEL>.plist(実際に動作させるもの)

ロード:

launchctl unload "$HOME/Library/LaunchAgents/<LABEL>.plist" 2>/dev/null
launchctl load   "$HOME/Library/LaunchAgents/<LABEL>.plist"
launchctl list | grep "<LABEL>"   # 登録確認

6b. Linux(systemd path unit)

templates/systemd.path と templates/systemd.service を ~/.config/systemd/user/ にコピーし、<DOMAIN>-config-watch.path および <DOMAIN>-config-watch.service にリネームします。ファイル内のプレースホルダを置き換えた後:

systemctl --user daemon-reload
systemctl --user enable --now <DOMAIN>-config-watch.path

6c. その他 / フォールバック

「監視 + コマンド実行」ができる任意のツールで OK:

  • gitwatch(クロスプラットフォームシェル):brew install gitwatch または apt install gitwatch
  • fswatch + 手動デーモン:fswatch <FILES> | xargs -n1 <BACKUP_ROOT>/auto-commit.sh
  • inotifywait(Linux)+ shell ループ

watcher プロセスは対応プラットフォームのサービス管理機能(OpenRC、runit、launchd、systemd)で管理します。

手順 7:エンドツーエンドテスト(必須、スキップ不可)

監視対象ファイルを変更し、スロットル間隔より 2 秒長く待って、ログと git log にそれぞれ 1 件追加されたことを確認します。まず一時フィールドを追加し、その後削除すると、2 つの commit が生成されるはずです:

# 例:JSON ファイルに一時キー _autoCommitTest を追加
# sleep 12(スロットル = 10s の場合)
tail -2 "<LOG>"
git -C "<WORKTREE>" log --oneline | head -3

手順 8:README を書く

各 <BACKUP_ROOT> には README.md を配置し、将来の移行に備えます。最低限以下の内容を含めます:

  • 目的(なぜこの仕組みがあるのか)
  • ファイル一覧表
  • 日常コマンド(履歴参照、ロールバック、watcher 状態確認、ログ確認)
  • メンテナンス(新しい監視ファイルの追加、スロットル間隔の変更)
  • 新しいマシンでの再構築手順
  • 完全なアンインストール手順

アンチパターン(明確に避けるべきこと)

❌ 間違ったやり方✅ 正しいやり方
複数の config ドメインを 1 つの git リポジトリに詰め込むドメインごとに 1 リポジトリ
.git を worktree 内に残す<BACKUP_ROOT> に移動し、gitdir ポインタを使用
ブラックリスト型 .gitignoreホワイトリスト型 .gitignore
エンドツーエンドテストをスキップして納品必ず実施し、commit が実際に生成されることを確認
plist/service ユニットをシステムディレクトリにのみ配置し、<BACKUP_ROOT> にテンプレートを残さない両方に配置し、ディレクトリが自己完結で移行可能であることを保証
commit 時に公開リモートにプッシュする禁止——設定にはトークンや機密情報が含まれる可能性がある。純粋にローカルリポジトリ
auto-commit.sh に git user.name/email をハードコードするgit のグローバル設定に任せる。スクリプトに個人情報を含めない
KeepAlive=true で fswatch を常駐させるイベント駆動(WatchPaths / .path unit)を優先。常駐プロセスは不要

エッジケースの処理

  • worktree ディレクトリが存在しない場合:先に mkdir -p する。初回の場合、監視対象ファイル自体も存在しない可能性がある——空ファイルを先に作成するかどうか確認する。
  • 監視対象ファイルがシンボリックリンクの場合:watcher でリンクパスとリンク先の実パスの両方を監視し、書き込み方法によって一方がトリガーされない問題を防ぐ。
  • 監視対象ファイルがバイナリの場合:動作はする(git は blob として保存)が、diff では内容を確認できない。
  • 同じ Label/サービスがすでに存在する場合:先に旧設定を unload/disable してから新しいものをロードする。
  • スロットル期間内に複数回書き込みがあった場合:スロットルウィンドウ内の複数変更は 1 回のコミットにまとめられる(意図した動作)。
  • アトミック書き込み(write-temp + rename):launchd WatchPaths は通常正しくトリガーする。特定のプログラムの書き込み方法で commit 漏れが発生する場合は、KeepAlive + gitwatch/fswatch メインループの利用をユーザーに提案する。

テンプレートファイル


設計哲学

  1. 可視 + 可読 + 手動修正可能:バージョン履歴はテキストベースの git。git を理解していれば誰でも履歴を確認・ロールバックでき、特定の GUI に依存しない。
  2. イベント駆動 ≫ ポーリング:アイドル時の CPU/ディスク消費を削減。
  3. フェイルセーフ:commit スクリプトに副作用なし——cd 失敗、diff 空の場合は静かに終了し、worktree を壊さない。
  4. ディレクトリ自己完結:<BACKUP_ROOT> にはデータ+スクリプト+plist/unit テンプレート+README がすべて含まれており、ディレクトリごとコピーすれば新しいマシンで復元可能。
  5. プッシュしない:機密設定がリモートにアップロードされるのを防止。リモートバックアップが必要な場合は、ファイルレベルのソリューション(Time Machine / Backblaze / 暗号化 syncthing)を使用する。

関連スキル