public inbox for git@vger.kernel.org
 help / color / mirror / Atom feed
From: Siddharth Asthana <siddharthasthana31@gmail.com>
To: git@vger.kernel.org
Cc: christian.couder@gmail.com, ps@pks.im, newren@gmail.com,
	gitster@pobox.com, phillip.wood123@gmail.com,
	karthik.188@gmail.com, johannes.schindelin@gmx.de,
	toon@iotcl.com, Siddharth Asthana <siddharthasthana31@gmail.com>
Subject: [PATCH v5 0/2] replay: add --revert mode to reverse commit changes
Date: Wed, 25 Mar 2026 03:33:59 +0530	[thread overview]
Message-ID: <20260324220401.47040-1-siddharthasthana31@gmail.com> (raw)
In-Reply-To: <20260313054035.26605-1-siddharthasthana31@gmail.com>

Hi,

git replay currently supports cherry-picking (--advance) and rebasing
(--onto), but not reverting. We need this at GitLab for Gitaly to
reverse commits directly on bare repositories without a checkout.

The approach is the same as sequencer.c -- cherry-pick and revert are
just the same three-way merge with swapped arguments. We swap the base
and pickme trees passed to merge_incore_nonrecursive() to reverse the
diff direction.

Patch 1 extracts the full revert message formatting logic into a new
sequencer_format_revert_message() function that handles everything in
one shared function rather than just the header. refer_to_commit() is
updated to take a struct repository and a bool instead of replay_opts
so it works outside the sequencer.

Patch 2 adds --revert <branch> as a standalone mode. Reverts are
processed newest-first (matching git revert) to reduce conflicts by
peeling off changes from the top.

The series is based on top of d181b9354c (The 13th batch, 2026-03-07).

Changes in v5:
- Made sequencer_format_revert_message() header comment more concise,
  using single quotes to avoid nested escaped double quotes
- Moved desired_reverse declaration up and removed the bare braces, so
  the same named variable is used when setting and checking
  revs.reverse
- Used die_for_incompatible_opt2() for --advance/--contained and
  --revert/--contained instead of die("--contained requires --onto")
- Dropped the erroneously re-added ellipsis from <revision-range>...
  in the SYNOPSIS
- Restored #define the_repository DO_NOT_USE_THE_REPOSITORY guard in
  replay.c
- Used ${SQ} instead of '"'"' for single-quote escaping in tests
- Link to v4: https://lore.kernel.org/git/20260313054035.26605-1-siddharthasthana31@gmail.com/
- Link to v3: https://public-inbox.org/git/20260218234215.89326-1-siddharthasthana31@gmail.com/
- Link to v2: https://public-inbox.org/git/20251202201611.22137-1-siddharthasthana31@gmail.com/
- Link to v1: https://public-inbox.org/git/20251125170056.34489-1-siddharthasthana31@gmail.com/

Thanks,
Siddharth

---
Siddharth Asthana (2):
  sequencer: extract revert message formatting into shared function
  replay: add --revert mode to reverse commit changes

 Documentation/git-replay.adoc |  43 ++++++++-
 builtin/replay.c              |  35 ++++++--
 replay.c                      | 161 +++++++++++++++++++++++++---------
 replay.h                      |  11 ++-
 sequencer.c                   |  78 +++++++++-------
 sequencer.h                   |  13 +++
 t/t3650-replay-basics.sh      | 111 +++++++++++++++++++++--
 7 files changed, 355 insertions(+), 97 deletions(-)

Range-diff versus v4:

