[RFC] git-pack-refs --prune

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



"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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]