diff options
author | Sven Strickroth <email@cs-ware.de> | 2018-10-05 12:47:32 +0200 |
---|---|---|
committer | Sven Strickroth <email@cs-ware.de> | 2018-10-13 16:13:53 +0200 |
commit | 9f48dc3b73be1036da7b2a5a5e03346513aebf9a (patch) | |
tree | 67fcc4fcc1add48a35e04ffa7367310e40bd157b | |
parent | 838a2f2918b6d9fad8768d2498575ff5d75c35f0 (diff) | |
download | libgit2-9f48dc3b73be1036da7b2a5a5e03346513aebf9a.tar.gz |
Remove empty directories when deleting refs
Signed-off-by: Sven Strickroth <email@cs-ware.de>
-rw-r--r-- | src/refdb_fs.c | 44 | ||||
-rw-r--r-- | tests/refs/branches/delete.c | 46 |
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); +} + |