+
Supported commands: 'list', 'import'.
+ 'check-connectivity'::
+ Can guarantee that when a clone is requested, the received
+ pack is self contained and is connected.
+
If a helper advertises 'connect', Git will use it if possible and
fall back to another capability if the helper requests so when
connecting (see the 'connect' command under COMMANDS).
carried out.
'refspec' <refspec>::
- This modifies the 'import' capability, allowing the produced
- fast-import stream to modify refs in a private namespace
- instead of writing to refs/heads or refs/remotes directly.
+ For remote helpers that implement 'import' or 'export', this capability
+ allows the refs to be constrained to a private namespace, instead of
+ writing to refs/heads or refs/remotes directly.
It is recommended that all importers providing the 'import'
- capability use this.
+ capability use this. It's mandatory for 'export'.
+
A helper advertising the capability
`refspec refs/heads/*:refs/svn/origin/branches/*`
This capability can be advertised multiple times. The first
applicable refspec takes precedence. The left-hand of refspecs
advertised with this capability must cover all refs reported by
-the list command. If a helper does not need a specific 'refspec'
-capability then it should advertise `refspec *:*`.
+the list command. If no 'refspec' capability is advertised,
+there is an implied `refspec *:*`.
'bidi-import'::
This modifies the 'import' capability.
GIT_DIR/objects/pack which is keeping a pack until refs can be
suitably updated.
+
+ If option 'check-connectivity' is requested, the helper must output
+ 'connectivity-ok' if the clone is self-contained and connected.
+ +
Supported if the helper has the "fetch" capability.
'push' +<src>:<dst>::
must not rely on this option being set before
connect request occurs.
+ 'option check-connectivity' \{'true'|'false'\}::
+ Request the helper to check connectivity of a clone.
+
SEE ALSO
--------
linkgit:git-remote[1]
#include "run-command.h"
#include "pkt-line.h"
#include "sideband.h"
+#include "argv-array.h"
static struct remote *remote;
static const char *url; /* always ends with a trailing slash */
int verbosity;
unsigned long depth;
unsigned progress : 1,
+ check_self_contained_and_connected : 1,
followtags : 1,
dry_run : 1,
thin : 1;
return -1;
return 0;
}
+ else if (!strcmp(name, "check-connectivity")) {
+ if (!strcmp(value, "true"))
+ options.check_self_contained_and_connected = 1;
+ else if (!strcmp(value, "false"))
+ options.check_self_contained_and_connected = 0;
+ else
+ return -1;
+ return 0;
+ }
else {
return 1 /* unsupported */;
}
struct strbuf preamble = STRBUF_INIT;
char *depth_arg = NULL;
int argc = 0, i, err;
- const char *argv[15];
+ const char *argv[16];
argv[argc++] = "fetch-pack";
argv[argc++] = "--stateless-rpc";
argv[argc++] = "-v";
argv[argc++] = "-v";
}
+ if (options.check_self_contained_and_connected)
+ argv[argc++] = "--check-self-contained-and-connected";
if (!options.progress)
argv[argc++] = "--no-progress";
if (options.depth) {
static int push_git(struct discovery *heads, int nr_spec, char **specs)
{
struct rpc_state rpc;
- const char **argv;
- int argc = 0, i, err;
+ int i, err;
+ struct argv_array args;
+
+ argv_array_init(&args);
+ argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
+ NULL);
- argv = xmalloc((10 + nr_spec) * sizeof(char*));
- argv[argc++] = "send-pack";
- argv[argc++] = "--stateless-rpc";
- argv[argc++] = "--helper-status";
if (options.thin)
- argv[argc++] = "--thin";
+ argv_array_push(&args, "--thin");
if (options.dry_run)
- argv[argc++] = "--dry-run";
+ argv_array_push(&args, "--dry-run");
if (options.verbosity == 0)
- argv[argc++] = "--quiet";
+ argv_array_push(&args, "--quiet");
else if (options.verbosity > 1)
- argv[argc++] = "--verbose";
- argv[argc++] = options.progress ? "--progress" : "--no-progress";
- argv[argc++] = url;
+ argv_array_push(&args, "--verbose");
+ argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
+ argv_array_push(&args, url);
for (i = 0; i < nr_spec; i++)
- argv[argc++] = specs[i];
- argv[argc++] = NULL;
+ argv_array_push(&args, specs[i]);
memset(&rpc, 0, sizeof(rpc));
rpc.service_name = "git-receive-pack",
- rpc.argv = argv;
+ rpc.argv = args.argv;
err = rpc_service(&rpc, heads);
if (rpc.result.len)
write_or_die(1, rpc.result.buf, rpc.result.len);
strbuf_release(&rpc.result);
- free(argv);
+ argv_array_clear(&args);
return err;
}
printf("fetch\n");
printf("option\n");
printf("push\n");
+ printf("check-connectivity\n");
printf("\n");
fflush(stdout);
} else {
#include "thread-utils.h"
#include "sigchain.h"
#include "argv-array.h"
+#include "refs.h"
static int debug;
push : 1,
connect : 1,
signed_tags : 1,
+ check_connectivity : 1,
no_disconnect_req : 1;
char *export_marks;
char *import_marks;
die_errno("Full write to remote helper failed");
}
-static int recvline_fh(FILE *helper, struct strbuf *buffer)
+static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)
{
strbuf_reset(buffer);
if (debug)
static int recvline(struct helper_data *helper, struct strbuf *buffer)
{
- return recvline_fh(helper->out, buffer);
+ return recvline_fh(helper->out, buffer, helper->name);
}
static void xchgline(struct helper_data *helper, struct strbuf *buffer)
data->bidi_import = 1;
else if (!strcmp(capname, "export"))
data->export = 1;
+ else if (!strcmp(capname, "check-connectivity"))
+ data->check_connectivity = 1;
else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
ALLOC_GROW(refspecs,
refspec_nr + 1,
for (i = 0; i < refspec_nr; i++)
free((char *)refspecs[i]);
free(refspecs);
+ } else if (data->import || data->bidi_import || data->export) {
+ warning("This remote helper should implement refspec capability.");
}
strbuf_release(&buf);
if (debug)
struct strbuf buf = STRBUF_INIT;
standard_options(transport);
+ if (data->check_connectivity &&
+ data->transport_options.check_self_contained_and_connected)
+ set_helper_option(transport, "check-connectivity", "true");
for (i = 0; i < nr_heads; i++) {
const struct ref *posn = to_fetch[i];
else
transport->pack_lockfile = xstrdup(name);
}
+ else if (data->check_connectivity &&
+ data->transport_options.check_self_contained_and_connected &&
+ !strcmp(buf.buf, "connectivity-ok"))
+ data->transport_options.self_contained_and_connected = 1;
else if (!buf.len)
break;
else
* were fetching.
*
* (If no "refspec" capability was specified, for historical
- * reasons we default to *:*.)
+ * reasons we default to the equivalent of *:*.)
*
* Store the result in to_fetch[i].old_sha1. Callers such
* as "git fetch" can use the value to write feedback to the
goto exit;
sendline(data, &cmdbuf);
- recvline_fh(input, &cmdbuf);
+ recvline_fh(input, &cmdbuf, name);
if (!strcmp(cmdbuf.buf, "")) {
data->no_disconnect_req = 1;
if (debug)
return -1;
}
-static void push_update_ref_status(struct strbuf *buf,
+static int push_update_ref_status(struct strbuf *buf,
struct ref **ref,
struct ref *remote_refs)
{
*ref = find_ref_by_name(remote_refs, refname);
if (!*ref) {
warning("helper reported unexpected status of %s", refname);
- return;
+ return 1;
}
if ((*ref)->status != REF_STATUS_NONE) {
* status reported by the remote helper if the latter is 'no match'.
*/
if (status == REF_STATUS_NONE)
- return;
+ return 1;
}
(*ref)->status = status;
(*ref)->remote_status = msg;
+ return !(status == REF_STATUS_OK);
}
static void push_update_refs_status(struct helper_data *data,
struct strbuf buf = STRBUF_INIT;
struct ref *ref = remote_refs;
for (;;) {
+ char *private;
+
recvline(data, &buf);
if (!buf.len)
break;
- push_update_ref_status(&buf, &ref, remote_refs);
+ if (push_update_ref_status(&buf, &ref, remote_refs))
+ continue;
+
+ if (!data->refspecs)
+ continue;
+
+ /* propagate back the update to the remote namespace */
+ private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
+ if (!private)
+ continue;
+ update_ref("update by helper", private, ref->new_sha1, NULL, 0, 0);
+ free(private);
}
strbuf_release(&buf);
}
struct string_list revlist_args = STRING_LIST_INIT_NODUP;
struct strbuf buf = STRBUF_INIT;
+ if (!data->refspecs)
+ die("remote-helper doesn't support push; refspec needed");
+
+ if (flags & TRANSPORT_PUSH_DRY_RUN) {
+ if (set_helper_option(transport, "dry-run", "true") != 0)
+ die("helper %s does not support dry-run", data->name);
+ }
+
helper = get_helper(transport);
write_constant(helper->in, "export\n");
char *private;
unsigned char sha1[20];
- if (!data->refspecs)
- continue;
+ if (ref->deletion)
+ die("remote-helpers do not support ref deletion");
+
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
if (private && !get_sha1(private, sha1)) {
strbuf_addf(&buf, "^%s", private);
}
free(private);
- if (ref->deletion) {
+ if (ref->deletion)
die("remote-helpers do not support ref deletion");
- }
- if (ref->peer_ref)
+ if (ref->peer_ref) {
+ if (strcmp(ref->peer_ref->name, ref->name))
+ die("remote-helpers do not support old:new syntax");
string_list_append(&revlist_args, ref->peer_ref->name);
-
+ }
}
if (get_exporter(transport, &exporter, &revlist_args))
#define PBUFFERSIZE 8192
/* Print bidirectional transfer loop debug message. */
+__attribute__((format (printf, 1, 2)))
static void transfer_debug(const char *fmt, ...)
{
va_list args;
return -1;
} else if (bytes == 0) {
transfer_debug("%s EOF (with %i bytes in buffer)",
- t->src_name, t->bufuse);
+ t->src_name, (int)t->bufuse);
t->state = SSTATE_FLUSHING;
} else if (bytes > 0) {
t->bufuse += bytes;
#ifndef NO_PTHREADS
/*
- * Join thread, with apporiate errors on failure. Name is name for the
+ * Join thread, with appropriate errors on failure. Name is name for the
* thread (for error messages). Returns 0 on success, 1 on failure.
*/
static int tloop_join(pthread_t thread, const char *name)
}
/*
- * Join process, with apporiate errors on failure. Name is name for the
+ * Join process, with appropriate errors on failure. Name is name for the
* process (for error messages). Returns 0 on success, 1 on failure.
*/
static int tloop_join(pid_t pid, const char *name)