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>
This commit is contained in:
Elijah Newren 2023-11-24 12:10:31 +01:00 committed by Junio C Hamano
parent b9d0991cc7
commit f920b0289b
11 changed files with 122 additions and 41 deletions

1
.gitignore vendored
View File

@ -135,6 +135,7 @@
/git-remote-ext
/git-repack
/git-replace
/git-replay
/git-request-pull
/git-rerere
/git-reset

View File

@ -0,0 +1,39 @@
git-replay(1)
=============
NAME
----
git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos too
SYNOPSIS
--------
[verse]
(EXPERIMENTAL!) 'git replay' --onto <newbase> <oldbase> <branch>
DESCRIPTION
-----------
Takes a range of commits, specified by <oldbase> and <branch>, and
replays them onto a new location (see `--onto` option below).
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
OPTIONS
-------
--onto <newbase>::
Starting point at which to create the new commits. May be any
valid commit, and not just an existing branch name.
EXIT STATUS
-----------
For a successful, non-conflicted replay, the exit status is 0. When
the replay has conflicts, the exit status is 1. If the replay is not
able to complete (or start) due to some kind of error, the exit status
is something other than 0 or 1.
GIT
---
Part of the linkgit:git[1] suite

View File

@ -799,7 +799,6 @@ TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
TEST_BUILTINS_OBJS += test-env-helper.o
TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-fast-rebase.o
TEST_BUILTINS_OBJS += test-find-pack.o
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
TEST_BUILTINS_OBJS += test-genrandom.o
@ -1290,6 +1289,7 @@ BUILTIN_OBJS += builtin/remote-fd.o
BUILTIN_OBJS += builtin/remote.o
BUILTIN_OBJS += builtin/repack.o
BUILTIN_OBJS += builtin/replace.o
BUILTIN_OBJS += builtin/replay.o
BUILTIN_OBJS += builtin/rerere.o
BUILTIN_OBJS += builtin/reset.o
BUILTIN_OBJS += builtin/rev-list.o

View File

@ -211,6 +211,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix);
int cmd_remote_ext(int argc, const char **argv, const char *prefix);
int cmd_remote_fd(int argc, const char **argv, const char *prefix);
int cmd_repack(int argc, const char **argv, const char *prefix);
int cmd_replay(int argc, const char **argv, const char *prefix);
int cmd_rerere(int argc, const char **argv, const char *prefix);
int cmd_reset(int argc, const char **argv, const char *prefix);
int cmd_restore(int argc, const char **argv, const char *prefix);

View File

