diff options
-rw-r--r-- | builtin/push.c | 7 | ||||
-rw-r--r-- | builtin/send-pack.c | 3 | ||||
-rw-r--r-- | remote.c | 61 | ||||
-rw-r--r-- | remote.h | 6 | ||||
-rw-r--r-- | transport.c | 6 | ||||
-rw-r--r-- | transport.h | 4 |
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); @@ -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); +} @@ -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" |