forked from bchanot/claude
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:
+12
-8
@@ -199,14 +199,18 @@ apply: the pre-commit hook (blocks code commits on main/develop, exempts
|
||||
`.claude/**` + `.githooks/**` + merges + the root commit) and Gitea branch
|
||||
protection on `main`/`develop`. Don't lean on `--no-verify` to bypass them.
|
||||
Every branch is pushed at `start` and every commit as it lands by the
|
||||
post-commit and post-merge hooks (warn, never block, on failure). The three
|
||||
hooks run in EVERY repo on the machine: `make link` generates `githooks/`
|
||||
from the lib and sets git's global `core.hooksPath` to `~/.claude/githooks`;
|
||||
a repo that ran `gitflow init` keeps its own `.githooks/`, refreshed at
|
||||
session start when it lags the lib. Foreign clone: `git config
|
||||
gitflow.protect false` / `gitflow.autopush false`. `GITFLOW_NO_PUSH=1` is
|
||||
for throwaway test repos only. A branch ahead of its upstream is a defect,
|
||||
not a state.
|
||||
post-commit and post-merge hooks (warn, never block, on failure). A branch
|
||||
is deleted only by `finish` or `gitflow.sh delete <br>`: never `main` or
|
||||
`develop`, never a branch not merged into develop or main (explicit
|
||||
ancestor check; `git branch -d` proves nothing once the branch has an
|
||||
auto-pushed upstream, T22a). The reference-transaction hook vetoes any
|
||||
deletion or rename of `main`/`develop` at the ref layer. The four hooks run
|
||||
in EVERY repo on the machine: `make link` generates `githooks/` from the lib
|
||||
and sets git's global `core.hooksPath` to `~/.claude/githooks`; a repo that
|
||||
ran `gitflow init` keeps its own `.githooks/`, refreshed at session start
|
||||
when it lags the lib. Foreign clone: `git config gitflow.protect false` /
|
||||
`gitflow.autopush false`. `GITFLOW_NO_PUSH=1` is for throwaway test repos
|
||||
only. A branch ahead of its upstream is a defect, not a state.
|
||||
|
||||
## Security — non-negotiable defaults
|
||||
|
||||
|
||||
Reference in New Issue
Block a user