replay: resolve the replay base outside pick_regular_commit()

Depending on what gets passed into the function pick_regular_commit(),
it decides the new base for the replayed commit. It first tries to find
the replayed results of `pickme`'s parent in the `replayed_commits` map.
If not found, it falls back to `onto`.

When using git-replay(1) with --onto, the fallback is the revision
passed in with this option, but when using --revert, the fallback is
`last_commit`.

It's rather confusing the base is decided partly inside
pick_regular_commit() and partly by its caller.

Move the base selection completely into the caller: replay_revisions().
This bundles all the logic of deciding on the base together. Also, this
reduces the number of parameters of pick_regular_commit(), making its
interface cleaner.

This refactoring doesn't bring any behavior changes.

Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
jch
Toon Claes 2026-07-07 21:07:26 +02:00 committed by Junio C Hamano
parent 4ae2ac8153
commit 8a7fba28ff
1 changed files with 21 additions and 13 deletions

View File

@ -280,25 +280,19 @@ static void put_mapped_commit(kh_oid_map_t *replayed_commits,

static struct commit *pick_regular_commit(struct repository *repo,
struct commit *pickme,
kh_oid_map_t *replayed_commits,
struct commit *onto,
struct commit *replayed_base,
struct merge_options *merge_opt,
struct merge_result *result,
enum replay_mode mode,
enum replay_empty_commit_action empty)
{
struct commit *base, *replayed_base;
struct tree *pickme_tree, *base_tree, *replayed_base_tree;

if (pickme->parents) {
base = pickme->parents->item;
base_tree = repo_get_commit_tree(repo, base);
} else {
base = NULL;
if (pickme->parents)
base_tree = repo_get_commit_tree(repo, pickme->parents->item);
else
base_tree = lookup_tree(repo, repo->hash_algo->empty_tree);
}

replayed_base = get_mapped_commit(replayed_commits, base, onto);
replayed_base_tree = repo_get_commit_tree(repo, replayed_base);
pickme_tree = repo_get_commit_tree(repo, pickme);

@ -439,12 +433,26 @@ int replay_revisions(struct rev_info *revs,
while ((commit = get_revision(revs))) {
const struct name_decoration *decoration;

/*
* Decide where to replay this commit on.
* If the parent commit was replayed already, the replayed result
* can be found in `replayed_commits`. Otherwise fall back to `onto`.
* When reverting, commits are replayed in reverse order and thus
* its parent isn't replayed yet. Therefore revert commits are
* always replayed onto `last_commit`.
*/
struct commit *parent = commit->parents ? commit->parents->item : NULL;
struct commit *base = get_mapped_commit(replayed_commits, parent, onto);

if (mode == REPLAY_MODE_REVERT)
base = last_commit;

if (commit->parents && commit->parents->next)
die(_("replaying merge commits is not supported yet!"));

last_commit = pick_regular_commit(revs->repo, commit, replayed_commits,
mode == REPLAY_MODE_REVERT ? last_commit : onto,
&merge_opt, &result, mode, opts->empty);
last_commit = pick_regular_commit(revs->repo, commit, base,
&merge_opt, &result,
mode, opts->empty);
if (!last_commit)
break;