From: Justin Tobler Date: Fri, 21 Mar 2025 00:44:37 +0000 (-0500) Subject: builtin/fetch: avoid aborting closed reference transaction X-Git-Tag: v2.50.0-rc0~112^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b9fadeead74df1f4fa4a4177e478903d63e600f5;p=thirdparty%2Fgit.git builtin/fetch: avoid aborting closed reference transaction As part of the reference transaction commit phase, the transaction is set to a closed state regardless of whether it was successful of not. Attempting to abort a closed transaction via `ref_transaction_abort()` results in a `BUG()`. In c92abe71df (builtin/fetch: fix leaking transaction with `--atomic`, 2024-08-22), logic to free a transaction after the commit phase is moved to the centralized exit path. In cases where the transaction commit failed, this results in a closed transaction being aborted and signaling a bug. Free the transaction and set it to NULL when the commit fails. This allows the exit path to correctly handle the error without attempting to abort the transaction. Signed-off-by: Justin Tobler Signed-off-by: Junio C Hamano --- diff --git a/builtin/fetch.c b/builtin/fetch.c index 80a64d0d26..5fb6d6bcf1 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1732,8 +1732,15 @@ static int do_fetch(struct transport *transport, goto cleanup; retcode = ref_transaction_commit(transaction, &err); - if (retcode) + if (retcode) { + /* + * Explicitly handle transaction cleanup to avoid + * aborting an already closed transaction. + */ + ref_transaction_free(transaction); + transaction = NULL; goto cleanup; + } } commit_fetch_head(&fetch_head); diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 0890b9f61c..4fcf2209f5 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -345,6 +345,19 @@ test_expect_success 'fetch --atomic --append appends to FETCH_HEAD' ' test_cmp expected atomic/.git/FETCH_HEAD ' +test_expect_success REFFILES 'fetch --atomic fails transaction if reference locked' ' + test_when_finished "rm -rf upstream repo" && + + git init upstream && + git -C upstream commit --allow-empty -m 1 && + git -C upstream switch -c foobar && + git clone --mirror upstream repo && + git -C upstream commit --allow-empty -m 2 && + touch repo/refs/heads/foobar.lock && + + test_must_fail git -C repo fetch --atomic origin +' + test_expect_success '--refmap="" ignores configured refspec' ' cd "$TRASH_DIRECTORY" && git clone "$D" remote-refs &&