replay: add --contained to rebase contained branches
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@tuxfamily.org> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Nov 24, 2023 at 12:10 UTC
c4611130f47242af19fbd8eca2be039742c122b1
3 files changed
+52
-3
Documentation/git-replay.txt
+11
-1
@@ -9,7 +9,7 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t
9
SYNOPSIS
10
--------
11
[verse]
12
-(EXPERIMENTAL!) 'git replay' (--onto <newbase> | --advance <branch>) <revision-range>...
12
+(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>...
13
14
DESCRIPTION
15
-----------
@@ -96,6 +96,16 @@ top of the exact same new base, they only differ in that the first
96
provides instructions to make mybranch point at the new commits and
97
the second provides instructions to make target point at them.
98
99
+What if you have a stack of branches, one depending upon another, and
100
+you'd really like to rebase the whole set?
101
+
102
+------------
103
+$ git replay --contained --onto origin/main origin/main..tipbranch
104
+update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
105
+update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
106
+update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH}
107
+------------
108
+
109
When calling `git replay`, one does not need to specify a range of
110
commits to replay using the syntax `A..B`; any range expression will
111
do:
builtin/replay.c
+12
-2
@@ -258,6 +258,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
258
const char *advance_name = NULL;
259
struct commit *onto = NULL;
260
const char *onto_name = NULL;
261
+ int contained = 0;
262
263
struct rev_info revs;
264
struct commit *last_commit = NULL;
@@ -268,7 +269,9 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
269
int ret = 0;
270
271
const char * const replay_usage[] = {
271
- N_("(EXPERIMENTAL!) git replay (--onto <newbase> | --advance <branch>) <revision-range>..."),
272
+ N_("(EXPERIMENTAL!) git replay "
273
+ "([--contained] --onto <newbase> | --advance <branch>) "
274
+ "<revision-range>..."),
275
NULL
276
};
277
struct option replay_options[] = {
@@ -278,6 +281,8 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
281
OPT_STRING(0, "onto", &onto_name,
282
N_("revision"),
283
N_("replay onto given commit")),
284
+ OPT_BOOL(0, "contained", &contained,
285
+ N_("advance all branches contained in revision-range")),
286
OPT_END()
287
};
288
@@ -289,6 +294,10 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
294
usage_with_options(replay_usage, replay_options);
295
}
296
297
+ if (advance_name && contained)
298
+ die(_("options '%s' and '%s' cannot be used together"),
299
+ "--advance", "--contained");
300
+
301
repo_init_revisions(the_repository, &revs, prefix);
302
303
/*
@@ -377,7 +386,8 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
386
continue;
387
while (decoration) {
388
if (decoration->type == DECORATION_REF_LOCAL &&
380
- strset_contains(update_refs, decoration->name)) {
389
+ (contained || strset_contains(update_refs,
390
+ decoration->name))) {
391
printf("update %s %s %s\n",
392
decoration->name,
393
oid_to_hex(&last_commit->object.oid),
t/t3650-replay-basics.sh
+29
@@ -114,4 +114,33 @@ test_expect_success 'replay fails when both --advance and --onto are omitted' '
114
test_must_fail git replay topic1..topic2 >result
115
'
116
117
+test_expect_success 'using replay to also rebase a contained branch' '
118
+ git replay --contained --onto main main..topic3 >result &&
119
+
120
+ test_line_count = 2 result &&
121
+ cut -f 3 -d " " result >new-branch-tips &&
122
+
123
+ git log --format=%s $(head -n 1 new-branch-tips) >actual &&
124
+ test_write_lines F C M L B A >expect &&
125
+ test_cmp expect actual &&
126
+
127
+ git log --format=%s $(tail -n 1 new-branch-tips) >actual &&
128
+ test_write_lines H G F C M L B A >expect &&
129
+ test_cmp expect actual &&
130
+
131
+ printf "update refs/heads/topic1 " >expect &&
132
+ printf "%s " $(head -n 1 new-branch-tips) >>expect &&
133
+ git rev-parse topic1 >>expect &&
134
+ printf "update refs/heads/topic3 " >>expect &&
135
+ printf "%s " $(tail -n 1 new-branch-tips) >>expect &&
136
+ git rev-parse topic3 >>expect &&
137
+
138
+ test_cmp expect result
139
+'
140
+
141
+test_expect_success 'using replay on bare repo to also rebase a contained branch' '
142
+ git -C bare replay --contained --onto main main..topic3 >result-bare &&
143
+ test_cmp expect result-bare
144
+'
145
+
146
test_done