replay: introduce new builtin

For now, this is just a rename from `t/helper/test-fast-rebase.c` into `builtin/replay.c` with minimal changes to make it build appropriately. Let's add a stub documentation and a stub test script though. Subsequent commits will flesh out the capabilities of the new command and make it a more standard regular builtin. Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> 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 f920b0289ba3971451a1cd478baa1d4fddbb0a0b
11 files changed +122 -41
.gitignore
+1
@@ -135,6 +135,7 @@
135 /git-remote-ext
136 /git-repack
137 /git-replace
138 +/git-replay
139 /git-request-pull
140 /git-rerere
141 /git-reset
Documentation/git-replay.txt new
+39
@@ -0,0 +1,39 @@
1 +git-replay(1)
2 +=============
3 +
4 +NAME
5 +----
6 +git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos too
7 +
8 +
9 +SYNOPSIS
10 +--------
11 +[verse]
12 +(EXPERIMENTAL!) 'git replay' --onto <newbase> <oldbase> <branch>
13 +
14 +DESCRIPTION
15 +-----------
16 +
17 +Takes a range of commits, specified by <oldbase> and <branch>, and
18 +replays them onto a new location (see `--onto` option below).
19 +
20 +THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
21 +
22 +OPTIONS
23 +-------
24 +
25 +--onto <newbase>::
26 + Starting point at which to create the new commits. May be any
27 + valid commit, and not just an existing branch name.
28 +
29 +EXIT STATUS
30 +-----------
31 +
32 +For a successful, non-conflicted replay, the exit status is 0. When
33 +the replay has conflicts, the exit status is 1. If the replay is not
34 +able to complete (or start) due to some kind of error, the exit status
35 +is something other than 0 or 1.
36 +
37 +GIT
38 +---
39 +Part of the linkgit:git[1] suite
Makefile
+1 -1
@@ -799,7 +799,6 @@ TEST_BUILTINS_OBJS += test-dump-split-index.o
799 TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
800 TEST_BUILTINS_OBJS += test-env-helper.o
801 TEST_BUILTINS_OBJS += test-example-decorate.o
802 -TEST_BUILTINS_OBJS += test-fast-rebase.o
802 TEST_BUILTINS_OBJS += test-find-pack.o
803 TEST_BUILTINS_OBJS += test-fsmonitor-client.o
804 TEST_BUILTINS_OBJS += test-genrandom.o
@@ -1290,6 +1289,7 @@ BUILTIN_OBJS += builtin/remote-fd.o
1289 BUILTIN_OBJS += builtin/remote.o
1290 BUILTIN_OBJS += builtin/repack.o
1291 BUILTIN_OBJS += builtin/replace.o
1292 +BUILTIN_OBJS += builtin/replay.o
1293 BUILTIN_OBJS += builtin/rerere.o
1294 BUILTIN_OBJS += builtin/reset.o
1295 BUILTIN_OBJS += builtin/rev-list.o
builtin.h
+1
@@ -211,6 +211,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix);
211 int cmd_remote_ext(int argc, const char **argv, const char *prefix);
212 int cmd_remote_fd(int argc, const char **argv, const char *prefix);
213 int cmd_repack(int argc, const char **argv, const char *prefix);
214 +int cmd_replay(int argc, const char **argv, const char *prefix);
215 int cmd_rerere(int argc, const char **argv, const char *prefix);
216 int cmd_reset(int argc, const char **argv, const char *prefix);
217 int cmd_restore(int argc, const char **argv, const char *prefix);
builtin/replay.c renamed
+9 -20
@@ -1,17 +1,11 @@
1 /*
2 - * "git fast-rebase" builtin command
3 - *
4 - * FAST: Forking Any Subprocesses (is) Taboo
5 - *
6 - * This is meant SOLELY as a demo of what is possible. sequencer.c and
7 - * rebase.c should be refactored to use the ideas here, rather than attempting
8 - * to extend this file to replace those (unless Phillip or Dscho say that
9 - * refactoring is too hard and we need a clean slate, but I'm guessing that
10 - * refactoring is the better route).
2 + * "git replay" builtin command
3 */
4
5 #define USE_THE_INDEX_VARIABLE
14 -#include "test-tool.h"
6 +#include "git-compat-util.h"
7 +
8 +#include "builtin.h"
9 #include "cache-tree.h"
10 #include "commit.h"
11 #include "environment.h"
@@ -27,7 +21,8 @@
21 #include "sequencer.h"
22 #include "setup.h"
23 #include "strvec.h"
30 -#include "tree.h"
24 +#include <oidset.h>
25 +#include <tree.h>
26
27 static const char *short_commit_name(struct commit *commit)
28 {
@@ -94,7 +89,7 @@ static struct commit *create_commit(struct tree *tree,
89 return (struct commit *)obj;
90 }
91
97 -int cmd__fast_rebase(int argc, const char **argv)
92 +int cmd_replay(int argc, const char **argv, const char *prefix)
93 {
94 struct commit *onto;
95 struct commit *last_commit = NULL, *last_picked_commit = NULL;
@@ -110,14 +105,8 @@ int cmd__fast_rebase(int argc, const char **argv)
105 struct strbuf branch_name = STRBUF_INIT;
106 int ret = 0;
107
113 - /*
114 - * test-tool stuff doesn't set up the git directory by default; need to
115 - * do that manually.
116 - */
117 - setup_git_directory();
118 -
108 if (argc == 2 && !strcmp(argv[1], "-h")) {
120 - printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
109 + printf("usage: (EXPERIMENTAL!) git replay --onto <newbase> <oldbase> <branch>\n");
110 exit(129);
111 }
112
@@ -136,7 +125,7 @@ int cmd__fast_rebase(int argc, const char **argv)
125 if (repo_read_index(the_repository) < 0)
126 BUG("Could not read index");
127
139 - repo_init_revisions(the_repository, &revs, NULL);
128 + repo_init_revisions(the_repository, &revs, prefix);
129 revs.verbose_header = 1;
130 revs.max_parents = 1;
131 revs.cherry_mark = 1;
command-list.txt
+1
@@ -160,6 +160,7 @@ git-reflog ancillarymanipulators complete
160 git-remote ancillarymanipulators complete
161 git-repack ancillarymanipulators complete
162 git-replace ancillarymanipulators complete
163 +git-replay plumbingmanipulators
164 git-request-pull foreignscminterface complete
165 git-rerere ancillaryinterrogators
166 git-reset mainporcelain history
git.c
+1
@@ -594,6 +594,7 @@ static struct cmd_struct commands[] = {
594 { "remote-fd", cmd_remote_fd, NO_PARSEOPT },
595 { "repack", cmd_repack, RUN_SETUP },
596 { "replace", cmd_replace, RUN_SETUP },
597 + { "replay", cmd_replay, RUN_SETUP },
598 { "rerere", cmd_rerere, RUN_SETUP },
599 { "reset", cmd_reset, RUN_SETUP },
600 { "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
t/helper/test-tool.c
-1
@@ -30,7 +30,6 @@ static struct test_cmd cmds[] = {
30 { "dump-untracked-cache", cmd__dump_untracked_cache },
31 { "env-helper", cmd__env_helper },
32 { "example-decorate", cmd__example_decorate },
33 - { "fast-rebase", cmd__fast_rebase },
33 { "find-pack", cmd__find_pack },
34 { "fsmonitor-client", cmd__fsmonitor_client },
35 { "genrandom", cmd__genrandom },
t/helper/test-tool.h
-1
@@ -24,7 +24,6 @@ int cmd__dump_untracked_cache(int argc, const char **argv);
24 int cmd__dump_reftable(int argc, const char **argv);
25 int cmd__env_helper(int argc, const char **argv);
26 int cmd__example_decorate(int argc, const char **argv);
27 -int cmd__fast_rebase(int argc, const char **argv);
27 int cmd__find_pack(int argc, const char **argv);
28 int cmd__fsmonitor_client(int argc, const char **argv);
29 int cmd__genrandom(int argc, const char **argv);
t/t3650-replay-basics.sh new
+60
@@ -0,0 +1,60 @@
1 +#!/bin/sh
2 +
3 +test_description='basic git replay tests'
4 +
5 +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7 +
8 +. ./test-lib.sh
9 +
10 +GIT_AUTHOR_NAME=author@name
11 +GIT_AUTHOR_EMAIL=bogus@email@address
12 +export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
13 +
14 +test_expect_success 'setup' '
15 + test_commit A &&
16 + test_commit B &&
17 +
18 + git switch -c topic1 &&
19 + test_commit C &&
20 + git switch -c topic2 &&
21 + test_commit D &&
22 + test_commit E &&
23 + git switch topic1 &&
24 + test_commit F &&
25 + git switch -c topic3 &&
26 + test_commit G &&
27 + test_commit H &&
28 + git switch -c topic4 main &&
29 + test_commit I &&
30 + test_commit J &&
31 +
32 + git switch -c next main &&
33 + test_commit K &&
34 + git merge -m "Merge topic1" topic1 &&
35 + git merge -m "Merge topic2" topic2 &&
36 + git merge -m "Merge topic3" topic3 &&
37 + >evil &&
38 + git add evil &&
39 + git commit --amend &&
40 + git merge -m "Merge topic4" topic4 &&
41 +
42 + git switch main &&
43 + test_commit L &&
44 + test_commit M &&
45 +
46 + git switch -c conflict B &&
47 + test_commit C.conflict C.t conflict
48 +'
49 +
50 +test_expect_success 'using replay to rebase two branches, one on top of other' '
51 + git switch main &&
52 +
53 + git replay --onto main topic1 topic2 >result &&
54 +
55 + git log --format=%s $(cut -f 3 -d " " result) >actual &&
56 + test_write_lines E D M L B A >expect &&
57 + test_cmp expect actual
58 +'
59 +
60 +test_done
t/t6429-merge-sequence-rename-caching.sh
+9 -18
@@ -71,9 +71,8 @@ test_expect_success 'caching renames does not preclude finding new ones' '
71
72 git switch upstream &&
73
74 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
74 + git replay --onto HEAD upstream~1 topic &&
75 git reset --hard topic &&
76 - #git cherry-pick upstream~1..topic
76
77 git ls-files >tracked-files &&
78 test_line_count = 2 tracked-files &&
@@ -141,8 +140,7 @@ test_expect_success 'cherry-pick both a commit and its immediate revert' '
140 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
141 export GIT_TRACE2_PERF &&
142
144 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
145 - #git cherry-pick upstream~1..topic &&
143 + git replay --onto HEAD upstream~1 topic &&
144
145 grep region_enter.*diffcore_rename trace.output >calls &&
146 test_line_count = 1 calls
@@ -200,9 +198,8 @@ test_expect_success 'rename same file identically, then reintroduce it' '
198 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
199 export GIT_TRACE2_PERF &&
200
203 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
201 + git replay --onto HEAD upstream~1 topic &&
202 git reset --hard topic &&
205 - #git cherry-pick upstream~1..topic &&
203
204 git ls-files >tracked &&
205 test_line_count = 2 tracked &&
@@ -278,9 +275,8 @@ test_expect_success 'rename same file identically, then add file to old dir' '
275 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
276 export GIT_TRACE2_PERF &&
277
281 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
278 + git replay --onto HEAD upstream~1 topic &&
279 git reset --hard topic &&
283 - #git cherry-pick upstream~1..topic &&
280
281 git ls-files >tracked &&
282 test_line_count = 4 tracked &&
@@ -356,8 +352,7 @@ test_expect_success 'cached dir rename does not prevent noticing later conflict'
352 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
353 export GIT_TRACE2_PERF &&
354
359 - test_must_fail test-tool fast-rebase --onto HEAD upstream~1 topic >output &&
360 - #git cherry-pick upstream..topic &&
355 + test_must_fail git replay --onto HEAD upstream~1 topic >output &&
356
357 grep region_enter.*diffcore_rename trace.output >calls &&
358 test_line_count = 2 calls
@@ -456,9 +451,8 @@ test_expect_success 'dir rename unneeded, then add new file to old dir' '
451 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
452 export GIT_TRACE2_PERF &&
453
459 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
454 + git replay --onto HEAD upstream~1 topic &&
455 git reset --hard topic &&
461 - #git cherry-pick upstream..topic &&
456
457 grep region_enter.*diffcore_rename trace.output >calls &&
458 test_line_count = 2 calls &&
@@ -523,9 +517,8 @@ test_expect_success 'dir rename unneeded, then rename existing file into old dir
517 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
518 export GIT_TRACE2_PERF &&
519
526 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
520 + git replay --onto HEAD upstream~1 topic &&
521 git reset --hard topic &&
528 - #git cherry-pick upstream..topic &&
522
523 grep region_enter.*diffcore_rename trace.output >calls &&
524 test_line_count = 3 calls &&
@@ -626,9 +619,8 @@ test_expect_success 'caching renames only on upstream side, part 1' '
619 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
620 export GIT_TRACE2_PERF &&
621
629 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
622 + git replay --onto HEAD upstream~1 topic &&
623 git reset --hard topic &&
631 - #git cherry-pick upstream..topic &&
624
625 grep region_enter.*diffcore_rename trace.output >calls &&
626 test_line_count = 1 calls &&
@@ -685,9 +677,8 @@ test_expect_success 'caching renames only on upstream side, part 2' '
677 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
678 export GIT_TRACE2_PERF &&
679
688 - test-tool fast-rebase --onto HEAD upstream~1 topic &&
680 + git replay --onto HEAD upstream~1 topic &&
681 git reset --hard topic &&
690 - #git cherry-pick upstream..topic &&
682
683 grep region_enter.*diffcore_rename trace.output >calls &&
684 test_line_count = 2 calls &&