重複ファイルを消したフォルダに「墓標ファイル」を置く —— 消したものと実体の所在をその場に残し、書き込み自体も差分で検査した

シリーズ: NASの重複整理
- 前提1: Windows機の
D:\SynologyDriveは NAS と双方向同期していて、D: で消すと NAS からも消えます - 前提2: その中の「仮置き」フォルダから、重複ファイル194件・190.90GiB を7バッチで消しました。この整理作業を「P22」と呼んでいます
- 前提3: 実行は Claude Code、承認は私です。消し方は Synology Driveの双方向同期で190GiBの重複削除を事故ゼロで終えた に書きました
結論: 消したフォルダごとに、テキストを1本置きました
重複を消したフォルダ43か所に、★P22削除済み_ここにあったファイル.txt を1本ずつ置きました。中身は「このフォルダにあったファイル、サイズ、削除日、バッチ、同じ内容の実体がある場所」の一覧です。全部で43本・195行・61,442バイトです。
置いたあと、D: と NAS の両方で「墓標1本の追加」以外の変化が0件であることを確かめています。
なぜ置くのか
重複の削除は「消す側」を消して「残す側」を残します。記録はリポジトリにありますが、1年後にそのフォルダを開くのは、記録の場所を覚えていない私です。
- フォルダを開いたとき、「何かあったはずなのに無い」と分かる
- 無くなったものの実体がどこにあるかが、その場で分かる
- リポジトリを開かなくても、メモ帳で読める
特に困るのは、動画編集ソフトのプロジェクトです。今回、3つの編集プロジェクトの素材が、別の場所にある同じ31本と重複していたので、プロジェクト側の素材を消しました。プロジェクトを開くと素材はオフライン表示になります。墓標には、再リンクすればよい場所が書いてあります。

中身と形式
墓標の中身は、次のような形です(パスはダミーです)。
このフォルダにあったファイルは、P22フェーズ2(D:ドライブ重複排除)で、重複として削除済みです。
同じ内容の実体は、下の各行(ファイル名 | サイズ | 削除日 | バッチ | 残存実体のD:パス)の最後の列の場所にあります。
詳細は P22 の作業リポジトリ、タグ p22-phase2-done を参照してください。
clip_01.mp4 | 212,987,048 バイト | 2026-09-14 | B5 | D:\SynologyDrive\仮置き\動画素材\元データ\clip_01.mp4
clip_02.mp4 | 227,835,720 バイト | 2026-09-14 | B5 | D:\SynologyDrive\仮置き\動画素材\元データ\clip_02.mp4
| 項目 | 決めたこと |
|---|---|
| 文字コード・改行 | UTF-8 BOM付き・CRLF(Windows のメモ帳で文字化けせずに開ける) |
| 冒頭 | 説明3行(何のファイルか、列の意味、詳細の参照先) |
| 本文 | 1行1ファイル。「ファイル名 | サイズ | 削除日 | バッチ | 残存実体のD:パス」 |
| 単位 | 1ディレクトリに1本。消したファイルをディレクトリごとにまとめる |
| 追記 | 特別な事情は末尾に書く(編集プロジェクトの素材なし化と、再リンク先など) |
| 生成元 | バッチの plan と execute の記録だけ。ファイルシステムは再スキャンしない |
| 扱い | 一時的なもの。そのフォルダが実体ごと消えるときに一緒に消える前提。正本はリポジトリ |
生成元を記録だけにしたのは、墓標の内容が「実際に消したもの」と1行もずれないようにするためです。195行(削除194行と、以前のテスト削除1件)が、どれか1本の墓標にちょうど1回ずつ載っていることを、生成物を読み戻して確かめました。
墓標を書くことも「変更」なので、検査した
墓標は新しいファイルを作るだけですが、双方向同期のフォルダへの書き込みです。何かの間違いで既存のファイルを上書きすると、それも NAS に届きます。そこで、削除と同じように、書く前と書いた後を検査しました。
| 段階 | 確かめたこと | 結果 |
|---|---|---|
| dry-run | 書き込み先43か所が D: と NAS に実在する / 同じ名前のファイルがまだ無い / 保護リスト・恒久除外に当たらない | すべて問題なし |
| 本番の直前 | 拒否の経路をわざと1回動かす(後述) | 拒否され、ファイルは作られなかった |
| 書き込み | 新規作成のみ(既存があれば失敗する開き方)。1本ごとに読み戻して SHA256 を照合 | 43/43 |
| 書いた直後 | 前後のファイル一覧を比べ、差分が「墓標1本の追加」だけか | D: 43/43 |
| 同期の後 | NAS 側でも同じ差分検査。抜き取り6本の SHA256 | NAS 43/43、6/6 一致 |
| 最後 | 削除全体の最終突合をもう一度 | PASS |
拒否の経路を、本番の前にわざと1回動かす
書き込みスクリプトは、送られた内容の SHA256 が期待値と違えば書かずに止まります。ただ、この経路は普段は通らないので、本当に止まるのかは試さないと分かりません。
そこで本番の1本目に、わざと間違った SHA256 を付けて送りました。結果は content hash mismatch before write で拒否され、書き込み先にファイルが無いこと(exists=0)を確かめてから、正しい値に戻して本番を続けました。
検査の側が間違えた2件
検査にも不具合がありました。書き込みの結果には影響していません。
| 起きたこと | 原因 | 直し方 |
|---|---|---|
| 書き込みの直後、差分検査が例外で止まった | 空のディレクトリを見分けるための目印行を、通常の行として読んでいた | 書き込みはやり直さず、保存済みの前後の一覧だけから差分を検査し直す機能を足した |
| 直したあと、4か所を「変化あり」と誤検出した | 書き込み先の中のサブディレクトリにも墓標が増え、その更新日時が変わっていた | 「サブディレクトリの日時の変化は、そこ自体が書き込み先のときだけ許す」に絞った |
絞った検査が甘くなっていないかを確かめるため、既存ファイルの削除・サイズの変更・余分な新規ファイル・書き込み先でないサブディレクトリの日時の変化、の4種類をわざと起こして、すべて検出されることも確かめました。

反省: 墓標は削除と同時に置く
今回は、削除がすべて終わってから墓標を作りました。後から作れたのは記録が全部そろっていたからですが、本来は削除のバッチの最後の手順に入れるべきでした。次からは次のようにしています。
- 削除バッチの承認申請に、墓標の書き込み先と件数を明示して含める。明示がない承認では書かない
- 名前にフェーズとバッチを付ける(既存の墓標を上書きしないため)
- フォルダごと消すときは、残る最も近い親フォルダに置き、消えたフォルダのパスと件数・総サイズを書く
- 不要として消すもの(実体がどこにも残らないもの)は、実体の欄に「なし(不要と判断: 承認日・根拠)」と書く
消した記録はリポジトリに残りますが、あとでそのフォルダを開く人が最初に見るのはフォルダの中身なので、消した場所そのものに「何があり、実体はどこにあるか」を書いた1本を置き、その書き込みも削除と同じように検査してください。