fix(gitflow): gitflow_finish validates its named branch against HEAD
gitflow_finish ignored its <type> <name> args and always merged the checked-out branch — `finish bugfix audit-bugs` run from feature/audit-tokens merged the wrong branch (audit UX trap, 2026-07-02). Args are now an optional safety ASSERTION: if present and != current branch, refuse loudly (rc 2) instead of merging the wrong thing. No args = unchanged (the only real caller, SKILL.md:36, passes none). +7 T12 regression assertions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XpphkdTosUzokBDNG7PToS
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
615b21289e
commit
d9fdd4cbdf
@@ -156,6 +156,22 @@ if bash "$HERE/gitflow.sh" protected-base main; then ok "cli protected-bas
|
|||||||
if bash "$HERE/gitflow.sh" protected-base feature/x; then no "cli protected-base feature (rc0?)"; else ok "cli protected-base feature → rc1"; fi
|
if bash "$HERE/gitflow.sh" protected-base feature/x; then no "cli protected-base feature (rc0?)"; else ok "cli protected-base feature → rc1"; fi
|
||||||
chk "cli base-for hotfix=main" '[ "$(bash "$HERE/gitflow.sh" base-for hotfix)" = main ]'
|
chk "cli base-for hotfix=main" '[ "$(bash "$HERE/gitflow.sh" base-for hotfix)" = main ]'
|
||||||
|
|
||||||
|
echo "T12 — finish arg-guard (named branch must equal current, else refuse)"
|
||||||
|
newrepo finargs; echo a>a; hookon; gitflow_init >/dev/null 2>&1
|
||||||
|
gitflow_start feature standon >/dev/null 2>&1; echo w>w.txt; git add w.txt; git commit -q -m w
|
||||||
|
# mismatch: standing on feature/standon but asking to finish bugfix/other → refuse
|
||||||
|
# shellcheck disable=SC2034 # mism_out/mism_rc are used in the deferred chk eval strings
|
||||||
|
mism_out="$(gitflow_finish bugfix other 2>&1)"; mism_rc=$?
|
||||||
|
chk "arg-mismatch → nonzero rc" "[ $mism_rc -ne 0 ]"
|
||||||
|
chk "arg-mismatch → HEAD untouched" '[ "$(git symbolic-ref --short HEAD)" = feature/standon ]'
|
||||||
|
chk "arg-mismatch → branch kept" 'git rev-parse --verify -q refs/heads/feature/standon >/dev/null'
|
||||||
|
chk "arg-mismatch → develop NOT merged" '! git log develop --oneline | grep -q "Merge feature/standon into develop"'
|
||||||
|
chk "arg-mismatch → message names both" 'printf "%s" "$mism_out" | grep -q "current branch" && printf "%s" "$mism_out" | grep -q "bugfix/other"'
|
||||||
|
# match: naming the current branch explicitly finishes exactly like the no-arg path
|
||||||
|
gitflow_finish feature standon >/dev/null 2>&1
|
||||||
|
chk "arg-match → merged into develop" 'git log develop --oneline | grep -q "Merge feature/standon into develop"'
|
||||||
|
chk "arg-match → branch deleted" '! git rev-parse --verify -q refs/heads/feature/standon >/dev/null'
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "==== RESULT: $PASS passed, $FAIL failed ===="
|
echo "==== RESULT: $PASS passed, $FAIL failed ===="
|
||||||
[ "$FAIL" -eq 0 ]
|
[ "$FAIL" -eq 0 ]
|
||||||
|
|||||||
+16
-3
@@ -97,11 +97,24 @@ _gitflow_delete() { # <branch>
|
|||||||
git branch -q -d "$br" || { echo "gitflow: '$br' not fully merged — branch kept" >&2; return 5; }
|
git branch -q -d "$br" || { echo "gitflow: '$br' not fully merged — branch kept" >&2; return 5; }
|
||||||
}
|
}
|
||||||
|
|
||||||
# gitflow_finish → directed merge of the CURRENT branch per its type, then delete.
|
# gitflow_finish [<type> <name>] → directed merge of the CURRENT branch per its
|
||||||
# WHEN to call this is the human gate (SKILL.md). This only performs the merge.
|
# type, then delete. WHEN to call this is the human gate (SKILL.md).
|
||||||
|
#
|
||||||
|
# The merge source is ALWAYS the checked-out branch (HEAD) — that is the contract.
|
||||||
|
# The optional <type> <name> is a SAFETY ASSERTION, not a target selector: if you
|
||||||
|
# name a branch it MUST equal the current one, else finish refuses loudly instead
|
||||||
|
# of silently merging whatever you happen to be standing on. (Guards the audit UX
|
||||||
|
# trap: `finish bugfix audit-bugs` run from feature/audit-tokens merged the wrong
|
||||||
|
# branch — args were silently ignored. See BLK-015 / LRN-089.) No args = unchanged.
|
||||||
gitflow_finish() {
|
gitflow_finish() {
|
||||||
local br type
|
local br type req_type="${1:-}" req_name="${2:-}"
|
||||||
br="$(git symbolic-ref --short -q HEAD)" || { echo "gitflow_finish: detached HEAD" >&2; return 3; }
|
br="$(git symbolic-ref --short -q HEAD)" || { echo "gitflow_finish: detached HEAD" >&2; return 3; }
|
||||||
|
if [ -n "$req_type" ] || [ -n "$req_name" ]; then
|
||||||
|
[ "$req_type/$req_name" = "$br" ] || {
|
||||||
|
echo "gitflow_finish: operates on the current branch '$br', but you asked '$req_type/$req_name' — checkout '$req_type/$req_name' first (or run finish with no args)." >&2
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
fi
|
||||||
type="$(gitflow_branch_type "$br")"
|
type="$(gitflow_branch_type "$br")"
|
||||||
case "$type" in
|
case "$type" in
|
||||||
feature|bugfix|chore)
|
feature|bugfix|chore)
|
||||||
|
|||||||
Reference in New Issue
Block a user