git_repository_set_head: use tag name in reflog When `git_repository_set_head` is provided a tag reference, update the reflog with the tag name, like we do with a branch. This helps consumers match the semantics of `git checkout tag`.
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
diff --git a/src/repository.c b/src/repository.c
index 0db4816..5d54acd 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2525,7 +2525,7 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new)
git_buf_puts(out, " to ");
- if (git_reference__is_branch(new))
+ if (git_reference__is_branch(new) || git_reference__is_tag(new))
git_buf_puts(out, git_reference__shorthand(new));
else
git_buf_puts(out, new);
@@ -2536,6 +2536,41 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new)
return 0;
}
+static int detach(git_repository *repo, const git_oid *id, const char *new)
+{
+ int error;
+ git_buf log_message = GIT_BUF_INIT;
+ git_object *object = NULL, *peeled = NULL;
+ git_reference *new_head = NULL, *current = NULL;
+
+ assert(repo && id);
+
+ if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0)
+ return error;
+
+ if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
+ goto cleanup;
+
+ if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
+ goto cleanup;
+
+ if (new == NULL)
+ new = git_oid_tostr_s(git_object_id(peeled));
+
+ if ((error = checkout_message(&log_message, current, new)) < 0)
+ goto cleanup;
+
+ error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
+
+cleanup:
+ git_buf_free(&log_message);
+ git_object_free(object);
+ git_object_free(peeled);
+ git_reference_free(current);
+ git_reference_free(new_head);
+ return error;
+}
+
int git_repository_set_head(
git_repository* repo,
const char* refname)
@@ -2567,7 +2602,8 @@ int git_repository_set_head(
error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
git_reference_name(ref), true, git_buf_cstr(&log_message));
} else {
- error = git_repository_set_head_detached(repo, git_reference_target(ref));
+ error = detach(repo, git_reference_target(ref),
+ git_reference_is_tag(ref) ? refname : NULL);
}
} else if (git_reference__is_branch(refname)) {
error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
@@ -2582,41 +2618,6 @@ cleanup:
return error;
}
-static int detach(git_repository *repo, const git_oid *id, const char *from)
-{
- int error;
- git_buf log_message = GIT_BUF_INIT;
- git_object *object = NULL, *peeled = NULL;
- git_reference *new_head = NULL, *current = NULL;
-
- assert(repo && id);
-
- if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0)
- return error;
-
- if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
- goto cleanup;
-
- if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
- goto cleanup;
-
- if (from == NULL)
- from = git_oid_tostr_s(git_object_id(peeled));
-
- if ((error = checkout_message(&log_message, current, from)) < 0)
- goto cleanup;
-
- error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
-
-cleanup:
- git_buf_free(&log_message);
- git_object_free(object);
- git_object_free(peeled);
- git_reference_free(current);
- git_reference_free(new_head);
- return error;
-}
-
int git_repository_set_head_detached(
git_repository* repo,
const git_oid* commitish)
diff --git a/tests/repo/head.c b/tests/repo/head.c
index 31c2287..ffde112 100644
--- a/tests/repo/head.c
+++ b/tests/repo/head.c
@@ -261,15 +261,17 @@ void test_repo_head__setting_head_updates_reflog(void)
cl_git_pass(git_revparse_single(&tag, repo, "tags/test"));
cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag)));
cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
+ cl_git_pass(git_repository_set_head(repo, "refs/tags/test"));
- test_reflog(repo, 2, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked");
- test_reflog(repo, 1, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d");
- test_reflog(repo, 0, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked");
+ test_reflog(repo, 3, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked");
+ test_reflog(repo, 2, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d");
+ test_reflog(repo, 1, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked");
+ test_reflog(repo, 0, "refs/heads/haacked", "tags/test^{commit}", "foo@example.com", "checkout: moving from haacked to test");
cl_git_pass(git_annotated_commit_from_revspec(&annotated, repo, "haacked~0"));
cl_git_pass(git_repository_set_head_detached_from_annotated(repo, annotated));
- test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from haacked to haacked~0");
+ test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked~0");
git_annotated_commit_free(annotated);
git_object_free(tag);