Skip to content

Commit 3916ec3

Browse files
newrenchriscool
authored andcommitted
replay: use standard revision ranges
Instead of the fixed "<oldbase> <branch>" arguments, the replay command now accepts "<revision-range>..." arguments in a similar way as many other Git commands. This makes its interface more standard and more flexible. This also enables many revision related options accepted and eaten by setup_revisions(). If the replay command was a high level one or had a high level mode, it would make sense to restrict some of the possible options, like those generating non-contiguous history, as they could be confusing for most users. Also as the interface of the command is now mostly finalized, we can add more documentation and more testcases to make sure the command will continue to work as designed in the future. We only document the rev-list related options among all the revision related options that are now accepted, as the rev-list related ones are probably the most useful for now. Helped-by: Dragan Simic <[email protected]> Helped-by: Linus Arver <[email protected]> Co-authored-by: Christian Couder <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Christian Couder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 81613be commit 3916ec3

File tree

4 files changed

+77
-32
lines changed

4 files changed

+77
-32
lines changed

Documentation/git-replay.txt

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t
99
SYNOPSIS
1010
--------
1111
[verse]
12-
(EXPERIMENTAL!) 'git replay' --onto <newbase> <oldbase> <branch>
12+
(EXPERIMENTAL!) 'git replay' --onto <newbase> <revision-range>...
1313

1414
DESCRIPTION
1515
-----------
1616

17-
Takes a range of commits, specified by <oldbase> and <branch>, and
18-
replays them onto a new location (see `--onto` option below). Leaves
17+
Takes ranges of commits and replays them onto a new location. Leaves
1918
the working tree and the index untouched, and updates no references.
2019
The output of this command is meant to be used as input to
21-
`git update-ref --stdin`, which would update the relevant branches.
20+
`git update-ref --stdin`, which would update the relevant branches
21+
(see the OUTPUT section below).
2222

2323
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
2424

@@ -28,6 +28,30 @@ OPTIONS
2828
--onto <newbase>::
2929
Starting point at which to create the new commits. May be any
3030
valid commit, and not just an existing branch name.
31+
+
32+
The update-ref command(s) in the output will update the branch(es) in
33+
the revision range to point at the new commits, similar to the way how
34+
`git rebase --update-refs` updates multiple branches in the affected
35+
range.
36+
37+
<revision-range>::
38+
Range of commits to replay; see "Specifying Ranges" in
39+
linkgit:git-rev-parse and the "Commit Limiting" options below.
40+
41+
include::rev-list-options.txt[]
42+
43+
OUTPUT
44+
------
45+
46+
When there are no conflicts, the output of this command is usable as
47+
input to `git update-ref --stdin`. It is of the form:
48+
49+
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
50+
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
51+
update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
52+
53+
where the number of refs updated depends on the arguments passed and
54+
the shape of the history being replayed.
3155

3256
EXIT STATUS
3357
-----------
@@ -37,6 +61,32 @@ the replay has conflicts, the exit status is 1. If the replay is not
3761
able to complete (or start) due to some kind of error, the exit status
3862
is something other than 0 or 1.
3963

64+
EXAMPLES
65+
--------
66+
67+
To simply rebase `mybranch` onto `target`:
68+
69+
------------
70+
$ git replay --onto target origin/main..mybranch
71+
update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}
72+
------------
73+
74+
When calling `git replay`, one does not need to specify a range of
75+
commits to replay using the syntax `A..B`; any range expression will
76+
do:
77+
78+
------------
79+
$ git replay --onto origin/main ^base branch1 branch2 branch3
80+
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
81+
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
82+
update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
83+
------------
84+
85+
This will simultaneously rebase `branch1`, `branch2`, and `branch3`,
86+
all commits they have since `base`, playing them on top of
87+
`origin/main`. These three branches may have commits on top of `base`
88+
that they have in common, but that does not need to be the case.
89+
4090
GIT
4191
---
4292
Part of the linkgit:git[1] suite

builtin/replay.c

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "parse-options.h"
1515
#include "refs.h"
1616
#include "revision.h"
17-
#include "strvec.h"
1817
#include <oidset.h>
1918
#include <tree.h>
2019

@@ -118,16 +117,14 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
118117
struct commit *onto;
119118
const char *onto_name = NULL;
120119
struct commit *last_commit = NULL;
121-
struct strvec rev_walk_args = STRVEC_INIT;
122120
struct rev_info revs;
123121
struct commit *commit;
124122
struct merge_options merge_opt;
125123
struct merge_result result;
126-
struct strbuf branch_name = STRBUF_INIT;
127124
int ret = 0;
128125

129126
const char * const replay_usage[] = {
130-
N_("(EXPERIMENTAL!) git replay --onto <newbase> <oldbase> <branch>"),
127+
N_("(EXPERIMENTAL!) git replay --onto <newbase> <revision-range>..."),
131128
NULL
132129
};
133130
struct option replay_options[] = {
@@ -145,18 +142,10 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
145142
usage_with_options(replay_usage, replay_options);
146143
}
147144

148-
if (argc != 3) {
149-
error(_("bad number of arguments"));
150-
usage_with_options(replay_usage, replay_options);
151-
}
152-
153145
onto = peel_committish(onto_name);
154-
strbuf_addf(&branch_name, "refs/heads/%s", argv[2]);
155146

156147
repo_init_revisions(the_repository, &revs, prefix);
157148

