From 0daf3ae63056d8adc654aeaef279ff1add1362b9 Mon Sep 17 00:00:00 2001 From: Taiga Date: Sat, 26 Sep 2026 09:55:33 +0000 Subject: [PATCH] [2026-09-26 09:55:33] taiga-vault: family/how-to/vault-git-sync.md family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md --- .../2026-09-26-commit-skip-pipefail.md | 101 ++++++++++++++++++ family/how-to/vault-git-sync.md | 10 ++ 2 files changed, 111 insertions(+) create mode 100644 family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md diff --git a/family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md b/family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md new file mode 100644 index 00000000..e68094b4 --- /dev/null +++ b/family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md @@ -0,0 +1,101 @@ +--- +title: sync-vault-lib.sh — pipefail + grep -q молча пропускал коммиты (492 файла застряли) +type: log +namespace: family +tags: [vault, sync, git, sync-script, pipefail, bug, fixed] +date: 2026-09-26 +--- + +# `git status --porcelain | grep -q .` под `set -o pipefail` = коммиты молча не создаются + +**Когда:** 2026-09-26 09:53 UTC, найдено и починено в cron-тике Taiga. +**Статус:** **фикс применён** (`/opt/data/sync-vault-lib.sh`), синк проверен. + +## Симптом + +Каждый тик печатал `Pushed ✓` ×3 и `Already up to date.`, exit 0, три SHA равны — +но рабочий каталог `/obsidian-syncthing` **не очищался**, и в нём накопилось +**492 изменения**, включая реальную правку пользователя: + +- 491 файл — смена режима `100644 → 100755` (класс «mode-flip», см. + `2026-09-26-mode-flip-644-755.md`), включая папки `personal/` 199, `family/` 166, `work/` 108; +- `personal/plans/music-tags-review/1-needs-decision.md` — 4 чекбокса `- [ ]` → `- [x]` + (пользователь отмечал разобранные треки, вероятно с телефона). + +То есть правки телефона **не доезжали до bare**, пока в клоне было мало изменений — +коммит делался; как только изменений становилось много, коммит перестал создаваться вообще. + +## Причина + +В `/opt/data/sync-vault-lib.sh`: + +```bash +set -euo pipefail +... +if git status --porcelain | grep -q .; then # ← вот это + git add -A 2>/dev/null || true + ... + git commit ... || true +else + true # ← «нечего коммитить», молча +fi +``` + +`grep -q` выходит сразу после первого совпадения. При большом выводе `git status` +(492 записи ≈ **23 КБ**) он продолжает писать в уже закрытый pipe, получает `SIGPIPE`, +и **`pipefail` объявляет весь pipeline упавшим (exit 141)**. `if` уходит в `else` — +ветка коммита не выполняется вообще. Ошибка полностью безмолвная: stderr у +`add`/`commit` погашен, `Pushed ✓` печатается как ни в чём не бывало. + +Порог — размер вывода: у коммита из 2 файлов (09:44:37) условие было истинным, +у 492 файлов — ложным. + +**Доказательство (воспроизведение):** + +```bash +cd /obsidian-syncthing +bash -c 'set -euo pipefail; if git status --porcelain | grep -q .; then echo IF=TRUE; else echo IF=FALSE; fi' +# → IF=FALSE (492 записи) +bash -c 'set -eu; if git status --porcelain | grep -q .; then echo IF=TRUE; else echo IF=FALSE; fi' +# → IF=TRUE (то же состояние, без pipefail) +``` + +## Фикс + +```bash +STATUS="$(git status --porcelain 2>/dev/null || true)" # подстановка не даёт SIGPIPE +if [ -n "$STATUS" ]; then + git add -A 2>/dev/null || true + MSG="$(printf '%s\n' "$STATUS" | awk 'NF{n++; if(n<=25) printf "%s ", $2} END{if(n>25) printf "(... +%d more)", n-25}' || true)" + git commit -m "[$STAMP] $LABEL: $MSG" 2>/dev/null || true +fi +``` + +Две правки в одном месте: + +1. **условие** через `$( )` вместо `| grep -q` — нет пайпа, нет SIGPIPE; +2. **сообщение коммита** собирается одним `awk` (читает вход целиком) — раньше при массовом + flip в сообщение и в `/tmp/vault-sync.log` попадали все ~500 путей; теперь первые 25 + `(... +N more)`. + ⚠️ Не заменять на `awk ... | head -25 | tr ...`: `head` рвёт пайп, `awk` получает SIGPIPE, + подстановка падает под `set -e` — тик завершается `exit 141` (проверено, первая версия фикса + так и падала). + +## Проверка после фикса + +``` +синк: exit 0, Pushed ✓ ×3 +bare = /vault = /obsidian-syncthing = 041885fa +git status --porcelain пуст в обоих клонах, маркеров конфликта 0 +Push failed 0, Fetch failed 4 (все исторические, тик 09:40 до origin-guard) +safe.directory 3 записи (без дублей), insteadOf 2 (без дублей) +коммит 12a7566e: 492 файла, сообщение "... (+467 more)" +чекбоксы [x] в bare HEAD и в /vault = 8 → правка телефона доехала +``` + +## Связанное + +- `2026-09-26-syncthing-clone-origin-url-flip.md` — flip `origin` в клоне (guard уже вшит) +- `2026-09-26-syncthing-clone-root-objects-acl-confusion.md` — root-объекты и ACL (разбор + другой сессии, решения за Alex): там же симптом «документ не доехал до телефона» +- `2026-09-26-mode-flip-644-755.md` — откуда берутся `100644 → 100755` +- `family/how-to/vault-git-sync.md`, skill `vault-sync-infrastructure` diff --git a/family/how-to/vault-git-sync.md b/family/how-to/vault-git-sync.md index ec94cfbd..9696aab2 100755 --- a/family/how-to/vault-git-sync.md +++ b/family/how-to/vault-git-sync.md @@ -89,6 +89,16 @@ tags: > > **STATE 2026-09-04:** починена потеря git identity в контейнере Taiga (слетела при рекреации после crashloop 09-02) — коммиты молча не проходили ~1.5 суток, изменения телефона не доезжали до bare. Фикс: `sync-vault.sh` теперь идемпотентно ставит `user.name "Taiga"` / `user.email "taiga@hermes"` при каждом запуске. Накопленное закоммичено (`2b45264`). Подробно: `family/documents/vault-sync/2026-09-04-git-identity-loss-silent-commit-failure.md`. > +> **STATE 2026-09-26 — `pipefail` + `grep -q` молча отменял коммиты в `sync-vault-lib.sh`.** При большом +> числе изменений (492 файла ≈ 23 КБ вывода) `git status --porcelain | grep -q .` падал по `SIGPIPE` +> (grep выходил после первого совпадения, git дописывал в закрытый pipe), `set -o pipefail` объявлял +> pipeline упавшим (exit 141) → ветка `else` → **коммит не создавался вообще**, при этом тик печатал +> `Pushed ✓` ×3 и exit 0. Так застряли 491 mode-flip и правка телефона (`1-needs-decision.md`, 4 чекбокса +> `[x]`). Фикс: условие через `STATUS="$(git status --porcelain)"` + `[ -n "$STATUS" ]`, сообщение +> коммита — одним `awk` (первые 25 путей, дальше `(... +N more)`). ⚠️ `awk | head -25` в подстановке +> даёт тот же SIGPIPE → тик падает с exit 141, так делать нельзя. Проверено: коммит `12a7566e` (492 файла), +> три SHA равны, `git status` пуст. Разбор: `family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md`. +> > **⛔ НОВАЯ проблема 2026-09-02 (не решена):** оба **Taiga-клиента** (`/storage/obsidian` и `/storage/obsidian-syncthing`) **отстали на месяц** — HEAD `ceea848` (2026-08-01) vs bare repo `2fab879` (2026-09-02). Причина: контейнер `hermes-taiga` в **crash-loop** (16339 рестартов) — `uv run hermes gateway run` не может докачать депы (pytz/markdown-it-py) с PyPI, т.к. весь HTTP идёт через **мёртвый `socks5://vless-proxy:1080`**, а `UV_CACHE_DIR=/tmp/uv-cache` пустеет на каждом рестарте. Taiga 3-phase sync (крон внутри агента) не выполняется => телефон видит устаревший vault. Подробно: `family/documents/vault-sync/2026-09-02-hermes-taiga-crashloop.md`. Фикс НЕ применён (ждёт Alex). > **Триггер cron на маке (Eagle) — это launchd, НЕ Hermes cron:** `~/Library/LaunchAgents/com.sync-vault.plist` → `/Users/admin/scripts/sync-vault.sh`, `StartInterval=300` (5 мин). Скрипт `sync-vault-lib.sh` намеренно глушит dead remote (`git fetch` fail → `exit 0`), поэтому launchd показывает `last exit code = 0` даже при фактически стоящем sync. Системный crontab на маке пуст.