{"record":{"id":"cfb2127db11b4bc5","repo":"affaan-m/ECC","slug":"git-rebase-failed","errorCode":null,"errorMessage":"git rebase failed: {}{}","messagePattern":"git rebase failed: (.+?)(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":950,"sourceCode":"            .arg(\"-C\")\n            .arg(&worktree.path)\n            .args([\"rebase\", \"--abort\"])\n            .output()\n            .context(\"Failed to abort unsuccessful rebase\")?;\n        let abort_warning = if abort_output.status.success() {\n            String::new()\n        } else {\n            format!(\n                \" (rebase abort warning: {})\",\n                String::from_utf8_lossy(&abort_output.stderr).trim()\n            )\n        };\n        let stderr = format!(\n            \"{}\\n{}\",\n            String::from_utf8_lossy(&output.stdout),\n            String::from_utf8_lossy(&output.stderr)\n        );\n        anyhow::bail!(\"git rebase failed: {}{}\", stderr.trim(), abort_warning);\n    }\n\n    let after_head = branch_head_oid_in_repo(&repo_root, &worktree.branch)?;\n    let rebase_output = format!(\n        \"{}\\n{}\",\n        String::from_utf8_lossy(&output.stdout),\n        String::from_utf8_lossy(&output.stderr)\n    );\n\n    Ok(RebaseOutcome {\n        branch: worktree.branch.clone(),\n        base_branch: worktree.base_branch.clone(),\n        already_up_to_date: before_head == after_head || rebase_output.contains(\"up to date\"),\n    })\n}\n\npub fn branch_head_oid(worktree: &WorktreeInfo, branch: &str) -> Result<String> {\n    let repo_root = base_checkout_path(worktree)?;","sourceCodeStart":932,"sourceCodeEnd":968,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L932-L968","documentation":"Thrown by rebase_onto_base at ecc2/src/worktree/mod.rs:950 when `git -C <worktree.path> rebase <base_branch>` exits non-zero. On failure the code first attempts `git -C <worktree.path> rebase --abort` to leave the worktree in a clean state, captures any abort warning, formats stdout+stderr from the failed rebase, and bails with both pieces. Unlike the merge path, this error always tries to clean up the in-progress rebase before propagating.","triggerScenarios":"Content conflicts between the worktree branch and base_branch during replay; the base branch ref no longer exists or was force-pushed; a rebase hook (post-checkout, pre-rebase) rejected a step; binary/LFS conflicts; the worktree path is locked by another git process.","commonSituations":"Base branch advanced with conflicting changes since the worktree branched off; rebase of a long-lived feature branch with many squashed commits; pre-rebase hook (e.g. branch-protection) returns non-zero; LFS object missing on the base side.","solutions":["Read the formatted stderr in the error message to find conflict paths; if the auto-abort succeeded the worktree is clean — resolve conflicts in a manual rebase (`git -C <worktree_path> rebase <base_branch>`), or pick a different strategy (merge instead).","If the abort also failed (the trailing `(rebase abort warning: ...)` is non-empty), run `git -C <worktree_path> rebase --abort` manually until HEAD stabilizes, then investigate.","Refresh the worktree's view of base_branch first: `git -C <worktree_path> fetch origin <base_branch>` so the rebase target is current.","Fall back to merge_into_base if conflicts are too entangled to rebase cleanly."],"exampleFix":"// before\nlet outcome = rebase_onto_base(&worktree)?;\n\n// after: fall back to merge when rebase conflicts\nlet outcome = match rebase_onto_base(&worktree) {\n    Ok(o) => o,\n    Err(e) => {\n        tracing::warn!(\"rebase failed, falling back to merge: {e}\");\n        // rebase_onto_base already aborted the in-progress rebase\n        merge_into_base(&worktree).map(|m| RebaseOutcome {\n            branch: m.branch,\n            base_branch: m.base_branch,\n            already_up_to_date: m.already_up_to_date,\n        })?\n    }\n};","handlingStrategy":"try-catch","validationCode":"// Ensure base_branch is current and the worktree can see it\nCommand::new(\"git\").arg(\"-C\").arg(&worktree.path)\n    .args([\"fetch\", \"origin\", &worktree.base_branch]).status()?;\nif has_uncommitted_changes(&worktree)? {\n    anyhow::bail!(\"worktree dirty; cannot safely rebase\");\n}","typeGuard":"null","tryCatchPattern":"match rebase_onto_base(&worktree) {\n    Ok(o) => Ok(o),\n    Err(e) if e.to_string().starts_with(\"git rebase failed\") => {\n        // rebase_onto_base already attempted --abort; fall back to a merge\n        tracing::warn!(\"rebase failed, falling back to merge: {e}\");\n        merge_into_base(&worktree).map(|m| RebaseOutcome {\n            branch: m.branch, base_branch: m.base_branch,\n            already_up_to_date: m.already_up_to_date,\n        })\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Fetch base_branch right before rebasing so the target is fresh.","Prefer merge over rebase for long-lived branches to avoid deep conflict replays.","Surface the abort-warning suffix to the user so they know whether the worktree is clean.","Record pre-rebase HEAD so you can detect the rare case where abort itself moved HEAD."],"tags":["git","rebase","conflict","worktree","subprocess-failure"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}