const git_signature *tagger,
const char *message);
+/**
+* Create a new tag in the repository from an OID
+* and overwrite an already existing tag reference, if any.
+*
+* @param oid Pointer where to store the OID of the
+* newly created tag
+*
+* @param repo Repository where to store the tag
+*
+* @param tag_name Name for the tag; this name is validated
+* for consistency.
+*
+* @param target OID to which this tag points; note that no
+* validation is done on this OID. Use the _o_f version of this
+* method to assure a proper object is being tagged
+*
+* @param target_type Type of the tagged OID; note that no
+* validation is performed here either
+*
+* @param tagger Signature of the tagger for this tag, and
+* of the tagging time
+*
+* @param message Full message for this tag
+*
+* @return 0 on success; error code otherwise.
+* A tag object is written to the ODB, and a proper reference
+* is written in the /refs/tags folder, pointing to it
+*/
+GIT_EXTERN(int) git_tag_create_f(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message);
+
+/**
+ * Create a new tag in the repository from an existing
+ * `git_object` instance and overwrite an already existing
+ * tag reference, if any.
+ *
+ * This method replaces the `target` and `target_type`
+ * paremeters of `git_tag_create_f` by a single instance
+ * of a `const git_object *`, which is assured to be
+ * a proper object in the ODB and hence will create
+ * a valid tag
+ *
+ * @see git_tag_create_f
+ */
+GIT_EXTERN(int) git_tag_create_o_f(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message);
+
/** @} */
GIT_END_DECL
#endif
return GIT_SUCCESS;
}
-int git_tag_create_o(
- git_oid *oid,
- git_repository *repo,
- const char *tag_name,
- const git_object *target,
- const git_signature *tagger,
- const char *message)
-{
- return git_tag_create(
- oid, repo, tag_name,
- git_object_id(target),
- git_object_type(target),
- tagger, message);
-}
-
-int git_tag_create(
+static int tag_create(
git_oid *oid,
git_repository *repo,
const char *tag_name,
const git_oid *target,
git_otype target_type,
const git_signature *tagger,
- const char *message)
+ const char *message,
+ int allow_ref_overwrite)
{
size_t final_size = 0;
git_odb_stream *stream;
char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
int type_str_len, tag_name_len, tagger_str_len, message_len;
- int error;
+ int error, should_update_ref = 0;
- /** Ensure the tag name doesn't conflict with an already existing reference **/
+ /** Ensure the tag name doesn't conflict with an already existing
+ reference unless overwriting has explictly been requested **/
git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
- if (!git_reference_lookup(&new_ref, repo, ref_name))
- return GIT_EEXISTS;
+ error = git_reference_lookup(&new_ref, repo, ref_name);
+
+ switch (error) {
+ case GIT_SUCCESS:
+ if (!allow_ref_overwrite)
+ return GIT_EEXISTS;
+ should_update_ref = 1;
+
+ /* Fall trough */
+
+ case GIT_ENOTFOUND:
+ break;
+
+ default:
+ return error;
+ }
type_str = git_object_type2string(target_type);
if (error < GIT_SUCCESS)
return error;
- return git_reference_create_oid(&new_ref, repo, ref_name, oid);
+ if (!should_update_ref)
+ error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
+ else
+ error = git_reference_set_oid(new_ref, oid);
+
+ return error;
+}
+
+int git_tag_create_o(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ git_object_id(target),
+ git_object_type(target),
+ tagger, message, 0);
+}
+
+int git_tag_create(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ target,
+ target_type,
+ tagger, message, 0);
+}
+
+int git_tag_create_o_f(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ git_object_id(target),
+ git_object_type(target),
+ tagger, message, 1);
}
+int git_tag_create_f(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ target,
+ target_type,
+ tagger, message, 1);
+}
int git_tag__parse(git_tag *tag, git_odb_object *obj)
{
END_TEST
+BEGIN_TEST(write3, "Replace an already existing tag")
+ git_repository *repo;
+ git_oid target_id, tag_id, old_tag_id;
+ const git_signature *tagger;
+ git_reference *ref_tag;
+
+ must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
+
+ git_oid_mkstr(&target_id, tagged_commit);
+
+ must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/very-simple"));
+ git_oid_cpy(&old_tag_id, git_reference_oid(ref_tag));
+
+ /* create signature */
+ tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
+ must_be_true(tagger != NULL);
+
+ must_pass(git_tag_create_f(
+ &tag_id, /* out id */
+ repo,
+ "very-simple",
+ &target_id,
+ GIT_OBJ_COMMIT,
+ tagger,
+ TAGGER_MESSAGE));
+
+ git_signature_free((git_signature *)tagger);
+
+ must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/very-simple"));
+ must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0);
+ must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &old_tag_id) != 0);
+
+ close_temp_repo(repo);
+
+END_TEST
BEGIN_SUITE(tag)
ADD_TEST(read0);
ADD_TEST(write0);
ADD_TEST(write1);
ADD_TEST(write2);
+ ADD_TEST(write3);
END_SUITE