On Tue, May 9, 2023 at 10:54 AM Christian Couder <christian.couder@xxxxxxxxx> wrote: > > From: Elijah Newren <newren@xxxxxxxxx> > > Let's add a `--contained` option that can be used along with > `--onto` to rebase all the branches contained in the <revision-range> > argument. > > Co-authored-by: Christian Couder <chriscool@xxxxxxxxxxxxx> > Signed-off-by: Elijah Newren <newren@xxxxxxxxx> > Signed-off-by: Christian Couder <chriscool@xxxxxxxxxxxxx> > --- > Documentation/git-replay.txt | 16 +++++++++++++++- > builtin/replay.c | 12 ++++++++++-- > t/t3650-replay-basics.sh | 29 +++++++++++++++++++++++++++++ > 3 files changed, 54 insertions(+), 3 deletions(-) > > diff --git a/Documentation/git-replay.txt b/Documentation/git-replay.txt > index 439b2f92e7..3e06ab2f5e 100644 > --- a/Documentation/git-replay.txt > +++ b/Documentation/git-replay.txt > @@ -9,7 +9,7 @@ git-replay - Replay commits on a different base, without touching working tree > SYNOPSIS > -------- > [verse] > -'git replay' (--onto <newbase> | --advance <branch>) <revision-range>... > +'git replay' [--contained] (--onto <newbase> | --advance <branch>) <revision-range>... Should this be 'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>... ? > > DESCRIPTION > ----------- > @@ -90,6 +90,20 @@ top of the exact same new base, they only differ in that the first > provides instructions to make mybranch point at the new commits and > the second provides instructions to make target point at them. > > +What if you have a stack of branches, one depending upon another, and > +you'd really like to rebase the whole set? > + > +------------ > +$ git replay --contained --onto origin/main origin/main..tipbranch > +update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH} > +update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH} > +update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH} > +------------ > + > +In contrast, trying to do this with rebase would require 3 separate > +rebases, eacho of which involves a different <ONTO> and <UPSTREAM> and s/eacho/each/ > +forces you to first check out each branch in turn. This paragraph isn't true anymore with rebase's --update-refs, right? > + > When calling `git replay`, one does not need to specify a range of > commits to replay using the syntax `A..B`; any range expression will > do: > diff --git a/builtin/replay.c b/builtin/replay.c > index c146f38f58..4d24eb95d8 100644 > --- a/builtin/replay.c > +++ b/builtin/replay.c > @@ -256,6 +256,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) > const char *advance_name = NULL; > struct commit *onto = NULL; > const char *onto_name = NULL; > + int contained = 0; > > struct rev_info revs; > struct commit *last_commit = NULL; > @@ -266,7 +267,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) > int ret = 0, i; > > const char * const replay_usage[] = { > - N_("git replay (--onto <newbase> | --advance <branch>) <revision-range>..."), > + N_("git replay [--contained] (--onto <newbase> | --advance <branch>) <revision-range>..."), Possibly need to update this here too. > NULL > }; > struct option replay_options[] = { > @@ -276,6 +277,8 @@ int cmd_replay(int argc, const char **argv, const char *prefix) > OPT_STRING(0, "onto", &onto_name, > N_("revision"), > N_("replay onto given commit")), > + OPT_BOOL(0, "contained", &contained, > + N_("advance all branches contained in revision-range")), > OPT_END() > }; > > @@ -301,6 +304,10 @@ int cmd_replay(int argc, const char **argv, const char *prefix) > usage_with_options(replay_usage, replay_options); > } > > + if (advance_name && contained) > + die(_("options '%s' and '%s' cannot be used together"), > + "--advance", "--contained"); But the code does check that these are incompatible. Good. > + > repo_init_revisions(the_repository, &revs, prefix); > > argc = setup_revisions(argc, argv, &revs, NULL); > @@ -363,7 +370,8 @@ int cmd_replay(int argc, const char **argv, const char *prefix) > continue; > while (decoration) { > if (decoration->type == DECORATION_REF_LOCAL && > - strset_contains(update_refs, decoration->name)) { > + (contained || strset_contains(update_refs, > + decoration->name))) { > printf("update %s %s %s\n", > decoration->name, > oid_to_hex(&last_commit->object.oid), > diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh > index bca405c431..3fb4167e69 100755 > --- a/t/t3650-replay-basics.sh > +++ b/t/t3650-replay-basics.sh > @@ -122,4 +122,33 @@ test_expect_success 'using replay on bare repo to perform basic cherry-pick' ' > test_cmp expect result-bare > ' > > +test_expect_success 'using replay to also rebase a contained branch' ' > + git replay --contained --onto main main..topic3 >result && > + > + test_line_count = 2 result && > + cut -f 3 -d " " result >new-branch-tips && > + > + git log --format=%s $(head -n 1 new-branch-tips) >actual && > + test_write_lines F C M L B A >expect && > + test_cmp expect actual && > + > + git log --format=%s $(tail -n 1 new-branch-tips) >actual && > + test_write_lines H G F C M L B A >expect && > + test_cmp expect actual && > + > + printf "update refs/heads/topic1 " >expect && > + printf "%s " $(head -n 1 new-branch-tips) >>expect && > + git rev-parse topic1 >>expect && > + printf "update refs/heads/topic3 " >>expect && > + printf "%s " $(tail -n 1 new-branch-tips) >>expect && > + git rev-parse topic3 >>expect && > + > + test_cmp expect result > +' > + > +test_expect_success 'using replay on bare repo to also rebase a contained branch' ' > + git -C bare replay --contained --onto main main..topic3 >result-bare && > + test_cmp expect result-bare > +' > + > test_done > -- > 2.40.1.491.gdff9a222ea >