nikivdev/code · error

Git operation in progress. Run `f git-repair` first.

Error message

Git operation in progress. Run `f git-repair` first.

What it means

ensure_git_not_busy guards destructive/reorganizing operations by checking the git dir for in-progress state: rebase, merge, cherry-pick (CHERRY_PICK_HEAD), revert (REVERT_HEAD), bisect (BISECT_LOG), or unmerged files. If any is present it bails so the wrapper doesn't run jj operations on top of a half-finished git operation.

Source

Thrown at src/jj.rs:3551

        .args(["show-ref", "--verify", name])
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::null())
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

fn ensure_git_not_busy(repo_root: &Path) -> Result<()> {
    let git_dir = git_dir(repo_root)?;
    let rebase = git_dir.join("rebase-merge").exists() || git_dir.join("rebase-apply").exists();
    let merge = git_dir.join("MERGE_HEAD").exists();
    let cherry_pick = git_dir.join("CHERRY_PICK_HEAD").exists();
    let revert = git_dir.join("REVERT_HEAD").exists();
    let bisect = git_dir.join("BISECT_LOG").exists();
    let unmerged = git_unmerged_files(repo_root);

    if rebase || merge || cherry_pick || revert || bisect || !unmerged.is_empty() {
        bail!("Git operation in progress. Run `f git-repair` first.");
    }
    Ok(())
}

fn git_unmerged_files(repo_root: &Path) -> Vec<String> {
    let output = Command::new("git")
        .current_dir(repo_root)
        .args(["diff", "--name-only", "--diff-filter=U"])
        .output();
    match output {
        Ok(out) => String::from_utf8_lossy(&out.stdout)
            .lines()
            .filter(|l| !l.trim().is_empty())
            .map(|l| l.trim().to_string())
            .collect(),
        Err(_) => Vec::new(),
    }
}

View on GitHub (pinned to a747e741ae)

Solutions

  1. Run `f git-repair` as the message instructs, which aborts/cleans the in-progress operation.
  2. Alternatively finish or abort manually: `git rebase --abort`, `git merge --abort`, `git cherry-pick --abort`, `git bisect reset`, then resolve unmerged files with `git status`.
  3. Re-run your flow command once the repo is clean.

Example fix

// before
flow sync   # blocked: REBASE_HEAD present
// after
f git-repair
flow sync
Defensive patterns

Strategy: validation

Validate before calling

// shell: detect in-progress git state before flow commands
GIT_DIR=$(git rev-parse --git-dir) || exit 1
for f in rebase-merge rebase-apply MERGE_HEAD CHERRY_PICK_HEAD REVERT_HEAD BISECT_LOG; do
  [ -e "$GIT_DIR/$f" ] && { echo "git operation in progress: $f — run f git-repair" >&2; exit 1; }
done
[ -z "$(git ls-files -u)" ] || { echo "unmerged files present" >&2; exit 1; }

Try / catch

match flow_sync() {
  Err(e) if e.contains("Git operation in progress") => {
    run("f git-repair");
    flow_sync()
  }
  r => r,
}

Prevention

When it happens

Trigger: Running a flow command that calls ensure_git_not_busy while .git contains REBASE/MERGE/CHERRY_PICK/REVERT_HEAD or BISECT_LOG, or `git ls-files -u` (git_unmerged_files) returns unresolved conflict entries.

Common situations: A previous `git rebase`/`git merge` was interrupted or left mid-conflict; a cherry-pick stopped on conflicts; bisect still active; someone used raw git alongside the jj colocated repo.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/9c32469cd932eba5. Report an issue: GitHub.