GitoxideLabs/gitoxide · error
the conflict checkout did not leave HEAD at
Error message
the conflict checkout did not leave HEAD at {commit} What it means
After performing a conflict checkout, the code re-opens the repository and verifies HEAD points exactly at the expected conflict commit. `anyhow::ensure!(id == commit, ...)` fires when HEAD resolved to a different object id, meaning the checkout did not land where the operation expected.
Solutions
- Re-run the conflict checkout ensuring no other git process runs concurrently.
- Verify HEAD manually (`git rev-parse HEAD`) and reset it to the expected commit before resuming.
- Check for IDE/CI git integrations that may move HEAD during the operation.
Example fix
// before
anyhow::ensure!(id == commit, "the conflict checkout did not leave HEAD at {commit}");
// after
if id != commit {
repository.set_head_commit_to(commit)?;
}
anyhow::ensure!(id == commit, "the conflict checkout did not leave HEAD at {commit}"); Defensive patterns
Strategy: validation
Validate before calling
let head_id = repo.head()?.id().map(|i| i.detach());
if head_id != Some(commit) {
eprintln!("HEAD is not at the expected conflict commit; re-run the checkout");
return;
} Type guard
fn head_is_at(repo: &gix::Repository, commit: gix::ObjectId) -> bool {
repo.head().ok().and_then(|h| h.id()).map(|i| i.detach()) == Some(commit)
} Try / catch
let result = conflict_checkout(commit);
match result {
Err(e) if e.to_string().contains("did not leave HEAD at") => retry_checkout(),
other => other,
} Prevention
- Ensure no other git processes (IDE, hooks, scripts) run during conflict checkout.
- Verify HEAD immediately after checkout and before further mutation.
- Make checkout operations set HEAD atomically within one transaction.
When it happens
Trigger: A conflict checkout whose `head()` resolves to an id other than the target `commit` — e.g. another process moved HEAD between checkout and verification, or the checkout silently kept an existing HEAD position.
Common situations: Concurrent git operations (another terminal, IDE git integration) running while the tool checks out a conflict; a `git checkout` that failed partially; scripted automation touching HEAD mid-operation.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- HEAD attachment changed while resolving the conflict…
- HEAD moved to an unrelated commit while resolving the…
- Tree conflicted
- File conflicted
- Tree conflicted, refusing to write commit
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/7ebcd035513669ac.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/lib.rs:4374
repository_path: &Path,
bare: bool,
title: &str,
changes: &mut Vec<edit::undo::RefChange>,
) -> Result<()> {
let result = record_undo(repository_path, bare, title, changes);
changes.clear();
result
}
fn conflict_head(repository_path: &Path, bare: bool, commit: gix::ObjectId) -> Result<ConflictHead> {
let repository = open_repository(repository_path, bare, false)
.context("could not reopen the repository after checking out a conflict")?;
let head = repository.head().context("could not inspect the conflicted HEAD")?;
let id = head
.id()
.map(gix::Id::detach)
.context("the conflicted HEAD is unborn")?;
anyhow::ensure!(id == commit, "the conflict checkout did not leave HEAD at {commit}");
let reference = head.referent_name().map(ToOwned::to_owned);
drop(head);
let name = reference
.clone()
.unwrap_or_else(|| "HEAD".try_into().expect("valid reference name"));
anyhow::ensure!(
edit::undo::state(&repository, name.as_ref())? == edit::undo::State::Object(commit),
"the conflicted HEAD attachment does not directly reference {commit}"
);
let parents = repository
.find_commit(commit)
.context("could not find the checked-out conflict commit")?
.parent_ids()
.map(gix::Id::detach)
.collect();
Ok(ConflictHead { reference, parents })
}
View on GitHub (pinned to e73179060b)