Skip to content

Commit bc21965

Browse files
authored
Merge pull request libgit2#4833 from csware/drop-empty-dirs
Remove empty (sub-)directories when deleting refs
2 parents 8b2670b + 9f48dc3 commit bc21965

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

src/refdb_fs.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,43 @@ static int refdb_fs_backend__write_tail(
13131313
return error;
13141314
}
13151315

1316+
static void refdb_fs_backend__try_delete_empty_ref_hierarchie(
1317+
refdb_fs_backend *backend,
1318+
const char *ref_name,
1319+
bool reflog)
1320+
{
1321+
git_buf relative_path = GIT_BUF_INIT;
1322+
git_buf base_path = GIT_BUF_INIT;
1323+
size_t commonlen;
1324+
1325+
assert(backend && ref_name);
1326+
1327+
if (git_buf_sets(&relative_path, ref_name) < 0)
1328+
goto cleanup;
1329+
1330+
git_path_squash_slashes(&relative_path);
1331+
if ((commonlen = git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path))) == strlen("refs/heads/") ||
1332+
(commonlen = git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path))) == strlen("refs/tags/") ||
1333+
(commonlen = git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path))) == strlen("refs/remotes/")) {
1334+
1335+
git_buf_truncate(&relative_path, commonlen);
1336+
1337+
if (reflog) {
1338+
if (git_buf_join3(&base_path, '/', backend->commonpath, GIT_REFLOG_DIR, git_buf_cstr(&relative_path)) < 0)
1339+
goto cleanup;
1340+
} else {
1341+
if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0)
1342+
goto cleanup;
1343+
}
1344+
1345+
git_futils_rmdir_r(ref_name + commonlen, git_buf_cstr(&base_path), GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT);
1346+
}
1347+
1348+
cleanup:
1349+
git_buf_dispose(&relative_path);
1350+
git_buf_dispose(&base_path);
1351+
}
1352+
13161353
static int refdb_fs_backend__delete(
13171354
git_refdb_backend *_backend,
13181355
const char *ref_name,
@@ -1393,7 +1430,8 @@ static int refdb_fs_backend__delete_tail(
13931430
cleanup:
13941431
git_buf_dispose(&loose_path);
13951432
git_filebuf_cleanup(file);
1396-
1433+
if (loose_deleted)
1434+
refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, ref_name, false);
13971435
return error;
13981436
}
13991437

@@ -2021,8 +2059,10 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name
20212059

20222060
error = retrieve_reflog_path(&path, repo, name);
20232061

2024-
if (!error && git_path_exists(path.ptr))
2062+
if (!error && git_path_exists(path.ptr)) {
20252063
error = p_unlink(path.ptr);
2064+
refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, name, true);
2065+
}
20262066

20272067
git_buf_dispose(&path);
20282068

tests/refs/branches/delete.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#include "refs.h"
33
#include "repo/repo_helpers.h"
44
#include "config/config_helpers.h"
5+
#include "fileops.h"
6+
#include "reflog.h"
57

68
static git_repository *repo;
79
static git_reference *fake_remote;
@@ -140,3 +142,47 @@ void test_refs_branches_delete__removes_reflog(void)
140142
git_reflog_free(log);
141143
}
142144

145+
void test_refs_branches_delete__removes_empty_folders(void)
146+
{
147+
const char *commondir = git_repository_commondir(repo);
148+
git_oid commit_id;
149+
git_commit *commit;
150+
git_reference *branch;
151+
152+
git_reflog *log;
153+
git_oid oidzero = {{0}};
154+
git_signature *sig;
155+
156+
git_buf ref_folder = GIT_BUF_INIT;
157+
git_buf reflog_folder = GIT_BUF_INIT;
158+
159+
/* Create a new branch with a nested name */
160+
cl_git_pass(git_oid_fromstr(&commit_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
161+
cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
162+
cl_git_pass(git_branch_create(&branch, repo, "some/deep/ref", commit, 0));
163+
git_commit_free(commit);
164+
165+
/* Ensure the reflog has at least one entry */
166+
cl_git_pass(git_signature_now(&sig, "Me", "user@example.com"));
167+
cl_git_pass(git_reflog_read(&log, repo, "refs/heads/some/deep/ref"));
168+
cl_git_pass(git_reflog_append(log, &oidzero, sig, "message"));
169+
cl_assert(git_reflog_entrycount(log) > 0);
170+
git_signature_free(sig);
171+
git_reflog_free(log);
172+
173+
cl_git_pass(git_buf_joinpath(&ref_folder, commondir, "refs/heads/some/deep"));
174+
cl_git_pass(git_buf_join3(&reflog_folder, '/', commondir, GIT_REFLOG_DIR, "refs/heads/some/deep"));
175+
176+
cl_assert(git_path_exists(git_buf_cstr(&ref_folder)) == true);
177+
cl_assert(git_path_exists(git_buf_cstr(&reflog_folder)) == true);
178+
179+
cl_git_pass(git_branch_delete(branch));
180+
181+
cl_assert(git_path_exists(git_buf_cstr(&ref_folder)) == false);
182+
cl_assert(git_path_exists(git_buf_cstr(&reflog_folder)) == false);
183+
184+
git_reference_free(branch);
185+
git_buf_dispose(&ref_folder);
186+
git_buf_dispose(&reflog_folder);
187+
}
188+

0 commit comments

Comments
 (0)