88#include "git-compat-util.h"
99
1010#include "builtin.h"
11+ #include "config.h"
1112#include "environment.h"
1213#include "hex.h"
1314#include "lockfile.h"
@@ -284,6 +285,26 @@ static struct commit *pick_regular_commit(struct repository *repo,
284285 return create_commit (repo , result -> tree , pickme , replayed_base );
285286}
286287
288+ static int handle_ref_update (const char * mode ,
289+ struct ref_transaction * transaction ,
290+ const char * refname ,
291+ const struct object_id * new_oid ,
292+ const struct object_id * old_oid ,
293+ struct strbuf * err )
294+ {
295+ if (!strcmp (mode , "print" )) {
296+ printf ("update %s %s %s\n" ,
297+ refname ,
298+ oid_to_hex (new_oid ),
299+ oid_to_hex (old_oid ));
300+ return 0 ;
301+ }
302+
303+ /* mode == "yes" - update refs directly */
304+ return ref_transaction_update (transaction , refname , new_oid , old_oid ,
305+ NULL , NULL , 0 , "git replay" , err );
306+ }
307+
287308int cmd_replay (int argc ,
288309 const char * * argv ,
289310 const char * prefix ,
@@ -294,6 +315,7 @@ int cmd_replay(int argc,
294315 struct commit * onto = NULL ;
295316 const char * onto_name = NULL ;
296317 int contained = 0 ;
318+ const char * update_refs_mode = NULL ;
297319
298320 struct rev_info revs ;
299321 struct commit * last_commit = NULL ;
@@ -302,12 +324,14 @@ int cmd_replay(int argc,
302324 struct merge_result result ;
303325 struct strset * update_refs = NULL ;
304326 kh_oid_map_t * replayed_commits ;
327+ struct ref_transaction * transaction = NULL ;
328+ struct strbuf transaction_err = STRBUF_INIT ;
305329 int ret = 0 ;
306330
307- const char * const replay_usage [] = {
331+ const char * const replay_usage [] = {
308332 N_ ("(EXPERIMENTAL!) git replay "
309333 "([--contained] --onto <newbase> | --advance <branch>) "
310- "<revision-range>..." ),
334+ "[--update-refs[=<mode>]] <revision-range>..." ),
311335 NULL
312336 };
313337 struct option replay_options [] = {
@@ -319,6 +343,9 @@ int cmd_replay(int argc,
319343 N_ ("replay onto given commit" )),
320344 OPT_BOOL (0 , "contained" , & contained ,
321345 N_ ("advance all branches contained in revision-range" )),
346+ OPT_STRING (0 , "update-refs" , & update_refs_mode ,
347+ N_ ("mode" ),
348+ N_ ("control ref update behavior (yes|print)" )),
322349 OPT_END ()
323350 };
324351
@@ -330,9 +357,31 @@ int cmd_replay(int argc,
330357 usage_with_options (replay_usage , replay_options );
331358 }
332359
333- if (advance_name_opt && contained )
334- die (_ ("options '%s' and '%s' cannot be used together" ),
335- "--advance" , "--contained" );
360+ die_for_incompatible_opt2 (!!advance_name_opt , "--advance" ,
361+ contained , "--contained" );
362+
363+ /* Set default mode from config if not specified on command line */
364+ if (!update_refs_mode ) {
365+ const char * config_value = NULL ;
366+ if (!repo_config_get_string_tmp (repo , "replay.defaultaction" , & config_value )) {
367+ if (!strcmp (config_value , "update-refs" ))
368+ update_refs_mode = "yes" ;
369+ else if (!strcmp (config_value , "show-commands" ))
370+ update_refs_mode = "print" ;
371+ else
372+ die (_ ("invalid value for replay.defaultAction: '%s' "
373+ "(expected 'update-refs' or 'show-commands')" ),
374+ config_value );
375+ } else {
376+ update_refs_mode = "yes" ;
377+ }
378+ }
379+
380+ /* Validate update-refs mode */
381+ if (strcmp (update_refs_mode , "yes" ) && strcmp (update_refs_mode , "print" ))
382+ die (_ ("invalid value for --update-refs: '%s' (expected 'yes' or 'print')" ),
383+ update_refs_mode );
384+
336385 advance_name = xstrdup_or_null (advance_name_opt );
337386
338387 repo_init_revisions (repo , & revs , prefix );
@@ -389,6 +438,17 @@ int cmd_replay(int argc,
389438 determine_replay_mode (repo , & revs .cmdline , onto_name , & advance_name ,
390439 & onto , & update_refs );
391440
441+ /* Initialize ref transaction if we're updating refs directly */
442+ if (!strcmp (update_refs_mode , "yes" )) {
443+ transaction = ref_store_transaction_begin (get_main_ref_store (repo ),
444+ 0 , & transaction_err );
445+ if (!transaction ) {
446+ ret = error (_ ("failed to begin ref transaction: %s" ),
447+ transaction_err .buf );
448+ goto cleanup ;
449+ }
450+ }
451+
392452 if (!onto ) /* FIXME: Should handle replaying down to root commit */
393453 die ("Replaying down to root commit is not supported yet!" );
394454
@@ -434,21 +494,40 @@ int cmd_replay(int argc,
434494 if (decoration -> type == DECORATION_REF_LOCAL &&
435495 (contained || strset_contains (update_refs ,
436496 decoration -> name ))) {
437- printf ("update %s %s %s\n" ,
438- decoration -> name ,
439- oid_to_hex (& last_commit -> object .oid ),
440- oid_to_hex (& commit -> object .oid ));
497+ if (handle_ref_update (update_refs_mode , transaction ,
498+ decoration -> name ,
499+ & last_commit -> object .oid ,
500+ & commit -> object .oid ,
501+ & transaction_err ) < 0 ) {
502+ ret = error (_ ("failed to update ref '%s': %s" ),
503+ decoration -> name , transaction_err .buf );
504+ goto cleanup ;
505+ }
441506 }
442507 decoration = decoration -> next ;
443508 }
444509 }
445510
446511 /* In --advance mode, advance the target ref */
447512 if (result .clean == 1 && advance_name ) {
448- printf ("update %s %s %s\n" ,
449- advance_name ,
450- oid_to_hex (& last_commit -> object .oid ),
451- oid_to_hex (& onto -> object .oid ));
513+ if (handle_ref_update (update_refs_mode , transaction ,
514+ advance_name ,
515+ & last_commit -> object .oid ,
516+ & onto -> object .oid ,
517+ & transaction_err ) < 0 ) {
518+ ret = error (_ ("failed to update ref '%s': %s" ),
519+ advance_name , transaction_err .buf );
520+ goto cleanup ;
521+ }
522+ }
523+
524+ /* Commit the ref transaction if we have one */
525+ if (transaction && result .clean == 1 ) {
526+ if (ref_transaction_commit (transaction , & transaction_err )) {
527+ ret = error (_ ("failed to commit ref transaction: %s" ),
528+ transaction_err .buf );
529+ goto cleanup ;
530+ }
452531 }
453532
454533 merge_finalize (& merge_opt , & result );
@@ -460,6 +539,9 @@ int cmd_replay(int argc,
460539 ret = result .clean ;
461540
462541cleanup :
542+ if (transaction )
543+ ref_transaction_free (transaction );
544+ strbuf_release (& transaction_err );
463545 release_revisions (& revs );
464546 free (advance_name );
465547
0 commit comments