From 968846015229fe0fec28e3c85db722e131c15f93 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 21 Sep 2006 00:06:06 -0700 Subject: git-pack-refs --prune "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. Also we do not bother trying to prune what was already packed, and we do not try pruning symbolic refs. Signed-off-by: Junio C Hamano --- builtin-pack-refs.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 9 deletions(-) (limited to 'builtin-pack-refs.c') diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c index 0fc8a555e7..246dd6372e 100644 --- a/builtin-pack-refs.c +++ b/builtin-pack-refs.c @@ -2,6 +2,20 @@ #include "refs.h" static const char *result_path, *lock_path; +static const char builtin_pack_refs_usage[] = +"git-pack-refs [--prune]"; + +struct ref_to_prune { + struct ref_to_prune *next; + unsigned char sha1[20]; + char name[FLEX_ARRAY]; +}; + +struct pack_refs_cb_data { + int prune; + struct ref_to_prune *ref_to_prune; + FILE *refs_file; +}; static void remove_lock_file(void) { @@ -9,21 +23,70 @@ static void remove_lock_file(void) unlink(lock_path); } +static int do_not_prune(int flags) +{ + /* If it is already packed or if it is a symref, + * do not prune it. + */ + return (flags & (REF_ISSYMREF|REF_ISPACKED)); +} + static int handle_one_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data) { - FILE *refs_file = cb_data; + struct pack_refs_cb_data *cb = cb_data; /* Do not pack the symbolic refs */ if (!(flags & REF_ISSYMREF)) - fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path); + fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path); + if (cb->prune && !do_not_prune(flags)) { + int namelen = strlen(path) + 1; + struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen); + hashcpy(n->sha1, sha1); + strcpy(n->name, path); + n->next = cb->ref_to_prune; + cb->ref_to_prune = n; + } return 0; } +/* make sure nobody touched the ref, and unlink */ +static void prune_ref(struct ref_to_prune *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(struct ref_to_prune *r) +{ + while (r) { + prune_ref(r); + r = r->next; + } +} + int cmd_pack_refs(int argc, const char **argv, const char *prefix) { - int fd; - FILE *refs_file; + int fd, i; + struct pack_refs_cb_data cbdata; + + memset(&cbdata, 0, sizeof(cbdata)); + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!strcmp(arg, "--prune")) { + cbdata.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)); @@ -33,14 +96,17 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix) die("unable to create new ref-pack file (%s)", strerror(errno)); atexit(remove_lock_file); - refs_file = fdopen(fd, "w"); - if (!refs_file) - die("unable to create ref-pack file structure (%s)", strerror(errno)); - for_each_ref(handle_one_ref, refs_file); + cbdata.refs_file = fdopen(fd, "w"); + if (!cbdata.refs_file) + die("unable to create ref-pack file structure (%s)", + strerror(errno)); + for_each_ref(handle_one_ref, &cbdata); fsync(fd); - fclose(refs_file); + fclose(cbdata.refs_file); if (rename(lock_path, result_path) < 0) die("unable to overwrite old ref-pack file (%s)", strerror(errno)); lock_path = NULL; + if (cbdata.prune) + prune_refs(cbdata.ref_to_prune); return 0; } -- cgit v1.2.3