nikivdev/code · error
git merge --ff-only {} failed: {}
Error message
git merge --ff-only {} failed: {} What it means
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.
Source
Thrown at src/sync.rs:4049
recorder.record(
stage,
format!("merging {} commits from {}", behind, remote_ref),
);
let ff_only_output = git_run_output_in(repo_root, &["merge", "--ff-only", &remote_ref])?;
if ff_only_output.status.success() {
recorder.record(stage, format!("fast-forwarded to {}", remote_ref));
return Ok(());
}
let ff_only_detail = git_output_text(&ff_only_output);
if is_git_index_lock_error(&ff_only_detail) {
bail!(
"Git index lock detected during merge. Remove stale .git/index.lock (if no git process is running) and re-run."
);
}
if !is_expected_ff_only_merge_failure(&ff_only_detail) {
bail!(
"git merge --ff-only {} failed: {}",
remote_ref,
ff_only_detail
);
}
let merge_output = git_run_output_in(repo_root, &["merge", &remote_ref, "--no-edit"])?;
if merge_output.status.success() {
recorder.record(stage, format!("merged {} with commit", remote_ref));
return Ok(());
}
let merge_detail = git_output_text(&merge_output);
if is_git_index_lock_error(&merge_detail) {
bail!(
"Git index lock detected during merge. Remove stale .git/index.lock (if no git process is running) and re-run."
);
}
View on GitHub (pinned to a747e741ae)
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).
Example fix
// before f sync // error: git merge --ff-only origin/main failed: fatal: Not possible to fast-forward, aborting. // after (integrate divergence explicitly) git pull --rebase origin main f sync
Defensive patterns
Strategy: try-catch
Validate before calling
let local = git_capture(&["rev-parse", "HEAD"])?;
let remote = git_capture(&["rev-parse", "--verify", "origin/main"])?;
let base = git_capture(&["merge-base", "HEAD", "origin/main"])?;
if base.trim() != local.trim() {
eprintln!("Branch diverged from origin/main; ff-only sync will fail or need integration.");
} Try / catch
match sync::run(&repo_root, &cmd) {
Err(e) if e.to_string().starts_with("git merge --ff-only") => {
eprintln!("ff-only merge failed: {} — integrate with rebase/merge first", e);
}
other => other,
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Git index lock detected during merge. Remove stale .git/inde
- sync agent cleared the raw stash conflicts but left the repo
- jj git export retry loop should always return
- Lin.app is not running
- No branches available to search
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/50d9b1e6c78e8010.
Report an issue: GitHub.