pack-refs: remove newly empty directories
In a large repository which uses directories to organize many refs, "git pack-refs --all --prune" does not improve performance so much as it should, unless we remove all the now-empty directories as well. Signed-off-by: Greg Price <price@ksplice.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Greg Price committed
Jul 6, 2010 at 19:29 UTC
be7c6d467e8cc4104e1a15e8ff2d7b207624c685
2 files changed
+38
pack-refs.c
+32
@@ -60,6 +60,37 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
60
return 0;
61
}
62
63
+/*
64
+ * Remove empty parents, but spare refs/ and immediate subdirs.
65
+ * Note: munges *name.
66
+ */
67
+static void try_remove_empty_parents(char *name)
68
+{
69
+ char *p, *q;
70
+ int i;
71
+ p = name;
72
+ for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */
73
+ while (*p && *p != '/')
74
+ p++;
75
+ /* tolerate duplicate slashes; see check_ref_format() */
76
+ while (*p == '/')
77
+ p++;
78
+ }
79
+ for (q = p; *q; q++)
80
+ ;
81
+ while (1) {
82
+ while (q > p && *q != '/')
83
+ q--;
84
+ while (q > p && *(q-1) == '/')
85
+ q--;
86
+ if (q == p)
87
+ break;
88
+ *q = '\0';
89
+ if (rmdir(git_path("%s", name)))
90
+ break;
91
+ }
92
+}
93
+
94
/* make sure nobody touched the ref, and unlink */
95
static void prune_ref(struct ref_to_prune *r)
96
{
@@ -68,6 +99,7 @@ static void prune_ref(struct ref_to_prune *r)
99
if (lock) {
100
unlink_or_warn(git_path("%s", r->name));
101
unlock_ref(lock);
102
+ try_remove_empty_parents(r->name);
103
}
104
}
105
t/t3210-pack-refs.sh
+6
@@ -60,6 +60,12 @@ test_expect_success 'see if git pack-refs --prune remove ref files' '
60
! test -f .git/refs/heads/f
61
'
62
63
+test_expect_success 'see if git pack-refs --prune removes empty dirs' '
64
+ git branch r/s/t &&
65
+ git pack-refs --all --prune &&
66
+ ! test -e .git/refs/heads/r
67
+'
68
+
69
test_expect_success \
70
'git branch g should work when git branch g/h has been deleted' \
71
'git branch g/h &&