@@ -79,11 +79,12 @@ int cmd_replay(int argc,
7979 struct ref_transaction * transaction = NULL ;
8080 struct strbuf transaction_err = STRBUF_INIT ;
8181 struct strbuf reflog_msg = STRBUF_INIT ;
82+ int desired_reverse ;
8283 int ret = 0 ;
8384
8485 const char * const replay_usage [] = {
8586 N_ ("(EXPERIMENTAL!) git replay "
86- "([--contained] --onto <newbase> | --advance <branch>) "
87+ "([--contained] --onto <newbase> | --advance <branch> | --revert <branch> ) "
8788 "[--ref-action[=<mode>]] <revision-range>" ),
8889 NULL
8990 };
@@ -96,6 +97,9 @@ int cmd_replay(int argc,
9697 N_ ("replay onto given commit" )),
9798 OPT_BOOL (0 , "contained" , & opts .contained ,
9899 N_ ("update all branches that point at commits in <revision-range>" )),
100+ OPT_STRING (0 , "revert" , & opts .revert ,
101+ N_ ("branch" ),
102+ N_ ("revert commits onto given branch" )),
99103 OPT_STRING (0 , "ref-action" , & ref_action ,
100104 N_ ("mode" ),
101105 N_ ("control ref update behavior (update|print)" )),
@@ -105,19 +109,31 @@ int cmd_replay(int argc,
105109 argc = parse_options (argc , argv , prefix , replay_options , replay_usage ,
106110 PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT );
107111
108- if (!opts .onto && !opts .advance ) {
109- error (_ ("option --onto or --advance is mandatory" ));
112+ /* Exactly one mode must be specified */
113+ if (!opts .onto && !opts .advance && !opts .revert ) {
114+ error (_ ("exactly one of --onto, --advance, or --revert is required" ));
110115 usage_with_options (replay_usage , replay_options );
111116 }
112117
118+ die_for_incompatible_opt3 (!!opts .onto , "--onto" ,
119+ !!opts .advance , "--advance" ,
120+ !!opts .revert , "--revert" );
113121 die_for_incompatible_opt2 (!!opts .advance , "--advance" ,
114122 opts .contained , "--contained" );
115- die_for_incompatible_opt2 (!!opts .advance , "--advance " ,
116- !! opts .onto , "--onto " );
123+ die_for_incompatible_opt2 (!!opts .revert , "--revert " ,
124+ opts .contained , "--contained " );
117125
118126 /* Parse ref action mode from command line or config */
119127 ref_mode = get_ref_action_mode (repo , ref_action );
120128
129+ /*
130+ * Cherry-pick/rebase need oldest-first ordering so that each
131+ * replayed commit can build on its already-replayed parent.
132+ * Revert needs newest-first ordering (like git revert) to
133+ * reduce conflicts by peeling off changes from the top.
134+ */
135+ desired_reverse = !opts .revert ;
136+
121137 repo_init_revisions (repo , & revs , prefix );
122138
123139 /*
@@ -129,7 +145,7 @@ int cmd_replay(int argc,
129145 * some options changing these values if we think they could
130146 * be useful.
131147 */
132- revs .reverse = 1 ;
148+ revs .reverse = desired_reverse ;
133149 revs .sort_order = REV_SORT_IN_GRAPH_ORDER ;
134150 revs .topo_order = 1 ;
135151 revs .simplify_history = 0 ;
@@ -144,11 +160,11 @@ int cmd_replay(int argc,
144160 * Detect and warn if we override some user specified rev
145161 * walking options.
146162 */
147- if (revs .reverse != 1 ) {
163+ if (revs .reverse != desired_reverse ) {
148164 warning (_ ("some rev walking options will be overridden as "
149165 "'%s' bit in 'struct rev_info' will be forced" ),
150166 "reverse" );
151- revs .reverse = 1 ;
167+ revs .reverse = desired_reverse ;
152168 }
153169 if (revs .sort_order != REV_SORT_IN_GRAPH_ORDER ) {
154170 warning (_ ("some rev walking options will be overridden as "
@@ -174,7 +190,9 @@ int cmd_replay(int argc,
174190 goto cleanup ;
175191
176192 /* Build reflog message */
177- if (opts .advance ) {
193+ if (opts .revert ) {
194+ strbuf_addf (& reflog_msg , "replay --revert %s" , opts .revert );
195+ } else if (opts .advance ) {
178196 strbuf_addf (& reflog_msg , "replay --advance %s" , opts .advance );
179197 } else {
180198 struct object_id oid ;
0 commit comments