158-
strvec_pushl(&rev_walk_args, "", argv[2], "--not", argv[1], NULL);
159-
160149
/*
161150
* Set desired values for rev walking options here. If they
162151
* are changed by some user specified option in setup_revisions()
@@ -171,8 +160,9 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
171160
revs.topo_order = 1;
172161
revs.simplify_history = 0;
173162

174-
if (setup_revisions(rev_walk_args.nr, rev_walk_args.v, &revs, NULL) > 1) {
175-
ret = error(_("unhandled options"));
163+
argc = setup_revisions(argc, argv, &revs, NULL);
164+
if (argc > 1) {
165+
ret = error(_("unrecognized argument: %s"), argv[1]);
176166
goto cleanup;
177167
}
178168

@@ -205,8 +195,6 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
205195
revs.simplify_history = 0;
206196
}
207197

208-
strvec_clear(&rev_walk_args);
209-
210198
if (prepare_revision_walk(&revs) < 0) {
211199
ret = error(_("error preparing revisions"));
212200
goto cleanup;
@@ -248,7 +236,6 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
248236
ret = result.clean;
249237

250238
cleanup:
251-
strbuf_release(&branch_name);
252239
release_revisions(&revs);
253240

254241
/* Return */

t/t3650-replay-basics.sh

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ test_expect_success 'setup bare' '
5252
'
5353

5454
test_expect_success 'using replay to rebase two branches, one on top of other' '
55-
git replay --onto main topic1 topic2 >result &&
55+
git replay --onto main topic1..topic2 >result &&
5656
5757
test_line_count = 1 result &&
5858
@@ -68,8 +68,16 @@ test_expect_success 'using replay to rebase two branches, one on top of other' '
6868
'
6969

7070
test_expect_success 'using replay on bare repo to rebase two branches, one on top of other' '
71-
git -C bare replay --onto main topic1 topic2 >result-bare &&
71+
git -C bare replay --onto main topic1..topic2 >result-bare &&
7272
test_cmp expect result-bare
7373
'
7474

75+
test_expect_success 'using replay to rebase with a conflict' '
76+
test_expect_code 1 git replay --onto topic1 B..conflict
77+
'
78+
79+
test_expect_success 'using replay on bare repo to rebase with a conflict' '
80+
test_expect_code 1 git -C bare replay --onto topic1 B..conflict
81+
'
82+
7583
test_done

t/t6429-merge-sequence-rename-caching.sh

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ test_expect_success 'caching renames does not preclude finding new ones' '
7171
7272
git switch upstream &&
7373
74-
git replay --onto HEAD upstream~1 topic >out &&
74+
git replay --onto HEAD upstream~1..topic >out &&
7575
git update-ref --stdin <out &&
7676
git checkout topic &&
7777
@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick both a commit and its immediate revert' '
141141
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
142142
export GIT_TRACE2_PERF &&
143143
144-
git replay --onto HEAD upstream~1 topic >out &&
144+
git replay --onto HEAD upstream~1..topic >out &&
145145
git update-ref --stdin <out &&
146146
git checkout topic &&
147147
@@ -201,7 +201,7 @@ test_expect_success 'rename same file identically, then reintroduce it' '
201201
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
202202
export GIT_TRACE2_PERF &&
203203
204-
git replay --onto HEAD upstream~1 topic >out &&
204+
git replay --onto HEAD upstream~1..topic >out &&
205205
git update-ref --stdin <out &&
206206
git checkout topic &&
207207
@@ -279,7 +279,7 @@ test_expect_success 'rename same file identically, then add file to old dir' '
279279
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
280280
export GIT_TRACE2_PERF &&
281281
282-
git replay --onto HEAD upstream~1 topic >out &&
282+
git replay --onto HEAD upstream~1..topic >out &&
283283
git update-ref --stdin <out &&
284284
git checkout topic &&
285285
@@ -357,7 +357,7 @@ test_expect_success 'cached dir rename does not prevent noticing later conflict'
357357
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
358358
export GIT_TRACE2_PERF &&
359359
360-
test_must_fail git replay --onto HEAD upstream~1 topic >output &&
360+
test_must_fail git replay --onto HEAD upstream~1..topic >output &&
361361
362362
grep region_enter.*diffcore_rename trace.output >calls &&
363363
test_line_count = 2 calls
@@ -456,7 +456,7 @@ test_expect_success 'dir rename unneeded, then add new file to old dir' '
456456
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
457457
export GIT_TRACE2_PERF &&
458458
459-
git replay --onto HEAD upstream~1 topic >out &&
459+
git replay --onto HEAD upstream~1..topic >out &&
460460
git update-ref --stdin <out &&
461461
git checkout topic &&
462462
@@ -523,7 +523,7 @@ test_expect_success 'dir rename unneeded, then rename existing file into old dir
523523
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
524524
export GIT_TRACE2_PERF &&
525525
526-
git replay --onto HEAD upstream~1 topic >out &&
526+
git replay --onto HEAD upstream~1..topic >out &&
527527
git update-ref --stdin <out &&
528528
git checkout topic &&
529529
@@ -626,7 +626,7 @@ test_expect_success 'caching renames only on upstream side, part 1' '
626626
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
627627
export GIT_TRACE2_PERF &&
628628
629-
git replay --onto HEAD upstream~1 topic >out &&
629+
git replay --onto HEAD upstream~1..topic >out &&
630630
git update-ref --stdin <out &&
631631
git checkout topic &&
632632
@@ -685,7 +685,7 @@ test_expect_success 'caching renames only on upstream side, part 2' '
685685
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
686686
export GIT_TRACE2_PERF &&
687687
688-
git replay --onto HEAD upstream~1 topic >out &&
688+
git replay --onto HEAD upstream~1..topic >out &&
689689
git update-ref --stdin <out &&
690690
git checkout topic &&
691691

0 commit comments

Comments
 (0)