From: Junio C Hamano Date: Tue, 28 Jul 2026 18:26:59 +0000 (-0700) Subject: Revert "Merge branch 'tc/replay-linearize' into next" X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b3b5e47172ef2180679b8b4a15aff66f98e8697d;p=thirdparty%2Fgit.git Revert "Merge branch 'tc/replay-linearize' into next" This reverts commit 371c2e9c3b9ad9a668ee0f5f47f81d479c1afac1, reversing changes made to fd2b979b73af2a6f37990768e06ca970519d4355, to re-queue the v8 iteration of the topic. --- diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc index 98e20c1c6e..a32f72aead 100644 --- a/Documentation/git-replay.adoc +++ b/Documentation/git-replay.adoc @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] (EXPERIMENTAL!) 'git replay' ([--contained] --onto= | --advance= | --revert=) - [--ref=] [--ref-action=] [--linearize] + [--ref=] [--ref-action=] 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 `` 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. - :: Range of commits to replay; see "Specifying Ranges" in linkgit:git-rev-parse[1]. In `--advance=` or diff --git a/builtin/replay.c b/builtin/replay.c index 5e6ff4191a..39e3a86f6c 100644 --- a/builtin/replay.c +++ b/builtin/replay.c @@ -85,7 +85,7 @@ int cmd_replay(int argc, const char *const replay_usage[] = { N_("(EXPERIMENTAL!) git replay " "([--contained] --onto= | --advance= | --revert=)\n" - "[--ref=] [--ref-action=] [--linearize] "), + "[--ref=] [--ref-action=] "), 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() }; diff --git a/replay.c b/replay.c index 154fec4a2a..463c900d6c 100644 --- 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) diff --git a/replay.h b/replay.h index 2c71afbfde..491db145e3 100644 --- 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()`. */ diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh index 4d3d442e8a..3353bc4a4d 100755 --- a/t/t3650-replay-basics.sh +++ b/t/t3650-replay-basics.sh @@ -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