#include "string-list.h"
#include "thread-utils.h"
#include "sigchain.h"
+#include "argv-array.h"
static int debug;
FILE *out;
unsigned fetch : 1,
import : 1,
+ bidi_import : 1,
export : 1,
option : 1,
push : 1,
static struct child_process *get_helper(struct transport *transport)
{
struct helper_data *data = transport->data;
+ struct argv_array argv = ARGV_ARRAY_INIT;
struct strbuf buf = STRBUF_INIT;
struct child_process *helper;
const char **refspecs = NULL;
helper->in = -1;
helper->out = -1;
helper->err = 0;
- helper->argv = xcalloc(4, sizeof(*helper->argv));
- strbuf_addf(&buf, "git-remote-%s", data->name);
- helper->argv[0] = strbuf_detach(&buf, NULL);
- helper->argv[1] = transport->remote->name;
- helper->argv[2] = remove_ext_force(transport->url);
+ argv_array_pushf(&argv, "git-remote-%s", data->name);
+ argv_array_push(&argv, transport->remote->name);
+ argv_array_push(&argv, remove_ext_force(transport->url));
+ helper->argv = argv_array_detach(&argv, NULL);
helper->git_cmd = 0;
helper->silent_exec_failure = 1;
data->push = 1;
else if (!strcmp(capname, "import"))
data->import = 1;
+ else if (!strcmp(capname, "bidi-import"))
+ data->bidi_import = 1;
else if (!strcmp(capname, "export"))
data->export = 1;
else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
close(data->helper->out);
fclose(data->out);
res = finish_command(data->helper);
- free((char *)data->helper->argv[0]);
- free(data->helper->argv);
+ argv_array_free_detached(data->helper->argv);
free(data->helper);
data->helper = NULL;
}
static int get_importer(struct transport *transport, struct child_process *fastimport)
{
struct child_process *helper = get_helper(transport);
+ struct helper_data *data = transport->data;
+ struct argv_array argv = ARGV_ARRAY_INIT;
+ int cat_blob_fd, code;
memset(fastimport, 0, sizeof(*fastimport));
fastimport->in = helper->out;
- fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
- fastimport->argv[0] = "fast-import";
- fastimport->argv[1] = "--quiet";
+ argv_array_push(&argv, "fast-import");
+ argv_array_push(&argv, debug ? "--stats" : "--quiet");
+ if (data->bidi_import) {
+ cat_blob_fd = xdup(helper->in);
+ argv_array_pushf(&argv, "--cat-blob-fd=%d", cat_blob_fd);
+ }
+ fastimport->argv = argv.argv;
fastimport->git_cmd = 1;
- return start_command(fastimport);
+
+ code = start_command(fastimport);
+ return code;
}
static int get_exporter(struct transport *transport,
}
write_constant(data->helper->in, "\n");
+ /*
+ * remote-helpers that advertise the bidi-import capability are required to
+ * buffer the complete batch of import commands until this newline before
+ * sending data to fast-import.
+ * These helpers read back data from fast-import on their stdin, which could
+ * be mixed with import commands, otherwise.
+ */
if (finish_command(&fastimport))
die("Error while running fast-import");
- free(fastimport.argv);
- fastimport.argv = NULL;
+ argv_array_free_detached(fastimport.argv);
+ /*
+ * The fast-import stream of a remote helper that advertises
+ * the "refspec" capability writes to the refs named after the
+ * right hand side of the first refspec matching each ref we
+ * were fetching.
+ *
+ * (If no "refspec" capability was specified, for historical
+ * reasons we default to *:*.)
+ *
+ * Store the result in to_fetch[i].old_sha1. Callers such
+ * as "git fetch" can use the value to write feedback to the
+ * terminal, populate FETCH_HEAD, and determine what new value
+ * should be written to peer_ref if the update is a
+ * fast-forward or this is a forced update.
+ */
for (i = 0; i < nr_heads; i++) {
char *private;
posn = to_fetch[i];
free(msg);
msg = NULL;
}
+ else if (!strcmp(msg, "already exists")) {
+ status = REF_STATUS_REJECT_ALREADY_EXISTS;
+ free(msg);
+ msg = NULL;
+ }
}
if (*ref)
/* Check for statuses set by set_ref_status_for_push() */
switch (ref->status) {
case REF_STATUS_REJECT_NONFASTFORWARD:
+ case REF_STATUS_REJECT_ALREADY_EXISTS:
case REF_STATUS_UPTODATE:
continue;
default: