From: Junio C Hamano Date: Mon, 6 Apr 2026 22:42:49 +0000 (-0700) Subject: Merge branch 'tc/replay-down-to-root' X-Git-Tag: v2.54.0-rc1~20 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=da54784d1cc3f4fdd90622fb9e3ae34a9e771702;p=thirdparty%2Fgit.git Merge branch 'tc/replay-down-to-root' git replay now supports replaying down to the root commit. * tc/replay-down-to-root: replay: support replaying down from root commit --- da54784d1cc3f4fdd90622fb9e3ae34a9e771702 diff --cc replay.c index d7239d4c83,92f2279156..cf1f0bcba0 --- a/replay.c +++ b/replay.c @@@ -271,45 -228,33 +274,53 @@@ static struct commit *pick_regular_comm struct commit *base, *replayed_base; struct tree *pickme_tree, *base_tree, *replayed_base_tree; - base = pickme->parents->item; - replayed_base = mapped_commit(replayed_commits, base, onto); + if (pickme->parents) { + base = pickme->parents->item; + base_tree = repo_get_commit_tree(repo, base); + } else { + base = NULL; + base_tree = lookup_tree(repo, repo->hash_algo->empty_tree); + } + replayed_base = mapped_commit(replayed_commits, base, onto); replayed_base_tree = repo_get_commit_tree(repo, replayed_base); pickme_tree = repo_get_commit_tree(repo, pickme); - base_tree = repo_get_commit_tree(repo, base); - merge_opt->branch1 = short_commit_name(repo, replayed_base); - merge_opt->branch2 = short_commit_name(repo, pickme); - if (pickme->parents) - merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2); - else - merge_opt->ancestor = xstrdup("empty tree"); - - merge_incore_nonrecursive(merge_opt, - base_tree, - replayed_base_tree, - pickme_tree, - result); - - free((char*)merge_opt->ancestor); + if (mode == REPLAY_MODE_PICK) { + /* Cherry-pick: normal order */ + merge_opt->branch1 = short_commit_name(repo, replayed_base); + merge_opt->branch2 = short_commit_name(repo, pickme); - merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2); ++ if (pickme->parents) ++ merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2); ++ else ++ merge_opt->ancestor = xstrdup("empty tree"); + + merge_incore_nonrecursive(merge_opt, + base_tree, + replayed_base_tree, + pickme_tree, + result); + + free((char *)merge_opt->ancestor); + } else if (mode == REPLAY_MODE_REVERT) { + /* Revert: swap base and pickme to reverse the diff */ + const char *pickme_name = short_commit_name(repo, pickme); + merge_opt->branch1 = short_commit_name(repo, replayed_base); + merge_opt->branch2 = xstrfmt("parent of %s", pickme_name); + merge_opt->ancestor = pickme_name; + + merge_incore_nonrecursive(merge_opt, + pickme_tree, + replayed_base_tree, + base_tree, + result); + + free((char *)merge_opt->branch2); + } else { + BUG("unexpected replay mode %d", mode); + } merge_opt->ancestor = NULL; + merge_opt->branch2 = NULL; if (!result->clean) return NULL; /* Drop commits that become empty */ @@@ -358,14 -301,9 +369,12 @@@ int replay_revisions(struct rev_info *r int ret; advance = xstrdup_or_null(opts->advance); + revert = xstrdup_or_null(opts->revert); + if (revert) + mode = REPLAY_MODE_REVERT; set_up_replay_mode(revs->repo, &revs->cmdline, opts->onto, - &detached_head, &advance, &onto, &update_refs); + &detached_head, &advance, &revert, &onto, &update_refs); - /* FIXME: Should allow replaying commits with the first as a root commit */ - if (prepare_revision_walk(revs) < 0) { ret = error(_("error preparing revisions")); goto out;