"git pack-refs --prune", after successfully packing the existing refs, removes the loose ref files. It tries to protect against race by doing the usual lock_ref_sha1() which makes sure the contents of the ref has not changed since we last looked at. I am not sure I got the locking right, hence this RFC. We would probably need to perform some sort of 'sync' after closing and renaming the lockfile to its final location before pruning. Is there a way cheaper than sync(2) to make sure the effect of rename(2) hits the disk platter? --- diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c index 0f5d827..2b3a483 100644 --- a/builtin-pack-refs.c +++ b/builtin-pack-refs.c @@ -3,6 +3,15 @@ #include "refs.h" static FILE *refs_file; static const char *result_path, *lock_path; +static const char builtin_pack_refs_usage[] = +"git-pack-refs [--prune]"; + +static int prune; +struct keepref { + struct keepref *next; + unsigned char sha1[20]; + char name[FLEX_ARRAY]; +} *keepref; static void remove_lock_file(void) { @@ -13,12 +22,50 @@ static void remove_lock_file(void) static int handle_one_ref(const char *path, const unsigned char *sha1) { fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path); + if (prune) { + int namelen = strlen(path) + 1; + struct keepref *n = xcalloc(1, sizeof(*n) + namelen); + hashcpy(n->sha1, sha1); + strcpy(n->name, path); + n->next = keepref; + keepref = n; + } return 0; } +/* make sure nobody touched the ref, and unlink */ +static void prune_ref(struct keepref *r) +{ + struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1, 1); + + if (lock) { + unlink(git_path(r->name)); + unlock_ref(lock); + } +} + +static void prune_refs(void) +{ + struct keepref *r; + for (r = keepref; r; r = r->next) + prune_ref(r); +} + int cmd_pack_refs(int argc, const char **argv, const char *prefix) { - int fd; + int fd, i; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!strcmp(arg, "--prune")) { + prune = 1; + continue; + } + /* perhaps other parameters later... */ + break; + } + if (i != argc) + usage(builtin_pack_refs_usage); result_path = xstrdup(git_path("packed-refs")); lock_path = xstrdup(mkpath("%s.lock", result_path)); @@ -37,5 +84,7 @@ int cmd_pack_refs(int argc, const char * if (rename(lock_path, result_path) < 0) die("unable to overwrite old ref-pack file (%s)", strerror(errno)); lock_path = NULL; + if (prune) + prune_refs(); return 0; } - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html