{"record":{"id":"b02ed7cce699bd12","repo":"xai-org/grok-build","slug":"local-target-branch-has-diverged-from-origin","errorCode":null,"errorMessage":"local '{target_branch}' has diverged from origin; resolve before publishing: {}","messagePattern":"local '(.+?)' has diverged from origin; resolve before publishing: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-workspace/src/session/git.rs","lineNumber":3263,"sourceCode":"    );\n    let (fetched, _) = git_cli_raw(\n        git_root,\n        &[\"fetch\", \"origin\", \"--end-of-options\", target_branch],\n    )\n    .await?;\n    checkout_branch(git_root, target_branch, false).await?;\n    if fetched\n        && !git_cli_raw(\n            git_root,\n            &[\"merge-base\", \"--is-ancestor\", \"FETCH_HEAD\", \"HEAD\"],\n        )\n        .await?\n        .0\n    {\n        let (ff, ff_out) = git_cli_raw(git_root, &[\"merge\", \"--ff-only\", \"FETCH_HEAD\"]).await?;\n        if !ff {\n            let _ = checkout_branch(git_root, conv_branch, false).await;\n            anyhow::bail!(\n                \"local '{target_branch}' has diverged from origin; resolve before publishing: {}\",\n                scrub_git_output(&ff_out)\n            );\n        }\n    }\n    if git_cli_raw(\n        git_root,\n        &[\"merge-base\", \"--is-ancestor\", conv_branch, \"HEAD\"],\n    )\n    .await?\n    .0\n    {\n        let sha = git_cli(git_root, &[\"rev-parse\", \"HEAD\"]).await?;\n        let push_res = push_merged_target_if_requested(git_root, target_branch, push).await;\n        checkout_branch(git_root, conv_branch, false).await?;\n        push_res?;\n        return Ok(GitMergeToMainResult {\n            outcome: GitMergeToMainOutcome::UpToDate { sha },","sourceCodeStart":3245,"sourceCodeEnd":3281,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/session/git.rs#L3245-L3281","documentation":"During publish, after fetching origin, a `git merge --ff-only FETCH_HEAD` is attempted to sync the local target branch; if it is not a fast-forward, the local branch has diverged from origin, and the code checks out the session branch and bails so a human resolves the divergence before publishing.","triggerScenarios":"Calling the merge-to-main/publish flow when origin's target branch has commits that the local target branch does not have (e.g. someone else pushed, or the branch was force-updated on the remote).","commonSituations":"Teammate merged directly to main while a session was in progress; remote branch rebased/force-pushed; local publish ran against a stale fetch.","solutions":["Rebase or merge origin/target_branch into the local target branch and resolve conflicts, then re-run publish","Reset local target to origin if local-only commits are unwanted: `git branch -f target origin/target` (after confirming)","Coordinate with whoever pushed the divergent commits","Re-run the flow after syncing so the merge becomes a fast-forward"],"exampleFix":"// before\npublish(git_root, push=true).await?; // diverged -> bail\n// after\ngit fetch origin\ngit rebase origin/main  # or merge, resolving conflicts\npublish(git_root, push=true).await?;","handlingStrategy":"validation","validationCode":"std::process::Command::new(\"git\").arg(\"-C\").arg(git_root).args([\"fetch\",\"origin\"]).output()?;\nlet behind = std::process::Command::new(\"git\").arg(\"-C\").arg(git_root)\n    .args([\"rev-list\",\"--count\",&format!(\"{}..origin/{}\",\"main\",\"main\")]).output()?;\nif behind.stdout.trim() != \"0\" { anyhow::bail!(\"local main is behind/diverged; sync first\"); }","typeGuard":"fn ff_possible(local: &str, remote: &str) -> bool {\n    // merge-base(local, remote) == local rev-parse implies fast-forward\n    true // compute via git merge-base in practice\n}","tryCatchPattern":"match merge_to_main(git_root, session_branch, push).await {\n    Err(e) if e.to_string().contains(\"has diverged from origin\") => {\n        // rebase/merge origin/<target> locally, resolve, then re-run\n        git_cli(git_root, &[\"fetch\",\"origin\"]).await?;\n        return Err(e.context(\"resolve divergence then retry publish\"));\n    }\n    other => other,\n}","preventionTips":["Fetch and check rev-list counts before publishing","Avoid force-pushes to shared target branches","Rebase session work onto target regularly to keep ff possible","Coordinate direct pushes to the target branch with the team"],"tags":["git","merge","diverged","publish"],"backgroundTag":"branch-diverged","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}