]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'tc/replay-down-to-root'
authorJunio C Hamano <gitster@pobox.com>
Mon, 6 Apr 2026 22:42:49 +0000 (15:42 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 6 Apr 2026 22:42:49 +0000 (15:42 -0700)
git replay now supports replaying down to the root commit.

* tc/replay-down-to-root:
  replay: support replaying down from root commit

1  2 
replay.c
t/t3650-replay-basics.sh

diff --cc replay.c
index d7239d4c8396d4dd6d9a0e22f5b17ae95a2bac0c,92f2279156d69a3156cb4ac28b082077cbe93b07..cf1f0bcba0b3330ef54c219c7c204f62114e235a
+++ 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;
Simple merge