Files
obsidian-vault/family/documents/vault-sync/2026-09-26-syncthing-clone-origin-url-flip.md
T

106 lines
6.6 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [vault, git, syncthing, incident]
date: 2026-09-26
---
# 2026-09-26 — Флип `origin` у клона `/obsidian-syncthing` (Syncthing переписал `.git/config`)
## Симптом
Первый за всю историю лога (21646 строк) провал fetch в тике 09:40:31:
```
[2026-09-26 09:40:31] [syncthing] Fetch failed (origin offline?) — skipping merge/push
[2026-09-26 09:40:31] [taiga-vault] Pushed ✓
[2026-09-26 09:40:31] [syncthing-out] Fetch failed (origin offline?) — skipping merge/push
```
Тик завершался `exit 0` (graceful skip в `sync-vault-lib.sh`), поэтому cron-задача
рапортовала «успех», хотя **фазы 1 и 3 не выполнялись вообще**:
- фаза 1 (`syncthing`): правки с телефона коммитились локально, но не доезжали до bare;
- фаза 3 (`syncthing-out`): правки агента/Eagle не доезжали до клона → и дальше по
Syncthing не уходили на телефон.
Состояние на момент обнаружения: bare и `/vault` = `5c939ed8`, `/obsidian-syncthing`
= `66d4d626` (отстал на один коммит Eagle), `git status --porcelain` пуст в обоих,
маркеров конфликта 0. Данные не потеряны — git идемпотентен, отставание догоняется
одним прогоном.
## Причина
`remote.origin.url` клона `/obsidian-syncthing` оказался
```
/mnt/RED_2TB/storage/git/obsidian-vault.git
```
— **хост-путь, которого в контейнере hermes-taiga нет** (`/mnt` пуст, mount-ов на
`/mnt/RED_2TB` нет; bare смонтирован как `/vault.git`). Проба вручную:
```
$ git -C /obsidian-syncthing fetch origin main
fatal: '/mnt/RED_2TB/storage/git/obsidian-vault.git' does not appear to be a git repository
```
До 09:35:33 фаза 1 успешно фетчила и мерджила (`reflog` клона: `merge origin/main:
Fast-forward` в 09:06, 09:12, 09:25, 09:35), а **в 09:36:19 файл `.git/config` был
перезаписан** — `mtime == ctime == 2026-09-26 09:36:19`, владелец uid 950 (наши git-процессы
в контейнере пишут файлы клона как root: `index`, `ORIG_HEAD`, `refs/remotes/origin/main`
— `root`, а сам `config` — `950:950`, `-rw-rw----`). Значит записал **внешний процесс,
а не наш контейнер**.
Это тот же механизм, что и `.sync-conflict`-файлы внутри `.git` (от 2026-05-29:
`config.sync-conflict-…`, `index.sync-conflict-…`, `FETCH_HEAD.sync-conflict-…`):
**каталог `.git` клона `/obsidian-syncthing` сам синкается Syncthing'ом с других
устройств**. Старая конфликт-копия конфига (2026-05-15) содержит совсем другой remote —
телефонный:
```
[remote "origin"] url = https://git.mallexxx.duckdns.org/git_admin/obsidian-vault.git
[user] name = alex phone S25
```
То есть у клона периодически «прилетает» `origin` с чужого устройства, и внутри
контейнера этот адрес не резолвится. Сегодня прилетел хост-путь.
## Что сделано (Taiga, 2026-09-26 09:42–09:43 UTC)
1. Клону вернули контейнерно-корректный remote: `origin = file:///vault.git`
(тот же bare, что и у `/vault`).
2. В `/opt/data/sync-vault.sh` добавлен **идемпотентный guard** (рядом с блоками
`safe.directory` и git identity) — он выполняется в начале каждого тика:
- если `remote.origin.url` клона ≠ `file:///vault.git` → `git remote set-url origin file:///vault.git`;
- в глобальный конфиг (`/root/.gitconfig`) добавляется правило перезаписи
`url."file:///vault.git".insteadOf` для обоих известных чужих адресов
(хост-путь `/mnt/RED_2TB/storage/git/obsidian-vault.git` и Gitea-URL
`https://git.mallexxx.duckdns.org/git_admin/obsidian-vault.git`) — на случай,
если Syncthing перепишет конфиг **посреди** тика, уже после guard'а.
Побочных эффектов нет: других репозиториев, использующих эти два адреса, в
контейнере нет (проверено `grep` по git-конфигам).
## Проверка (после правки)
- `bash -n /opt/data/sync-vault.sh` → syntax OK;
- три прогона, все `exit 0`, `Pushed ✓` ×3, новых `Fetch failed` нет (в логе остались
только 4 исторические строки тика 09:40);
- три SHA равны: `bare` = `/vault` = `/obsidian-syncthing` = `3edbddf5`;
- `git status --porcelain` пуст в обоих клонах, маркеров конфликта 0, `Push failed` 0;
- idempotency guard'а: два прогона подряд → правила `insteadOf` не дублируются (2 шт.);
- функциональный тест перезаписи: временный клон с `origin = /mnt/RED_2TB/storage/git/obsidian-vault.git`
→ `git fetch origin main` проходит (**REWRITE_OK**), т.е. даже чужой адрес теперь
разрешается в локальный bare.
## Осталось за владельцем (Taiga молча не делает)
- **Корень класса** — `.git` клона `/obsidian-syncthing` синкается Syncthing'ом между
устройствами (отсюда и `.sync-conflict-*` внутри `.git`, и флип remote'а). Правильное
лечение — исключить `.git/` из синка этого folder'а на стороне Syncthing
(`.stignore` в корне folder'а или в конфиге демона). Это правка чужой инфраструктуры,
решение Алексея. Пока guard в `sync-vault.sh` держит fetch рабочим независимо от
содержимого `.git/config`.
- Конфиги `/root/.gitconfig` и `/opt/data/sync-vault.sh` живут в контейнере:
скрипт персистентен (`/opt/data` = ZFS), глобальный конфиг — нет, но он
пересоздаётся при каждом тике самим скриптом.