repo: Make git_repository_head_tree() return error codes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
diff --git a/src/checkout.c b/src/checkout.c
index eff1481..c4e4f99 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -440,7 +440,9 @@ static int checkout_get_actions(
const git_index_entry *he;
/* if there is no HEAD, that's okay - we'll make an empty iterator */
- (void)git_repository_head_tree(&head, data->repo);
+ if (((error = git_repository_head_tree(&head, data->repo)) < 0) &&
+ !(error == GIT_ENOTFOUND || error == GIT_EORPHANEDHEAD))
+ return -1;
if ((error = git_iterator_for_tree_range(
&hiter, data->repo, head, pfx, pfx)) < 0)
diff --git a/src/object.c b/src/object.c
index 2e45eb8..3d95303 100644
--- a/src/object.c
+++ b/src/object.c
@@ -304,46 +304,6 @@ size_t git_object__size(git_otype type)
return git_objects_table[type].size;
}
-int git_object__resolve_to_type(git_object **obj, git_otype type)
-{
- int error = 0;
- git_object *scan, *next;
-
- if (type == GIT_OBJ_ANY)
- return 0;
-
- scan = *obj;
-
- while (!error && scan && git_object_type(scan) != type) {
-
- switch (git_object_type(scan)) {
- case GIT_OBJ_COMMIT:
- {
- git_tree *tree = NULL;
- error = git_commit_tree(&tree, (git_commit *)scan);
- next = (git_object *)tree;
- break;
- }
-
- case GIT_OBJ_TAG:
- error = git_tag_target(&next, (git_tag *)scan);
- break;
-
- default:
- giterr_set(GITERR_REFERENCE, "Object does not resolve to type");
- error = -1;
- next = NULL;
- break;
- }
-
- git_object_free(scan);
- scan = next;
- }
-
- *obj = scan;
- return error;
-}
-
static int peel_error(int error, const char* msg)
{
giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
diff --git a/src/repository.c b/src/repository.c
index f82dc10..deab771 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -1384,22 +1384,21 @@ int git_repository_is_bare(git_repository *repo)
int git_repository_head_tree(git_tree **tree, git_repository *repo)
{
- git_oid head_oid;
- git_object *obj = NULL;
+ git_reference *head;
+ git_object *obj;
+ int error;
- if (git_reference_name_to_oid(&head_oid, repo, GIT_HEAD_FILE) < 0) {
- /* cannot resolve HEAD - probably brand new repo */
- giterr_clear();
- *tree = NULL;
- return 0;
- }
+ if ((error = git_repository_head(&head, repo)) < 0)
+ return error;
- if (git_object_lookup(&obj, repo, &head_oid, GIT_OBJ_ANY) < 0 ||
- git_object__resolve_to_type(&obj, GIT_OBJ_TREE) < 0)
- return -1;
+ if ((error = git_reference_peel(&obj, head, GIT_OBJ_TREE)) < 0)
+ goto cleanup;
*tree = (git_tree *)obj;
- return 0;
+
+cleanup:
+ git_reference_free(head);
+ return error;
}
int git_repository_message(char *buffer, size_t len, git_repository *repo)
diff --git a/src/status.c b/src/status.c
index b8c15ef..b832cfe 100644
--- a/src/status.c
+++ b/src/status.c
@@ -121,8 +121,10 @@ int git_status_foreach_ext(
(err = git_repository__ensure_not_bare(repo, "status")) < 0)
return err;
- if ((err = git_repository_head_tree(&head, repo)) < 0)
- return err;
+ /* if there is no HEAD, that's okay - we'll make an empty iterator */
+ if (((err = git_repository_head_tree(&head, repo)) < 0) &&
+ !(err == GIT_ENOTFOUND || err == GIT_EORPHANEDHEAD))
+ return err;
memset(&diffopt, 0, sizeof(diffopt));
memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
diff --git a/tests-clar/repo/headtree.c b/tests-clar/repo/headtree.c
new file mode 100644
index 0000000..0e7fe93
--- /dev/null
+++ b/tests-clar/repo/headtree.c
@@ -0,0 +1,53 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "repo_helpers.h"
+#include "posix.h"
+
+static git_repository *repo;
+static git_tree *tree;
+
+void test_repo_headtree__initialize(void)
+{
+ repo = cl_git_sandbox_init("testrepo.git");
+ tree = NULL;
+}
+
+void test_repo_headtree__cleanup(void)
+{
+ git_tree_free(tree);
+ cl_git_sandbox_cleanup();
+}
+
+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_head_tree(&tree, repo));
+
+ cl_assert(git_oid_streq(git_tree_id(tree), "az"));
+}
+
+void test_repo_headtree__can_retrieve_the_root_tree_from_a_non_detached_head(void)
+{
+ cl_assert_equal_i(false, git_repository_head_detached(repo));
+
+ cl_git_pass(git_repository_head_tree(&tree, repo));
+
+ cl_assert(git_oid_streq(git_tree_id(tree), "az"));
+}
+
+void test_repo_headtree__when_head_is_orphaned_returns_EORPHANEDHEAD(void)
+{
+ make_head_orphaned(repo, NON_EXISTING_HEAD);
+
+ cl_assert_equal_i(true, git_repository_head_orphan(repo));
+
+ cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_head_tree(&tree, repo));
+}
+
+void test_repo_headtree__when_head_is_missing_returns_ENOTFOUND(void)
+{
+ delete_head(repo);
+
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head_tree(&tree, repo));
+}