Show 213 quoted lines
>
> Hi,
>
> I'm back with another iteration of the patch series to implement
> --linearize into git-replay(1). My apologies for the long period of
> radio silence, but this topic was stalled on reviews for a while, and
> when I got some feedback I was on leave, so I'm finally back.
>
> As far as I could tell there weren't any remaining comments on the
> implementation itself, only on commit message and docs.
>
> Laters,
> Toon
>
> Original cover letter:
> ===
>
> As an alternative to dscho's patch series to replay merges[1], add
> an option to git-replay(1) to linearize merges. This mimics what
> git-rebase(1) does with --no-rebase-merges (the default).
>
> The first two patches do some refactoring. The third patch implements
> the actual change. The original patch was kindly provided by Dscho,
> which I've tweaked to be upstreamed.
>
> The --linearize option is only added to git-replay(1) and not to
> git-history(1) because in my opinion it doesn't make much sense to do
> so, but I'm happy to hear if anyone disagrees.
>
> Dscho's series to replay merges[1] needs a bit of rework to fit on top
> of this, but I'm happy to help figuring that out. We've been discussing
> to either name the option --flatten or --linearize, but I've decided on
> "linearize" because the documentation of git-rebase(1) also mentions
> "linearize".
>
> [1]: <pull.2106.git.1778107405.gitgitgadget@gmail.com>
>
> ---
> Changes in v9:
> - Rephrase "multiple revision ranges" to "multiple branches".
> - Reword some things in the commit message.
> - Tweak wording in replay.adoc.
> - Link to v8: https://patch.msgid.link/20260728-toon-git-replay-drop-merges-v8-0-ced11dffe749@iotcl.com
>
> Changes in v8:
> - Disallow multiple revision ranges with --linearize.
> - Disallow --contained with --linearize.
> - Link to v7: https://patch.msgid.link/20260707-toon-git-replay-drop-merges-v7-0-808ab9b4afa6@iotcl.com
>
> Changes in v7:
> - Allow --revert and --linearize to be used together.
> - Because quite a lot of changes have been made since the original
> patch, change author from Johannes to Toon for the last commit.
> Johannes already told me he doesn't really care about authorship when
> he initially shared the patch with me.
> - Link to v6: https://patch.msgid.link/20260702-toon-git-replay-drop-merges-v6-0-78a07cdd0382@iotcl.com
>
> Changes in v6:
> - Reworked the second commit that moves picking the base completely
> outside pick_regular_commit(), instead of adding more explanation.
> - Drastically extended the commit message on commit #3.
> - Extended docs on flattening multiple revision ranges and how it's
> different from git-rebase(1)'s --no-rebase-merges.
> - Added a bunch of tests to cover various scenarios.
> - Remove newline from BUG() message.
> - Link to v5: https://patch.msgid.link/20260626-toon-git-replay-drop-merges-v5-0-5e120738b9d0@iotcl.com
>
> Changes in v5:
> - Dropped the enum->bool patch and instead added a patch that better
> explains how pick_regular_commit() picks a base.
> - Order of commits is shuffled.
> - (BIGGEST CHANGE) When working on a refactor to undo the enum->bool
> patch, I extended the code comments to explain how things work. This
> made me realize the use of the "replayed_base" was incorrect when
> multiple branches are rebased with --onto. This is fixed now and a
> test is added for this scenario.
> - Link to v4: https://patch.msgid.link/20260622-toon-git-replay-drop-merges-v4-0-ff257f534319@iotcl.com
>
> Changes in v4:
> - Use test_grep instead of a bare grep in the range-diff test, to
> prepare for mm/test-grep-lint.
> - Link to v3: https://patch.msgid.link/20260616-toon-git-replay-drop-merges-v3-0-153e9eb99ce1@iotcl.com
>
> Changes in v3:
> - Add --linearize to Documentation SYNOPSIS, and mention it's
> incompatible with --revert.
> - Small language change in help message for --linearize.
> - Rephrase comment to include last_commit isn't modified when
> linearizing merges.
> - Remove test that was added in earlier versions, but actually is
> a duplicate of 'replaying merge commits is not supported yet'.
> - Add test to verify --revert and --linearize are incompatible.
> - Properly test that replaying down to root with --linearize works.
> - Add test for --linearize with --advance.
> - Add test that uses git-range-diff(1) to verify the patches created by
> --linearize are correct.
> - Link to v2: https://patch.msgid.link/20260610-toon-git-replay-drop-merges-v2-0-5714a71c6d83@iotcl.com
>
> Changes in v2:
> - Restructured the conditions to detect merge commits and added a line
> of comment why the loop continues.
> - Rewrote tests to use the history from the setup step and added a few
> test cases.
> - Re-added Johannes's Signed-off-by trailer. Johannes gave me the
> patches with this trailer, and if I understand correctly, I can keep
> it. Please let me know if that wrong.
> - Link to v1: https://patch.msgid.link/20260608-toon-git-replay-drop-merges-v1-0-e3ee71fce7b4@iotcl.com
>
> ---
> Toon Claes (3):
> replay: add helper to put entry into replayed_commits
> replay: resolve the replay base outside pick_regular_commit()
> replay: offer an option to linearize the commit topology
>
> Documentation/git-replay.adoc | 17 ++++++-
> builtin/replay.c | 6 ++-
> replay.c | 87 +++++++++++++++++++++++----------
> replay.h | 5 ++
> t/t3650-replay-basics.sh | 109 +++++++++++++++++++++++++++++++++++++++++-
> 5 files changed, 196 insertions(+), 28 deletions(-)
>
> Range-diff versus v8:
>
> 1: 9fd3641eaf = 1: 3ea73d7c98 replay: add helper to put entry into replayed_commits
> 2: 0bd4cd9b9c = 2: 4a40c42684 replay: resolve the replay base outside pick_regular_commit()
> 3: 45faa926f8 ! 3: d6247ea743 replay: offer an option to linearize the commit topology
> @@ Commit message
> If a ref was pointing to a merge commit, that ref is updated to the
> merge's last replayed ancestor.
>
> - git-replay(1) accepts multiple revision ranges, for example:
> + git-replay(1) accepts multiple branches, for example:
>
> $ git replay --onto main topic1 topic2
>
> Without `--linearize` this replays 'topic1' and 'topic2' onto 'main'
> - independently and updates both refs.
> + (keeping shared portions of history shared and divergent parts
> + divergent) and updates both refs.
>
> - For now this is disallowed with option `--linearize`. Linearizing more
> - than one branch at once would concatenate unrelated histories into a
> - single line, and update each branch to some point in that line. That
> - won't be the result most users want, especially because the order
> - depends on the order of the revision walk, not the order of the branch
> - names on the command line.
> -
> - For the same reason disallow the use of `--contained` with
> - `--linearize`.
> + Due to current implementation limitations, replaying multiple branches
> + with `--linearize` is disallowed to avoid concatenating unrelated
> + histories into a single line. For the same reason disallow the use of
> + `--contained` with `--linearize`.
>
> Users who want to linearize multiple branches are advised to do this in
> separate git-replay(1) invocations. Linearizing multiple branches at
> @@ Documentation/git-replay.adoc: SYNOPSIS
>
> DESCRIPTION
> -----------
> -@@ Documentation/git-replay.adoc: incompatible with `--contained` (which is a modifier for `--onto` only).
> +@@ Documentation/git-replay.adoc: Expanded description list compared to 'replay.refAction'.
> +
> The default mode can be configured via the `replay.refAction` configuration variable.
>
> @@ Documentation/git-replay.adoc: incompatible with `--contained` (which is a modif
> + 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.
> ++When a merge commit is encountered, all commits in the range reachable
> ++from the merge commit are replayed into the 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 matches the
> ++behavior of git-rebase(1)'s `--no-rebase-merges` option.)
> ++
> -+Only a single branch can be linearized at a time: `--linearize` cannot
> -+be combined with multiple positive revisions or with `--contained`,
> -+because that would concatenate otherwise unrelated histories into one
> -+line. To linearize several branches, replay them in separate `git
> -+replay` invocations.
> ++`--linearize` cannot be combined with multiple branches or with
> ++`--contained`. To linearize several branches, replay them in separate
> ++`git replay` invocations.
> +
> <revision-range>::
> Range of commits to replay; see "Specifying Ranges" in
> @@ replay.c: int replay_revisions(struct rev_info *revs,
>
> + if (opts->linearize &&
> + update_refs && strset_get_size(update_refs) > 1) {
> -+ ret = error(_("'--linearize' cannot be used with multiple revision ranges"));
> ++ ret = error(_("'--linearize' cannot be used with multiple branches"));
> + goto out;
> + }
> +
> @@ t/t3650-replay-basics.sh: test_expect_success '--onto with --ref rejects multipl
> + test_line_count = 3 out
> +'
> +
> -+test_expect_success '--linearize rejects multiple revision ranges' '
> ++test_expect_success '--linearize rejects multiple branches' '
> + test_must_fail git replay --ref-action=print --linearize \
> + --onto main ^B topic2 topic3 topic4 2>err &&
> -+ test_grep "cannot be used with multiple revision ranges" err
> ++ test_grep "cannot be used with multiple branches" err
> +'
> +
> +test_expect_success 'replay with --linearize of a divergent merge keeps both sides' 'Thanks for making all these changes! I think this version is good to go.
Reviewed-by: Elijah Newren <newren@gmail.com>