@ -1,17 +1,11 @@
/*
* "git fast-rebase" builtin command
*
* FAST: Forking Any Subprocesses (is) Taboo
*
* This is meant SOLELY as a demo of what is possible. sequencer.c and
* rebase.c should be refactored to use the ideas here, rather than attempting
* to extend this file to replace those (unless Phillip or Dscho say that
* refactoring is too hard and we need a clean slate, but I'm guessing that
* refactoring is the better route).
* "git replay" builtin command
*/
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "git-compat-util.h"
#include "builtin.h"
#include "cache-tree.h"
#include "commit.h"
#include "environment.h"
@ -27,7 +21,8 @@
#include "sequencer.h"
#include "setup.h"
#include "strvec.h"
#include "tree.h"
#include <oidset.h>
#include <tree.h>
static const char *short_commit_name(struct commit *commit)
{
@ -94,7 +89,7 @@ static struct commit *create_commit(struct tree *tree,
return (struct commit *)obj;
}
int cmd__fast_rebase(int argc, const char **argv)
int cmd_replay(int argc, const char **argv, const char *prefix)
{
struct commit *onto;
struct commit *last_commit = NULL, *last_picked_commit = NULL;
@ -110,14 +105,8 @@ int cmd__fast_rebase(int argc, const char **argv)
struct strbuf branch_name = STRBUF_INIT;
int ret = 0;
/*
* test-tool stuff doesn't set up the git directory by default; need to
* do that manually.
*/
setup_git_directory();
if (argc == 2 && !strcmp(argv[1], "-h")) {
printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
printf("usage: (EXPERIMENTAL!) git replay --onto <newbase> <oldbase> <branch>\n");
exit(129);
}
@ -136,7 +125,7 @@ int cmd__fast_rebase(int argc, const char **argv)
if (repo_read_index(the_repository) < 0)
BUG("Could not read index");
repo_init_revisions(the_repository, &revs, NULL);
repo_init_revisions(the_repository, &revs, prefix);
revs.verbose_header = 1;
revs.max_parents = 1;
revs.cherry_mark = 1;

View File

@ -160,6 +160,7 @@ git-reflog ancillarymanipulators complete
git-remote ancillarymanipulators complete
git-repack ancillarymanipulators complete
git-replace ancillarymanipulators complete
git-replay plumbingmanipulators
git-request-pull foreignscminterface complete
git-rerere ancillaryinterrogators
git-reset mainporcelain history

1
git.c
View File

@ -594,6 +594,7 @@ static struct cmd_struct commands[] = {
{ "remote-fd", cmd_remote_fd, NO_PARSEOPT },
{ "repack", cmd_repack, RUN_SETUP },
{ "replace", cmd_replace, RUN_SETUP },
{ "replay", cmd_replay, RUN_SETUP },
{ "rerere", cmd_rerere, RUN_SETUP },
{ "reset", cmd_reset, RUN_SETUP },
{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },

View File

@ -30,7 +30,6 @@ static struct test_cmd cmds[] = {
{ "dump-untracked-cache", cmd__dump_untracked_cache },
{ "env-helper", cmd__env_helper },
{ "example-decorate", cmd__example_decorate },
{ "fast-rebase", cmd__fast_rebase },
{ "find-pack", cmd__find_pack },
{ "fsmonitor-client", cmd__fsmonitor_client },
{ "genrandom", cmd__genrandom },

View File

@ -24,7 +24,6 @@ int cmd__dump_untracked_cache(int argc, const char **argv);
int cmd__dump_reftable(int argc, const char **argv);
int cmd__env_helper(int argc, const char **argv);
int cmd__example_decorate(int argc, const char **argv);
int cmd__fast_rebase(int argc, const char **argv);
int cmd__find_pack(int argc, const char **argv);
int cmd__fsmonitor_client(int argc, const char **argv);
int cmd__genrandom(int argc, const char **argv);

60
t/t3650-replay-basics.sh Executable file
View File

@ -0,0 +1,60 @@
#!/bin/sh
test_description='basic git replay tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
GIT_AUTHOR_NAME=author@name
GIT_AUTHOR_EMAIL=bogus@email@address
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
test_expect_success 'setup' '
test_commit A &&
test_commit B &&
git switch -c topic1 &&
test_commit C &&
git switch -c topic2 &&
test_commit D &&
test_commit E &&
git switch topic1 &&
test_commit F &&
git switch -c topic3 &&
test_commit G &&
test_commit H &&
git switch -c topic4 main &&
test_commit I &&
test_commit J &&
git switch -c next main &&
test_commit K &&
git merge -m "Merge topic1" topic1 &&
git merge -m "Merge topic2" topic2 &&
git merge -m "Merge topic3" topic3 &&
>evil &&
git add evil &&
git commit --amend &&
git merge -m "Merge topic4" topic4 &&
git switch main &&
test_commit L &&
test_commit M &&
git switch -c conflict B &&
test_commit C.conflict C.t conflict
'
test_expect_success 'using replay to rebase two branches, one on top of other' '
git switch main &&
git replay --onto main topic1 topic2 >result &&
git log --format=%s $(cut -f 3 -d " " result) >actual &&
test_write_lines E D M L B A >expect &&
test_cmp expect actual
'
test_done

View File

@ -71,9 +71,8 @@ test_expect_success 'caching renames does not preclude finding new ones' '
git switch upstream &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream~1..topic
git ls-files >tracked-files &&
test_line_count = 2 tracked-files &&
@ -141,8 +140,7 @@ test_expect_success 'cherry-pick both a commit and its immediate revert' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
#git cherry-pick upstream~1..topic &&
git replay --onto HEAD upstream~1 topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 1 calls
@ -200,9 +198,8 @@ test_expect_success 'rename same file identically, then reintroduce it' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream~1..topic &&
git ls-files >tracked &&
test_line_count = 2 tracked &&
@ -278,9 +275,8 @@ test_expect_success 'rename same file identically, then add file to old dir' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream~1..topic &&
git ls-files >tracked &&
test_line_count = 4 tracked &&
@ -356,8 +352,7 @@ test_expect_success 'cached dir rename does not prevent noticing later conflict'
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test_must_fail test-tool fast-rebase --onto HEAD upstream~1 topic >output &&
#git cherry-pick upstream..topic &&
test_must_fail git replay --onto HEAD upstream~1 topic >output &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 2 calls
@ -456,9 +451,8 @@ test_expect_success 'dir rename unneeded, then add new file to old dir' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream..topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 2 calls &&
@ -523,9 +517,8 @@ test_expect_success 'dir rename unneeded, then rename existing file into old dir
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream..topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 3 calls &&
@ -626,9 +619,8 @@ test_expect_success 'caching renames only on upstream side, part 1' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream..topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 1 calls &&
@ -685,9 +677,8 @@ test_expect_success 'caching renames only on upstream side, part 2' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
test-tool fast-rebase --onto HEAD upstream~1 topic &&
git replay --onto HEAD upstream~1 topic &&
git reset --hard topic &&
#git cherry-pick upstream..topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 2 calls &&