]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Revert "Merge branch 'tc/replay-linearize' into next"
authorJunio C Hamano <gitster@pobox.com>
Tue, 28 Jul 2026 18:26:59 +0000 (11:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 28 Jul 2026 18:26:59 +0000 (11:26 -0700)
This reverts commit 371c2e9c3b9ad9a668ee0f5f47f81d479c1afac1,
reversing changes made to fd2b979b73af2a6f37990768e06ca970519d4355,
to re-queue the v8 iteration of the topic.

Documentation/git-replay.adoc
builtin/replay.c
replay.c
replay.h
t/t3650-replay-basics.sh

index 98e20c1c6eeca0b12796cae7ccad85ebbae44676..a32f72aead3750c4c34fb397e1a4d644621d9fb2 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 (EXPERIMENTAL!) 'git replay' ([--contained] --onto=<newbase> | --advance=<branch> | --revert=<branch>)
-                            [--ref=<ref>] [--ref-action=<mode>] [--linearize] <revision-range>
+                            [--ref=<ref>] [--ref-action=<mode>] <revision-range>
 
 DESCRIPTION
 -----------
@@ -88,23 +88,6 @@ incompatible with `--contained` (which is a modifier for `--onto` only).
 +
 The default mode can be configured via the `replay.refAction` configuration variable.
 
---linearize::
-       In this mode, each replayed commit is stacked on top of the
-       previously replayed one, so all replayed commits are flattened into
-       a single linear history.
-+
-When a merge commit is encountered, the behavior of git-rebase(1)'s
-option `--no-rebase-merges` is imitated. All commits in the range
-reachable from the merge commit are replayed into a linear history, and
-the merge commit itself is dropped. A ref that pointed to a merge commit
-is updated to the merge's last replayed ancestor.
-+
-This flattens the `<revision-range>` as a whole. When multiple revision
-ranges are given they are stacked on top of each other into one linear
-history. Each of their refs is updated to point to its position in that
-history. To linearize ranges separately, replay them in separate `git
-replay` invocations.
-
 <revision-range>::
        Range of commits to replay; see "Specifying Ranges" in
        linkgit:git-rev-parse[1]. In `--advance=<branch>` or
index 5e6ff4191ae4860e2b823d872a0a2ceaff244b0c..39e3a86f6c10ab70cf7fb56b0335dbf569fde2a3 100644 (file)
@@ -85,7 +85,7 @@ int cmd_replay(int argc,
        const char *const replay_usage[] = {
                N_("(EXPERIMENTAL!) git replay "
                   "([--contained] --onto=<newbase> | --advance=<branch> | --revert=<branch>)\n"
-                  "[--ref=<ref>] [--ref-action=<mode>] [--linearize] <revision-range>"),
+                  "[--ref=<ref>] [--ref-action=<mode>] <revision-range>"),
                NULL
        };
        struct option replay_options[] = {
@@ -111,8 +111,6 @@ int cmd_replay(int argc,
                             N_("mode"),
                             N_("control ref update behavior (update|print)"),
                             PARSE_OPT_NONEG),
-               OPT_BOOL(0, "linearize", &opts.linearize,
-                        N_("drop merge commits, replaying only non-merge commits")),
                OPT_END()
        };
 
index 154fec4a2a599c2043a1ff288b33ed8513110792..463c900d6c7c56b6b2638fefd5976b8102e83b62 100644 (file)
--- a/replay.c
+++ b/replay.c
@@ -254,9 +254,9 @@ static void set_up_replay_mode(struct repository *repo,
        strset_clear(&rinfo.positive_refs);
 }
 
-static struct commit *get_mapped_commit(kh_oid_map_t *replayed_commits,
-                                       struct commit *commit,
-                                       struct commit *fallback)
+static struct commit *mapped_commit(kh_oid_map_t *replayed_commits,
+                                   struct commit *commit,
+                                   struct commit *fallback)
 {
        khint_t pos;
        if (!commit)
@@ -267,36 +267,27 @@ static struct commit *get_mapped_commit(kh_oid_map_t *replayed_commits,
        return kh_value(replayed_commits, pos);
 }
 
-static void put_mapped_commit(kh_oid_map_t *replayed_commits,
-                             struct commit *commit,
-                             struct commit *new_commit)
-{
-       khint_t pos;
-       int ret;
-
-       pos = kh_put_oid_map(replayed_commits, commit->object.oid, &ret);
-       if (ret == 0)
-               BUG("Duplicate rewritten commit: %s",
-                   oid_to_hex(&commit->object.oid));
-
-       kh_value(replayed_commits, pos) = new_commit;
-}
-
 static struct commit *pick_regular_commit(struct repository *repo,
                                          struct commit *pickme,
-                                         struct commit *replayed_base,
+                                         kh_oid_map_t *replayed_commits,
+                                         struct commit *onto,
                                          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_tree = repo_get_commit_tree(repo, pickme->parents->item);
-       else
+       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);
 
@@ -436,46 +427,24 @@ int replay_revisions(struct rev_info *revs,
        replayed_commits = kh_init_oid_map();
        while ((commit = get_revision(revs))) {
                const struct name_decoration *decoration;
+               khint_t pos;
+               int hr;
 
-               if (commit->parents && commit->parents->next) {
-                       if (!opts->linearize)
-                               die(_("replaying merge commits is not supported yet!"));
-                       /*
-                        * Drop the merge commit: do not pick it, leave
-                        * `last_commit` unchanged, and fall through to the
-                        * rest of the loop. As a result:
-                        * - refs pointing to the merge commit will be updated
-                        *   to `last_commit`.
-                        * - the next replayed commit uses `last_commit` as its
-                        *   `base`.
-                        */
-               } else {
-                       /*
-                        * Decide where to replay this commit onto.
-                        * 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`.
-                        * Also when opts->linearize is true, set the base to
-                        * `last_commit` to create a single linear history.
-                        */
-                       struct commit *parent = commit->parents ? commit->parents->item : NULL;
-                       struct commit *base = get_mapped_commit(replayed_commits, parent, onto);
-
-                       if (opts->linearize || mode == REPLAY_MODE_REVERT)
-                               base = last_commit;
-
-                       last_commit = pick_regular_commit(revs->repo, commit, base,
-                                                         &merge_opt, &result,
-                                                         mode, opts->empty);
-               }
+               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);
                if (!last_commit)
                        break;
 
                /* Record commit -> last_commit mapping */
-               put_mapped_commit(replayed_commits, commit, last_commit);
+               pos = kh_put_oid_map(replayed_commits, commit->object.oid, &hr);
+               if (hr == 0)
+                       BUG("Duplicate rewritten commit: %s\n",
+                           oid_to_hex(&commit->object.oid));
+               kh_value(replayed_commits, pos) = last_commit;
 
                /* Update any necessary branches */
                if (ref)
index 2c71afbfde05b4365a73452376310686f66dcfca..491db145e301514f641854616810b153081a6e70 100644 (file)
--- a/replay.h
+++ b/replay.h
@@ -62,11 +62,6 @@ struct replay_revisions_options {
         * Defaults to REPLAY_EMPTY_COMMIT_DROP.
         */
        enum replay_empty_commit_action empty;
-
-       /*
-        * Whether to linearize the commits (i.e. drop merge commits).
-        */
-       int linearize;
 };
 
 /* This struct is used as an out-parameter by `replay_revisions()`. */
index 4d3d442e8aad5e25e4df7a0170c9401d597bb417..3353bc4a4dc6ed4691a7c096cec68ee0c264cbc4 100755 (executable)
@@ -52,19 +52,8 @@ test_expect_success 'setup' '
        test_merge P O --no-ff &&
        git switch main &&
 
-       git switch --orphan unrelated &&
-       test_commit unrelated-root &&
-
        git switch -c conflict B &&
-       test_commit C.conflict C.t conflict &&
-       git branch -D unrelated &&
-
-       git switch -c divergent-x main &&
-       test_commit X &&
-       git switch -c divergent-y main &&
-       test_commit Y &&
-       git switch divergent-x &&
-       test_merge Z divergent-y --no-ff
+       test_commit C.conflict C.t conflict
 '
 
 test_expect_success 'setup bare' '
@@ -576,131 +565,4 @@ test_expect_success '--onto with --ref rejects multiple revision ranges' '
        test_grep "cannot be used with multiple revision ranges" err
 '
 
-test_expect_success 'replay to rebase merge commit with --linearize' '
-       git replay --ref-action=print --linearize \
-               --onto main I..topic-with-merge >result &&
-
-       test_line_count = 1 result &&
-
-       git log --format=%s $(cut -f 3 -d " " result) >actual &&
-       test_write_lines O N J M L B A >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success 'replay to rebase merge commit with --linearize down to the root commit' '
-       git replay --ref-action=print --linearize \
-               --onto unrelated-root topic-with-merge >result &&
-
-       test_line_count = 1 result &&
-
-       git log --format=%s $(cut -f 3 -d " " result) >actual &&
-       test_write_lines O N J I B A unrelated-root >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success 'replay to cherry-pick merge commit with --linearize' '
-       git replay --ref-action=print --linearize \
-               --advance main I..topic-with-merge >result &&
-
-       test_line_count = 1 result &&
-
-       git log --format=%s $(cut -f 3 -d " " result) >actual &&
-       test_write_lines O N J M L B A >expect &&
-       test_cmp expect actual &&
-
-       printf "update refs/heads/main " >expect &&
-       printf "%s " $(cut -f 3 -d " " result) >>expect &&
-       git rev-parse main >>expect &&
-       test_cmp expect result
-'
-
-test_expect_success 'replay --linearize produces the same patches' '
-       git replay --ref-action=print --linearize \
-               --onto main I..topic-with-merge >result &&
-
-       test_line_count = 1 result &&
-       tip=$(cut -f 3 -d " " result) &&
-
-       # range-diff does not care about the dropped merge,
-       # so the original commits (I..topic-with-merge)
-       # and the replayed chain (main..tip) must produce identical patches.
-       git range-diff I..topic-with-merge main..$tip >out &&
-       test_file_not_empty out &&
-       test_grep ! -v "=" out &&
-
-       git log --oneline main..$tip >out &&
-       test_line_count = 3 out
-'
-
-test_expect_success 'replay with --linearize rebase multiple divergent branches into a single line' '
-       git replay --ref-action=print --linearize \
-               --onto main ^B topic2 topic3 topic4 >result &&
-
-       test_line_count = 3 result &&
-       cut -f 3 -d " " result >new-branch-tips &&
-
-       >expect &&
-       for i in 2 3 4
-       do
-               printf "update refs/heads/topic$i " >>expect &&
-               printf "%s " $(grep topic$i result | cut -f 3 -d " ") >>expect &&
-               git rev-parse topic$i >>expect || return 1
-       done &&
-
-       test_cmp expect result &&
-
-       test_write_lines           E D C M L B A >expect2 &&
-       test_write_lines     H G F E D C M L B A >expect3 &&
-       test_write_lines J I H G F E D C M L B A >expect4 &&
-
-       for i in 2 3 4
-       do
-               git log --format=%s $(grep topic$i result | cut -f 3 -d " ") >actual &&
-               test_cmp expect$i actual || return 1
-       done
-'
-
-test_expect_success 'replay with --linearize of a divergent merge keeps both sides' '
-       git replay --ref-action=print --linearize \
-               --onto main main..divergent-x >result &&
-       test_line_count = 1 result &&
-       tip=$(cut -f 3 -d " " result) &&
-
-       # The merge Z is dropped, but both X and Y are linearized onto main;
-       # neither side is lost.
-       git log --format=%s main..$tip >actual &&
-       test_write_lines Y X >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success '--linearize with --contained updates contained refs' '
-       git replay --ref-action=print --linearize --contained \
-               --onto main ^B topic-with-merge >result &&
-
-       test_line_count = 2 result &&
-
-       git log --format=%s $(head -n 1 result | cut -f 3 -d " ") >actual &&
-       test_write_lines J I M L B A >expect &&
-       test_cmp expect actual &&
-
-       git log --format=%s $(tail -n 1 result | cut -f 3 -d " ") >actual &&
-       test_write_lines O N J I M L B A >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success 'replay --revert with --linearize reverts a range containing a merge' '
-       git replay --ref-action=print --revert=divergent-x --linearize \
-               main..divergent-x >result &&
-       test_line_count = 1 result &&
-       tip=$(cut -f 3 -d " " result) &&
-
-       git log --format=%s $tip >actual &&
-       test_write_lines \
-               "Revert \"X\"" "Revert \"Y\"" Z Y X M L B A >expect &&
-       test_cmp expect actual &&
-
-       test_must_fail git cat-file -e $tip:X.t &&
-       test_must_fail git cat-file -e $tip:Y.t
-'
-
 test_done