]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs: cleanup directories when deleting packed ref
authorWill Chandler <wfc@wfchandler.org>
Sat, 8 May 2021 05:00:43 +0000 (01:00 -0400)
committerJunio C Hamano <gitster@pobox.com>
Tue, 11 May 2021 04:59:57 +0000 (13:59 +0900)
When deleting a packed ref via 'update-ref -d', a lockfile is made in
the directory that would contain the loose copy of that ref, creating
any directories in the ref's path that do not exist. When the
transaction completes, the lockfile is deleted, but any empty parent
directories made when creating the lockfile are left in place.  These
empty directories are not removed by 'pack-refs' or other housekeeping
tasks and will accumulate over time.

When deleting a loose ref, we remove all empty parent directories at the
end of the transaction.

This commit applies the parent directory cleanup logic used when
deleting loose refs to packed refs as well.

Signed-off-by: Will Chandler <wfc@wfchandler.org>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs/files-backend.c
t/t1400-update-ref.sh

index 119972ee16f89f629e96b552e520f0b8190e54a7..49e6ee069a2afe8f9090dcc3d300c7887539a445 100644 (file)
 #define REF_UPDATE_VIA_HEAD (1 << 8)
 
 /*
- * Used as a flag in ref_update::flags when the loose reference has
- * been deleted.
+ * Used as a flag in ref_update::flags when a reference has been
+ * deleted and the ref's parent directories may need cleanup.
  */
-#define REF_DELETED_LOOSE (1 << 9)
+#define REF_DELETED_RMDIR (1 << 9)
 
 struct ref_lock {
        char *ref_name;
@@ -2852,6 +2852,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
 
                if (update->flags & REF_DELETING &&
                    !(update->flags & REF_LOG_ONLY)) {
+                       update->flags |= REF_DELETED_RMDIR;
                        if (!(update->type & REF_ISPACKED) ||
                            update->type & REF_ISSYMREF) {
                                /* It is a loose reference. */
@@ -2861,7 +2862,6 @@ static int files_transaction_finish(struct ref_store *ref_store,
                                        ret = TRANSACTION_GENERIC_ERROR;
                                        goto cleanup;
                                }
-                               update->flags |= REF_DELETED_LOOSE;
                        }
                }
        }
@@ -2874,9 +2874,9 @@ cleanup:
        for (i = 0; i < transaction->nr; i++) {
                struct ref_update *update = transaction->updates[i];
 
-               if (update->flags & REF_DELETED_LOOSE) {
+               if (update->flags & REF_DELETED_RMDIR) {
                        /*
-                        * The loose reference was deleted. Delete any
+                        * The reference was deleted. Delete any
                         * empty parent directories. (Note that this
                         * can only work because we have already
                         * removed the lockfile.)
index e31f65f381c9bdbdc3a9dc4c10a90e5051cf9bc6..4506cd435b050b1f8395824cfc161bdeb1703030 100755 (executable)
@@ -1598,4 +1598,13 @@ test_expect_success 'transaction cannot restart ongoing transaction' '
        test_must_fail git show-ref --verify refs/heads/restart
 '
 
+test_expect_success 'directory not created deleting packed ref' '
+       git branch d1/d2/r1 HEAD &&
+       git pack-refs --all &&
+       test_path_is_missing .git/refs/heads/d1/d2 &&
+       git update-ref -d refs/heads/d1/d2/r1 &&
+       test_path_is_missing .git/refs/heads/d1/d2 &&
+       test_path_is_missing .git/refs/heads/d1
+'
+
 test_done