Resolve value supplied for no-colon push refspecs
When pushing a refspec like "HEAD", we used to treat it as "HEAD:HEAD", which didn't work without rewriting. Instead, we should resolve the ref. If it's a symref, further require it to point to a branch, to avoid doing anything especially unexpected. Also remove the rewriting previously added in builtin-push. Since the code for "HEAD" uses the regular refspec parsing, it automatically handles "+HEAD" without anything special. [jc: added a further test to make sure that "remote.*.push = HEAD" works] Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Daniel Barkalow committed
Feb 20, 2008 at 12:54 UTC
9f0ea7e8283da126c8e1d5e0c3b39c39200258ad
3 files changed
+52
-10
builtin-push.c
-9
@@ -44,15 +44,6 @@ static void set_refspecs(const char **refs, int nr)
44
strcat(tag, refs[i]);
45
ref = tag;
46
}
47
- if (!strcmp("HEAD", ref)) {
48
- unsigned char sha1_dummy[20];
49
- ref = resolve_ref(ref, sha1_dummy, 1, NULL);
50
- if (!ref)
51
- die("HEAD cannot be resolved.");
52
- if (prefixcmp(ref, "refs/heads/"))
53
- die("HEAD cannot be resolved to branch.");
54
- ref = xstrdup(ref + 11);
55
- }
47
add_refspec(ref);
48
}
49
}
remote.c
+9
-1
@@ -643,9 +643,17 @@ static int match_explicit(struct ref *src, struct ref *dst,
643
errs = 1;
644
645
if (!dst_value) {
646
+ unsigned char sha1[20];
647
+ int flag;
648
+
649
if (!matched_src)
650
return errs;
648
- dst_value = matched_src->name;
651
+ dst_value = resolve_ref(matched_src->name, sha1, 1, &flag);
652
+ if (!dst_value ||
653
+ ((flag & REF_ISSYMREF) &&
654
+ prefixcmp(dst_value, "refs/heads/")))
655
+ die("%s cannot be resolved to branch.",
656
+ matched_src->name);
657
}
658
659
switch (count_refspec_match(dst_value, dst, &matched_dst)) {
t/t5516-fetch-push.sh
+43
@@ -271,6 +271,49 @@ test_expect_success 'push with HEAD nonexisting at remote' '
271
check_push_result $the_commit heads/local
272
'
273
274
+test_expect_success 'push with +HEAD' '
275
+
276
+ mk_test heads/master &&
277
+ git checkout master &&
278
+ git branch -D local &&
279
+ git checkout -b local &&
280
+ git push testrepo master local &&
281
+ check_push_result $the_commit heads/master &&
282
+ check_push_result $the_commit heads/local &&
283
+
284
+ # Without force rewinding should fail
285
+ git reset --hard HEAD^ &&
286
+ ! git push testrepo HEAD &&
287
+ check_push_result $the_commit heads/local &&
288
+
289
+ # With force rewinding should succeed
290
+ git push testrepo +HEAD &&
291
+ check_push_result $the_first_commit heads/local
292
+
293
+'
294
+
295
+test_expect_success 'push with config remote.*.push = HEAD' '
296
+
297
+ mk_test heads/local &&
298
+ git checkout master &&
299
+ git branch -f local $the_commit &&
300
+ (
301
+ cd testrepo &&
302
+ git checkout local &&
303
+ git reset --hard $the_first_commit
304
+ ) &&
305
+ git config remote.there.url testrepo &&
306
+ git config remote.there.push HEAD &&
307
+ git config branch.master.remote there &&
308
+ git push &&
309
+ check_push_result $the_commit heads/master &&
310
+ check_push_result $the_first_commit heads/local
311
+'
312
+
313
+# clean up the cruft left with the previous one
314
+git config --remove-section remote.there
315
+git config --remove-section branch.master
316
+
317
test_expect_success 'push with dry-run' '
318
319
mk_test heads/master &&