Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions src/refdb_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,43 @@ static int refdb_fs_backend__write_tail(
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,
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);

Expand Down
46 changes: 46 additions & 0 deletions tests/refs/branches/delete.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}