# Git-гигиена после мержа PR (форк → апстрим) > Создан 2026-09-29. Извлечено из уборки после мержа `baldaworks/balda#8` + > `normahq/runtime#4/#5/#7`. > Связано: [[personal/plans/balda-mm-pr-plan]], [[personal/plans/balda-runtime-rebuild-mm-validation]], > [[personal/tech/balda-go-fx-pitfalls]]. --- ## 1. Порядок операций (он обязателен) ``` worktree remove --force → worktree prune → branch -D → push origin --delete → remote prune ``` Перестановка шагов = падение. Подробности ниже. ```bash cd git checkout main && git pull --no-rebase main # merge, НЕ rebase git worktree list # 🔴 СНАЧАЛА посмотреть git worktree remove --force && git worktree prune git branch -D git push origin --delete git remote prune origin && git remote prune upstream git status --short # ?? — untracked, разобрать отдельно ``` 📌 `AGENTS.md` Балды: **синхронизация общих веток — через `merge` (`git pull --no-rebase`), не rebase.** --- ## 2. 🔴 Питфолл: git-регистрация worktree ≠ путь на диске Самый дорогой сюрприз. `git worktree list` показывает **пути, которых уже нет**: ``` /private/tmp/balda-mm-pr8-review 06b2b8d0 (detached HEAD) ← каталог снесён из /tmp ``` `.git/worktrees/` остаётся жить. Такая регистрация **держит ветку**, и удаление падает даже при отсутствующем каталоге: ``` error: cannot delete branch 'fix/openai-tool-call-roundtrip-v2' used by worktree at '/Users/admin/Developer/runtime-local' # ← это про ТЕКУЩИЙ worktree, не про мёртвый ``` Из двух провалов в одной сессии: - `codex/mattermost-prod-fix` — держал мёртвый `/private/tmp/balda-mm-pr8-prod-fix`; - `fix/openai-tool-call-roundtrip-v2` — держал **активный** worktree, где я стоял сам. **Лечение:** `git worktree remove --force ` (работает и для несуществующего каталога — просто убирает регистрацию) → `git worktree prune` → и только потом `git branch -D`. ⚠️ **Проверять `git worktree list` ДО удаления веток.** Иначе получишь список «неудаляемых» веток и будешь думать, что они не смержены. ⚠️ `git worktree remove` на `/private/tmp/...` **уходит на апрув** — это удаление каталога, а не безобидная мета-операция. Нормально, просто ожидаемо. 📌 Ещё: `git checkout main` **невозможен**, пока стоишь в worktree удаляемой ветки — отсюда второй `cannot delete branch ... used by worktree` в логе. --- ## 3. ⚠️ `git pull origin main` → `Already up to date` — это НЕ «всё чисто» После мержа PR в апстрим **ветка форка остаётся на старом коммите**, а мерж живёт только в `upstream/main`. `origin` (форк) мержа не содержит вообще. ```bash git pull --no-rebase origin main # → Already up to date ← вводит в заблуждение git log --oneline -1 upstream/main # ← здесь правда git merge-base --is-ancestor upstream/main && echo MERGED # ← доказательство ``` **Как доказывать факт мержа** (не по доке, а фактически): ```bash gh api repos//pulls/ --jq '{merged, merge_commit_sha, head_sha, base_sha}' git merge-base --is-ancestor upstream/main && echo YES || echo NO ``` Чтобы догнать апстрим локально — `git merge upstream/main` (не rebase). --- ## 4. `git branch -r --merged upstream/main` = список веток под снос Один вызов отвечает «какие ветки уже в апстриме»: ```bash git branch -r --merged upstream/main ``` ⚠️ В списке появятся ветки, которые **не твои** (`upstream/feature/*`, `upstream/docs/*`) — их не трогать. Смотреть на `origin/*` (свой форк). --- ## 5. Что не трогать | Объект | Почему | |---|---| | `__dolt_remote_info__` | служебная ветка апстрима (Dolt), появляется в fetch, восстановится сама | | untracked рабочие инструменты (`tools/*.py`, `deltas-*.json`) | не в git, значит и не «мусор». Проверять `git ls-files tools/` — пусто ≠ удалить | | файлы вне PR, нужные для локальной сборки | `go.mod`, `Dockerfile.release`, `go.sum`, `app.go`, `preflight.go` — `checkout -- .`/`stash`/`reset --hard` их снесёт | ## 6. Stash `git stash list` — перед любым решением выгружать содержимое, а не удалять вслепую: ```bash git stash show --name-only stash@{N} git stash show -p stash@{N} > /path/patch.diff # восстановимо после drop ``` `git stash drop` — **только с явного подтверждения**. Дата в сообщении stash (`whale-20260623`) говорит, как давно он лежит; старый stash обычно надо сначала прочитать, потом решать. --- ## 7. 📌 Реакция Alex: бэкап не предлагать Предложение «сделать бэкап веток перед сносом» получило резкий отказ. **Смерженный код восстанавливается из апстрима — бэкапить нечего.** Бэкап в этом контексте = лишний шаг, который читается как неуверенность. | Предлагать бэкап | НЕ предлагать | |---|---| | Продовые конфиги, БД, данные без копии | Смерженные git-ветки | | Хостовые файлы вне git | Worktree-регистрации в `/tmp` | | `navidrome.db` (правило: согласовывать КАЖДЫЙ раз) | untracked-мусор на смерженных коммитах | Формулировать так: «ветка смержена в `upstream/main` (`bf4a6ae4`), сношу» — без слова «бэкап». --- ## 8. Проверка результата ```bash git worktree list # только рабочий каталог git branch -a # main + remotes, без дев-веток git status --short # пусто или объяснимые untracked ```