1:  bdc710b265 ! 1:  6bd2ce4515 sequencer: extract revert message formatting into shared function
    @@ sequencer.h: int sequencer_determine_whence(struct repository *r, enum commit_wh
      int sequencer_get_update_refs_state(const char *wt_dir, struct string_list *refs);
      
     +/*
    -+ * Formats a complete revert commit message following standard Git conventions.
    -+ * Handles regular reverts ("Revert \"<subject>\""), revert of revert cases
    -+ * ("Reapply \"<subject>\""), and the --reference style. Appends "This reverts
    -+ * commit <ref>." using either the abbreviated or full commit reference
    -+ * depending on use_commit_reference. Also handles merge-parent references.
    ++ * Format a revert commit message with appropriate 'Revert "<subject>"' or
    ++ * 'Reapply "<subject>"' prefix and 'This reverts commit <ref>.' body.
    ++ * When use_commit_reference is set, <ref> is an abbreviated hash with
    ++ * subject and date; otherwise the full hex hash is used.
     + */
     +void sequencer_format_revert_message(struct repository *r,
     +				     const char *subject,
2:  bea6229575 ! 2:  9fd92497b9 replay: add --revert mode to reverse commit changes
    @@ Documentation/git-replay.adoc: git-replay - EXPERIMENTAL: Replay commits on a ne
      --------
      [verse]
     -(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) [--ref-action[=<mode>]] <revision-range>
    -+(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) [--ref-action[=<mode>]] <revision-range>...
    ++(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) [--ref-action[=<mode>]] <revision-range>
      
      DESCRIPTION
      -----------
    @@ builtin/replay.c: int cmd_replay(int argc,
      	const char *const replay_usage[] = {
      		N_("(EXPERIMENTAL!) git replay "
     -		   "([--contained] --onto <newbase> | --advance <branch>) "
    --		   "[--ref-action[=<mode>]] <revision-range>"),
     +		   "([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) "
    -+		   "[--ref-action[=<mode>]] <revision-range>..."),
    + 		   "[--ref-action[=<mode>]] <revision-range>"),
      		NULL
      	};
    - 	struct option replay_options[] = {
     @@ builtin/replay.c: int cmd_replay(int argc,
      			   N_("replay onto given commit")),
      		OPT_BOOL(0, "contained", &opts.contained,
    @@ builtin/replay.c: int cmd_replay(int argc,
      		usage_with_options(replay_usage, replay_options);
      	}
      
    --	die_for_incompatible_opt2(!!opts.advance, "--advance",
    --				  opts.contained, "--contained");
    --	die_for_incompatible_opt2(!!opts.advance, "--advance",
    --				  !!opts.onto, "--onto");
     +	die_for_incompatible_opt3(!!opts.onto, "--onto",
     +				  !!opts.advance, "--advance",
     +				  !!opts.revert, "--revert");
    -+	if (opts.contained && !opts.onto)
    -+		die(_("--contained requires --onto"));
    + 	die_for_incompatible_opt2(!!opts.advance, "--advance",
    + 				  opts.contained, "--contained");
    +-	die_for_incompatible_opt2(!!opts.advance, "--advance",
    +-				  !!opts.onto, "--onto");
    ++	die_for_incompatible_opt2(!!opts.revert, "--revert",
    ++				  opts.contained, "--contained");
      
      	/* Parse ref action mode from command line or config */
      	ref_mode = get_ref_action_mode(repo, ref_action);
    -@@ builtin/replay.c: int cmd_replay(int argc,
    - 	 * some options changing these values if we think they could
    - 	 * be useful.
    - 	 */
    --	revs.reverse = 1;
    + 
     +	/*
     +	 * Cherry-pick/rebase need oldest-first ordering so that each
     +	 * replayed commit can build on its already-replayed parent.
     +	 * Revert needs newest-first ordering (like git revert) to
     +	 * reduce conflicts by peeling off changes from the top.
     +	 */
    -+	revs.reverse = opts.revert ? 0 : 1;
    ++	int desired_reverse = !opts.revert;
    ++
    + 	repo_init_revisions(repo, &revs, prefix);
    + 
    + 	/*
    +@@ builtin/replay.c: int cmd_replay(int argc,
    + 	 * some options changing these values if we think they could
    + 	 * be useful.
    + 	 */
    +-	revs.reverse = 1;
    ++	revs.reverse = desired_reverse;
      	revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
      	revs.topo_order = 1;
      	revs.simplify_history = 0;
    @@ builtin/replay.c: int cmd_replay(int argc,
      	 * walking options.
      	 */
     -	if (revs.reverse != 1) {
    --		warning(_("some rev walking options will be overridden as "
    --			  "'%s' bit in 'struct rev_info' will be forced"),
    --			"reverse");
    ++	if (revs.reverse != desired_reverse) {
    + 		warning(_("some rev walking options will be overridden as "
    + 			  "'%s' bit in 'struct rev_info' will be forced"),
    + 			"reverse");
     -		revs.reverse = 1;
    -+	{
    -+		int desired_reverse = opts.revert ? 0 : 1;
    -+		if (revs.reverse != desired_reverse) {
    -+			warning(_("some rev walking options will be overridden as "
    -+				  "'%s' bit in 'struct rev_info' will be forced"),
    -+				"reverse");
    -+			revs.reverse = desired_reverse;
    -+		}
    ++		revs.reverse = desired_reverse;
      	}
      	if (revs.sort_order != REV_SORT_IN_GRAPH_ORDER) {
      		warning(_("some rev walking options will be overridden as "
    @@ replay.c
      #include "strmap.h"
      #include "tree.h"
      
    --/*
    -- * We technically need USE_THE_REPOSITORY_VARIABLE for DEFAULT_ABBREV, but
    -- * do not want to use the_repository.
    -- */
    --#define the_repository DO_NOT_USE_THE_REPOSITORY
    +@@
    +  */
    + #define the_repository DO_NOT_USE_THE_REPOSITORY
    + 
     +enum replay_mode {
     +	REPLAY_MODE_PICK,
     +	REPLAY_MODE_REVERT,
     +};
    - 
    ++
      static const char *short_commit_name(struct repository *repo,
      				     struct commit *commit)
    + {
     @@ replay.c: static char *get_author(const char *message)
      	return NULL;
      }
    @@ t/t3650-replay-basics.sh: test_expect_success 'no base or negative ref gives no-
     -test_expect_success 'options --advance and --contained cannot be used together' '
     -	printf "fatal: options ${SQ}--advance${SQ} " >expect &&
     -	printf "and ${SQ}--contained${SQ} cannot be used together\n" >>expect &&
    -+test_expect_success '--contained requires --onto' '
    -+	echo "fatal: --contained requires --onto" >expect &&
    ++test_expect_success '--advance and --contained cannot be used together' '
      	test_must_fail git replay --advance=main --contained \
      		topic1..topic2 2>actual &&
    - 	test_cmp expect actual
    +-	test_cmp expect actual
    ++	test_grep "cannot be used together" actual
      '
      
      test_expect_success 'cannot advance target ... ordering would be ill-defined' '
     -	echo "fatal: cannot advance target with multiple sources because ordering would be ill-defined" >expect &&
    -+	cat >expect <<-\EOF &&
    -+	fatal: '"'"'--advance'"'"' cannot be used with multiple revision ranges because the ordering would be ill-defined
    -+	EOF
    ++	echo "fatal: ${SQ}--advance${SQ} cannot be used with multiple revision ranges because the ordering would be ill-defined" >expect &&
      	test_must_fail git replay --advance=main main topic1 topic2 2>actual &&
      	test_cmp expect actual
      '
    @@ t/t3650-replay-basics.sh: test_expect_success 'invalid replay.refAction value' '
     +'
     +
     +test_expect_success 'cannot revert with multiple sources' '
    -+	cat >expect <<-\EOF &&
    -+	fatal: '"'"'--revert'"'"' cannot be used with multiple revision ranges because the ordering would be ill-defined
    -+	EOF
    ++	echo "fatal: ${SQ}--revert${SQ} cannot be used with multiple revision ranges because the ordering would be ill-defined" >expect &&
     +	test_must_fail git replay --revert main main topic1 topic2 2>actual &&
     +	test_cmp expect actual
     +'
    @@ t/t3650-replay-basics.sh: test_expect_success 'invalid replay.refAction value' '
     +
     +test_expect_success 'git replay --revert incompatible with --contained' '
     +	test_must_fail git replay --revert topic4 --contained topic4~1..topic4 2>error &&
    -+	test_grep "requires --onto" error
    ++	test_grep "cannot be used together" error
     +'
     +
     +test_expect_success 'git replay --revert incompatible with --onto' '

base-commit: d181b9354cf85b44455ce3ca9e6af0b9559e0ae2
-- 
2.51.0


  parent reply	other threads:[~2026-03-24 22:04 UTC|newest]

Thread overview: 92+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-25 17:00 [PATCH 0/1] replay: add --revert option to reverse commit changes Siddharth Asthana
2025-11-25 17:00 ` [PATCH 1/1] " Siddharth Asthana
2025-11-25 19:22   ` Junio C Hamano
2025-11-25 19:30     ` Junio C Hamano
2025-11-25 19:39       ` Junio C Hamano
2025-11-25 20:06         ` Junio C Hamano
2025-11-26 19:31           ` Siddharth Asthana
2025-11-26 19:28         ` Siddharth Asthana
2025-11-26 19:26     ` Siddharth Asthana
2025-11-26 21:13       ` Junio C Hamano
2025-11-27 19:23         ` Siddharth Asthana
2025-11-26 11:10   ` Phillip Wood
2025-11-26 17:35     ` Elijah Newren
2025-11-26 18:41       ` Junio C Hamano
2025-11-26 21:17         ` Junio C Hamano
2025-11-26 23:06           ` Elijah Newren
2025-11-26 23:14             ` Junio C Hamano
2025-11-26 23:57               ` Elijah Newren
2025-11-26 19:50       ` Siddharth Asthana
2025-11-26 19:39     ` Siddharth Asthana
2025-11-27 16:21       ` Phillip Wood
2025-11-27 19:24         ` Siddharth Asthana
2025-11-25 17:25 ` [PATCH 0/1] " Johannes Schindelin
2025-11-25 18:02   ` Junio C Hamano
2025-11-26 19:18   ` Siddharth Asthana
2025-11-26 21:04     ` Junio C Hamano
2025-11-27 19:21       ` Siddharth Asthana
2025-11-27 20:17         ` Junio C Hamano
2025-11-28  8:07         ` Elijah Newren
2025-11-28  8:24           ` Siddharth Asthana
2025-11-28 16:35             ` Junio C Hamano
2025-11-28 17:07               ` Elijah Newren
2025-11-28 20:50                 ` Junio C Hamano
2025-11-28 22:03                   ` Elijah Newren
2025-11-29  5:59                     ` Junio C Hamano
2025-12-02 20:16 ` [PATCH v2 0/2] replay: add --revert mode " Siddharth Asthana
2025-12-02 20:16   ` [PATCH v2 1/2] sequencer: extract revert message formatting into shared function Siddharth Asthana
2025-12-05 11:33     ` Patrick Steinhardt
2025-12-07 23:00       ` Siddharth Asthana
2025-12-08  7:07         ` Patrick Steinhardt
2026-02-11 13:03           ` Toon Claes
2026-02-11 13:40             ` Patrick Steinhardt
2026-02-11 15:23             ` Kristoffer Haugsbakk
2026-02-11 17:41               ` Junio C Hamano
2026-02-18 22:53             ` Siddharth Asthana
2025-12-02 20:16   ` [PATCH v2 2/2] replay: add --revert mode to reverse commit changes Siddharth Asthana
2025-12-05 11:33     ` Patrick Steinhardt
2025-12-07 23:03       ` Siddharth Asthana
2025-12-16 16:23     ` Phillip Wood
2026-02-18 23:42   ` [PATCH v3 0/2] " Siddharth Asthana
2026-02-18 23:42     ` [PATCH v3 1/2] sequencer: extract revert message formatting into shared function Siddharth Asthana
2026-02-20 17:01       ` Toon Claes
2026-02-25 21:53         ` Junio C Hamano
2026-03-06  4:55           ` Siddharth Asthana
2026-03-06  4:31         ` Siddharth Asthana
2026-02-26 14:27       ` Phillip Wood
2026-03-06  5:00         ` Siddharth Asthana
2026-02-18 23:42     ` [PATCH v3 2/2] replay: add --revert mode to reverse commit changes Siddharth Asthana
2026-02-20 17:35       ` Toon Claes
2026-02-20 20:23         ` Junio C Hamano
2026-02-23  9:13         ` Christian Couder
2026-02-23 11:23           ` Toon Claes
2026-03-06  5:05         ` Siddharth Asthana
2026-02-26 14:45       ` Phillip Wood
2026-03-06  5:28         ` Siddharth Asthana
2026-03-06 15:52           ` Phillip Wood
2026-03-06 16:20             ` Siddharth Asthana
2026-03-13  5:40     ` [PATCH v4 0/2] " Siddharth Asthana
2026-03-13  5:40       ` [PATCH v4 1/2] sequencer: extract revert message formatting into shared function Siddharth Asthana
2026-03-13 15:53         ` Junio C Hamano
2026-03-16 19:12           ` Toon Claes
2026-03-16 16:57         ` Phillip Wood
2026-03-13  5:40       ` [PATCH v4 2/2] replay: add --revert mode to reverse commit changes Siddharth Asthana
2026-03-16 16:57         ` Phillip Wood
2026-03-16 19:52         ` Toon Claes
2026-03-17 10:11           ` Phillip Wood
2026-03-16 16:59       ` [PATCH v4 0/2] " Phillip Wood
2026-03-16 19:53       ` Toon Claes
2026-03-24 22:03       ` Siddharth Asthana [this message]
2026-03-24 22:04         ` [PATCH v5 1/2] sequencer: extract revert message formatting into shared function Siddharth Asthana
2026-03-24 22:04         ` [PATCH v5 2/2] replay: add --revert mode to reverse commit changes Siddharth Asthana
2026-03-25  6:29           ` Junio C Hamano
2026-03-25 15:10             ` Toon Claes
2026-03-25 15:38               ` Siddharth Asthana
2026-03-25 16:44               ` Phillip Wood
2026-03-25 15:36             ` Siddharth Asthana
2026-03-25 20:23         ` [PATCH v6 0/2] " Siddharth Asthana
2026-03-25 20:23           ` [PATCH v6 1/2] sequencer: extract revert message formatting into shared function Siddharth Asthana
2026-03-25 20:23           ` [PATCH v6 2/2] replay: add --revert mode to reverse commit changes Siddharth Asthana
2026-03-28  4:33             ` Tian Yuchen
2026-03-25 20:23           ` [PATCH v6 1/2] sequencer: extract revert message formatting into shared function Siddharth Asthana
2026-03-25 20:23           ` [PATCH v6 2/2] replay: add --revert mode to reverse commit changes Siddharth Asthana

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260324220401.47040-1-siddharthasthana31@gmail.com \
    --to=siddharthasthana31@gmail.com \
    --cc=christian.couder@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=johannes.schindelin@gmx.de \
    --cc=karthik.188@gmail.com \
    --cc=newren@gmail.com \
    --cc=phillip.wood123@gmail.com \
    --cc=ps@pks.im \
    --cc=toon@iotcl.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox