summaryrefslogtreecommitdiff
path: root/pack-refs.c
diff options
context:
space:
mode:
authorGreg Price <price@ksplice.com>2010-07-06 23:29:19 (GMT)
committerJunio C Hamano <gitster@pobox.com>2010-07-07 16:11:37 (GMT)
commitbe7c6d467e8cc4104e1a15e8ff2d7b207624c685 (patch)
treecb23a29c9a86b0017534892ed0db31e9fe821541 /pack-refs.c
parent78db709ae59da26de76264b79df3a7dc4d87e65c (diff)
downloadgit-be7c6d467e8cc4104e1a15e8ff2d7b207624c685.zip
git-be7c6d467e8cc4104e1a15e8ff2d7b207624c685.tar.gz
git-be7c6d467e8cc4104e1a15e8ff2d7b207624c685.tar.bz2
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>
Diffstat (limited to 'pack-refs.c')
-rw-r--r--pack-refs.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/pack-refs.c b/pack-refs.c
index 7f43f8a..1290570 100644
--- a/pack-refs.c
+++ b/pack-refs.c
@@ -60,6 +60,37 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
return 0;
}
+/*
+ * Remove empty parents, but spare refs/ and immediate subdirs.
+ * Note: munges *name.
+ */
+static void try_remove_empty_parents(char *name)
+{
+ char *p, *q;
+ int i;
+ p = name;
+ for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */
+ while (*p && *p != '/')
+ p++;
+ /* tolerate duplicate slashes; see check_ref_format() */
+ while (*p == '/')
+ p++;
+ }
+ for (q = p; *q; q++)
+ ;
+ while (1) {
+ while (q > p && *q != '/')
+ q--;
+ while (q > p && *(q-1) == '/')
+ q--;
+ if (q == p)
+ break;
+ *q = '\0';
+ if (rmdir(git_path("%s", name)))
+ break;
+ }
+}
+
/* make sure nobody touched the ref, and unlink */
static void prune_ref(struct ref_to_prune *r)
{
@@ -68,6 +99,7 @@ static void prune_ref(struct ref_to_prune *r)
if (lock) {
unlink_or_warn(git_path("%s", r->name));
unlock_ref(lock);
+ try_remove_empty_parents(r->name);
}
}