{"record":{"id":"d5ab9b11827d0530","repo":"abhigyanpatwari/GitNexus","slug":"source-branch-name-must-not-be-head","errorCode":null,"errorMessage":"${source}: branch name must not be \"HEAD\".","messagePattern":"(.+?): branch name must not be \"HEAD\"\\.","errorType":"validation","errorClass":"InvalidBranchError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/git-ref.ts","lineNumber":86,"sourceCode":"  // git ref-name rules (subset): reject characters git itself forbids in refs.\n  if (/[~^:?*[\\\\]/.test(trimmed)) {\n    throw new InvalidBranchError(\n      `${source}: branch name contains characters not allowed in a git ref (~ ^ : ? * [ \\\\).`,\n    );\n  }\n  if (trimmed.startsWith('-')) {\n    throw new InvalidBranchError(`${source}: branch name must not start with \"-\".`);\n  }\n  // Force-refspec prefix (`git fetch origin +main` / `+refs/heads/main:…`).\n  // Rejected here so neither the CLI nor HTTP can pass a force-update refspec\n  // through as a \"branch\" (#3199 review, defense in depth).\n  if (trimmed.startsWith('+')) {\n    throw new InvalidBranchError(`${source}: branch name must not start with \"+\".`);\n  }\n  // The symbolic ref HEAD (case-sensitive). A repo can have a branch named\n  // `head`; git itself treats only `HEAD` as the current-commit alias.\n  if (trimmed === 'HEAD') {\n    throw new InvalidBranchError(`${source}: branch name must not be \"HEAD\".`);\n  }\n  if (trimmed.includes('..')) {\n    throw new InvalidBranchError(`${source}: branch name must not contain \"..\".`);\n  }\n  // The remaining `git check-ref-format` rules. Without these the validator\n  // accepted refs git itself refuses (`feature.lock`, `/feature`, `feature/`,\n  // `feature//next`, `@`, `.hidden`), so the failure surfaced later from the\n  // git subprocess instead of here. No real branch can violate them — git\n  // could not have created one — so nothing that works today starts failing.\n  if (trimmed.endsWith('.lock') || trimmed.split('/').some((part) => part.endsWith('.lock'))) {\n    throw new InvalidBranchError(`${source}: branch name must not end with \".lock\".`);\n  }\n  if (trimmed.startsWith('/') || trimmed.endsWith('/')) {\n    throw new InvalidBranchError(`${source}: branch name must not start or end with \"/\".`);\n  }\n  if (trimmed.includes('//')) {\n    throw new InvalidBranchError(`${source}: branch name must not contain consecutive slashes.`);\n  }","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/git-ref.ts#L68-L104","documentation":"validateBranchName rejects the literal string 'HEAD' (case-sensitive) because HEAD is git's symbolic ref for the current commit, not a real branch name. Using it as a branch argument would make the library operate on an alias rather than a concrete branch, so it is refused up front. Lower-case 'head' is a legal branch name and is allowed.","triggerScenarios":"Calling validateBranchName with branch='HEAD', e.g. `gitnexus impact --branch HEAD`, or an HTTP call with {\"branch\":\"HEAD\"}.","commonSituations":"Scripts defaulting to `$(git symbolic-ref HEAD)` or the literal 'HEAD'; CI configs passing a HEAD placeholder where the checked-out branch name is expected; users confusing the current-commit alias with a branch.","solutions":["Pass the actual branch name (e.g. read it with `git rev-parse --abbrev-ref HEAD`) instead of the literal 'HEAD'.","If you mean 'whatever is checked out', use the library's default-branch/current-commit option rather than naming HEAD.","For lower-case 'head', no error occurs — verify you did not accidentally capitalize the branch name."],"exampleFix":"// before\nconst branch = \"HEAD\";\nvalidateBranchName(branch);\n// after\nconst branch = execSync(\"git rev-parse --abbrev-ref HEAD\").toString().trim(); // e.g. \"main\"\nvalidateBranchName(branch);","handlingStrategy":"validation","validationCode":"if (typeof branch === \"string\" && branch === \"HEAD\") {\n  branch = execSync(\"git rev-parse --abbrev-ref HEAD\").toString().trim();\n}","typeGuard":"function isConcreteBranch(v: unknown): v is string {\n  return typeof v === \"string\" && v !== \"HEAD\" && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  validateBranchName(branch, \"cli\");\n} catch (e) {\n  if (e instanceof InvalidBranchError && e.message.includes('\"HEAD\"')) {\n    branch = execSync(\"git rev-parse --abbrev-ref HEAD\").toString().trim();\n    validateBranchName(branch, \"cli\");\n  } else throw e;\n}","preventionTips":["Resolve HEAD to a concrete branch name before passing it as a branch parameter.","In CI, capture the checked-out branch via GITHUB_REF_NAME / CI_COMMIT_REF_NAME rather than the literal 'HEAD'.","Remember the check is case-sensitive: 'head' is valid, 'HEAD' is not.","Prefer the library's default/current-commit option when you mean 'whatever is checked out'."],"tags":["git","branch-name","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-09-15T23:29:44.066Z","contentChangedAt":"2026-09-15T23:29:44.066Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}