summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Strickroth <email@cs-ware.de>2018-10-05 12:47:32 +0200
committerSven Strickroth <email@cs-ware.de>2018-10-13 16:13:53 +0200
commit9f48dc3b73be1036da7b2a5a5e03346513aebf9a (patch)
tree67fcc4fcc1add48a35e04ffa7367310e40bd157b
parent838a2f2918b6d9fad8768d2498575ff5d75c35f0 (diff)
downloadlibgit2-9f48dc3b73be1036da7b2a5a5e03346513aebf9a.tar.gz
Remove empty directories when deleting refs
Signed-off-by: Sven Strickroth <email@cs-ware.de>
-rw-r--r--src/refdb_fs.c44
-rw-r--r--tests/refs/branches/delete.c46
2 files changed, 88 insertions, 2 deletions
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 49b567c08..dfff5d396 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -1305,6 +1305,43 @@ on_error:
return error;
}
+static void refdb_fs_backend__try_delete_empty_ref_hierarchie(
+ refdb_fs_backend *backend,
+ const char *ref_name,
+ bool reflog)
+{
+ git_buf relative_path = GIT_BUF_INIT;
+ git_buf base_path = GIT_BUF_INIT;
+ size_t commonlen;
+
+ assert(backend && ref_name);
+
+ if (git_buf_sets(&relative_path, ref_name) < 0)
+ goto cleanup;
+
+ git_path_squash_slashes(&relative_path);
+ if ((commonlen = git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path))) == strlen("refs/heads/") ||
+ (commonlen = git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path))) == strlen("refs/tags/") ||
+ (commonlen = git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path))) == strlen("refs/remotes/")) {
+
+ git_buf_truncate(&relative_path, commonlen);
+
+ if (reflog) {
+ if (git_buf_join3(&base_path, '/', backend->commonpath, GIT_REFLOG_DIR, git_buf_cstr(&relative_path)) < 0)
+ goto cleanup;
+ } else {
+ if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0)
+ goto cleanup;
+ }
+
+ git_futils_rmdir_r(ref_name + commonlen, git_buf_cstr(&base_path), GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT);
+ }
+
+cleanup:
+ git_buf_dispose(&relative_path);
+ git_buf_dispose(&base_path);
+}
+
static int refdb_fs_backend__delete(
git_refdb_backend *_backend,
const char *ref_name,
@@ -1385,7 +1422,8 @@ static int refdb_fs_backend__delete_tail(
cleanup:
git_buf_dispose(&loose_path);
git_filebuf_cleanup(file);
-
+ if (loose_deleted)
+ refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, ref_name, false);
return error;
}
@@ -2013,8 +2051,10 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name
error = retrieve_reflog_path(&path, repo, name);
- if (!error && git_path_exists(path.ptr))
+ if (!error && git_path_exists(path.ptr)) {
error = p_unlink(path.ptr);
+ refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, name, true);
+ }
git_buf_dispose(&path);
diff --git a/tests/refs/branches/delete.c b/tests/refs/branches/delete.c
index 8807db231..928adf73a 100644
--- a/tests/refs/branches/delete.c
+++ b/tests/refs/branches/delete.c
@@ -2,6 +2,8 @@
#include "refs.h"
#include "repo/repo_helpers.h"
#include "config/config_helpers.h"
+#include "fileops.h"
+#include "reflog.h"
static git_repository *repo;
static git_reference *fake_remote;
@@ -140,3 +142,47 @@ void test_refs_branches_delete__removes_reflog(void)
git_reflog_free(log);
}
+void test_refs_branches_delete__removes_empty_folders(void)
+{
+ const char *commondir = git_repository_commondir(repo);
+ git_oid commit_id;
+ git_commit *commit;
+ git_reference *branch;
+
+ git_reflog *log;
+ git_oid oidzero = {{0}};
+ git_signature *sig;
+
+ git_buf ref_folder = GIT_BUF_INIT;
+ git_buf reflog_folder = GIT_BUF_INIT;
+
+ /* Create a new branch with a nested name */
+ cl_git_pass(git_oid_fromstr(&commit_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
+ cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
+ cl_git_pass(git_branch_create(&branch, repo, "some/deep/ref", commit, 0));
+ git_commit_free(commit);
+
+ /* Ensure the reflog has at least one entry */
+ cl_git_pass(git_signature_now(&sig, "Me", "user@example.com"));
+ cl_git_pass(git_reflog_read(&log, repo, "refs/heads/some/deep/ref"));
+ cl_git_pass(git_reflog_append(log, &oidzero, sig, "message"));
+ cl_assert(git_reflog_entrycount(log) > 0);
+ git_signature_free(sig);
+ git_reflog_free(log);
+
+ cl_git_pass(git_buf_joinpath(&ref_folder, commondir, "refs/heads/some/deep"));
+ cl_git_pass(git_buf_join3(&reflog_folder, '/', commondir, GIT_REFLOG_DIR, "refs/heads/some/deep"));
+
+ cl_assert(git_path_exists(git_buf_cstr(&ref_folder)) == true);
+ cl_assert(git_path_exists(git_buf_cstr(&reflog_folder)) == true);
+
+ cl_git_pass(git_branch_delete(branch));
+
+ cl_assert(git_path_exists(git_buf_cstr(&ref_folder)) == false);
+ cl_assert(git_path_exists(git_buf_cstr(&reflog_folder)) == false);
+
+ git_reference_free(branch);
+ git_buf_dispose(&ref_folder);
+ git_buf_dispose(&reflog_folder);
+}
+