push --force-with-lease: tie it all together
This teaches the deepest part of the callchain for "git push" (and "git send-pack") to enforce "the old value of the ref must be this, otherwise fail this push" (aka "compare-and-swap" / "--lockref"). Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Jul 8, 2013 at 14:42 UTC
631b5ef219c41027c144218e25075062b91f9471
6 files changed
+54
-13
builtin/send-pack.c
+5
@@ -55,6 +55,11 @@ static void print_helper_status(struct ref *ref)
55
msg = "needs force";
56
break;
57
58
+ case REF_STATUS_REJECT_STALE:
59
+ res = "error";
60
+ msg = "stale info";
61
+ break;
62
+
63
case REF_STATUS_REJECT_ALREADY_EXISTS:
64
res = "error";
65
msg = "already exists";
remote.c
+36
-13
@@ -1396,12 +1396,13 @@ int match_push_refs(struct ref *src, struct ref **dst,
1396
}
1397
1398
void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
1399
- int force_update)
1399
+ int force_update)
1400
{
1401
struct ref *ref;
1402
1403
for (ref = remote_refs; ref; ref = ref->next) {
1404
int force_ref_update = ref->force || force_update;
1405
+ int reject_reason = 0;
1406
1407
if (ref->peer_ref)
1408
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
@@ -1416,6 +1417,26 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
1417
}
1418
1419
/*
1420
+ * Bypass the usual "must fast-forward" check but
1421
+ * replace it with a weaker "the old value must be
1422
+ * this value we observed". If the remote ref has
1423
+ * moved and is now different from what we expect,
1424
+ * reject any push.
1425
+ *
1426
+ * It also is an error if the user told us to check
1427
+ * with the remote-tracking branch to find the value
1428
+ * to expect, but we did not have such a tracking
1429
+ * branch.
1430
+ */
1431
+ if (ref->expect_old_sha1) {
1432
+ if (ref->expect_old_no_trackback ||
1433
+ hashcmp(ref->old_sha1, ref->old_sha1_expect))
1434
+ reject_reason = REF_STATUS_REJECT_STALE;
1435
+ }
1436
+
1437
+ /*
1438
+ * The usual "must fast-forward" rules.
1439
+ *
1440
* Decide whether an individual refspec A:B can be
1441
* pushed. The push will succeed if any of the
1442
* following are true:
@@ -1433,24 +1454,26 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
1454
* passing the --force argument
1455
*/
1456
1436
- if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
1437
- int why = 0; /* why would this push require --force? */
1438
-
1457
+ else if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
1458
if (!prefixcmp(ref->name, "refs/tags/"))
1440
- why = REF_STATUS_REJECT_ALREADY_EXISTS;
1459
+ reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
1460
else if (!has_sha1_file(ref->old_sha1))
1442
- why = REF_STATUS_REJECT_FETCH_FIRST;
1461
+ reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
1462
else if (!lookup_commit_reference_gently(ref->old_sha1, 1) ||
1463
!lookup_commit_reference_gently(ref->new_sha1, 1))
1445
- why = REF_STATUS_REJECT_NEEDS_FORCE;
1464
+ reject_reason = REF_STATUS_REJECT_NEEDS_FORCE;
1465
else if (!ref_newer(ref->new_sha1, ref->old_sha1))
1447
- why = REF_STATUS_REJECT_NONFASTFORWARD;
1448
-
1449
- if (!force_ref_update)
1450
- ref->status = why;
1451
- else if (why)
1452
- ref->forced_update = 1;
1466
+ reject_reason = REF_STATUS_REJECT_NONFASTFORWARD;
1467
}
1468
+
1469
+ /*
1470
+ * "--force" will defeat any rejection implemented
1471
+ * by the rules above.
1472
+ */
1473
+ if (!force_ref_update)
1474
+ ref->status = reject_reason;
1475
+ else if (reject_reason)
1476
+ ref->forced_update = 1;
1477
}
1478
}
1479
remote.h
+1
@@ -107,6 +107,7 @@ struct ref {
107
REF_STATUS_REJECT_NODELETE,
108
REF_STATUS_REJECT_FETCH_FIRST,
109
REF_STATUS_REJECT_NEEDS_FORCE,
110
+ REF_STATUS_REJECT_STALE,
111
REF_STATUS_UPTODATE,
112
REF_STATUS_REMOTE_REJECT,
113
REF_STATUS_EXPECTING_REPORT
send-pack.c
+1
@@ -227,6 +227,7 @@ int send_pack(struct send_pack_args *args,
227
case REF_STATUS_REJECT_ALREADY_EXISTS:
228
case REF_STATUS_REJECT_FETCH_FIRST:
229
case REF_STATUS_REJECT_NEEDS_FORCE:
230
+ case REF_STATUS_REJECT_STALE:
231
case REF_STATUS_UPTODATE:
232
continue;
233
default:
transport-helper.c
+6
@@ -683,6 +683,11 @@ static int push_update_ref_status(struct strbuf *buf,
683
free(msg);
684
msg = NULL;
685
}
686
+ else if (!strcmp(msg, "stale info")) {
687
+ status = REF_STATUS_REJECT_STALE;
688
+ free(msg);
689
+ msg = NULL;
690
+ }
691
}
692
693
if (*ref)
@@ -756,6 +761,7 @@ static int push_refs_with_push(struct transport *transport,
761
/* Check for statuses set by set_ref_status_for_push() */
762
switch (ref->status) {
763
case REF_STATUS_REJECT_NONFASTFORWARD:
764
+ case REF_STATUS_REJECT_STALE:
765
case REF_STATUS_REJECT_ALREADY_EXISTS:
766
case REF_STATUS_UPTODATE:
767
continue;
transport.c
+5
@@ -709,6 +709,10 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
709
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
710
"needs force", porcelain);
711
break;
712
+ case REF_STATUS_REJECT_STALE:
713
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
714
+ "stale info", porcelain);
715
+ break;
716
case REF_STATUS_REMOTE_REJECT:
717
print_ref_status('!', "[remote rejected]", ref,
718
ref->deletion ? NULL : ref->peer_ref,
@@ -1078,6 +1082,7 @@ static int run_pre_push_hook(struct transport *transport,
1082
for (r = remote_refs; r; r = r->next) {
1083
if (!r->peer_ref) continue;
1084
if (r->status == REF_STATUS_REJECT_NONFASTFORWARD) continue;
1085
+ if (r->status == REF_STATUS_REJECT_STALE) continue;
1086
if (r->status == REF_STATUS_UPTODATE) continue;
1087
1088
strbuf_reset(&buf);