Files
obsidian-vault/family/documents/vault-sync/2026-09-26-commit-skip-pipefail.md
T

5.4 KiB
Executable File
Raw Blame History

title, type, namespace, tags, date
title type namespace tags date
sync-vault-lib.sh — pipefail + grep -q молча пропускал коммиты (492 файла застряли) log family
vault
sync
git
sync-script
pipefail
bug
fixed
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

Две правки в одном месте:

  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