Subject: [PATCH v3 28/28] prune: clean .git/shallow after pruning objects

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Mon, 25 Nov 2013 10:55:54 +0700

This patch teaches "prune" to remove shallow roots that are no longer
reachable from any refs (e.g. when the relevant refs are removed).

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 builtin/gc.c    |  1 +
 builtin/prune.c |  4 ++++
 commit.h        |  1 +
 shallow.c       | 43 +++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index c14190f..cec8ecd 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -16,6 +16,7 @@
 #include "run-command.h"
 #include "sigchain.h"
 #include "argv-array.h"
+#include "commit.h"
 
 #define FAILED_RUN "failed to run %s"
 
diff --git a/builtin/prune.c b/builtin/prune.c
index 6366917..023aea8 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -170,5 +170,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 	s = mkpathdup("%s/pack", get_object_directory());
 	remove_temporary_files(s);
 	free(s);
+
+	if (!show_only && is_repository_shallow())
+		prune_shallow();
+
 	return 0;
 }
diff --git a/commit.h b/commit.h
index 0ff70fa..ff93a59 100644
--- a/commit.h
+++ b/commit.h
@@ -215,6 +215,7 @@ extern void remove_reachable_shallow_points(struct extra_have_objects *out,
 extern int mark_new_shallow_refs(const struct extra_have_objects *ref,
 				 int *ref_status, uint32_t **used,
 				 const struct extra_have_objects *shallow);
+extern void prune_shallow(void);
 
 int is_descendant_of(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit *);
diff --git a/shallow.c b/shallow.c
index abb04db..0eda40f 100644
--- a/shallow.c
+++ b/shallow.c
@@ -157,6 +157,7 @@ struct write_shallow_data {
 	struct strbuf *out;
 	int use_pack_protocol;
 	int count;
+	int seen_only;
 };
 
 static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
@@ -165,6 +166,11 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
 	const char *hex = sha1_to_hex(graft->sha1);
 	if (graft->nr_parent != -1)
 		return 0;
+	if (data->seen_only) {
+		struct commit *c = lookup_commit(graft->sha1);
+		if (!c || !(c->object.flags & SEEN))
+			return 0;
+	}
 	data->count++;
 	if (data->use_pack_protocol)
 		packet_buf_write(data->out, "shallow %s", hex);
@@ -175,14 +181,16 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
 	return 0;
 }
 
-int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
-			  const struct extra_have_objects *extra)
+static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol,
+				   const struct extra_have_objects *extra,
+				   int seen_only)
 {
 	struct write_shallow_data data;
 	int i;
 	data.out = out;
 	data.use_pack_protocol = use_pack_protocol;
 	data.count = 0;
+	data.seen_only = seen_only;
 	for_each_commit_graft(write_one_shallow, &data);
 	if (!extra)
 		return data.count;
@@ -194,6 +202,12 @@ int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
 	return data.count;
 }
 
+int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
+			  const struct extra_have_objects *extra)
+{
+	return write_shallow_commits_1(out, use_pack_protocol, extra, 0);
+}
+
 char *setup_temporary_shallow(const struct extra_have_objects *extra)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -515,3 +529,28 @@ int mark_new_shallow_refs(const struct extra_have_objects *ref,
 
 	return ret;
 }
+
+/*
+ * mark_reachable_objects() should have been run prior to this and all
+ * reachable commits marked as "SEEN".
+ */
+void prune_shallow(void)
+{
+	static struct lock_file shallow_lock;
+	struct strbuf sb = STRBUF_INIT;
+	int fd;
+
+	check_shallow_file_for_update();
+	fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
+				       LOCK_DIE_ON_ERROR);
+	if (write_shallow_commits_1(&sb, 0, NULL, 1)) {
+		if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+			die_errno("failed to write to %s",
+				  shallow_lock.filename);
+		commit_lock_file(&shallow_lock);
+	} else {
+		unlink(git_path("shallow"));
+		rollback_lock_file(&shallow_lock);
+	}
+	strbuf_release(&sb);
+}
-- 
1.8.2.83.gc99314b