fix(hooks): catch the bypass short flag anywhere in a cluster (#2668)

isCommitNoVerifyShortFlag anchored on the first character, so it only recognised the flag when it led the cluster. Git clusters short options, which means git commit -an is -a plus the bypass flag and skips the hooks. -sn and -vn slip through the same way, while -na and -nm are caught — the difference is position, not intent.

Scanning now walks the cluster and stops at a value-taking option, since that option swallows the rest as its inline value. The n in -mn stays message text, and the existing -tn case keeps working.

Adds 4 tests: the three clustered forms that were escaping, plus -mn to pin the inline-value boundary. Verified the three fail against current main. Suite 25 to 29.

Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
This commit is contained in:
Peopleoftech
2026-08-04 17:08:56 -04:00
committed by GitHub
co-authored by haelyra
parent f235549cb8
commit a8c6da485d
2 changed files with 41 additions and 1 deletions
+19 -1
View File
@@ -248,7 +248,25 @@ function getCommitShortValueOption(value) {
}
function isCommitNoVerifyShortFlag(value) {
return value === '-n' || /^-n[a-zA-Z]/.test(value);
if (!value.startsWith('-') || value.startsWith('--') || value === '-') {
return false;
}
// Short options cluster, so -n need not lead: `git commit -an` is -a plus -n
// and bypasses the hooks just as `-n` does. Anchoring on the first character
// let -an, -sn and -vn through.
//
// Scanning stops at a value-taking option because that option swallows the
// rest of the cluster as its inline value — the n in `-mn` is message text,
// not a flag.
const options = value.slice(1);
for (let i = 0; i < options.length; i++) {
const option = options.charAt(i);
if (option === 'n') return true;
if (COMMIT_SHORT_OPTIONS_WITH_VALUE.has(option)) return false;
}
return false;
}
/**