]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs/files: use correct error type when lock exists
authorKarthik Nayak <karthik.188@gmail.com>
Wed, 17 Sep 2025 15:25:12 +0000 (17:25 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Sep 2025 16:19:08 +0000 (09:19 -0700)
When fetching references into a repository, if a lock for a particular
reference exists, then `lock_raw_ref()` throws:

    - REF_TRANSACTION_ERROR_CASE_CONFLICT: when there is a conflict
    because the transaction contains conflicting references while being
    on a case-insensitive filesystem.

    - REF_TRANSACTION_ERROR_GENERIC: for all other errors.

The latter causes the entire set of batched updates to fail, even in
case sensitive filessystems.

Instead, return a 'REF_TRANSACTION_ERROR_CREATE_EXISTS' error. This
allows batched updates to reject the individual update which conflicts
with the existing file, while updating the rest of the references.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs/files-backend.c
t/t5510-fetch.sh

index 01df32904bee61cff4cdb75fcba972fe4d232409..d1af5d6bc7f3b647b9c70a2823d6c4d4190bbd88 100644 (file)
@@ -797,9 +797,24 @@ retry:
                        goto retry;
                } else {
                        unable_to_lock_message(ref_file.buf, myerr, err);
-                       if (myerr == EEXIST && ignore_case &&
-                           transaction_has_case_conflicting_update(transaction, update))
-                               ret = REF_TRANSACTION_ERROR_CASE_CONFLICT;
+                       if (myerr == EEXIST) {
+                               if (ignore_case &&
+                                   transaction_has_case_conflicting_update(transaction, update)) {
+                                       /*
+                                        * In case-insensitive filesystems, ensure that conflicts within a
+                                        * given transaction are handled. Pre-existing refs on a
+                                        * case-insensitive system will be overridden without any issue.
+                                        */
+                                       ret = REF_TRANSACTION_ERROR_CASE_CONFLICT;
+                               } else {
+                                       /*
+                                        * Pre-existing case-conflicting reference locks should also be
+                                        * specially categorized to avoid failing all batched updates.
+                                        */
+                                       ret = REF_TRANSACTION_ERROR_CREATE_EXISTS;
+                               }
+                       }
+
                        goto error_return;
                }
        }
index 57f60da81bd61bfc8ed5432aaa05a685bfb9f4a4..6f8db0ace4c9478bc236d0129542388701b5bfe8 100755 (executable)
@@ -1546,6 +1546,32 @@ test_expect_success CASE_INSENSITIVE_FS,REFFILES 'existing references in a case
        )
 '
 
+test_expect_success REFFILES 'existing reference lock in repo' '
+       test_when_finished rm -rf base repo &&
+       (
+               git init --ref-format=reftable base &&
+               cd base &&
+               echo >file update &&
+               git add . &&
+               git commit -m "updated" &&
+               git branch -M main &&
+
+               git update-ref refs/heads/foo @ &&
+               git update-ref refs/heads/branch @ &&
+               cd .. &&
+
+               git init --ref-format=files --bare repo &&
+               cd repo &&
+               git remote add origin ../base &&
+               touch refs/heads/foo.lock &&
+               test_must_fail git fetch -f origin "refs/heads/*:refs/heads/*" 2>err &&
+               test_grep "error: fetching ref refs/heads/foo failed: reference already exists" err &&
+               git rev-parse refs/heads/main >expect &&
+               git rev-parse refs/heads/branch >actual &&
+               test_cmp expect actual
+       )
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd