Commit ccd59372d46759a92c8197717ca02ba0eb31b7be

Vicent Martí 2011-06-28T10:44:19

Merge pull request #279 from carlosmn/detached-orphan Add detached and orphan convenience functions

diff --git a/include/git2/repository.h b/include/git2/repository.h
index 27c3138..ddadab4 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -219,6 +219,30 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo);
 GIT_EXTERN(int) git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare);
 
 /**
+ * Check if a repository's HEAD is detached
+ *
+ * A repository's HEAD is detached when it points directly to a commit
+ * instead of a branch.
+ *
+ * @param repo Repo to test
+ * @return 1 if HEAD is detached, 0 if i'ts not; error code if there
+ * was an error.
+ */
+int git_repository_is_detached(git_repository *repo);
+
+/**
+ * Check if the current branch is an orphan
+ *
+ * An orphan branch is one named from HEAD but which doesn't exist in
+ * the refs namespace, because it doesn't have any commit to point to.
+ *
+ * @param repo Repo to test
+ * @return 1 if the current branch is an orphan, 0 if it's not; error
+ * code if therewas an error
+ */
+int git_repository_is_orphan(git_repository *repo);
+
+/**
  * Check if a repository is empty
  *
  * An empty repository has just been initialized and contains
diff --git a/src/repository.c b/src/repository.c
index 7e3f26e..a99c301 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -752,6 +752,47 @@ cleanup:
 	return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
 }
 
+int git_repository_is_detached(git_repository *repo)
+{
+	git_reference *ref;
+	int error;
+	size_t GIT_UNUSED(_size);
+	git_otype type;
+
+	error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
+	if (error < GIT_SUCCESS)
+		return error;
+
+	if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
+		return 0;
+
+	error = git_odb_read_header(&_size, &type, repo->db, git_reference_oid(ref));
+	if (error < GIT_SUCCESS)
+		return error;
+
+	if (type != GIT_OBJ_COMMIT)
+		return git__throw(GIT_EOBJCORRUPTED, "HEAD is not a commit");
+
+	return 1;
+}
+
+int git_repository_is_orphan(git_repository *repo)
+{
+	git_reference *ref;
+	int error;
+
+	error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
+	if (error < GIT_SUCCESS)
+		return error;
+
+	if (git_reference_type(ref) == GIT_REF_OID)
+		return 0;
+
+	error = git_reference_resolve(&ref, ref);
+
+	return error == GIT_ENOTFOUND ? 1 : error;
+}
+
 int git_repository_is_empty(git_repository *repo)
 {
 	git_reference *head, *branch;
diff --git a/tests/t12-repo.c b/tests/t12-repo.c
index 3447f2b..b67d27f 100644
--- a/tests/t12-repo.c
+++ b/tests/t12-repo.c
@@ -268,6 +268,46 @@ BEGIN_TEST(empty0, "test if a repository is empty or not")
 	git_repository_free(repo_empty);
 END_TEST
 
+BEGIN_TEST(detached0, "test if HEAD is detached")
+	git_repository *repo;
+	git_reference *ref;
+	git_oid oid;
+
+	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+
+	must_be_true(git_repository_is_detached(repo) == 0);
+
+	/* detach the HEAD */
+	git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd");
+	must_pass(git_reference_create_oid_f(&ref, repo, "HEAD", &oid));
+	must_be_true(git_repository_is_detached(repo) == 1);
+
+	/* take the reop back to it's original state */
+	must_pass(git_reference_create_symbolic_f(&ref, repo, "HEAD", "refs/heads/master"));
+	must_be_true(git_repository_is_detached(repo) == 0);
+
+	git_repository_free(repo);
+END_TEST
+
+BEGIN_TEST(orphan0, "test if HEAD is orphan")
+	git_repository *repo;
+	git_reference *ref;
+
+	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+
+	must_be_true(git_repository_is_orphan(repo) == 0);
+
+	/* orphan HEAD */
+	must_pass(git_reference_create_symbolic_f(&ref, repo, "HEAD", "refs/heads/orphan"));
+	must_be_true(git_repository_is_orphan(repo) == 1);
+
+	/* take the reop back to it's original state */
+	must_pass(git_reference_create_symbolic_f(&ref, repo, "HEAD", "refs/heads/master"));
+	must_be_true(git_repository_is_orphan(repo) == 0);
+
+	git_repository_free(repo);
+END_TEST
+
 #define DISCOVER_FOLDER TEST_RESOURCES "/discover.git"
 
 #define SUB_REPOSITORY_FOLDER_NAME "sub_repo"
@@ -416,6 +456,8 @@ BEGIN_SUITE(repository)
 	ADD_TEST(open1);
 	ADD_TEST(open2);
 	ADD_TEST(empty0);
+	ADD_TEST(detached0);
+	ADD_TEST(orphan0);
 	ADD_TEST(discover0);
 END_SUITE