Commit f2c41884c3082984f51743d557644cfa2136b878

Russell Belfer 2013-06-27T22:48:46

Merge pull request #1688 from arrbee/submodule-load-ignore-orphaned-head Test submodules with empty index or orphaned head

diff --git a/src/submodule.c b/src/submodule.c
index 89eba2a..dcd58d0 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -1176,8 +1176,11 @@ static int load_submodule_config_from_head(
 	git_iterator *i;
 	const git_index_entry *entry;
 
-	if ((error = git_repository_head_tree(&head, repo)) < 0)
-		return error;
+	/* if we can't look up current head, then there's no submodule in it */
+	if (git_repository_head_tree(&head, repo) < 0) {
+		giterr_clear();
+		return 0;
+	}
 
 	if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0) {
 		git_tree_free(head);
diff --git a/tests-clar/submodule/lookup.c b/tests-clar/submodule/lookup.c
index acf8f64..013bbdf 100644
--- a/tests-clar/submodule/lookup.c
+++ b/tests-clar/submodule/lookup.c
@@ -1,6 +1,7 @@
 #include "clar_libgit2.h"
 #include "submodule_helpers.h"
 #include "posix.h"
+#include "git2/sys/repository.h"
 
 static git_repository *g_repo = NULL;
 
@@ -112,3 +113,73 @@ void test_submodule_lookup__foreach(void)
 	cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data));
 	cl_assert_equal_i(8, data.count);
 }
+
+void test_submodule_lookup__lookup_even_with_orphaned_head(void)
+{
+	git_reference *orphan;
+	git_submodule *sm;
+
+	/* orphan the head */
+	cl_git_pass(git_reference_symbolic_create(
+		&orphan, g_repo, "HEAD", "refs/heads/garbage", 1));
+	git_reference_free(orphan);
+
+	/* lookup existing */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+	cl_assert(sm);
+
+	/* lookup pending change in .gitmodules that is not in HEAD */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+	cl_assert(sm);
+
+	/* lookup pending change in .gitmodules that is neither in HEAD nor index */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
+	cl_assert(sm);
+
+	/* lookup git repo subdir that is not added as submodule */
+	cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule"));
+
+	/* lookup existing directory that is not a submodule */
+	cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir"));
+
+	/* lookup existing file that is not a submodule */
+	cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_file"));
+
+	/* lookup non-existent item */
+	cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "no_such_file"));
+}
+
+void test_submodule_lookup__lookup_even_with_missing_index(void)
+{
+	git_index *idx;
+	git_submodule *sm;
+
+	/* give the repo an empty index */
+	cl_git_pass(git_index_new(&idx));
+	git_repository_set_index(g_repo, idx);
+	git_index_free(idx);
+
+	/* lookup existing */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+	cl_assert(sm);
+
+	/* lookup pending change in .gitmodules that is not in HEAD */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+	cl_assert(sm);
+
+	/* lookup pending change in .gitmodules that is neither in HEAD nor index */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
+	cl_assert(sm);
+
+	/* lookup git repo subdir that is not added as submodule */
+	cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule"));
+
+	/* lookup existing directory that is not a submodule */
+	cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir"));
+
+	/* lookup existing file that is not a submodule */
+	cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_file"));
+
+	/* lookup non-existent item */
+	cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "no_such_file"));
+}