From: "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Elijah Newren <newren@gmail.com>, Patrick Steinhardt <ps@pks.im>,
Johannes Schindelin <johannes.schindelin@gmx.de>
Subject: [PATCH/RFC 0/5] replay: support replaying 2-parent merges
Date: Wed, 06 May 2026 22:43:19 +0000 [thread overview]
Message-ID: <pull.2106.git.1778107405.gitgitgadget@gmail.com> (raw)
git history, the new history-rewriting builtin in v2.54, dies on any merge
in the rewrite path with replaying merge commits is not supported yet!. That
makes it not very useful for the workflows I actually have, where almost
every interesting branch contains at least one merge of a feature topic. The
natural fallback, git rebase --rebase-merges, is interactive and stops to
ask for re-resolution even when no re-resolution is needed.
This series lifts that limitation for the common 2-parent case. The
algorithm itself is not new: Elijah Newren wrote it down in his replay
design notes
[https://github.com/newren/git/blob/replay/replay-design-notes.txt] and
prototyped it in a 2022 work-in-progress sketch
[https://github.com/newren/git/commit/4c45e8955ef9bf7d01fd15d9106b3bdb8ea91b45].
What is new is wiring it into the replay_revisions() API that backs both git
replay and git history, plus three specific tweaks that make the trickier
cases work where the WIP sketch bailed out: identical conflict-marker labels
for the inner remerges of the original and the rewritten parents (so their
conflict-markered trees compare equal in the regions the user did not
touch), tolerating result.clean == 0 from those inner merges (their
well-defined conflict-markered trees are valid inputs to the outer 3-way
merge), and self-fallback for both merge parents combined with mapping the
rev-range boundary commits to the onto commit.
Octopus merges and revert-of-merge are surfaced as explicit errors at the
dispatch point. The split sub-command of git history continues to refuse
when its target is a merge: split semantics simply do not apply there. The
xdiff special mode for matching conflict-marker hunks across inner remerges,
the XDL_MERGE_FAVOR_BASE variant, and the modify/delete and binary-file
specials that the design notes flag as future work all remain future work.
While I was at it, git history reword had a pre-existing silent-success bug:
a positive return from replay_revisions() (which means "conflict, no updates
queued") was treated as success. Obviously this should never occur, as a
reword simply does not change any of the file contents, but bugs do happen.
The merge-replay work is complex enough to make that class of bugs more
likely, therefore I introduce error messages for those instances.
Johannes Schindelin (5):
replay: support replaying 2-parent merges
replay: short-circuit merge replay when parent and base trees are
unchanged
history.adoc: describe merge-replay support and its limits
test-tool: add a "historian" subcommand for building merge fixtures
t3454: cover merge-replay scenarios with the historian helper
Documentation/git-history.adoc | 27 ++-
Makefile | 1 +
builtin/history.c | 16 +-
replay.c | 258 +++++++++++++++++++++++++--
t/helper/meson.build | 1 +
t/helper/test-historian.c | 189 ++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/meson.build | 1 +
t/t3451-history-reword.sh | 21 ++-
t/t3452-history-split.sh | 6 +-
t/t3454-history-merges.sh | 308 +++++++++++++++++++++++++++++++++
t/t3650-replay-basics.sh | 46 ++++-
13 files changed, 840 insertions(+), 36 deletions(-)
create mode 100644 t/helper/test-historian.c
create mode 100755 t/t3454-history-merges.sh
base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2106%2Fdscho%2Fsupport-merge-commits-in-git-history-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2106/dscho/support-merge-commits-in-git-history-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2106
--
gitgitgadget
next reply other threads:[~2026-05-06 22:43 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-06 22:43 Johannes Schindelin via GitGitGadget [this message]
2026-05-06 22:43 ` [PATCH/RFC 1/5] replay: support replaying 2-parent merges Johannes Schindelin via GitGitGadget
2026-05-08 9:36 ` Phillip Wood
2026-05-08 10:05 ` Phillip Wood
2026-05-17 14:33 ` Johannes Schindelin
2026-05-17 14:32 ` Johannes Schindelin
2026-05-06 22:43 ` [PATCH/RFC 2/5] replay: short-circuit merge replay when parent and base trees are unchanged Johannes Schindelin via GitGitGadget
2026-05-06 22:43 ` [PATCH/RFC 3/5] history.adoc: describe merge-replay support and its limits Johannes Schindelin via GitGitGadget
2026-05-06 22:43 ` [PATCH/RFC 4/5] test-tool: add a "historian" subcommand for building merge fixtures Johannes Schindelin via GitGitGadget
2026-05-12 10:54 ` Toon Claes
2026-05-17 11:40 ` Johannes Schindelin
2026-05-06 22:43 ` [PATCH/RFC 5/5] t3454: cover merge-replay scenarios with the historian helper Johannes Schindelin via GitGitGadget
2026-05-07 14:14 ` [PATCH/RFC 0/5] replay: support replaying 2-parent merges D. Ben Knoble
2026-05-07 15:06 ` Johannes Schindelin
2026-05-07 15:39 ` Ben Knoble
2026-05-17 11:33 ` Johannes Schindelin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.2106.git.1778107405.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=johannes.schindelin@gmx.de \
--cc=newren@gmail.com \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.