From a9bfefd9dd2ffebcd0eb4efcd77df810ab20e584 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 25 Jun 2026 09:52:04 +0200 Subject: [PATCH] history: close COMMIT_EDITMSG before launching the editor The `git history reword` and `git history fixup` subcommands prepare the commit message by writing it to COMMIT_EDITMSG and then opening that same file a second time, in append mode, through `wt_status`'s `fp` field to append the status information. That second handle is never closed before `launch_editor()` runs, so the editor is started while git still holds the file open. Everywhere this leaks a file descriptor, but on Windows it is outright broken: a process cannot replace a file that another process keeps open, so an editor that rewrites COMMIT_EDITMSG by creating a fresh file in its place fails. This surfaced while running Git for Windows' test suite with BusyBox' `ash` as the POSIX shell: the fake editor's `cp message "$1"` aborts with "cp: can't create '.../COMMIT_EDITMSG': File exists" (MSYS2's coreutils `cp` hides the problem via its POSIX unlink emulation, BusyBox' native `cp` does not), making t3451-history-reword and t3453-history-fixup fail wholesale. Close the handle once the status has been written, before handing the file off to the editor. Assisted-by: Opus 4.8 Signed-off-by: Johannes Schindelin --- builtin/history.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/builtin/history.c b/builtin/history.c index 952693808574b7..4a5d9192f3cc9c 100644 --- a/builtin/history.c +++ b/builtin/history.c @@ -74,6 +74,14 @@ static int fill_commit_message(struct repository *repo, wt_status_collect_free_buffers(&s); string_list_clear_func(&s.change, change_data_free); + /* + * Close the handle before launching the editor: on Windows an open + * handle would prevent the editor from replacing the file (e.g. + * BusyBox' `ash` cannot overwrite a file that another process keeps + * open), and leaving it open leaks the descriptor everywhere else. + */ + fclose(s.fp); + strbuf_reset(out); if (launch_editor(path, out, NULL)) { fprintf(stderr, _("Aborting commit as launching the editor failed.\n"));