5.4 KiB
Executable File
title, type, namespace, tags, date
| title | type | namespace | tags | date | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| sync-vault-lib.sh — pipefail + grep -q молча пропускал коммиты (492 файла застряли) | log | family |
|
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:
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 файлов — ложным.
Доказательство (воспроизведение):
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)
Фикс
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
Две правки в одном месте:
- условие через
$( )вместо| grep -q— нет пайпа, нет SIGPIPE; - сообщение коммита собирается одним
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— fliporiginв клоне (guard уже вшит)2026-09-26-syncthing-clone-root-objects-acl-confusion.md— root-объекты и ACL (разбор другой сессии, решения за Alex): там же симптом «документ не доехал до телефона»2026-09-26-mode-flip-644-755.md— откуда берутся100644 → 100755family/how-to/vault-git-sync.md, skillvault-sync-infrastructure