replay: add --revert option to reverse commit changes

Hello 👋🏻

This MR adds revert functionality to git replay, enabling it to reverse commit changes in addition to cherry-picking them. This addresses GitLab issue #233 and complements the existing replay capabilities.

Current Limitation

The git replay command currently only supports replaying (cherry-picking) commits onto a new base. However, it cannot revert commits, which is a complementary operation that's quite similar. For server-side tools like Gitaly that plan to use git replay, having both forward (cherry-pick) and reverse (revert) operations through a single command would simplify their codebase significantly.

Our implementation

This patch introduces a --revert option that reverses the diff direction when replaying commits:

Cherry-pick commits (default behavior)

git replay --onto main feature~3..feature

Revert commits (new functionality)

git replay --revert --onto main feature~3..feature### Implementation Approach

The key insight from analyzing sequencer.c is that cherry-pick and revert are essentially the same merge operation but with swapped arguments:

  • Cherry-pick: merge(parent, HEAD, commit) - applies the diff
  • Revert: merge(commit, HEAD, parent) - reverses the diff

By swapping the base and pickme trees in merge_incore_nonrecursive(), we effectively reverse the diff direction. This approach:

  • Reuses all existing infrastructure (merge-ort backend, conflict handling, ref updates)
  • Requires minimal code changes (~100 lines in builtin/replay.c)
  • Works seamlessly with bare repositories (critical for server-side use)
  • Generates appropriate commit messages:
    • Regular revert: Revert "Original subject"
    • Revert of revert: Reapply "Original subject"
    • Includes the SHA of the commit being reverted

Compatibility

The --revert option is incompatible with --contained, as reverting multiple branches simultaneously would be semantically unclear. This is enforced using die_for_incompatible_opt2().

Testing

  • 9 new tests added covering:
    • Basic revert with --onto and --advance modes
    • Bare repository support
    • Revert of a revert (generates "Reapply" message)
    • Conflict handling
    • Multiple reverts in a single operation

Benefits for Gitaly

This feature will help simplify server-side code in tools like Gitaly by providing:

  • Unified interface for both cherry-pick and revert operations
  • No working tree required
  • Efficient merge-ort backend
  • Works in bare repositories out of the box

Merge request reports

Loading