{"record":{"id":"50d9b1e6c78e8010","repo":"nikivdev/code","slug":"git-merge-ff-only-failed","errorCode":null,"errorMessage":"git merge --ff-only {} failed: {}","messagePattern":"git merge --ff-only (.+?) failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/sync.rs","lineNumber":4049,"sourceCode":"    recorder.record(\n        stage,\n        format!(\"merging {} commits from {}\", behind, remote_ref),\n    );\n\n    let ff_only_output = git_run_output_in(repo_root, &[\"merge\", \"--ff-only\", &remote_ref])?;\n    if ff_only_output.status.success() {\n        recorder.record(stage, format!(\"fast-forwarded to {}\", remote_ref));\n        return Ok(());\n    }\n\n    let ff_only_detail = git_output_text(&ff_only_output);\n    if is_git_index_lock_error(&ff_only_detail) {\n        bail!(\n            \"Git index lock detected during merge. Remove stale .git/index.lock (if no git process is running) and re-run.\"\n        );\n    }\n    if !is_expected_ff_only_merge_failure(&ff_only_detail) {\n        bail!(\n            \"git merge --ff-only {} failed: {}\",\n            remote_ref,\n            ff_only_detail\n        );\n    }\n\n    let merge_output = git_run_output_in(repo_root, &[\"merge\", &remote_ref, \"--no-edit\"])?;\n    if merge_output.status.success() {\n        recorder.record(stage, format!(\"merged {} with commit\", remote_ref));\n        return Ok(());\n    }\n    let merge_detail = git_output_text(&merge_output);\n    if is_git_index_lock_error(&merge_detail) {\n        bail!(\n            \"Git index lock detected during merge. Remove stale .git/index.lock (if no git process is running) and re-run.\"\n        );\n    }\n","sourceCodeStart":4031,"sourceCodeEnd":4067,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/sync.rs#L4031-L4067","documentation":"Thrown in src/sync.rs when `git merge --ff-only <remote_ref>` fails with an unexpected error. First the tool checks for an index-lock problem (separate error); if the failure is NOT one of the expected, tolerated ff-only merge outcomes (`is_expected_ff_only_merge_failure`), it bails including the remote ref and the full git output. Expected divergent-history outcomes are handled downstream instead of erroring.","triggerScenarios":"During sync's fast-forward path, `git merge --ff-only <remote_ref>` exits non-zero with output that is neither an index-lock error nor a recognized expected failure — e.g., 'not possible to fast-forward', unborn branch, or detached HEAD oddities outside the expected set.","commonSituations":"Local branch diverged from the remote in a way the tool doesn't classify; the branch checked out is not what sync expects (detached HEAD); upstream history was force-pushed; shallow clone missing objects.","solutions":["Read the git output after the colon — it contains git's own merge failure reason.","If histories diverged, decide: `git pull --rebase` or a real merge, then re-run sync.","Check `git status` / `git rev-parse --abbrev-ref HEAD` — ensure you are on the expected branch, not detached HEAD.","If upstream was force-pushed, fetch and hard-reset deliberately: `git fetch && git reset --hard origin/<branch>` (discards local commits)."],"exampleFix":"// before\nf sync\n// error: git merge --ff-only origin/main failed: fatal: Not possible to fast-forward, aborting.\n\n// after (integrate divergence explicitly)\ngit pull --rebase origin main\nf sync","handlingStrategy":"try-catch","validationCode":"let local = git_capture(&[\"rev-parse\", \"HEAD\"])?;\nlet remote = git_capture(&[\"rev-parse\", \"--verify\", \"origin/main\"])?;\nlet base = git_capture(&[\"merge-base\", \"HEAD\", \"origin/main\"])?;\nif base.trim() != local.trim() {\n    eprintln!(\"Branch diverged from origin/main; ff-only sync will fail or need integration.\");\n}","typeGuard":null,"tryCatchPattern":"match sync::run(&repo_root, &cmd) {\n    Err(e) if e.to_string().starts_with(\"git merge --ff-only\") => {\n        eprintln!(\"ff-only merge failed: {} — integrate with rebase/merge first\", e);\n    }\n    other => other,\n}","preventionTips":["Rebase or merge onto the upstream branch before syncing when histories diverged.","Stay on the expected branch; avoid detached HEAD states before running sync.","Investigate force-pushes promptly (`git log --oneline origin/main -5`) as they break ff assumptions.","Avoid shallow clones for repos where sync fast-forwards are expected."],"tags":["git","merge","fast-forward","diverged-history"],"backgroundTag":"git-merge-ff-only-failed","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}