環境情報
- Git: 2.43.0
- OS: Ubuntu 22.04 LTS / macOS 14.5
- GUI: Fork 2.x, SourceTree 4.x, VS Code 1.90
- バッチ: Python 3.11 + cron / systemd timer
- 保存形式: Parquet / CSV / SQLite
- データ量: 1晩あたり 200MB、数晩で 1GB 超
- 元の保存先:
<worktree>/data/(.gitignore済み) - 移行後:
/var/lib/myapp/dataまたは$MYAPP_DATA_DIR
結論
-
.gitignoreは「Git 管理から外す」だけで「削除から守る」ではない。 - worktree 削除はディレクトリを丸ごと消す。ignored ファイルは警告に出ないことがある。
- 削除前に
git status --ignoredとgit log origin/main..HEADを見る。 - データはリポジトリ外の固定パスに置き、環境変数で上書き可能にする。
- リポジトリ内に置きたいなら symlink を使い、実体を外に出す。
何が起きたか
夜間バッチで集めたデータを、git worktree 内の data/ に置いていました。data/ は .gitignore 済みです。GUI で作業済みワークツリーを削除した瞬間、データごと消えました。
盲点は「Git の管理外=削除対象」です。削除確認には「未コミットの変更なし」としか出ず、ignored ファイルが消えるとは示されません。数晩分の収集が一度で飛びました。
再現手順
- worktree を作成する。
git worktree add ../worktrees/collector -b feature/collector
cd ../worktrees/collector
mkdir data
echo '/data/' >> .gitignore
- 夜間バッチが
data/に出力する。
python collect.py --out data/$(date +%F).parquet
- 状態を確認する。
git statusではクリーンに見える。
git status
# On branch feature/collector
# nothing to commit, working tree clean
git status --ignored --short
# !! data/
- GUI で worktree を削除する。
data/も消える。ダイアログは「未コミットの変更なし」だけ。
なぜ見落とすのか
git status は ignored を表示しません。git clean -ndx も ignored を削除候補に出します。worktree は別ディレクトリなので、削除はそのディレクトリの rm -rf に近い動きになります。
削除前に見るべきコマンド
# ignored を含む全ファイル
git status --ignored --short
# ignored ファイルだけを一覧
git ls-files --others --ignored --exclude-standard
# サイズも確認
git ls-files --others --ignored --exclude-standard -z \
| xargs -0 -r du -sh
# main に未マージのコミット数
git rev-list --count origin/main..HEAD
# 未マージコミット一覧
git log --oneline --decorate origin/main..HEAD
特に git ls-files --others --ignored --exclude-standard は、.gitignore で隠れたデータを明示できます。data/ が出たら削除前に退避します。
安全な削除ラッパー
#!/usr/bin/env bash
set -euo pipefail
MAIN_REPO="/path/to/main-repo"
WT="$1"
if [ ! -d "$WT" ]; then
echo "worktree not found: $WT" >&2
exit 1
fi
ignored="$(git -C "$WT" ls-files --others --ignored --exclude-standard || true)"
if [ -n "$ignored" ]; then
echo "WARNING: ignored files exist in $WT" >&2
echo "$ignored" | sed 's/^/ /' >&2
if [ "${ALLOW_IGNORED_DELETE:-0}" != "1" ]; then
echo "Set ALLOW_IGNORED_DELETE=1 to delete anyway." >&2
exit 2
fi
fi
unmerged="$(git -C "$WT" rev-list --count origin/main..HEAD || echo 0)"
if [ "$unmerged" -gt 0 ]; then
echo "WARNING: $unmerged commits are not merged into origin/main" >&2
git -C "$WT" log --oneline origin/main..HEAD >&2
if [ "${ALLOW_UNMERGED_DELETE:-0}" != "1" ]; then
exit 3
fi
fi
git -C "$MAIN_REPO" worktree remove --force "$WT"
データをリポジトリ外に移す
export MYAPP_DATA_DIR="${MYAPP_DATA_DIR:-/var/lib/myapp/data}"
mkdir -p "$MYAPP_DATA_DIR/collector"
python collect.py --out "$MYAPP_DATA_DIR/collector/$(date +%F).parquet"
cron なら次のようにします。
MYAPP_DATA_DIR=/var/lib/myapp/data
0 2 * * * MYAPP_DATA_DIR=$MYAPP_DATA_DIR /opt/myapp/collect.sh
systemd なら次のようにします。
[Service]
Environment=MYAPP_DATA_DIR=/var/lib/myapp/data
ExecStart=/opt/myapp/collect.sh
この設計なら worktree を消してもデータは残ります。
リポジトリ内のパスを維持したい場合
実体を外に置き、worktree 内は symlink にします。
mkdir -p /var/lib/myapp/data
ln -s /var/lib/myapp/data ./data
echo '/data' >> .gitignore
worktree 削除で消えるのは symlink だけです。ただし git clean -fdx やバックアップツールが symlink 先を追う場合があるので注意します。
削除方法ごとの危険度
| 方法 | tracked 変更 | untracked | ignored | 危険度 |
|---|---|---|---|---|
git status だけ見て GUI 削除 |
警告 | 警告あり | 警告なしの可能性 | 高 |
git worktree remove |
拒否 | 拒否 | バージョン依存 | 中 |
git worktree remove --force |
無視 | 無視 | 削除 | 高 |
rm -rf <worktree> |
無視 | 無視 | 削除 | 最高 |
| リポジトリ外保存 + 削除前チェック | 影響なし | 影響なし | 影響なし | 低 |
ハマりポイント
-
.gitignoreに入れたから安全、は誤り。管理外は削除対象。 -
git statusがクリーンでも ignored が存在する。 - GUI の確認ダイアログは ignored を表示しない製品がある。
-
git clean -fdxは ignored も削除する。-nで必ず予行演習する。 - worktree の削除は main repo 側から実行する。worktree 内から
git worktree remove .はできない。 -
origin/main..HEADは main 未マージ確認。リモート名がupstreamなら読み替える。
FAQ
Q. .gitignore に入れれば削除されない?
A. されないとは言えない。Git 管理外なので、worktree 削除や rm -rf では普通に消える。
Q. git status でクリーンなのに?
A. ignored はデフォルト非表示。git status --ignored を使う。
Q. 消したデータは Git から復元できる?
A. できない。Git 管理外だから。OS のゴミ箱、Time Machine、クラウドバックアップ、ディスク復元ツールを確認する。ただし確実性は低い。
Q. データをリポジトリ内に置きたい。
A. symlink か bind mount で実体を外に出す。CI では artifact や object storage に逃がす。
Q. 削除前チェックを自動化するには?
A. 上記ラッパーを git wt-safe-remove として alias 化し、GUI 削除の代わりにそれを使う。CI では git status --ignored --porcelain を検査する。
まとめ
作業ディレクトリを消す前に、Git が無視しているファイルの中身を確認する。削除前チェックでは、まず git status --ignored、次に git ls-files --others --ignored --exclude-standard、最後に origin/main..HEAD を見る。データはリポジトリ外の固定パスに置き、環境変数で上書き可能にする。これで数晩分の取得データが一瞬で飛ぶ事故を防げる。
この記事を書いた人
BENTEN Web Works — 業務自動化・システム開発のフリーランスエンジニアです。
GAS / Python / RPA を使った業務自動化や、Web制作・システム開発のご相談を承っています。
「こんなこと自動化できる?」というご質問だけでもお気軽にどうぞ。
👉 業務自動化サービス — 詳細・お問い合わせはこちら
🐦 X(旧Twitter) — 日々の知見を発信中