Obsidian の保管場所(Google ドライブ)でノートが 1,400 個以上に増えた話 ― 原因の調べ方・片付け・再発に気づく仕組み
メモやプロジェクトの記録は Obsidian で書き、保管場所(Vault)は Google ドライブに置いて、MacBook 2台と Mac mini で共有しています。ある日 Obsidian を開くと、「コメントデータベース仕様書 (1) (1) (1) (1) …」という名前のノートが大量に並んでいました。数えてみると、1つのノートが同期の衝突で 1,400 個以上に増えていました。その原因の調べ方と片付け、再発にすぐ気づくための仕組みをまとめます。
何が起きていたか

- 1つのフォルダの中に、「コメントデータベース仕様書 (1) (1) (1) …」という名前のファイルが 1,404 個(1台目の Mac から見えた数)
- 名前に付いた「(1)」は 49〜51 個。いちばん長い名前は 249 文字で、ファイル名の長さの上限(255)の手前で止まっていた
- 中身はすべて同じ。作られた日時も、すべて同じ 1 秒の中
- 「(1)」が付いていない、本来のファイルは無くなっていて、ほかのノートからのリンクが切れていた
原因(推定)
Google ドライブ(パソコン版)は、同じ場所に同じ名前のファイルがぶつかると、片方の名前に「 (1)」を付けて別のファイルとして残します。これ自体は、データを失わないための正しい動きです。
ところが今回は、「(1)」を付けたファイルがまた別のファイルとぶつかり、さらに「(1)」を付けるという動きが一瞬で何百回も繰り返されたようです。名前が長くなりすぎてそれ以上付けられなくなったところで、ようやく止まったと考えています。
起きた時刻は、2台の Mac で同じプロジェクトのノートを同時に編集していた時間帯でした。はっきりした引き金は分かっていませんが、同じ保管場所を複数の端末から同時に書き換えたことが関係していそうです。
調べ方
ファイルが 1,000 個を超えると、Finder や Obsidian の画面で眺めても全体がつかめません。小さな Python のスクリプトで、次の3点を数えました。
import os, hashlib, collections, datetime
d = "保管場所/03_Projects/対象のフォルダ"
dups = [n for n in os.listdir(d) if "(1)" in n]
h = lambda p: hashlib.sha256(open(p, "rb").read()).hexdigest()[:12]
print(len(dups), "個")
print("中身の種類:", collections.Counter(h(os.path.join(d, n)) for n in dups))
print("作られた日時:", collections.Counter(
datetime.datetime.fromtimestamp(os.stat(os.path.join(d, n)).st_birthtime).strftime("%m-%d %H:%M:%S") for n in dups))
- 中身のハッシュ(指紋)が 1 種類だけ → すべて同じ内容のコピーで、どれか1つを残せば失うものはない
- 作られた日時がすべて同じ → 誰かが作ったのではなく、同期の処理が一度に作った
- Google ドライブのフォルダでは
lsが空を返すことがありました。Python のos.listdirのほうが確実でした
片付けでつまずいたこと
方針は「1つだけ本来の名前に戻して残し、残りはゴミ箱へ」です。Google ドライブ側でも、削除したファイルはゴミ箱に約30日残るので、いざとなれば戻せます。ところが、すんなりとはいきませんでした。
1. 同じ名前なのに一致しない(文字の形の違い)
最初に「コメントデータベース仕様書 (1)」で始まるファイルを探したら、1,404 個のうち 481 個しか見つかりませんでした。原因は、濁点の付いた文字(デ・ベなど)の内部の表し方が2種類混ざっていたことです。「デ」を1文字で表す形(NFC)と、「テ」+「゛」の2文字で表す形(NFD)があり、Mac のファイル名では後者になることがあります。見た目は同じでも、プログラムで比べると別の文字列になります。
import unicodedata
name = unicodedata.normalize("NFC", n) # 比べる前に形をそろえる
2. 消したはずのコピーが後から現れる
全部片付けたはずが、数分後にまた1つ、2つと現れました。作られた日時は同じ(=新しく作られたものではない)なので、クラウド側にあったコピーが、手元の一覧に遅れて出てきたようです。しばらくのあいだ、30秒ごとに「中身が同じコピーが現れたらゴミ箱へ移す」小さなループを動かして対処しました。
3. 別の Mac からは、まだたくさん見える
別の Mac から同じフォルダを見ると、まだ 600 個以上のコピーが見えていました。これは、その Mac の Google ドライブが削除を反映し終わっていないためで、時間とともに数が減っていきました。あわせて、その Mac で動いていた ToDo の取り込みのスクリプトが、一覧に出たのに開けないファイルで止まっていたことも分かりました(開けないファイルは飛ばすように修正)。
再発にすぐ気づく仕組み
同期の衝突そのものは Google ドライブ側の動きなので、完全には防げません。そこで「起きたらすぐ気づく」ことにしました。
もともと、家のサーバーが 15 分ごとに Mac mini から Obsidian の ToDo を受け取り、自宅のトップページに表示する仕組みがあります。その受け取るデータに、保管場所の健康状態を加えました。
import os, re, unicodedata
from pathlib import Path
# 「名前 (1).md」「名前 (1) (1).md」「名前 2.md」、途中で切れた「名前 (1) (1 417.md」
COPY_RE = re.compile(r" (d+)| (d+ d+$| d$")
def vault_health(vault):
copies, empty, long_names = [], [], []
for root, dirs, files in os.walk(vault):
dirs[:] = [d for d in dirs if not d.startswith(".")] # .obsidian などは除く
for f in files:
name = unicodedata.normalize("NFC", f) # 文字の形をそろえる
if COPY_RE.search(Path(name).stem): copies.append(name)
if len(name) > 150: long_names.append(name)
try:
if name.endswith(".md") and os.path.getsize(os.path.join(root, f)) == 0:
empty.append(name)
except FileNotFoundError: # 同期中に消えたファイル
pass
return {"copies": len(copies), "empty": len(empty), "long_names": len(long_names)}
- 衝突のコピー:「 (1)」「 2」が付いた名前
- 空のノート:0 バイトの .md。同期の競合でノートの中身が消えることがあるため
- 長すぎる名前:今回のように「(1)」が積み重なった名前
- 保管場所全体(約 1,500 ファイル)を調べても 0.3 秒ほどで終わるので、15 分ごとに動かしても負担にならない
どれかが 1 つでも見つかると、トップページの ToDo の上に赤い警告が出ます。

