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>
This commit is contained in:
Greg Price 2010-07-06 19:29:19 -04:00 committed by Junio C Hamano
parent 78db709ae5
commit be7c6d467e
2 changed files with 38 additions and 0 deletions

View File

@ -60,6 +60,37 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
return 0; 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 */ /* make sure nobody touched the ref, and unlink */
static void prune_ref(struct ref_to_prune *r) static void prune_ref(struct ref_to_prune *r)
{ {
@ -68,6 +99,7 @@ static void prune_ref(struct ref_to_prune *r)
if (lock) { if (lock) {
unlink_or_warn(git_path("%s", r->name)); unlink_or_warn(git_path("%s", r->name));
unlock_ref(lock); unlock_ref(lock);
try_remove_empty_parents(r->name);
} }
} }

View File

@ -60,6 +60,12 @@ test_expect_success 'see if git pack-refs --prune remove ref files' '
! test -f .git/refs/heads/f ! test -f .git/refs/heads/f
' '
test_expect_success 'see if git pack-refs --prune removes empty dirs' '
git branch r/s/t &&
git pack-refs --all --prune &&
! test -e .git/refs/heads/r
'
test_expect_success \ test_expect_success \
'git branch g should work when git branch g/h has been deleted' \ 'git branch g should work when git branch g/h has been deleted' \
'git branch g/h && 'git branch g/h &&