]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs: implement removal of ref storages
authorPatrick Steinhardt <ps@pks.im>
Thu, 6 Jun 2024 05:29:39 +0000 (07:29 +0200)
committerJunio C Hamano <gitster@pobox.com>
Thu, 6 Jun 2024 16:04:33 +0000 (09:04 -0700)
We're about to introduce logic to migrate ref storages. One part of the
migration will be to delete the files that are part of the old ref
storage format. We don't yet have a way to delete such data generically
across ref backends though.

Implement a new `delete` callback and expose it via a new
`ref_storage_delete()` function.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs.c
refs.h
refs/files-backend.c
refs/packed-backend.c
refs/refs-internal.h
refs/reftable-backend.c

diff --git a/refs.c b/refs.c
index fa3b0a82d45a8ebaa8ac8b41f5fd16a434f8de34..31fd391214896b00c5f247026ffb896df06ed784 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1861,6 +1861,11 @@ int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e
        return refs->be->create_on_disk(refs, flags, err);
 }
 
+int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err)
+{
+       return refs->be->remove_on_disk(refs, err);
+}
+
 int repo_resolve_gitlink_ref(struct repository *r,
                             const char *submodule, const char *refname,
                             struct object_id *oid)
diff --git a/refs.h b/refs.h
index 50a2b3ab098fc571ef2ea1a42fe3cd095fd1a9db..61ee7b7a1536226e2358d02981110aa952bf5a3d 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -129,6 +129,11 @@ int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e
  */
 void ref_store_release(struct ref_store *ref_store);
 
+/*
+ * Remove the ref store from disk. This deletes all associated data.
+ */
+int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err);
+
 /*
  * Return the peeled value of the oid currently being iterated via
  * for_each_ref(), etc. This is equivalent to calling:
index de8cc83174007fa78fd25d3b227db6d1a6fd77da..e6637811992f0115d1a1522e0b9c72cc41b8ed93 100644 (file)
@@ -3342,11 +3342,73 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,
        return 0;
 }
 
+struct remove_one_root_ref_data {
+       const char *gitdir;
+       struct strbuf *err;
+};
+
+static int remove_one_root_ref(const char *refname,
+                              void *cb_data)
+{
+       struct remove_one_root_ref_data *data = cb_data;
+       struct strbuf buf = STRBUF_INIT;
+       int ret = 0;
+
+       strbuf_addf(&buf, "%s/%s", data->gitdir, refname);
+
+       ret = unlink(buf.buf);
+       if (ret < 0)
+               strbuf_addf(data->err, "could not delete %s: %s\n",
+                           refname, strerror(errno));
+
+       strbuf_release(&buf);
+       return ret;
+}
+
+static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
+                                         struct strbuf *err)
+{
+       struct files_ref_store *refs =
+               files_downcast(ref_store, REF_STORE_WRITE, "remove");
+       struct remove_one_root_ref_data data = {
+               .gitdir = refs->base.gitdir,
+               .err = err,
+       };
+       struct strbuf sb = STRBUF_INIT;
+       int ret = 0;
+
+       strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+       if (remove_dir_recursively(&sb, 0) < 0) {
+               strbuf_addf(err, "could not delete refs: %s",
+                           strerror(errno));
+               ret = -1;
+       }
+       strbuf_reset(&sb);
+
+       strbuf_addf(&sb, "%s/logs", refs->base.gitdir);
+       if (remove_dir_recursively(&sb, 0) < 0) {
+               strbuf_addf(err, "could not delete logs: %s",
+                           strerror(errno));
+               ret = -1;
+       }
+       strbuf_reset(&sb);
+
+       if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0)
+               ret = -1;
+
+       if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0)
+               ret = -1;
+
+       strbuf_release(&sb);
+       return ret;
+}
+
 struct ref_storage_be refs_be_files = {
        .name = "files",
        .init = files_ref_store_init,
        .release = files_ref_store_release,
        .create_on_disk = files_ref_store_create_on_disk,
+       .remove_on_disk = files_ref_store_remove_on_disk,
 
        .transaction_prepare = files_transaction_prepare,
        .transaction_finish = files_transaction_finish,
index 2789fd92f5d4d3bb3ec9c162033303b18a4cce4a..c4c1e36aa29c0f83bf640c6d58444971f58d7246 100644 (file)
@@ -1,5 +1,6 @@
 #include "../git-compat-util.h"
 #include "../config.h"
+#include "../dir.h"
 #include "../gettext.h"
 #include "../hash.h"
 #include "../hex.h"
@@ -1266,6 +1267,19 @@ static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED,
        return 0;
 }
 
+static int packed_ref_store_remove_on_disk(struct ref_store *ref_store,
+                                          struct strbuf *err)
+{
+       struct packed_ref_store *refs = packed_downcast(ref_store, 0, "remove");
+
+       if (remove_path(refs->path) < 0) {
+               strbuf_addstr(err, "could not delete packed-refs");
+               return -1;
+       }
+
+       return 0;
+}
+
 /*
  * Write the packed refs from the current snapshot to the packed-refs
  * tempfile, incorporating any changes from `updates`. `updates` must
@@ -1724,6 +1738,7 @@ struct ref_storage_be refs_be_packed = {
        .init = packed_ref_store_init,
        .release = packed_ref_store_release,
        .create_on_disk = packed_ref_store_create_on_disk,
+       .remove_on_disk = packed_ref_store_remove_on_disk,
 
        .transaction_prepare = packed_transaction_prepare,
        .transaction_finish = packed_transaction_finish,
index 33749fbd83986064c209249c0fda8bba24157b1a..cbcb6f9c36b209a3f04333a5d2c347724e60aaab 100644 (file)
@@ -517,6 +517,12 @@ typedef int ref_store_create_on_disk_fn(struct ref_store *refs,
                                        int flags,
                                        struct strbuf *err);
 
+/*
+ * Remove the reference store from disk.
+ */
+typedef int ref_store_remove_on_disk_fn(struct ref_store *refs,
+                                       struct strbuf *err);
+
 typedef int ref_transaction_prepare_fn(struct ref_store *refs,
                                       struct ref_transaction *transaction,
                                       struct strbuf *err);
