{"record":{"id":"affd6914969b4f03","repo":"plandex-ai/plandex","slug":"conflict-popping-git-stash-s","errorCode":null,"errorMessage":"conflict popping git stash: %s","messagePattern":"conflict popping git stash: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/git.go","lineNumber":142,"sourceCode":"\nfunc GitStashPop(forceOverwrite bool) error {\n\tgitMutex.Lock()\n\tdefer gitMutex.Unlock()\n\n\tres, err := exec.Command(\"git\", \"stash\", \"pop\").CombinedOutput()\n\n\t// we should no longer have conflicts since we are forcing an update before\n\t// running the 'apply' command as well as resetting any files with uncommitted change\n\t// still leaving this though in case something goes wrong\n\n\tif err != nil {\n\t\tlog.Println(\"Error popping git stash:\", string(res))\n\n\t\tif strings.Contains(string(res), PopStashConflictMsg) {\n\t\t\tlog.Println(\"Conflicts detected\")\n\n\t\t\tif !forceOverwrite {\n\t\t\t\treturn fmt.Errorf(\"conflict popping git stash: %s\", string(res))\n\t\t\t}\n\n\t\t\t// Parse the output to find which files have conflicts\n\t\t\tconflictFiles := parseConflictFiles(string(res))\n\n\t\t\tlog.Println(\"Conflicting files:\", conflictFiles)\n\n\t\t\tfor _, file := range conflictFiles {\n\t\t\t\t// Reset each conflicting file individually\n\t\t\t\tcheckoutRes, err := exec.Command(\"git\", \"checkout\", \"--ours\", file).CombinedOutput()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error resetting file %s: %v\", file, string(checkoutRes))\n\t\t\t\t}\n\t\t\t}\n\t\t\tdropRes, err := exec.Command(\"git\", \"stash\", \"drop\").CombinedOutput()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error dropping git stash: %v\", string(dropRes))\n\t\t\t}","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/git.go#L124-L160","documentation":"GitStashPop detects a merge conflict when applying the stash — git's output contains the marker 'overwritten by merge' (PopStashConflictMsg). When forceOverwrite is false, the function refuses to resolve conflicts itself and returns this error with git's raw output instead. The caller must decide whether to retry with forceOverwrite=true.","triggerScenarios":"Calling GitStashPop(false) after GitStashCreate when tracked files changed between stash and pop such that applying the stash would overwrite local modifications — i.e. git reports 'Your local changes to the following files would be overwritten by merge'.","commonSituations":"Files modified externally (editor, build tooling, another process) between stash and pop; applying a stash created before a rewind/update operation onto changed working tree; concurrent agents editing the same checkout.","solutions":["If overwriting local changes is acceptable, call GitStashPop(true) to force-resolve with `git checkout --ours` per conflicted file.","Inspect the git output in the error to see which files conflict.","Manually commit or discard the interfering local changes, then pop again.","Re-run the operation that expects a clean tree (e.g. GitClearUncommittedChanges) before popping.","If the stash content is no longer needed, `git stash drop` instead of popping."],"exampleFix":"// before\nerr := lib.GitStashPop(false)\n// after: force-resolve conflicts by taking current tree\nerr := lib.GitStashPop(true)","handlingStrategy":"fallback","validationCode":"// Go: minimize conflict window by restoring/updating the tree right before pop\nif dirty, _ := lib.CheckUncommittedChanges(); dirty {\n    lib.GitClearUncommittedChanges()\n}","typeGuard":"func isStashConflict(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"conflict popping git stash\")\n}","tryCatchPattern":"if err := lib.GitStashPop(false); err != nil {\n    if isStashConflict(err) {\n        // escalate: caller decides whether local changes may be clobbered\n        if allowOverwrite {\n            err = lib.GitStashPop(true)\n        }\n    }\n}","preventionTips":["Avoid external writes to the working tree between GitStashCreate and GitStashPop.","Call GitClearUncommittedChanges before pop when the tree is expected clean.","Make forceOverwrite an explicit user decision, not a silent default.","Keep git versions consistent across environments, since conflict detection relies on output text matching."],"tags":["git","stash","conflict","go"],"backgroundTag":"git-stash-conflict","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}