Skip to content

Commit 47dcc4b

Browse files
authored
Merge pull request libgit2#6345 from arroz/fix/branch-move-reflog
Fixes libgit2#6344: git_branch_move now renames the reflog instead of deleting.
2 parents 633cde0 + 3e8f470 commit 47dcc4b

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

src/libgit2/refdb_fs.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,40 +1785,41 @@ static int refdb_fs_backend__rename(
17851785
(error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0)
17861786
return error;
17871787

1788-
if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) {
1788+
if ((error = loose_lock(&file, backend, old->name)) < 0) {
17891789
git_reference_free(old);
17901790
return error;
17911791
}
17921792

17931793
new = git_reference__realloc(&old, new_name);
17941794
if (!new) {
17951795
git_reference_free(old);
1796+
git_filebuf_cleanup(&file);
17961797
return -1;
17971798
}
17981799

1799-
if ((error = loose_lock(&file, backend, new->name)) < 0) {
1800+
if ((error = refdb_fs_backend__delete_tail(_backend, &file, old_name, NULL, NULL)) < 0) {
18001801
git_reference_free(new);
1802+
git_filebuf_cleanup(&file);
18011803
return error;
18021804
}
18031805

1804-
/* Try to rename the refog; it's ok if the old doesn't exist */
1805-
error = refdb_reflog_fs__rename(_backend, old_name, new_name);
1806-
if (((error == 0) || (error == GIT_ENOTFOUND)) &&
1807-
((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) {
1806+
if ((error = loose_lock(&file, backend, new_name)) < 0) {
18081807
git_reference_free(new);
1809-
git_filebuf_cleanup(&file);
18101808
return error;
18111809
}
18121810

1813-
if (error < 0) {
1811+
/* Try to rename the refog; it's ok if the old doesn't exist */
1812+
error = refdb_reflog_fs__rename(_backend, old_name, new_name);
1813+
if (((error == 0) || (error == GIT_ENOTFOUND)) &&
1814+
((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) {
18141815
git_reference_free(new);
18151816
git_filebuf_cleanup(&file);
18161817
return error;
18171818
}
18181819

1819-
18201820
if ((error = loose_commit(&file, new)) < 0 || out == NULL) {
18211821
git_reference_free(new);
1822+
git_filebuf_cleanup(&file);
18221823
return error;
18231824
}
18241825

@@ -2401,7 +2402,12 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name
24012402
if ((error = reflog_path(&path, backend->repo, name)) < 0)
24022403
goto out;
24032404

2404-
if (!git_fs_path_exists(path.ptr))
2405+
/*
2406+
* If a reference was moved downwards, eg refs/heads/br2 -> refs/heads/br2/new-name,
2407+
* refs/heads/br2 does exist but it's a directory. That's a valid situation.
2408+
* Proceed only if it's a file.
2409+
*/
2410+
if (!git_fs_path_isfile(path.ptr))
24052411
goto out;
24062412

24072413
if ((error = p_unlink(path.ptr)) < 0)

tests/libgit2/refs/branches/move.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,41 @@ void test_refs_branches_move__can_move_with_unicode(void)
210210
git_reference_free(original_ref);
211211
git_reference_free(new_ref);
212212
}
213+
214+
void test_refs_branches_move__moves_reflog_correctly(void)
215+
{
216+
git_reference *original_ref, *new_ref;
217+
git_reflog *original_reflog, *new_reflog;
218+
219+
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
220+
221+
cl_git_pass(git_reflog_read(&original_reflog, repo, "refs/heads/br2"));
222+
cl_assert_equal_i(2, git_reflog_entrycount(original_reflog));
223+
224+
cl_git_pass(git_branch_move(&new_ref, original_ref, NEW_BRANCH_NAME, 0));
225+
cl_assert_equal_s(GIT_REFS_HEADS_DIR NEW_BRANCH_NAME, git_reference_name(new_ref));
226+
227+
cl_git_pass(git_reflog_read(&new_reflog, repo, GIT_REFS_HEADS_DIR NEW_BRANCH_NAME));
228+
cl_assert_equal_i(3, git_reflog_entrycount(new_reflog));
229+
230+
git_reference_free(original_ref);
231+
git_reference_free(new_ref);
232+
git_reflog_free(original_reflog);
233+
git_reflog_free(new_reflog);
234+
}
235+
236+
void test_refs_branches_move__failed_move_restores_reflog(void)
237+
{
238+
git_reference *original_ref, *new_ref;
239+
git_reflog *recovered_reflog;
240+
241+
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
242+
243+
cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_move(&new_ref, original_ref, "Inv@{id", 0));
244+
245+
cl_git_pass(git_reflog_read(&recovered_reflog, repo, "refs/heads/br2"));
246+
cl_assert_equal_i(2, git_reflog_entrycount(recovered_reflog));
247+
248+
git_reference_free(original_ref);
249+
git_reflog_free(recovered_reflog);
250+
}

0 commit comments

Comments
 (0)