Commit abeefbbe18710f86077eb4c5b825255256b8b6bc

Michael Schubert 2012-12-26T19:16:23

push: properly handle tags Currently, push doesn't really handle tags when queueing objects. Fix it.

diff --git a/include/git2/refs.h b/include/git2/refs.h
index 09cf613..d586917 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -124,7 +124,7 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, 
  * not a symbolic one).
  *
  * To find the OID of a symbolic ref, call `git_reference_resolve()` and
- * then this function (or maybe use `git_reference_name_to_oid()` to
+ * then this function (or maybe use `git_reference_name_to_id()` to
  * directly resolve a reference name all the way through to an OID).
  *
  * @param ref The reference
diff --git a/src/push.c b/src/push.c
index 6e856bd..7122364 100644
--- a/src/push.c
+++ b/src/push.c
@@ -85,15 +85,15 @@ static int check_lref(git_push *push, char *ref)
 	int error = git_revparse_single(&obj, push->repo, ref);
 
 	if (error) {
-		if(error == GIT_ENOTFOUND)
-			giterr_set(GITERR_REFERENCE, "src refspec '%s' does not match any existing object", ref);
+		if (error == GIT_ENOTFOUND)
+			giterr_set(GITERR_REFERENCE,
+				"src refspec '%s' does not match any existing object", ref);
 		else
 			giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref);
 
 		return -1;
-	} else {
+	} else
 		git_object_free(obj);
-	}
 
 	return 0;
 }
@@ -138,7 +138,8 @@ static int parse_refspec(git_push *push, push_spec **spec, const char *str)
 	/* If rref is ommitted, use the same ref name as lref */
 	if (!s->rref) {
 		s->rref = git__strdup(s->lref);
-		check(s->rref);
+		if (!s->rref || check_rref(s->rref) < 0)
+			goto on_error;
 	}
 
 	*spec = s;
@@ -175,6 +176,9 @@ static int revwalk(git_vector *commits, git_push *push)
 	git_revwalk_sorting(rw, GIT_SORT_TIME);
 
 	git_vector_foreach(&push->specs, i, spec) {
+		git_otype type;
+		size_t size;
+
 		if (git_oid_iszero(&spec->loid))
 			/*
 			 * Delete reference on remote side;
@@ -185,7 +189,39 @@ static int revwalk(git_vector *commits, git_push *push)
 		if (git_oid_equal(&spec->loid, &spec->roid))
 			continue; /* up-to-date */
 
-		if (git_revwalk_push(rw, &spec->loid) < 0)
+		if (git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid) < 0)
+			goto on_error;
+
+		if (type == GIT_OBJ_TAG) {
+			git_tag *tag;
+			git_object *target;
+
+			if (git_packbuilder_insert(push->pb, &spec->loid, NULL) < 0)
+				goto on_error;
+
+			if (git_tag_lookup(&tag, push->repo, &spec->loid) < 0)
+				goto on_error;
+
+			if (git_tag_peel(&target, tag) < 0) {
+				git_tag_free(tag);
+				goto on_error;
+			}
+			git_tag_free(tag);
+
+			if (git_object_type(target) == GIT_OBJ_COMMIT) {
+				if (git_revwalk_push(rw, git_object_id(target)) < 0) {
+					git_object_free(target);
+					goto on_error;
+				}
+			} else {
+				if (git_packbuilder_insert(
+					push->pb, git_object_id(target), NULL) < 0) {
+					git_object_free(target);
+					goto on_error;
+				}
+			}
+			git_object_free(target);
+		} else if (git_revwalk_push(rw, &spec->loid) < 0)
 			goto on_error;
 
 		if (!spec->force) {
diff --git a/tests-clar/online/push.c b/tests-clar/online/push.c
index c06d94c..15351ae 100644
--- a/tests-clar/online/push.c
+++ b/tests-clar/online/push.c
@@ -22,6 +22,11 @@ static git_oid _oid_b3;
 static git_oid _oid_b2;
 static git_oid _oid_b1;
 
+static git_oid _tag_commit;
+static git_oid _tag_tree;
+static git_oid _tag_blob;
+static git_oid _tag_lightweight;
+
 static int cred_acquire_cb(git_cred **cred, const char *url, unsigned int allowed_types, void *payload)
 {
 	GIT_UNUSED(url);
@@ -154,6 +159,11 @@ void test_online_push__initialize(void)
 	git_oid_fromstr(&_oid_b2, "a78705c3b2725f931d3ee05348d83cc26700f247");
 	git_oid_fromstr(&_oid_b1, "a78705c3b2725f931d3ee05348d83cc26700f247");
 
+	git_oid_fromstr(&_tag_commit, "805c54522e614f29f70d2413a0470247d8b424ac");
+	git_oid_fromstr(&_tag_tree, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e");
+	git_oid_fromstr(&_tag_blob, "b483ae7ba66decee9aee971f501221dea84b1498");
+	git_oid_fromstr(&_tag_lightweight, "951bbbb90e2259a4c8950db78946784fb53fcbce");
+
 	/* Remote URL environment variable must be set.  User and password are optional.  */
 	_remote_url = cl_getenv("GITTEST_REMOTE_URL");
 	_remote_user = cl_getenv("GITTEST_REMOTE_USER");
@@ -404,6 +414,46 @@ void test_online_push__fast_fwd(void)
 		exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0);
 }
 
+void test_online_push__tag_commit(void)
+{
+	const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" };
+	push_status exp_stats[] = { { "refs/tags/tag-commit", NULL } };
+	expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } };
+	do_push(specs, ARRAY_SIZE(specs),
+		exp_stats, ARRAY_SIZE(exp_stats),
+		exp_refs, ARRAY_SIZE(exp_refs), 0);
+}
+
+void test_online_push__tag_tree(void)
+{
+	const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" };
+	push_status exp_stats[] = { { "refs/tags/tag-tree", NULL } };
+	expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } };
+	do_push(specs, ARRAY_SIZE(specs),
+		exp_stats, ARRAY_SIZE(exp_stats),
+		exp_refs, ARRAY_SIZE(exp_refs), 0);
+}
+
+void test_online_push__tag_blob(void)
+{
+	const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" };
+	push_status exp_stats[] = { { "refs/tags/tag-blob", NULL } };
+	expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } };
+	do_push(specs, ARRAY_SIZE(specs),
+		exp_stats, ARRAY_SIZE(exp_stats),
+		exp_refs, ARRAY_SIZE(exp_refs), 0);
+}
+
+void test_online_push__tag_lightweight(void)
+{
+	const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" };
+	push_status exp_stats[] = { { "refs/tags/tag-lightweight", NULL } };
+	expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } };
+	do_push(specs, ARRAY_SIZE(specs),
+		exp_stats, ARRAY_SIZE(exp_stats),
+		exp_refs, ARRAY_SIZE(exp_refs), 0);
+}
+
 void test_online_push__force(void)
 {
 	const char *specs1[] = {"refs/heads/b3:refs/heads/tgt"};
@@ -523,7 +573,7 @@ void test_online_push__expressions(void)
 		NULL, 0, 0);
 }
 
