push --force-with-lease: implement logic to populate old_sha1_expect[]

This plugs the push_cas_option data collected by the command line option parser to the transport system with a new function apply_push_cas(), which is called after match_push_refs() has already been called. At this point, we know which remote we are talking to, and what remote refs we are going to update, so we can fill in the details that may have been missing from the command line, such as (1) what abbreviated refname the user gave us matches the actual refname at the remote; and (2) which remote-tracking branch in our local repository to read the value of the object to expect at the remote. to populate the old_sha1_expect[] field of each of the remote ref. As stated in the documentation, the use of remote-tracking branch as the default is a tentative one, and we may come up with a better logic as we gain experience. Still nobody uses this information, which is the topic of the next patch. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jul 9, 2013 at 11:01 UTC 91048a9537a4716c84934e4f8ed114a20606d3ff
6 files changed +87
builtin/push.c
+7
@@ -299,6 +299,13 @@ static int push_with_options(struct transport *transport, int flags)
299 if (thin)
300 transport_set_option(transport, TRANS_OPT_THIN, "yes");
301
302 + if (!is_empty_cas(&cas)) {
303 + if (!transport->smart_options)
304 + die("underlying transport does not support --%s option",
305 + CAS_OPT_NAME);
306 + transport->smart_options->cas = &cas;
307 + }
308 +
309 if (verbosity > 0)
310 fprintf(stderr, _("Pushing to %s\n"), transport->url);
311 err = transport_push(transport, refspec_nr, refspec, flags,
builtin/send-pack.c
+3
@@ -242,6 +242,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
242 if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
243 return -1;
244
245 + if (!is_empty_cas(&cas))
246 + apply_push_cas(&cas, remote, remote_refs);
247 +
248 set_ref_status_for_push(remote_refs, args.send_mirror,
249 args.force_update);
250
remote.c
+61
@@ -1978,3 +1978,64 @@ int parseopt_push_cas_option(const struct option *opt, const char *arg, int unse
1978 {
1979 return parse_push_cas_option(opt->value, arg, unset);
1980 }
1981 +
1982 +int is_empty_cas(const struct push_cas_option *cas)
1983 +{
1984 + return !cas->use_tracking_for_rest && !cas->nr;
1985 +}
1986 +
1987 +/*
1988 + * Look at remote.fetch refspec and see if we have a remote
1989 + * tracking branch for the refname there. Fill its current
1990 + * value in sha1[].
1991 + * If we cannot do so, return negative to signal an error.
1992 + */
1993 +static int remote_tracking(struct remote *remote, const char *refname,
1994 + unsigned char sha1[20])
1995 +{
1996 + char *dst;
1997 +
1998 + dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
1999 + if (!dst)
2000 + return -1; /* no tracking ref for refname at remote */
2001 + if (read_ref(dst, sha1))
2002 + return -1; /* we know what the tracking ref is but we cannot read it */
2003 + return 0;
2004 +}
2005 +
2006 +static void apply_cas(struct push_cas_option *cas,
2007 + struct remote *remote,
2008 + struct ref *ref)
2009 +{
2010 + int i;
2011 +
2012 + /* Find an explicit --<option>=<name>[:<value>] entry */
2013 + for (i = 0; i < cas->nr; i++) {
2014 + struct push_cas *entry = &cas->entry[i];
2015 + if (!refname_match(entry->refname, ref->name, ref_rev_parse_rules))
2016 + continue;
2017 + ref->expect_old_sha1 = 1;
2018 + if (!entry->use_tracking)
2019 + hashcpy(ref->old_sha1_expect, cas->entry[i].expect);
2020 + else if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
2021 + ref->expect_old_no_trackback = 1;
2022 + return;
2023 + }
2024 +
2025 + /* Are we using "--<option>" to cover all? */
2026 + if (!cas->use_tracking_for_rest)
2027 + return;
2028 +
2029 + ref->expect_old_sha1 = 1;
2030 + if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
2031 + ref->expect_old_no_trackback = 1;
2032 +}
2033 +
2034 +void apply_push_cas(struct push_cas_option *cas,
2035 + struct remote *remote,
2036 + struct ref *remote_refs)
2037 +{
2038 + struct ref *ref;
2039 + for (ref = remote_refs; ref; ref = ref->next)
2040 + apply_cas(cas, remote, ref);
2041 +}
remote.h
+6
@@ -77,10 +77,13 @@ struct ref {
77 struct ref *next;
78 unsigned char old_sha1[20];
79 unsigned char new_sha1[20];
80 + unsigned char old_sha1_expect[20]; /* used by expect-old */
81 char *symref;
82 unsigned int
83 force:1,
84 forced_update:1,
85 + expect_old_sha1:1,
86 + expect_old_no_trackback:1,
87 deletion:1,
88 matched:1;
89
@@ -248,4 +251,7 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
251 extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset);
252 extern void clear_cas_option(struct push_cas_option *);
253
254 +extern int is_empty_cas(const struct push_cas_option *);
255 +void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
256 +
257 #endif
transport.c
+6
@@ -1142,6 +1142,12 @@ int transport_push(struct transport *transport,
1142 return -1;
1143 }
1144
1145 + if (transport->smart_options &&
1146 + transport->smart_options->cas &&
1147 + !is_empty_cas(transport->smart_options->cas))
1148 + apply_push_cas(transport->smart_options->cas,
1149 + transport->remote, remote_refs);
1150 +
1151 set_ref_status_for_push(remote_refs,
1152 flags & TRANSPORT_PUSH_MIRROR,
1153 flags & TRANSPORT_PUSH_FORCE);
transport.h
+4
@@ -14,6 +14,7 @@ struct git_transport_options {
14 int depth;
15 const char *uploadpack;
16 const char *receivepack;
17 + struct push_cas_option *cas;
18 };
19
20 struct transport {
@@ -127,6 +128,9 @@ struct transport *transport_get(struct remote *, const char *);
128 /* Transfer the data as a thin pack if not null */
129 #define TRANS_OPT_THIN "thin"
130
131 +/* Check the current value of the remote ref */
132 +#define TRANS_OPT_CAS "cas"
133 +
134 /* Keep the pack that was transferred if not null */
135 #define TRANS_OPT_KEEP "keep"
136