push --force-with-lease: implement logic to populate old_sha1_expect[]
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2013 18:01:06 +0000 (11:01 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 23 Jul 2013 05:18:19 +0000 (22:18 -0700)
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>
builtin/push.c
builtin/send-pack.c
remote.c
remote.h
transport.c
transport.h
index 31a5ba085d48ee1412f59704f939526e923f2aa2..2fd0a70fa807b1cb081ba8cebcf961aa5bfdfd33 100644 (file)
@@ -299,6 +299,13 @@ static int push_with_options(struct transport *transport, int flags)
        if (thin)
                transport_set_option(transport, TRANS_OPT_THIN, "yes");
 
+       if (!is_empty_cas(&cas)) {
+               if (!transport->smart_options)
+                       die("underlying transport does not support --%s option",
+                           CAS_OPT_NAME);
+               transport->smart_options->cas = &cas;
+       }
+
        if (verbosity > 0)
                fprintf(stderr, _("Pushing to %s\n"), transport->url);
        err = transport_push(transport, refspec_nr, refspec, flags,
index a23b26db17934cb4d320d7838f5883de72a14ebb..6027ead5a9f60cf1986d0ad6aeb7dca9f776c9b5 100644 (file)
@@ -242,6 +242,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
                return -1;
 
+       if (!is_empty_cas(&cas))
+               apply_push_cas(&cas, remote, remote_refs);
+
        set_ref_status_for_push(remote_refs, args.send_mirror,
                args.force_update);
 
index 0d383533d4eaabcb33a66428c21d7b8019c31223..52e3a12d6c1a9114648d3e45a8d7c565cfefc8da 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1978,3 +1978,64 @@ int parseopt_push_cas_option(const struct option *opt, const char *arg, int unse
 {
        return parse_push_cas_option(opt->value, arg, unset);
 }
+
+int is_empty_cas(const struct push_cas_option *cas)
+{
+       return !cas->use_tracking_for_rest && !cas->nr;
+}
+
+/*
+ * Look at remote.fetch refspec and see if we have a remote
+ * tracking branch for the refname there.  Fill its current
+ * value in sha1[].
+ * If we cannot do so, return negative to signal an error.
+ */
+static int remote_tracking(struct remote *remote, const char *refname,
+                          unsigned char sha1[20])
+{
+       char *dst;
+
+       dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+       if (!dst)
+               return -1; /* no tracking ref for refname at remote */
+       if (read_ref(dst, sha1))
+               return -1; /* we know what the tracking ref is but we cannot read it */
+       return 0;
+}
+
+static void apply_cas(struct push_cas_option *cas,
+                     struct remote *remote,
+                     struct ref *ref)
+{
+       int i;
+
+       /* Find an explicit --<option>=<name>[:<value>] entry */
+       for (i = 0; i < cas->nr; i++) {
+               struct push_cas *entry = &cas->entry[i];
+               if (!refname_match(entry->refname, ref->name, ref_rev_parse_rules))
+                       continue;
+               ref->expect_old_sha1 = 1;
+               if (!entry->use_tracking)
+                       hashcpy(ref->old_sha1_expect, cas->entry[i].expect);
+               else if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
+                       ref->expect_old_no_trackback = 1;
+               return;
+       }
+
+       /* Are we using "--<option>" to cover all? */
+       if (!cas->use_tracking_for_rest)
+               return;
+
+       ref->expect_old_sha1 = 1;
+       if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
+               ref->expect_old_no_trackback = 1;
+}
+
+void apply_push_cas(struct push_cas_option *cas,
+                   struct remote *remote,
+                   struct ref *remote_refs)
+{
+       struct ref *ref;
+       for (ref = remote_refs; ref; ref = ref->next)
+               apply_cas(cas, remote, ref);
+}
index 843c3cef45f5de22bd37ee3bc943e42e569522a6..ca3c8c8de8737e4eded1181c5bd88abd87edb5de 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -77,10 +77,13 @@ struct ref {
        struct ref *next;
        unsigned char old_sha1[20];
        unsigned char new_sha1[20];
+       unsigned char old_sha1_expect[20]; /* used by expect-old */
        char *symref;
        unsigned int
                force:1,
                forced_update:1,
+               expect_old_sha1:1,
+               expect_old_no_trackback:1,
                deletion:1,
                matched:1;
 
@@ -248,4 +251,7 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
 extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset);
 extern void clear_cas_option(struct push_cas_option *);
 
+extern int is_empty_cas(const struct push_cas_option *);
+void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
+
 #endif
index b84dbf086c65674ba9300bd2741f2bb7d854a9d9..5dd92b7801b4189f78112965f23ee16d49b15aad 100644 (file)
@@ -1142,6 +1142,12 @@ int transport_push(struct transport *transport,
                        return -1;
                }
 
+               if (transport->smart_options &&
+                   transport->smart_options->cas &&
+                   !is_empty_cas(transport->smart_options->cas))
+                       apply_push_cas(transport->smart_options->cas,
+                                      transport->remote, remote_refs);
+
                set_ref_status_for_push(remote_refs,
                        flags & TRANSPORT_PUSH_MIRROR,
                        flags & TRANSPORT_PUSH_FORCE);
index b551f991108c8142eda6c8cb5497d37782b6dd53..10f7556001c98c9da533c959b1e1c7b3ba8b2ca0 100644 (file)
@@ -14,6 +14,7 @@ struct git_transport_options {
        int depth;
        const char *uploadpack;
        const char *receivepack;
+       struct push_cas_option *cas;
 };
 
 struct transport {
@@ -127,6 +128,9 @@ struct transport *transport_get(struct remote *, const char *);
 /* Transfer the data as a thin pack if not null */
 #define TRANS_OPT_THIN "thin"
 
+/* Check the current value of the remote ref */
+#define TRANS_OPT_CAS "cas"
+
 /* Keep the pack that was transferred if not null */
 #define TRANS_OPT_KEEP "keep"