summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/push.c7
-rw-r--r--builtin/send-pack.c3
-rw-r--r--remote.c61
-rw-r--r--remote.h6
-rw-r--r--transport.c6
-rw-r--r--transport.h4
6 files changed, 87 insertions, 0 deletions
diff --git a/builtin/push.c b/builtin/push.c
index 31a5ba085d..2fd0a70fa8 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -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,
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index a23b26db17..6027ead5a9 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -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);
diff --git a/remote.c b/remote.c
index 0d383533d4..52e3a12d6c 100644
--- 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);
+}
diff --git a/remote.h b/remote.h
index 843c3cef45..ca3c8c8de8 100644
--- 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
diff --git a/transport.c b/transport.c
index b84dbf086c..5dd92b7801 100644
--- a/transport.c
+++ b/transport.c
@@ -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);
diff --git a/transport.h b/transport.h
index b551f99110..10f7556001 100644
--- a/transport.h
+++ b/transport.h
@@ -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"