Commit 087f64d3e3ea224dadb9b4ae1130b9499f49cff9

Jameson Miller 2012-12-17T18:48:26

Relax refspecs accepted by push

diff --git a/include/git2/refs.h b/include/git2/refs.h
index a0abbc3..09cf613 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -44,7 +44,7 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, 
  * allocate or free any `git_reference` objects for simple situations.
  *
  * The name will be checked for validity.
- * See `git_reference_create_symbolic()` for rules about valid names.
+ * See `git_reference_symbolic_create()` for rules about valid names.
  *
  * @param out Pointer to oid to be filled in
  * @param repo The repository in which to look up the reference
diff --git a/src/push.c b/src/push.c
index 634634d..6e856bd 100644
--- a/src/push.c
+++ b/src/push.c
@@ -68,18 +68,37 @@ static void free_status(push_status *status)
 	git__free(status);
 }
 
-static int check_ref(char *ref)
+static int check_rref(char *ref)
 {
-	if (strcmp(ref, "HEAD") &&
-	    git__prefixcmp(ref, "refs/heads/") &&
-	    git__prefixcmp(ref, "refs/tags/")) {
-		giterr_set(GITERR_INVALID, "No valid reference '%s'", ref);
+	if (git__prefixcmp(ref, "refs/")) {
+		giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref);
 		return -1;
 	}
+
 	return 0;
 }
 
-static int parse_refspec(push_spec **spec, const char *str)
+static int check_lref(git_push *push, char *ref)
+{
+	/* lref must be resolvable to an existing object */
+	git_object *obj;
+	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);
+		else
+			giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref);
+
+		return -1;
+	} else {
+		git_object_free(obj);
+	}
+
+	return 0;
+}
+
+static int parse_refspec(git_push *push, push_spec **spec, const char *str)
 {
 	push_spec *s;
 	char *delim;
@@ -94,22 +113,22 @@ static int parse_refspec(push_spec **spec, const char *str)
 		str++;
 	}
 
-#define check(ref) \
-	if (!ref || check_ref(ref) < 0) goto on_error
-
 	delim = strchr(str, ':');
 	if (delim == NULL) {
 		s->lref = git__strdup(str);
-		check(s->lref);
+		if (!s->lref || check_lref(push, s->lref) < 0)
+			goto on_error;
 	} else {
 		if (delim - str) {
 			s->lref = git__strndup(str, delim - str);
-			check(s->lref);
+			if (!s->lref || check_lref(push, s->lref) < 0)
+				goto on_error;
 		}
 
 		if (strlen(delim + 1)) {
 			s->rref = git__strdup(delim + 1);
-			check(s->rref);
+			if (!s->rref || check_rref(s->rref) < 0)
+				goto on_error;
 		}
 	}
 
@@ -122,8 +141,6 @@ static int parse_refspec(push_spec **spec, const char *str)
 		check(s->rref);
 	}
 
-#undef check
-
 	*spec = s;
 	return 0;
 
@@ -136,7 +153,7 @@ int git_push_add_refspec(git_push *push, const char *refspec)
 {
 	push_spec *spec;
 
-	if (parse_refspec(&spec, refspec) < 0 ||
+	if (parse_refspec(push, &spec, refspec) < 0 ||
 	    git_vector_insert(&push->specs, spec) < 0)
 		return -1;
 
diff --git a/tests-clar/online/push.c b/tests-clar/online/push.c
index 9d949b7..0fc5779 100644
--- a/tests-clar/online/push.c
+++ b/tests-clar/online/push.c
@@ -525,3 +525,25 @@ void test_online_push__expressions(void)
 		exp_stats_right_expr, ARRAY_SIZE(exp_stats_right_expr),
 		NULL, 0, 0);
 }
+
+void test_network_push__notes(void)
+{
+	git_oid note_oid, *target_oid, expected_oid;
+	git_signature *signature;
+	const char *specs[] = { "refs/notes/commits:refs/notes/commits" };
+	push_status exp_stats[] = { { "refs/notes/commits", NULL } };
+	expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } };
+	git_oid_fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
+
+	target_oid = &_oid_b6;
+
+	/* 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"));
+
+	do_push(specs, ARRAY_SIZE(specs),
+		exp_stats, ARRAY_SIZE(exp_stats),
+		exp_refs, ARRAY_SIZE(exp_refs), 0);
+
+	git_signature_free(signature);
+}