From 8b05bea87042010c2d9c71d0be17f45bf5bea2a3 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 19 Oct 2012 17:07:39 +0200 Subject: [PATCH] errors: deploy GIT_EORPHANEDHEAD usage --- include/git2/checkout.h | 3 ++- include/git2/repository.h | 6 ++++-- src/branch.c | 2 +- src/checkout.c | 16 +++++++++----- src/repository.c | 16 ++++++++------ tests-clar/checkout/head.c | 24 +++++++++++++++++++++ tests-clar/refs/branches/delete.c | 12 +++++++++++ tests-clar/refs/branches/ishead.c | 24 +++++++++++++++++++++ tests-clar/repo/head.c | 36 +++++++++++++++++++++++++------ 9 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 tests-clar/checkout/head.c diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 0bac5690a..b4f9ad081 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -81,7 +81,8 @@ typedef struct git_checkout_opts { * @param repo repository to check out (must be non-bare) * @param opts specifies checkout options (may be NULL) * @param stats structure through which progress information is reported - * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information + * @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing + * branch, GIT_ERROR otherwise (use giterr_last for information * about the error) */ GIT_EXTERN(int) git_checkout_head( diff --git a/include/git2/repository.h b/include/git2/repository.h index 025a0a95d..32a2f6449 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -272,7 +272,8 @@ GIT_EXTERN(int) git_repository_init_ext( * @param head_out pointer to the reference which will be retrieved * @param repo a repository object * - * @return 0 on success; error code otherwise + * @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing + * branch, an error code otherwise */ GIT_EXTERN(int) git_repository_head(git_reference **head_out, git_repository *repo); @@ -562,7 +563,8 @@ GIT_EXTERN(int) git_repository_set_head_detached( * Otherwise, the HEAD will be detached and point to the peeled Commit. * * @param repo Repository pointer - * @return 0 on success, or an error code + * @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing + * branchor an error code */ GIT_EXTERN(int) git_repository_detach_head( git_repository* repo); diff --git a/src/branch.c b/src/branch.c index d9fa9eb97..991314508 100644 --- a/src/branch.c +++ b/src/branch.c @@ -274,7 +274,7 @@ int git_branch_is_head( error = git_repository_head(&head, git_reference_owner(branch)); - if (error == GIT_ENOTFOUND) + if (error == GIT_EORPHANEDHEAD) return false; if (error < 0) diff --git a/src/checkout.c b/src/checkout.c index 4782f7724..b56b459d2 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -430,17 +430,23 @@ int git_checkout_head( git_checkout_opts *opts, git_indexer_stats *stats) { + git_reference *head; int error; - git_tree *tree = NULL; + git_object *tree = NULL; assert(repo); - if (git_repository_head_tree(&tree, repo) < 0) - return -1; + if ((error = git_repository_head(&head, repo)) < 0) + return error; + + if ((error = git_reference_peel(&tree, head, GIT_OBJ_TREE)) < 0) + goto cleanup; - error = git_checkout_tree(repo, (git_object *)tree, opts, stats); + error = git_checkout_tree(repo, tree, opts, stats); - git_tree_free(tree); +cleanup: + git_reference_free(head); + git_object_free(tree); return error; } diff --git a/src/repository.c b/src/repository.c index 5f7fa3cea..db0888a89 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1206,7 +1206,11 @@ int git_repository_head_detached(git_repository *repo) int git_repository_head(git_reference **head_out, git_repository *repo) { - return git_reference_lookup_resolved(head_out, repo, GIT_HEAD_FILE, -1); + int error; + + error = git_reference_lookup_resolved(head_out, repo, GIT_HEAD_FILE, -1); + + return error == GIT_ENOTFOUND ? GIT_EORPHANEDHEAD : error; } int git_repository_head_orphan(git_repository *repo) @@ -1217,7 +1221,7 @@ int git_repository_head_orphan(git_repository *repo) error = git_repository_head(&ref, repo); git_reference_free(ref); - if (error == GIT_ENOTFOUND) + if (error == GIT_EORPHANEDHEAD) return 1; if (error < 0) @@ -1519,14 +1523,14 @@ int git_repository_detach_head( git_reference *old_head = NULL, *new_head = NULL; git_object *object = NULL; - int error = -1; + int error; assert(repo); - if (git_repository_head(&old_head, repo) < 0) - return -1; + if ((error = git_repository_head(&old_head, repo)) < 0) + return error; - if (git_object_lookup(&object, repo, git_reference_oid(old_head), GIT_OBJ_COMMIT) < 0) + if ((error = git_object_lookup(&object, repo, git_reference_oid(old_head), GIT_OBJ_COMMIT)) < 0) goto cleanup; error = git_reference_create_oid(&new_head, repo, GIT_HEAD_FILE, git_reference_oid(old_head), 1); diff --git a/tests-clar/checkout/head.c b/tests-clar/checkout/head.c new file mode 100644 index 000000000..f2f81e5e2 --- /dev/null +++ b/tests-clar/checkout/head.c @@ -0,0 +1,24 @@ +#include "clar_libgit2.h" +#include "refs.h" + +static git_repository *g_repo; + +void test_checkout_head__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo"); +} + +void test_checkout_head__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_checkout_head__checking_out_an_orphaned_head_returns_GIT_EORPHANEDHEAD(void) +{ + git_reference *head; + + cl_git_pass(git_reference_create_symbolic(&head, g_repo, GIT_HEAD_FILE, "refs/heads/hide/and/seek", 1)); + git_reference_free(head); + + cl_assert_equal_i(GIT_EORPHANEDHEAD, git_checkout_head(g_repo, NULL, NULL)); +} diff --git a/tests-clar/refs/branches/delete.c b/tests-clar/refs/branches/delete.c index 1a97dc822..99af44ef4 100644 --- a/tests-clar/refs/branches/delete.c +++ b/tests-clar/refs/branches/delete.c @@ -50,6 +50,18 @@ void test_refs_branches_delete__can_delete_a_branch_even_if_HEAD_is_missing(void cl_git_pass(git_branch_delete(branch)); } +void test_refs_branches_delete__can_delete_a_branch_when_HEAD_is_orphaned(void) +{ + git_reference *head; + git_reference *branch; + + cl_git_pass(git_reference_create_symbolic(&head, repo, GIT_HEAD_FILE, "refs/heads/hide/and/seek", 1)); + git_reference_free(head); + + cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); +} + void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void) { git_reference *master, *head, *branch; diff --git a/tests-clar/refs/branches/ishead.c b/tests-clar/refs/branches/ishead.c index c40a43189..0d57f00a3 100644 --- a/tests-clar/refs/branches/ishead.c +++ b/tests-clar/refs/branches/ishead.c @@ -22,6 +22,30 @@ void test_refs_branches_ishead__can_tell_if_a_branch_is_pointed_at_by_HEAD(void) cl_assert_equal_i(true, git_branch_is_head(branch)); } +static void make_head_orphaned(void) +{ + git_reference *head; + + cl_git_pass(git_reference_create_symbolic(&head, repo, GIT_HEAD_FILE, "refs/heads/hide/and/seek", 1)); + git_reference_free(head); +} + +void test_refs_branches_ishead__can_properly_handle_orphaned_HEAD(void) +{ + git_repository_free(repo); + + repo = cl_git_sandbox_init("testrepo.git"); + + make_head_orphaned(); + + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); + + cl_assert_equal_i(false, git_branch_is_head(branch)); + + cl_git_sandbox_cleanup(); + repo = NULL; +} + void test_refs_branches_ishead__can_tell_if_a_branch_is_not_pointed_at_by_HEAD(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/br2")); diff --git a/tests-clar/repo/head.c b/tests-clar/repo/head.c index 64dec69dd..4113289f0 100644 --- a/tests-clar/repo/head.c +++ b/tests-clar/repo/head.c @@ -33,18 +33,26 @@ void test_repo_head__head_detached(void) git_reference_free(ref); } +static void make_head_orphaned(void) +{ + git_reference *head; + + cl_git_pass(git_reference_create_symbolic(&head, repo, GIT_HEAD_FILE, "refs/heads/hide/and/seek", 1)); + git_reference_free(head); +} + void test_repo_head__head_orphan(void) { git_reference *ref; cl_assert(git_repository_head_orphan(repo) == 0); - /* orphan HEAD */ - cl_git_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/orphan", 1)); - cl_assert(git_repository_head_orphan(repo) == 1); - git_reference_free(ref); + make_head_orphaned(); - /* take the reop back to it's original state */ + cl_assert(git_repository_head_orphan(repo) == 1); + + + /* take the repo back to it's original state */ cl_git_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/master", 1)); cl_assert(git_repository_head_orphan(repo) == 0); @@ -59,7 +67,7 @@ void test_repo_head__set_head_Attaches_HEAD_to_un_unborn_branch_when_the_branch_ cl_assert_equal_i(false, git_repository_head_detached(repo)); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head(&head, repo)); + cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_head(&head, repo)); } void test_repo_head__set_head_Returns_ENOTFOUND_when_the_reference_doesnt_exist(void) @@ -163,3 +171,19 @@ void test_repo_head__detach_head_Fails_if_HEAD_and_point_to_a_non_commitish(void git_reference_free(head); } + +void test_repo_head__detaching_an_orphaned_head_returns_GIT_EORPHANEDHEAD(void) +{ + make_head_orphaned(); + + cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_detach_head(repo)); +} + +void test_repo_head__retrieving_an_orphaned_head_returns_GIT_EORPHANEDHEAD(void) +{ + git_reference *head; + + make_head_orphaned(); + + cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_head(&head, repo)); +}