xai-org/grok-build · error · anyhow::Error

local '{target_branch}' has diverged from origin; resolve be

Error message

local '{target_branch}' has diverged from origin; resolve before publishing: {}

What it means

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.

Source

Thrown at crates/codegen/xai-grok-workspace/src/session/git.rs:3263

    );
    let (fetched, _) = git_cli_raw(
        git_root,
        &["fetch", "origin", "--end-of-options", target_branch],
    )
    .await?;
    checkout_branch(git_root, target_branch, false).await?;
    if fetched
        && !git_cli_raw(
            git_root,
            &["merge-base", "--is-ancestor", "FETCH_HEAD", "HEAD"],
        )
        .await?
        .0
    {
        let (ff, ff_out) = git_cli_raw(git_root, &["merge", "--ff-only", "FETCH_HEAD"]).await?;
        if !ff {
            let _ = checkout_branch(git_root, conv_branch, false).await;
            anyhow::bail!(
                "local '{target_branch}' has diverged from origin; resolve before publishing: {}",
                scrub_git_output(&ff_out)
            );
        }
    }
    if git_cli_raw(
        git_root,
        &["merge-base", "--is-ancestor", conv_branch, "HEAD"],
    )
    .await?
    .0
    {
        let sha = git_cli(git_root, &["rev-parse", "HEAD"]).await?;
        let push_res = push_merged_target_if_requested(git_root, target_branch, push).await;
        checkout_branch(git_root, conv_branch, false).await?;
        push_res?;
        return Ok(GitMergeToMainResult {
            outcome: GitMergeToMainOutcome::UpToDate { sha },

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Rebase or merge origin/target_branch into the local target branch and resolve conflicts, then re-run publish
  2. Reset local target to origin if local-only commits are unwanted: `git branch -f target origin/target` (after confirming)
  3. Coordinate with whoever pushed the divergent commits
  4. Re-run the flow after syncing so the merge becomes a fast-forward

Example fix

// before
publish(git_root, push=true).await?; // diverged -> bail
// after
git fetch origin
git rebase origin/main  # or merge, resolving conflicts
publish(git_root, push=true).await?;
Defensive patterns

Strategy: validation

Validate before calling

std::process::Command::new("git").arg("-C").arg(git_root).args(["fetch","origin"]).output()?;
let behind = std::process::Command::new("git").arg("-C").arg(git_root)
    .args(["rev-list","--count",&format!("{}..origin/{}","main","main")]).output()?;
if behind.stdout.trim() != "0" { anyhow::bail!("local main is behind/diverged; sync first"); }

Type guard

fn ff_possible(local: &str, remote: &str) -> bool {
    // merge-base(local, remote) == local rev-parse implies fast-forward
    true // compute via git merge-base in practice
}

Try / catch

match merge_to_main(git_root, session_branch, push).await {
    Err(e) if e.to_string().contains("has diverged from origin") => {
        // rebase/merge origin/<target> locally, resolve, then re-run
        git_cli(git_root, &["fetch","origin"]).await?;
        return Err(e.context("resolve divergence then retry publish"));
    }
    other => other,
}

Prevention

When it happens

Trigger: 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).

Common situations: Teammate merged directly to main while a session was in progress; remote branch rebased/force-pushed; local publish ran against a stale fetch.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/b02ed7cce699bd12. Report an issue: GitHub.