[PATCH v2 1/4] replay: fail gracefully when a merge input is unreadable
From: Elijah Newren via GitGitGadget <hidden>
Date: 2026-08-25 19:00:33
Subsystem:
the rest · Maintainer:
Linus Torvalds
From: Elijah Newren <redacted> When objects involved in the merge cannot be read, the merge machinery will return early with result.clean = -1, and result.tree left as NULL. pick_regular_commit() tested only "if (!result->clean)", ignoring the case where "clean < 0". That causes the code to try to use result->tree, resulting in a SIGSEGV. Handle clean < 0 explicitly; the merge machinery will already have printed messages such as "Could not read <object>" and "collecting merge info failed for trees...", so we don't need to add much detail beyond the fact that the merge failed. Signed-off-by: Elijah Newren <redacted> --- replay.c | 7 +++++++ t/t3650-replay-basics.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
diff --git a/replay.c b/replay.c
index 463c900d6c..33e21b2032 100644
--- a/replay.c
+++ b/replay.c@@ -327,6 +327,13 @@ static struct commit *pick_regular_commit(struct repository *repo, merge_opt->ancestor = NULL; merge_opt->branch2 = NULL; + if (result->clean < 0) { + error(_("merge of %s onto %s failed"), + oid_to_hex(&pickme->object.oid), + oid_to_hex(&replayed_base->object.oid)); + return NULL; + } + if (!result->clean) return NULL;
diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh
index 3353bc4a4d..12348b4a5f 100755
--- a/t/t3650-replay-basics.sh
+++ b/t/t3650-replay-basics.sh@@ -565,4 +565,38 @@ test_expect_success '--onto with --ref rejects multiple revision ranges' ' test_grep "cannot be used with multiple revision ranges" err ' +test_expect_success 'replay fails without segfault when objects are missing' ' + test_when_finished "rm -fr unreadable" && + git init unreadable && + ( + cd unreadable && + + test_write_lines l1 l2 l3 l4 l5 l6 l7 l8 >f && + git add f && + git commit -m base && + git branch base && + + test_write_lines l1 l2 l3 l4 l5 l6 l7 CHANGED >f && + git commit -am side && + git branch side && + + git switch -c onto base && + test_write_lines CHANGED l2 l3 l4 l5 l6 l7 l8 >f && + git commit -am onto && + + # The replay works while every object is readable. + git replay --onto onto base..side && + + # Removing the onto tree makes parse_tree() fail during the + # incore merge, driving clean < 0 with a NULL result tree. + onto_tree=$(git rev-parse onto^{tree}) && + obj=$(test_oid_to_path "$onto_tree") && + mv .git/objects/${obj} saved-tree && + + # Ensure replay gracefully handles the missing object + test_must_fail git replay --onto onto base..side 2>err && + test_grep -e "Could not read" -e "collecting merge info failed" err + ) +' + test_done
--
gitgitgadget