@@ -649,6 +655,7 @@ struct ref_storage_be {
        ref_store_init_fn *init;
        ref_store_release_fn *release;
        ref_store_create_on_disk_fn *create_on_disk;
+       ref_store_remove_on_disk_fn *remove_on_disk;
 
        ref_transaction_prepare_fn *transaction_prepare;
        ref_transaction_finish_fn *transaction_finish;
index bffed9257f3bfb40f60459ba2a2abc81d0df1bee..da6b3162f33424384db1fdd9d99beedf677dc264 100644 (file)
@@ -1,6 +1,7 @@
 #include "../git-compat-util.h"
 #include "../abspath.h"
 #include "../chdir-notify.h"
+#include "../dir.h"
 #include "../environment.h"
 #include "../gettext.h"
 #include "../hash.h"
@@ -343,6 +344,56 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store,
        return 0;
 }
 
+static int reftable_be_remove_on_disk(struct ref_store *ref_store,
+                                     struct strbuf *err)
+{
+       struct reftable_ref_store *refs =
+               reftable_be_downcast(ref_store, REF_STORE_WRITE, "remove");
+       struct strbuf sb = STRBUF_INIT;
+       int ret = 0;
+
+       /*
+        * Release the ref store such that all stacks are closed. This is
+        * required so that the "tables.list" file is not open anymore, which
+        * would otherwise make it impossible to remove the file on Windows.
+        */
+       reftable_be_release(ref_store);
+
+       strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
+       if (remove_dir_recursively(&sb, 0) < 0) {
+               strbuf_addf(err, "could not delete reftables: %s",
+                           strerror(errno));
+               ret = -1;
+       }
+       strbuf_reset(&sb);
+
+       strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
+       if (unlink(sb.buf) < 0) {
+               strbuf_addf(err, "could not delete stub HEAD: %s",
+                           strerror(errno));
+               ret = -1;
+       }
+       strbuf_reset(&sb);
+
+       strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
+       if (unlink(sb.buf) < 0) {
+               strbuf_addf(err, "could not delete stub heads: %s",
+                           strerror(errno));
+               ret = -1;
+       }
+       strbuf_reset(&sb);
+
+       strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+       if (rmdir(sb.buf) < 0) {
+               strbuf_addf(err, "could not delete refs directory: %s",
+                           strerror(errno));
+               ret = -1;
+       }
+
+       strbuf_release(&sb);
+       return ret;
+}
+
 struct reftable_ref_iterator {
        struct ref_iterator base;
        struct reftable_ref_store *refs;
@@ -2196,6 +2247,7 @@ struct ref_storage_be refs_be_reftable = {
        .init = reftable_be_init,
        .release = reftable_be_release,
        .create_on_disk = reftable_be_create_on_disk,
+       .remove_on_disk = reftable_be_remove_on_disk,
 
        .transaction_prepare = reftable_be_transaction_prepare,
        .transaction_finish = reftable_be_transaction_finish,