]> git.proxmox.com Git - libgit2.git/commitdiff
repository: introduce git_repository_set_head()
authornulltoken <emeric.fermas@gmail.com>
Sat, 15 Sep 2012 20:07:45 +0000 (22:07 +0200)
committernulltoken <emeric.fermas@gmail.com>
Mon, 17 Sep 2012 08:48:35 +0000 (10:48 +0200)
include/git2/repository.h
src/repository.c
tests-clar/repo/head.c

index 59a7d2c9848b06476231a54dac10c9bc9e49a111..025a0a95decbca652fc54ee8362509df20b8de23 100644 (file)
@@ -506,6 +506,28 @@ GIT_EXTERN(int) git_repository_hashfile(
     git_otype type,
     const char *as_path);
 
+/**
+ * Make the repository HEAD point to the specified reference.
+ *
+ * If the provided reference points to a Tree or a Blob, the HEAD is
+ * unaltered and -1 is returned.
+ *
+ * If the provided reference points to a branch, the HEAD will point
+ * to that branch, staying attached, or become attached if it isn't yet.
+ * If the branch doesn't exist yet, no error will be return. The HEAD
+ * will then be attached to an unborn branch.
+ *
+ * Otherwise, the HEAD will be detached and will directly point to
+ * the Commit.
+ *
+ * @param repo Repository pointer
+ * @param refname Canonical name of the reference the HEAD should point at
+ * @return 0 on success, or an error code
+ */
+GIT_EXTERN(int) git_repository_set_head(
+       git_repository* repo,
+       const char* refname);
+
 /**
  * Make the repository HEAD directly point to the Commit.
  *
index a3e781478df97714c6b62046e2fa6050a351458d..734cab43dbc298e0d68a563b7374f157e72536ff 100644 (file)
@@ -1442,6 +1442,38 @@ cleanup:
        return error;
 }
 
+static bool looks_like_a_branch(const char *refname)
+{
+       return git__prefixcmp(refname, GIT_REFS_HEADS_DIR) == 0;
+}
+
+int git_repository_set_head(
+       git_repository* repo,
+       const char* refname)
+{
+       git_reference *ref,
+               *new_head = NULL;
+       int error;
+
+       assert(repo && refname);
+
+       error = git_reference_lookup(&ref, repo, refname);
+       if (error < 0 && error != GIT_ENOTFOUND)
+               return error;
+
+       if (!error) {
+               if (git_reference_is_branch(ref))
+                       error = git_reference_create_symbolic(&new_head, repo, GIT_HEAD_FILE, git_reference_name(ref), 1);
+               else
+                       error = git_repository_set_head_detached(repo, git_reference_oid(ref));
+       } else if (looks_like_a_branch(refname))
+               error = git_reference_create_symbolic(&new_head, repo, GIT_HEAD_FILE, refname, 1);
+
+       git_reference_free(ref);
+       git_reference_free(new_head);
+       return error;
+}
+
 int git_repository_set_head_detached(
        git_repository* repo,
        const git_oid* commitish)
index 372cdd61de096fea30d8090f7bbd4d875a2951ad..64dec69dd8f86a9c5197ded5ce79a154e379ef62 100644 (file)
@@ -51,6 +51,41 @@ void test_repo_head__head_orphan(void)
        git_reference_free(ref);
 }
 
+void test_repo_head__set_head_Attaches_HEAD_to_un_unborn_branch_when_the_branch_doesnt_exist(void)
+{
+       git_reference *head;
+
+       cl_git_pass(git_repository_set_head(repo, "refs/heads/doesnt/exist/yet"));
+
+       cl_assert_equal_i(false, git_repository_head_detached(repo));
+
+       cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head(&head, repo));
+}
+
+void test_repo_head__set_head_Returns_ENOTFOUND_when_the_reference_doesnt_exist(void)
+{
+       cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head(repo, "refs/tags/doesnt/exist/yet"));
+}
+
+void test_repo_head__set_head_Fails_when_the_reference_points_to_a_non_commitish(void)
+{
+       cl_git_fail(git_repository_set_head(repo, "refs/tags/point_to_blob"));
+}
+
+void test_repo_head__set_head_Attaches_HEAD_when_the_reference_points_to_a_branch(void)
+{
+       git_reference *head;
+
+       cl_git_pass(git_repository_set_head(repo, "refs/heads/br2"));
+
+       cl_assert_equal_i(false, git_repository_head_detached(repo));
+
+       cl_git_pass(git_repository_head(&head, repo));
+       cl_assert_equal_s("refs/heads/br2", git_reference_name(head));
+
+       git_reference_free(head);
+}
+
 static void assert_head_is_correctly_detached(void)
 {
        git_reference *head;
@@ -66,6 +101,15 @@ static void assert_head_is_correctly_detached(void)
        git_reference_free(head);
 }
 
+void test_repo_head__set_head_Detaches_HEAD_when_the_reference_doesnt_point_to_a_branch(void)
+{
+       cl_git_pass(git_repository_set_head(repo, "refs/tags/test"));
+
+       cl_assert_equal_i(true, git_repository_head_detached(repo));
+
+       assert_head_is_correctly_detached();
+}
+
 void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_exist(void)
 {
        git_oid oid;