Prevent tag_create() from creating a conflicting reference
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
diff --git a/include/git2/tag.h b/include/git2/tag.h
index ee92cd5..b83d447 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -140,7 +140,8 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *t);
* @param repo Repository where to store the tag
*
* @param tag_name Name for the tag; this name is validated
- * for consistency
+ * for consistency. It should also not conflict with an
+ * already existing tag name
*
* @param target OID to which this tag points; note that no
* validation is done on this OID. Use the _o version of this
diff --git a/src/tag.c b/src/tag.c
index 7baabab..9a00694 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -182,10 +182,18 @@ int git_tag_create(
const char *type_str;
char *tagger_str;
+ git_reference *new_ref;
+
+ char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
int type_str_len, tag_name_len, tagger_str_len, message_len;
int error;
+ /** Ensure the tag name doesn't conflict with an already existing reference **/
+ git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
+ if (!git_reference_lookup(&new_ref, repo, ref_name))
+ return GIT_EEXISTS;
+
type_str = git_object_type2string(target_type);
@@ -223,14 +231,10 @@ int git_tag_create(
error = stream->finalize_write(oid, stream);
stream->free(stream);
- if (error == GIT_SUCCESS) {
- char ref_name[512];
- git_reference *new_ref;
- git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
- error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
- }
+ if (error < GIT_SUCCESS)
+ return error;
- return error;
+ return git_reference_create_oid(&new_ref, repo, ref_name, oid);
}
diff --git a/tests/t08-tag.c b/tests/t08-tag.c
index 7b3c886..371f862 100644
--- a/tests/t08-tag.c
+++ b/tests/t08-tag.c
@@ -156,9 +156,38 @@ BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid
END_TEST
+BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already existing tag")
+ git_repository *repo;
+ git_oid target_id, tag_id;
+ const git_signature *tagger;
+
+ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+
+ git_oid_mkstr(&target_id, tagged_commit);
+
+ /* create signature */
+ tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
+ must_be_true(tagger != NULL);
+
+ must_fail(git_tag_create(
+ &tag_id, /* out id */
+ repo,
+ "very-simple",
+ &target_id,
+ GIT_OBJ_COMMIT,
+ tagger,
+ TAGGER_MESSAGE));
+
+ git_signature_free((git_signature *)tagger);
+
+ git_repository_free(repo);
+
+END_TEST
+
BEGIN_SUITE(tag)
ADD_TEST(read0);
ADD_TEST(write0);
ADD_TEST(write1);
+ ADD_TEST(write2);
END_SUITE