can1357/oh-my-pi · warning · Error

cherry-pick of {sha} is empty

Error message

cherry-pick of {sha} is empty

What it means

Error::EmptyCherryPick is raised when cherry-picking a commit produced an empty result — the change was already applied upstream or auto-resolved to HEAD, so nothing was committed. It deliberately replaces the historical stderr-regex `/the previous cherry-pick is now empty/`, letting callers handle the skip-and-continue case structurally instead of scraping git output.

Source

Thrown at crates/pi-vcs/src/error.rs:41

	#[error("reference not found: {name}")]
	RefNotFound {
		/// The ref name as given by the caller.
		name: String,
	},

	/// A revision/object lookup failed (`rev-parse` style spec, blob path,
	/// tree).
	#[error("object not found: {spec}")]
	ObjectNotFound {
		/// The revision or object spec as given by the caller.
		spec: String,
	},

	/// Cherry-picking `sha` produced an empty commit (already applied or
	/// auto-resolved to HEAD). Callers should skip and continue the range —
	/// replaces the historical `/the previous cherry-pick is now empty/` stderr
	/// regex.
	#[error("cherry-pick of {sha} is empty")]
	EmptyCherryPick {
		/// The commit that collapsed to a no-op.
		sha: String,
	},

	/// A merge-style operation (cherry-pick, stash pop, 3-way apply) hit
	/// conflicting changes.
	#[error("merge conflict in {} file(s)", paths.len())]
	Conflict {
		/// Worktree-relative paths left in a conflicted state.
		paths: Vec<String>,
	},

	/// A patch did not apply (context mismatch, missing file, malformed input).
	#[error("patch does not apply: {message}")]
	PatchFailed {
		/// Human-readable reason, including the offending path when known.
		message: String,

View on GitHub (pinned to 9690622007)

Solutions

  1. Treat this as non-fatal: skip the sha and continue cherry-picking the remaining commits in the range.
  2. If the change is genuinely needed, check whether it landed with a different content (merge commit vs squash) and pick the right original commit.
  3. Verify with `git log --cherry-pick --right-only HEAD...<sha>^..` whether the commit is already applied.
  4. If you truly want an empty commit to record it, re-run with `--allow-empty` semantics if the API exposes it.

Example fix

// before
repo.cherry_pick("abc123")?; // whole batch fails on duplicate
// after
match repo.cherry_pick(sha) {
    Err(Error::EmptyCherryPick { .. }) => continue, // skip already-applied commit
    Err(e) => return Err(e),
    Ok(()) => {}
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn already_applied(repo: &pi_vcs::Vcs, sha: &str) -> bool {
    // equivalent of `git log --cherry-pick --right-only HEAD...<sha>^..<sha>` being empty
    repo.cherry_check(sha).map(|c| c.is_empty()).unwrap_or(false)
}
let pending: Vec<_> = shas.into_iter().filter(|s| !already_applied(&repo, s)).collect();

Type guard

fn is_empty_cherry_pick(err: &pi_vcs::Error) -> bool {
    matches!(err, pi_vcs::Error::EmptyCherryPick { .. })
}

Try / catch

for sha in range {
    match repo.cherry_pick(sha) {
        Err(pi_vcs::Error::EmptyCherryPick { sha }) => {
            log::info!("skipping {sha}: already applied to HEAD");
        }
        other => other?,
    }
}

Prevention

When it happens

Trigger: Cherry-picking a range where a commit's changes are already contained in HEAD (duplicate pick, rebase replay, backport of an already-merged fix). The library detects the no-op and returns this error with the offending sha so callers can skip and continue.

Common situations: Backporting a PR that was partially merged before, cherry-picking a range that overlaps an earlier cherry-pick batch, replaying commits onto a branch that already contains them, double-clicking a pick in a tool.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f9e20876393f51c0. Report an issue: GitHub.