git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 5/5] git-pack-refs --prune

From
Junio C Hamano <junkio@cox.net>
Date
Sep 21, 2006, 07:06 UTC
Message-ID
<7vhcz1aech.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<7v64fhd7ns.fsf@assigned-by-dhcp.cox.net>

"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 <junkio@cox.net>
---
 builtin-pack-refs.c |   84 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 75 insertions(+), 9 deletions(-)
diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index 0fc8a55..246dd63 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -2,6 +2,20 @@ #include "cache.h"
 #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 *
 		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;
 }
-- 
1.4.2.1.g4dc7
Previous: Junio C HamanoNext: Linus Torvalds
Message 19 of 21 in “Allow multiple "git_path()" uses”
  1. Linus TorvaldsSep 11, 2006
  2. Start handling references internally as a sorted in-memory listLinus Torvalds, Sep 11, 2006
  3. Linus TorvaldsSep 11, 2006
  4. Junio C HamanoSep 11, 2006
  5. Linus TorvaldsSep 12, 2006
  6. Chris WedgwoodSep 12, 2006
  7. Add support for negative refsLinus Torvalds, Sep 12, 2006
  8. Make ref resolution sanerLinus Torvalds, Sep 12, 2006
  9. Jeff KingSep 12, 2006
  10. Linus TorvaldsSep 12, 2006
  11. [RFC] git-pack-refs --pruneJunio C Hamano, Sep 18, 2006
  12. Linus TorvaldsSep 18, 2006
  13. Junio C HamanoSep 18, 2006
  14. Junio C HamanoSep 21, 2006
  15. 1/5 symbolit-ref: fix resolve_ref conversion.Junio C Hamano, Sep 21, 2006
  16. 2/5 Add callback data to for_each_ref() family.Junio C Hamano, Sep 21, 2006
  17. 3/5 Tell between packed, unpacked and symbolic refs.Junio C Hamano, Sep 21, 2006
  18. 4/5 pack-refs: do not pack symbolic refs.Junio C Hamano, Sep 21, 2006
  19. 5/5 git-pack-refs --pruneJunio C Hamano, Sep 21, 2006
  20. Linus TorvaldsSep 21, 2006
  21. Junio C HamanoSep 22, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.