builtin/history: check for merges before asking for user input

The replay infrastructure is not yet capable of replaying merge commits. Unfortunately, we only notice that we're about to replay merges after we have already asked the user for input, so any commit message that the user may have written will be discarded in that case. Fix this by checking whether the revwalk contains merge commits before we ask for user input. Adapt one of the tests that is expected to fail because of this check to use false(1) as editor. If the editor had been executed by Git, it would fail with the error message "Aborting commit as launching the editor failed." Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Feb 16, 2026 at 07:45 UTC 0f2a0c507701f5b166de62ddfe23d48ed2d884e1
2 files changed +40 -1
builtin/history.c
+39
@@ -177,6 +177,41 @@ static int parse_ref_action(const struct option *opt, const char *value, int uns
177 return 0;
178 }
179
180 +static int revwalk_contains_merges(struct repository *repo,
181 + const struct strvec *revwalk_args)
182 +{
183 + struct strvec args = STRVEC_INIT;
184 + struct rev_info revs;
185 + int ret;
186 +
187 + strvec_pushv(&args, revwalk_args->v);
188 + strvec_push(&args, "--min-parents=2");
189 +
190 + repo_init_revisions(repo, &revs, NULL);
191 +
192 + setup_revisions_from_strvec(&args, &revs, NULL);
193 + if (args.nr != 1)
194 + BUG("revisions were set up with invalid argument");
195 +
196 + if (prepare_revision_walk(&revs) < 0) {
197 + ret = error(_("error preparing revisions"));
198 + goto out;
199 + }
200 +
201 + if (get_revision(&revs)) {
202 + ret = error(_("replaying merge commits is not supported yet!"));
203 + goto out;
204 + }
205 +
206 + reset_revision_walk();
207 + ret = 0;
208 +
209 +out:
210 + release_revisions(&revs);
211 + strvec_clear(&args);
212 + return ret;
213 +}
214 +
215 static int setup_revwalk(struct repository *repo,
216 enum ref_action action,
217 struct commit *original,
@@ -236,6 +271,10 @@ static int setup_revwalk(struct repository *repo,
271 strvec_push(&args, "HEAD");
272 }
273
274 + ret = revwalk_contains_merges(repo, &args);
275 + if (ret < 0)
276 + goto out;
277 +
278 setup_revisions_from_strvec(&args, revs, NULL);
279 if (args.nr != 1)
280 BUG("revisions were set up with invalid argument");
t/t3451-history-reword.sh
+1 -1
@@ -203,7 +203,7 @@ test_expect_success 'can reword a merge commit' '
203
204 # It is not possible to replay merge commits embedded in the
205 # history (yet).
206 - test_must_fail git history reword HEAD~ 2>err &&
206 + test_must_fail git -c core.editor=false history reword HEAD~ 2>err &&
207 test_grep "replaying merge commits is not supported yet" err &&
208
209 # But it is possible to reword a merge commit directly.