-void test_network_push__notes(void)
+void test_online_push__notes(void)
 {
 	git_oid note_oid, *target_oid, expected_oid;
 	git_signature *signature;
@@ -536,7 +586,7 @@ void test_network_push__notes(void)
 
 	/* Create note to push */
 	cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
-	cl_git_pass(git_note_create(&note_oid, _repo, signature, signature, NULL, target_oid, "hello world\n"));
+	cl_git_pass(git_note_create(&note_oid, _repo, signature, signature, NULL, target_oid, "hello world\n", 0));
 
 	do_push(specs, ARRAY_SIZE(specs),
 		exp_stats, ARRAY_SIZE(exp_stats),
diff --git a/tests-clar/resources/push_src/.gitted/objects/80/5c54522e614f29f70d2413a0470247d8b424ac b/tests-clar/resources/push_src/.gitted/objects/80/5c54522e614f29f70d2413a0470247d8b424ac
new file mode 100644
index 0000000..552670c
Binary files /dev/null and b/tests-clar/resources/push_src/.gitted/objects/80/5c54522e614f29f70d2413a0470247d8b424ac differ
diff --git a/tests-clar/resources/push_src/.gitted/objects/b4/83ae7ba66decee9aee971f501221dea84b1498 b/tests-clar/resources/push_src/.gitted/objects/b4/83ae7ba66decee9aee971f501221dea84b1498
new file mode 100644
index 0000000..1e0bd3b
--- /dev/null
+++ b/tests-clar/resources/push_src/.gitted/objects/b4/83ae7ba66decee9aee971f501221dea84b1498
@@ -0,0 +1,3 @@
+x5K
+1D];1i"^'|d`dooqQEͫ*Pݢ+
+	3$,
}%Rw+s9y輨r`+ܦ2p/[mp~u8-Sr=,?Z+g
\ No newline at end of file
diff --git a/tests-clar/resources/push_src/.gitted/objects/ff/83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e b/tests-clar/resources/push_src/.gitted/objects/ff/83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e
new file mode 100644
index 0000000..10f25eb
--- /dev/null
+++ b/tests-clar/resources/push_src/.gitted/objects/ff/83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e
@@ -0,0 +1,4 @@
+x5M
+1`=E4NAHooq{/G@5=$+SO)nx[@4y
+h1ڄvmSyz'
+Wk-ziQc<ޢfS~pv+
\ No newline at end of file
diff --git a/tests-clar/resources/push_src/.gitted/refs/tags/tag-blob b/tests-clar/resources/push_src/.gitted/refs/tags/tag-blob
new file mode 100644
index 0000000..abfebf2
--- /dev/null
+++ b/tests-clar/resources/push_src/.gitted/refs/tags/tag-blob
@@ -0,0 +1 @@
+b483ae7ba66decee9aee971f501221dea84b1498
diff --git a/tests-clar/resources/push_src/.gitted/refs/tags/tag-commit b/tests-clar/resources/push_src/.gitted/refs/tags/tag-commit
new file mode 100644
index 0000000..c023b84
--- /dev/null
+++ b/tests-clar/resources/push_src/.gitted/refs/tags/tag-commit
@@ -0,0 +1 @@
+805c54522e614f29f70d2413a0470247d8b424ac
diff --git a/tests-clar/resources/push_src/.gitted/refs/tags/tag-lightweight b/tests-clar/resources/push_src/.gitted/refs/tags/tag-lightweight
new file mode 100644
index 0000000..711e466
--- /dev/null
+++ b/tests-clar/resources/push_src/.gitted/refs/tags/tag-lightweight
@@ -0,0 +1 @@
+951bbbb90e2259a4c8950db78946784fb53fcbce
diff --git a/tests-clar/resources/push_src/.gitted/refs/tags/tag-tree b/tests-clar/resources/push_src/.gitted/refs/tags/tag-tree
new file mode 100644
index 0000000..7a530d3
--- /dev/null
+++ b/tests-clar/resources/push_src/.gitted/refs/tags/tag-tree
@@ -0,0 +1 @@
+ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e