diff --git a/include/git2/repository.h b/include/git2/repository.h index 648667cd6..bf12c7a69 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -615,11 +615,15 @@ GIT_EXTERN(int) git_repository_set_head_detached( * Otherwise, the HEAD will be detached and point to the peeled Commit. * * @param repo Repository pointer + * @param signature The identity that will used to populate the reflog entry + * @param log_message The one line long message to be appended to the reflog * @return 0 on success, GIT_EUNBORNBRANCH when HEAD points to a non existing * branch or an error code */ GIT_EXTERN(int) git_repository_detach_head( - git_repository* repo); + git_repository* repo, + const git_signature *signature, + const char *reflog_message); typedef enum { GIT_REPOSITORY_STATE_NONE, diff --git a/src/repository.c b/src/repository.c index 2c1b60266..848aa565d 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1891,7 +1891,9 @@ cleanup: } int git_repository_detach_head( - git_repository* repo) + git_repository* repo, + const git_signature *signature, + const char *reflog_message) { git_reference *old_head = NULL, *new_head = NULL; @@ -1906,7 +1908,8 @@ int git_repository_detach_head( if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJ_COMMIT)) < 0) goto cleanup; - error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), 1, NULL, NULL); + error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), + 1, signature, reflog_message); cleanup: git_object_free(object); diff --git a/tests/refs/branches/delete.c b/tests/refs/branches/delete.c index 7d1d400c8..ed5f1627b 100644 --- a/tests/refs/branches/delete.c +++ b/tests/refs/branches/delete.c @@ -78,7 +78,7 @@ void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD( git_reference_free(head); /* Detach HEAD and make it target the commit that "master" points to */ - git_repository_detach_head(repo); + git_repository_detach_head(repo, NULL, NULL); cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); diff --git a/tests/repo/head.c b/tests/repo/head.c index 127176d12..c5965fac6 100644 --- a/tests/repo/head.c +++ b/tests/repo/head.c @@ -15,21 +15,42 @@ void test_repo_head__cleanup(void) cl_git_sandbox_cleanup(); } +static void check_last_reflog_entry(const char *email, const char *message) +{ + git_reflog *log; + const git_reflog_entry *entry; + + cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE)); + cl_assert(git_reflog_entrycount(log) > 0); + entry = git_reflog_entry_byindex(log, 0); + if (email) + cl_assert_equal_s(email, git_reflog_entry_committer(entry)->email); + if (message) + cl_assert_equal_s(message, git_reflog_entry_message(entry)); + git_reflog_free(log); +} + void test_repo_head__head_detached(void) { git_reference *ref; + git_signature *sig; - cl_git_pass(git_repository_head_detached(repo)); - - cl_git_pass(git_repository_detach_head(repo)); - - cl_assert_equal_i(true, git_repository_head_detached(repo)); - - /* take the reop back to it's original state */ - cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master", 1, NULL, NULL)); - git_reference_free(ref); + cl_git_pass(git_signature_now(&sig, "Foo Bar", "foo@example.com")); cl_assert_equal_i(false, git_repository_head_detached(repo)); + + cl_git_pass(git_repository_detach_head(repo, sig, "CABLE DETACHED")); + check_last_reflog_entry(sig->email, "CABLE DETACHED"); + cl_assert_equal_i(true, git_repository_head_detached(repo)); + + /* take the repo back to it's original state */ + cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master", + true, sig, "REATTACH")); + git_reference_free(ref); + + check_last_reflog_entry(sig->email, "REATTACH"); + cl_assert_equal_i(false, git_repository_head_detached(repo)); + git_signature_free(sig); } void test_repo_head__unborn_head(void) @@ -147,7 +168,7 @@ void test_repo_head__detach_head_Detaches_HEAD_and_make_it_point_to_the_peeled_c { cl_assert_equal_i(false, git_repository_head_detached(repo)); - cl_git_pass(git_repository_detach_head(repo)); + cl_git_pass(git_repository_detach_head(repo, NULL, NULL)); assert_head_is_correctly_detached(); } @@ -158,7 +179,7 @@ void test_repo_head__detach_head_Fails_if_HEAD_and_point_to_a_non_commitish(void cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/tags/point_to_blob", 1, NULL, NULL)); - cl_git_fail(git_repository_detach_head(repo)); + cl_git_fail(git_repository_detach_head(repo, NULL, NULL)); git_reference_free(head); } @@ -167,7 +188,7 @@ void test_repo_head__detaching_an_unborn_branch_returns_GIT_EUNBORNBRANCH(void) { make_head_unborn(repo, NON_EXISTING_HEAD); - cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_detach_head(repo)); + cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_detach_head(repo, NULL, NULL)); } void test_repo_head__retrieving_an_unborn_branch_returns_GIT_EUNBORNBRANCH(void) diff --git a/tests/repo/headtree.c b/tests/repo/headtree.c index e899ac399..79d88c0a7 100644 --- a/tests/repo/headtree.c +++ b/tests/repo/headtree.c @@ -20,7 +20,7 @@ void test_repo_headtree__cleanup(void) void test_repo_headtree__can_retrieve_the_root_tree_from_a_detached_head(void) { - cl_git_pass(git_repository_detach_head(repo)); + cl_git_pass(git_repository_detach_head(repo, NULL, NULL)); cl_git_pass(git_repository_head_tree(&tree, repo)); diff --git a/tests/repo/state.c b/tests/repo/state.c index 5a0a5f360..5e7227205 100644 --- a/tests/repo/state.c +++ b/tests/repo/state.c @@ -37,7 +37,7 @@ void test_repo_state__none_with_HEAD_attached(void) void test_repo_state__none_with_HEAD_detached(void) { - cl_git_pass(git_repository_detach_head(_repo)); + cl_git_pass(git_repository_detach_head(_repo, NULL, NULL)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); } diff --git a/tests/reset/soft.c b/tests/reset/soft.c index 6469fce6d..c889c0355 100644 --- a/tests/reset/soft.c +++ b/tests/reset/soft.c @@ -45,7 +45,7 @@ void test_reset_soft__can_reset_the_non_detached_Head_to_the_specified_commit(vo void test_reset_soft__can_reset_the_detached_Head_to_the_specified_commit(void) { - git_repository_detach_head(repo); + git_repository_detach_head(repo, NULL, NULL); assert_reset_soft(true); } @@ -118,7 +118,7 @@ void test_reset_soft__fails_when_merging(void) { git_buf merge_head_path = GIT_BUF_INIT; - cl_git_pass(git_repository_detach_head(repo)); + cl_git_pass(git_repository_detach_head(repo, NULL, NULL)); cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_mkfile(git_buf_cstr(&merge_head_path), "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef\n"); diff --git a/tests/stash/save.c b/tests/stash/save.c index 293a89a97..b5a793eef 100644 --- a/tests/stash/save.c +++ b/tests/stash/save.c @@ -196,7 +196,7 @@ void test_stash_save__cannot_stash_against_a_bare_repository(void) void test_stash_save__can_stash_against_a_detached_head(void) { - git_repository_detach_head(repo); + git_repository_detach_head(repo, NULL, NULL); cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));