summaryrefslogtreecommitdiffstats
path: root/transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'transport.c')
-rw-r--r--transport.c85
1 files changed, 75 insertions, 10 deletions
diff --git a/transport.c b/transport.c
index c3f156ea04..08e4fa0354 100644
--- a/transport.c
+++ b/transport.c
@@ -8,6 +8,7 @@
#include "bundle.h"
#include "dir.h"
#include "refs.h"
+#include "branch.h"
/* rsync support */
@@ -135,6 +136,53 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
}
}
+static void set_upstreams(struct transport *transport, struct ref *refs,
+ int pretend)
+{
+ struct ref *ref;
+ for (ref = refs; ref; ref = ref->next) {
+ const char *localname;
+ const char *tmp;
+ const char *remotename;
+ unsigned char sha[20];
+ int flag = 0;
+ /*
+ * Check suitability for tracking. Must be successful /
+ * already up-to-date ref create/modify (not delete).
+ */
+ if (ref->status != REF_STATUS_OK &&
+ ref->status != REF_STATUS_UPTODATE)
+ continue;
+ if (!ref->peer_ref)
+ continue;
+ if (!ref->new_sha1 || is_null_sha1(ref->new_sha1))
+ continue;
+
+ /* Follow symbolic refs (mainly for HEAD). */
+ localname = ref->peer_ref->name;
+ remotename = ref->name;
+ tmp = resolve_ref(localname, sha, 1, &flag);
+ if (tmp && flag & REF_ISSYMREF &&
+ !prefixcmp(tmp, "refs/heads/"))
+ localname = tmp;
+
+ /* Both source and destination must be local branches. */
+ if (!localname || prefixcmp(localname, "refs/heads/"))
+ continue;
+ if (!remotename || prefixcmp(remotename, "refs/heads/"))
+ continue;
+
+ if (!pretend)
+ install_branch_config(BRANCH_CONFIG_VERBOSE,
+ localname + 11, transport->remote->name,
+ remotename);
+ else
+ printf("Would set upstream of '%s' to '%s' of '%s'\n",
+ localname + 11, remotename + 11,
+ transport->remote->name);
+ }
+}
+
static const char *rsync_url(const char *url)
{
return prefixcmp(url, "rsync://") ? skip_prefix(url, "rsync:") : url;
@@ -864,20 +912,20 @@ static int external_specification_len(const char *url)
struct transport *transport_get(struct remote *remote, const char *url)
{
+ const char *helper;
struct transport *ret = xcalloc(1, sizeof(*ret));
if (!remote)
die("No remote provided to transport_get()");
+ ret->got_remote_refs = 0;
ret->remote = remote;
+ helper = remote->foreign_vcs;
- if (!url && remote && remote->url)
+ if (!url && remote->url)
url = remote->url[0];
ret->url = url;
- /* In case previous URL had helper forced, reset it. */
- remote->foreign_vcs = NULL;
-
/* maybe it is a foreign URL? */
if (url) {
const char *p = url;
@@ -885,11 +933,11 @@ struct transport *transport_get(struct remote *remote, const char *url)
while (isalnum(*p))
p++;
if (!prefixcmp(p, "::"))
- remote->foreign_vcs = xstrndup(url, p - url);
+ helper = xstrndup(url, p - url);
}
- if (remote && remote->foreign_vcs) {
- transport_helper_init(ret, remote->foreign_vcs);
+ if (helper) {
+ transport_helper_init(ret, helper);
} else if (!prefixcmp(url, "rsync:")) {
ret->get_refs_list = get_refs_via_rsync;
ret->fetch = fetch_objs_via_rsync;
@@ -974,6 +1022,10 @@ int transport_push(struct transport *transport,
verify_remote_names(refspec_nr, refspec);
if (transport->push) {
+ /* Maybe FIXME. But no important transport uses this case. */
+ if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
+ die("This transport does not support using --set-upstream");
+
return transport->push(transport, refspec_nr, refspec, flags);
} else if (transport->push_refs) {
struct ref *remote_refs =
@@ -983,7 +1035,8 @@ int transport_push(struct transport *transport,
int verbose = flags & TRANSPORT_PUSH_VERBOSE;
int quiet = flags & TRANSPORT_PUSH_QUIET;
int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
- int ret;
+ int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
+ int ret, err;
if (flags & TRANSPORT_PUSH_ALL)
match_flags |= MATCH_REFS_ALL;
@@ -995,13 +1048,23 @@ int transport_push(struct transport *transport,
return -1;
}
+ set_ref_status_for_push(remote_refs,
+ flags & TRANSPORT_PUSH_MIRROR,
+ flags & TRANSPORT_PUSH_FORCE);
+
ret = transport->push_refs(transport, remote_refs, flags);
+ err = push_had_errors(remote_refs);
+
+ ret |= err;
- if (!quiet || push_had_errors(remote_refs))
+ if (!quiet || err)
print_push_status(transport->url, remote_refs,
verbose | porcelain, porcelain,
nonfastforward);
+ if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
+ set_upstreams(transport, remote_refs, pretend);
+
if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next)
@@ -1017,8 +1080,10 @@ int transport_push(struct transport *transport,
const struct ref *transport_get_remote_refs(struct transport *transport)
{
- if (!transport->remote_refs)
+ if (!transport->got_remote_refs) {
transport->remote_refs = transport->get_refs_list(transport, 0);
+ transport->got_remote_refs = 1;
+ }
return transport->remote_refs;
}