plandex-ai/plandex · error

error checking out git branch for dir: %s, err: %v, output:

Error message

error checking out git branch for dir: %s, err: %v, output: %s

What it means

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).

Source

Thrown at app/server/db/git.go:455

	cmd := exec.Command("git", "-C", repoDir, "branch", "--show-current")
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("error getting current git branch for dir: %s, err: %v", repoDir, err)
	}

	currentBranch := strings.TrimSpace(out.String())
	log.Printf("[Git] gitCheckoutBranch - currentBranch: %s", currentBranch)

	if currentBranch == branch {
		log.Printf("[Git] gitCheckoutBranch - already on branch %s, skipping", branch)
		return nil
	}

	log.Println("[Git] gitCheckoutBranch - checking out branch:", branch)
	res, err := exec.Command("git", "-C", repoDir, "checkout", branch).CombinedOutput()
	if err != nil {
		return fmt.Errorf("error checking out git branch for dir: %s, err: %v, output: %s", repoDir, err, string(res))
	}
	return nil
}

func gitRewindToSha(repoDir, sha string) error {
	res, err := exec.Command("git", "-C", repoDir, "reset", "--hard", sha).CombinedOutput()
	if err != nil {
		return fmt.Errorf("error executing git reset for dir: %s, sha: %s, err: %v, output: %s", repoDir, sha, err, string(res))
	}

	return nil
}

func getLatestCommit(dir string) (sha, body string, err error) {
	var out bytes.Buffer
	cmd := exec.Command("git", "log", "--pretty=%h@@|@@%at@@|@@%B@>>>@")
	cmd.Dir = dir
	cmd.Stdout = &out

View on GitHub (pinned to e2d772072e)

Solutions

  1. 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").
  2. If the branch is missing, create it first (`git checkout -b <branch>`) or verify the branch name spelling against `git branch --list`.
  3. Remove a stale .git/index.lock after confirming no git process is running, then retry the checkout.
  4. Serialize concurrent checkouts with a repo-level lock (lockRepoDB) and ensure working-tree cleanliness (`git status --porcelain`) before switching branches.

Example fix

// before
res, err := exec.Command("git", "-C", repoDir, "checkout", branch).CombinedOutput()
// after (create-if-missing fallback)
res, err := exec.Command("git", "-C", repoDir, "checkout", branch).CombinedOutput()
if err != nil {
    if strings.Contains(string(res), "did not match") {
        res2, err2 := exec.Command("git", "-C", repoDir, "checkout", "-b", branch).CombinedOutput()
        if err2 != nil {
            return fmt.Errorf("error checking out git branch for dir: %s, err: %v, output: %s", repoDir, err2, string(res2))
        }
        return nil
    }
    return fmt.Errorf("error checking out git branch for dir: %s, err: %v, output: %s", repoDir, err, string(res))
}
Defensive patterns

Strategy: fallback

Validate before calling

out, _ := exec.Command("git", "-C", repoDir, "branch", "--list", branch).Output()
branchExists := len(strings.Fields(string(out))) > 0
if !branchExists {
    // create it: git checkout -b <branch>
}
if dirty, _ := exec.Command("git", "-C", repoDir, "status", "--porcelain").Output(); len(dirty) > 0 {
    // stash or commit before switching branches
}

Try / catch

if err := gitCheckoutBranch(repoDir, branch); err != nil {
    if strings.Contains(err.Error(), "error checking out git branch") {
        log.Printf("checkout failed for %s in %s; git said: %s", branch, repoDir, extractGitOutput(err))
        // fallback: create branch if missing, clear stale index.lock, or abort cleanly
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/584fdb2e8e19078d. Report an issue: GitHub.