feat(gitflow): delete a branch only after a verified merge, main/develop undeletable

Since BDR-095 `start` sets an auto-pushed upstream, so `git branch -d`
checked "merged into origin/<branch>" (always true, the post-commit hook
keeps it in sync) instead of "merged into develop". T22a proves it: an
unmerged feature with its upstream in sync is deleted by `-d` alone.

- `gitflow_delete` is the single delete path (finish + CLI `delete`):
  refuses main/develop (rc 6) and any branch that is not an ancestor of
  develop or main (rc 5, `gitflow_merged_into_base`, fail closed when
  neither base exists), then `-d` as a second layer. CLI `merged`, `hooks`.
- Fourth generated hook `reference-transaction`: in the `prepared` call,
  a deletion of refs/heads/main or refs/heads/develop exits 1, whatever
  issued it (branch -d/-D, update-ref -d, rename, script, sub-agent).
  `git config gitflow.protect false` opts a foreign clone out.
- `GITFLOW_HOOKS` is the one hook list: write/emit/reconcile, T19d and
  doctor.sh (`gitflow.sh hooks`) read it. `.githooks/` and `githooks/`
  regenerated with the fourth hook.
- settings.json: static deny on hand `git branch -d/--delete/-dr/-rd` and
  on renames of main/develop; hard_deny "Branch deletion by hand"; the
  Disarming entry covers all four hooks and `gitflow.*` config; the
  protected-branches environment line states the rule.
- Doctrine (CLAUDE.global.md gitflow section), gitflow SKILL (`delete`
  op, rc 5/6 rows, common mistake), guard-bash spec T8w flips to deny,
  SETTINGS.md, README, CHANGELOG.
- Tests: T22 (12) lib guard incl. the premise proof, T23 (11) hook;
  T19 covers the fourth hook. 152/154, the 2 failures are the
  pre-existing T16a (gitleaks absent on this host).
This commit is contained in:
bastien
2026-09-24 11:35:01 +02:00
parent 72d4662289
commit 32d8f981df
12 changed files with 228 additions and 34 deletions
+1 -1
View File
@@ -177,7 +177,7 @@ deny T8s 'git stash drop'
deny T8t 'cd x && git push -f'
allow T8u 'git push -u origin feature/x'
allow T8v 'git push'
allow T8w 'git branch -d x'
deny T8w 'git branch -d x' # only gitflow.sh delete/finish: -d checks the upstream, not develop
allow T8x 'git stash'
allow T8y 'git stash pop'
allow T8z 'git reset --soft HEAD~1'