実際、仕組みを入れた直後に、別の Mac から見えていた 600 個以上のコピーを検出しました。今回のような増え方をしても、15 分以内に気づけます。
後日談:同じ日のうちに、また 20 個現れた
片付けてから半日ほどたったころ、同じフォルダに「コメントデータベース仕様書 (1) (1) …」がまた並んでいるのに気づきました。今度は Mac 2台から 20 個、もう1台からは一時 29 個見えていました。
- 20 個とも大きさは同じ 12,650 バイト、作られた日時も前回と同じ「10/29 23:35:56」
- 中身のハッシュも、残しておいた本来のノートと同じ
- 本来のノートは無事で、リンクも切れていない
つまり新しく衝突が起きたのではなく、前回の一団のうち、クラウド側に残っていたものが何時間も遅れて手元に現れたようです。「数分見張れば終わり」ではなかったことになります。前回と同じく、中身が同じことを確かめてからゴミ箱へ移し、その後 10 分間見張りました。今回は新たに現れたコピーは 0 個で、ほかの Mac 2台からも 0 個に見えることを確かめました。
もう1つ気づいたのは、中身を読んで比べる処理が、Google ドライブの読み込み待ちで止まることがある点です。ファイルの一覧は見えていても、中身がまだ手元に届いていないと、読み込みがいつまでも終わりません。今回は、処理に時間の上限(timeout)を付けてやり直しました。
timeout 150 python3 check_copies.py # 150 秒で打ち切る
片付けたのに、トップページの警告が消えない
片付けが終わった後も、トップページには赤い警告が出たままでした。調べると、理由は2つありました。
- 表示していたのが、片付ける前の点検結果だった。点検の結果をサーバーに取り込むのは 15 分ごとで、しかも点検をしているのは片付けた Mac とは別の Mac です。片付けがその Mac に同期で届くまでの時間も加わり、しばらく古い結果が出続けていました
- 衝突ではないファイルを、衝突として数えていた。Obsidian で新しいキャンバスを続けて作ると、2つ目は「無題のファイル 1.canvas」という名前になります。点検は名前の「 1」で衝突を見分けていたため、空のキャンバスを衝突のコピーと数えていました
そこで、次のように直しました。
- 点検結果の取り込みを 15 分ごとから 5 分ごとに(点検は 0.3 秒ほどで終わるので、負担はほとんどありません)
- 警告に「何時の点検結果か」を表示。古い結果が出ているのかどうかが、ひと目で分かるようにした
- 中身が空の「無題のファイル」(キャンバス2つと Base 1つ)はゴミ箱へ。名前を付けないまま放置しないのも、保管場所のルールにしています
# crontab(点検結果を受け取る間隔)
*/5 * * * * $HOME/bin/fetch_todo.sh # 変更前は */15
今回も、片付けた Mac からの削除がほかの Mac に届くまでに数分以上かかりました。点検を別の Mac で行う以上、同期が届くまでの遅れは残ります。警告に点検の時刻が出ていれば、「まだ届いていないだけ」と判断できます。
起こりにくくするために
- 同じノートを、2台の端末で同時に編集しない。特に、AI のアシスタントなど自動でノートを書き換えるものを複数の端末で同時に動かすときは注意
- 書き込む前に、ファイルの大きさを確認する(0 バイトになっていないか)
- 同期の仕組みを見直すのも手です。Obsidian 公式の同期サービス(Obsidian Sync、有料)は保管場所専用なので、この種の衝突が起きにくいとされています。Google ドライブのまま使うなら、保管場所のフォルダだけを「ミラーリング」(ファイルを常に Mac に保存しておく方式)にする方法もあります
このノートは、AI のアシスタント(Claude Code・Codex など)が作業の記録を書き込むことが多い場所です。そこで、どの AI ツールも読む共通のルールのファイル(AGENTS.md)に、次のルールを足しました。
- 1つのノートを書き換えるのは、同時に1か所(1台・1ツール)だけ。他の端末で同じプロジェクトを扱っているときは、追記だけにする
- Obsidian が起動している端末では、Obsidian を通して書く(書き込みの窓口を1つにそろえる)
- ファイルの作成・名前の変更・移動・削除を、短い間に繰り返さない。たくさんのファイルを作る処理は保管場所の外で行い、最後に1回だけ入れる
- 書き込みの前後に「 (1)」付きのコピーや 0 バイトのファイルが無いか確かめ、見つけたら作業を止めて知らせる(AI が自分の判断で消さない)
- 読み込み待ちで止まったら、同じ操作を繰り返さない
AI ツールで共通のルールを1つのファイルにまとめた方法は、こちらの記事に書きました。
まとめ
- Google ドライブの「(1)」を付けて残す動きが繰り返され、1つのノートが 1,400 個以上に増えた
- 片付けでは、中身のハッシュで同じものか確かめる・文字の形(NFC/NFD)をそろえて比べる・遅れて現れるコピーに備える、の3つが大事だった
- 完全には防げないので、15 分ごとの点検とトップページの警告で「すぐ気づく」ようにした
- 片付けた後も、クラウドに残ったコピーが何時間も遅れて現れることがある。中身を比べる処理には時間の上限を付ける
- AI ツールにも「同時に書き換えない」「コピーを見つけたら止まる」ルールを持たせた
- 警告には点検の時刻を出す。古い結果なのか、まだ問題があるのかを見分けられる
クラウドの同期はとても便利ですが、たまにこういうことが起きます。大事なノートほど、どこか別の場所にもバックアップを取っておくと安心です。
