{"record":{"id":"584fdb2e8e19078d","repo":"plandex-ai/plandex","slug":"error-checking-out-git-branch-for-dir-s-err-v","errorCode":null,"errorMessage":"error checking out git branch for dir: %s, err: %v, output: %s","messagePattern":"error checking out git branch for dir: (.+?), err: (.+?), output: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/git.go","lineNumber":455,"sourceCode":"\tcmd := exec.Command(\"git\", \"-C\", repoDir, \"branch\", \"--show-current\")\n\tcmd.Stdout = &out\n\terr := cmd.Run()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting current git branch for dir: %s, err: %v\", repoDir, err)\n\t}\n\n\tcurrentBranch := strings.TrimSpace(out.String())\n\tlog.Printf(\"[Git] gitCheckoutBranch - currentBranch: %s\", currentBranch)\n\n\tif currentBranch == branch {\n\t\tlog.Printf(\"[Git] gitCheckoutBranch - already on branch %s, skipping\", branch)\n\t\treturn nil\n\t}\n\n\tlog.Println(\"[Git] gitCheckoutBranch - checking out branch:\", branch)\n\tres, err := exec.Command(\"git\", \"-C\", repoDir, \"checkout\", branch).CombinedOutput()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error checking out git branch for dir: %s, err: %v, output: %s\", repoDir, err, string(res))\n\t}\n\treturn nil\n}\n\nfunc gitRewindToSha(repoDir, sha string) error {\n\tres, err := exec.Command(\"git\", \"-C\", repoDir, \"reset\", \"--hard\", sha).CombinedOutput()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error executing git reset for dir: %s, sha: %s, err: %v, output: %s\", repoDir, sha, err, string(res))\n\t}\n\n\treturn nil\n}\n\nfunc getLatestCommit(dir string) (sha, body string, err error) {\n\tvar out bytes.Buffer\n\tcmd := exec.Command(\"git\", \"log\", \"--pretty=%h@@|@@%at@@|@@%B@>>>@\")\n\tcmd.Dir = dir\n\tcmd.Stdout = &out","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/git.go#L437-L473","documentation":"If the requested branch differs from the current one, gitCheckoutBranch runs `git -C repoDir checkout <branch>` and, on failure, wraps both the exec error and git's combined stdout/stderr output in this message. The included git output is the key diagnostic — it usually says exactly why the checkout was refused (unknown branch, dirty conflicts, lock files).","triggerScenarios":"Checking out a branch that does not exist locally (never created), a corrupted or locked repo (index.lock), untracked/modified files conflicting with the target branch, or a bare/invalid repo.","commonSituations":"Requesting a plan branch that was never committed to; interrupted prior git operation leaving index.lock; concurrent processes checking out branches in the same repo without locking; repo on read-only mount.","solutions":["Read the `output:` portion of the message — it contains git's own reason (e.g. \"pathspec 'X' did not match any file(s) known to git\").","If the branch is missing, create it first (`git checkout -b <branch>`) or verify the branch name spelling against `git branch --list`.","Remove a stale .git/index.lock after confirming no git process is running, then retry the checkout.","Serialize concurrent checkouts with a repo-level lock (lockRepoDB) and ensure working-tree cleanliness (`git status --porcelain`) before switching branches."],"exampleFix":"// before\nres, err := exec.Command(\"git\", \"-C\", repoDir, \"checkout\", branch).CombinedOutput()\n// after (create-if-missing fallback)\nres, err := exec.Command(\"git\", \"-C\", repoDir, \"checkout\", branch).CombinedOutput()\nif err != nil {\n    if strings.Contains(string(res), \"did not match\") {\n        res2, err2 := exec.Command(\"git\", \"-C\", repoDir, \"checkout\", \"-b\", branch).CombinedOutput()\n        if err2 != nil {\n            return fmt.Errorf(\"error checking out git branch for dir: %s, err: %v, output: %s\", repoDir, err2, string(res2))\n        }\n        return nil\n    }\n    return fmt.Errorf(\"error checking out git branch for dir: %s, err: %v, output: %s\", repoDir, err, string(res))\n}","handlingStrategy":"fallback","validationCode":"out, _ := exec.Command(\"git\", \"-C\", repoDir, \"branch\", \"--list\", branch).Output()\nbranchExists := len(strings.Fields(string(out))) > 0\nif !branchExists {\n    // create it: git checkout -b <branch>\n}\nif dirty, _ := exec.Command(\"git\", \"-C\", repoDir, \"status\", \"--porcelain\").Output(); len(dirty) > 0 {\n    // stash or commit before switching branches\n}","typeGuard":null,"tryCatchPattern":"if err := gitCheckoutBranch(repoDir, branch); err != nil {\n    if strings.Contains(err.Error(), \"error checking out git branch\") {\n        log.Printf(\"checkout failed for %s in %s; git said: %s\", branch, repoDir, extractGitOutput(err))\n        // fallback: create branch if missing, clear stale index.lock, or abort cleanly\n    }\n}","preventionTips":["Always read the git `output:` embedded in the error — it names the exact refusal reason.","Create plan branches explicitly at plan creation instead of assuming they exist.","Serialize all checkouts on a repo with a lock to avoid racing index files.","Keep the working tree clean (commit/stash) before branch switches.","Remove stale .git/index.lock only when no git process is running."],"tags":["git","branch","checkout"],"backgroundTag":"git-checkout-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}