Skip to content

Commit

Permalink
replay: add --contained to rebase contained branches
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Elijah Newren <[email protected]>
Signed-off-by: Christian Couder <[email protected]>
  • Loading branch information
newren and chriscool committed Nov 15, 2023
1 parent 081864e commit 19c4016
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
12 changes: 11 additions & 1 deletion Documentation/git-replay.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t
SYNOPSIS
--------
[verse]
'git replay' (--onto <newbase> | --advance <branch>) <revision-range>... # EXPERIMENTAL
'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>... # EXPERIMENTAL

DESCRIPTION
-----------
Expand Down Expand Up @@ -96,6 +96,16 @@ 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}
------------

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:
Expand Down
13 changes: 11 additions & 2 deletions builtin/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,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;
Expand All @@ -268,7 +269,8 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
int ret = 0;

const char * const replay_usage[] = {
N_("git replay (--onto <newbase> | --advance <branch>) <revision-range>... # EXPERIMENTAL"),
N_("git replay ([--contained] --onto <newbase> | --advance <branch>) "
"<revision-range>... # EXPERIMENTAL"),
NULL
};
struct option replay_options[] = {
Expand All @@ -278,6 +280,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()
};

Expand All @@ -289,6 +293,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");

repo_init_revisions(the_repository, &revs, prefix);

/*
Expand Down Expand Up @@ -377,7 +385,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),
Expand Down
29 changes: 29 additions & 0 deletions t/t3650-replay-basics.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,33 @@ test_expect_success 'replay fails when both --advance and --onto are omitted' '
test_must_fail git replay topic1..topic2 >result
'

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

0 comments on commit 19c4016

Please sign in to comment.