summaryrefslogtreecommitdiff
path: root/builtin-send-pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin-send-pack.c')
-rw-r--r--builtin-send-pack.c257
1 files changed, 56 insertions, 201 deletions
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 76c72065de..6019eac918 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -7,6 +7,7 @@
#include "remote.h"
#include "send-pack.h"
#include "quote.h"
+#include "transport.h"
static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -169,156 +170,6 @@ static int receive_status(int in, struct ref *refs)
return ret;
}
-static void update_tracking_ref(struct remote *remote, struct ref *ref)
-{
- struct refspec rs;
-
- if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
- return;
-
- rs.src = ref->name;
- rs.dst = NULL;
-
- if (!remote_find_tracking(remote, &rs)) {
- if (args.verbose)
- fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
- if (ref->deletion) {
- delete_ref(rs.dst, NULL, 0);
- } else
- update_ref("update by push", rs.dst,
- ref->new_sha1, NULL, 0, 0);
- free(rs.dst);
- }
-}
-
-#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
-
-static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
-{
- fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
- if (from)
- fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
- else
- fputs(prettify_refname(to->name), stderr);
- if (msg) {
- fputs(" (", stderr);
- fputs(msg, stderr);
- fputc(')', stderr);
- }
- fputc('\n', stderr);
-}
-
-static const char *status_abbrev(unsigned char sha1[20])
-{
- return find_unique_abbrev(sha1, DEFAULT_ABBREV);
-}
-
-static void print_ok_ref_status(struct ref *ref)
-{
- if (ref->deletion)
- print_ref_status('-', "[deleted]", ref, NULL, NULL);
- else if (is_null_sha1(ref->old_sha1))
- print_ref_status('*',
- (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
- "[new branch]"),
- ref, ref->peer_ref, NULL);
- else {
- char quickref[84];
- char type;
- const char *msg;
-
- strcpy(quickref, status_abbrev(ref->old_sha1));
- if (ref->nonfastforward) {
- strcat(quickref, "...");
- type = '+';
- msg = "forced update";
- } else {
- strcat(quickref, "..");
- type = ' ';
- msg = NULL;
- }
- strcat(quickref, status_abbrev(ref->new_sha1));
-
- print_ref_status(type, quickref, ref, ref->peer_ref, msg);
- }
-}
-
-static int print_one_push_status(struct ref *ref, const char *dest, int count)
-{
- if (!count)
- fprintf(stderr, "To %s\n", dest);
-
- switch(ref->status) {
- case REF_STATUS_NONE:
- print_ref_status('X', "[no match]", ref, NULL, NULL);
- break;
- case REF_STATUS_REJECT_NODELETE:
- print_ref_status('!', "[rejected]", ref, NULL,
- "remote does not support deleting refs");
- break;
- case REF_STATUS_UPTODATE:
- print_ref_status('=', "[up to date]", ref,
- ref->peer_ref, NULL);
- break;
- case REF_STATUS_REJECT_NONFASTFORWARD:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "non-fast-forward");
- break;
- case REF_STATUS_REMOTE_REJECT:
- print_ref_status('!', "[remote rejected]", ref,
- ref->deletion ? NULL : ref->peer_ref,
- ref->remote_status);
- break;
- case REF_STATUS_EXPECTING_REPORT:
- print_ref_status('!', "[remote failure]", ref,
- ref->deletion ? NULL : ref->peer_ref,
- "remote failed to report status");
- break;
- case REF_STATUS_OK:
- print_ok_ref_status(ref);
- break;
- }
-
- return 1;
-}
-
-static void print_push_status(const char *dest, struct ref *refs)
-{
- struct ref *ref;
- int n = 0;
-
- if (args.verbose) {
- for (ref = refs; ref; ref = ref->next)
- if (ref->status == REF_STATUS_UPTODATE)
- n += print_one_push_status(ref, dest, n);
- }
-
- for (ref = refs; ref; ref = ref->next)
- if (ref->status == REF_STATUS_OK)
- n += print_one_push_status(ref, dest, n);
-
- for (ref = refs; ref; ref = ref->next) {
- if (ref->status != REF_STATUS_NONE &&
- ref->status != REF_STATUS_UPTODATE &&
- ref->status != REF_STATUS_OK)
- n += print_one_push_status(ref, dest, n);
- }
-}
-
-static int refs_pushed(struct ref *ref)
-{
- for (; ref; ref = ref->next) {
- switch(ref->status) {
- case REF_STATUS_NONE:
- case REF_STATUS_UPTODATE:
- break;
- default:
- return 1;
- }
- }
- return 0;
-}
-
static void print_helper_status(struct ref *ref)
{
struct strbuf buf = STRBUF_INIT;
@@ -372,6 +223,14 @@ static void print_helper_status(struct ref *ref)
strbuf_release(&buf);
}
+static int sideband_demux(int in, int out, void *data)
+{
+ int *fd = data;
+ int ret = recv_sideband("send-pack", fd[0], out);
+ close(out);
+ return ret;
+}
+
int send_pack(struct send_pack_args *args,
int fd[], struct child_process *conn,
struct ref *remote_refs,
@@ -382,18 +241,22 @@ int send_pack(struct send_pack_args *args,
struct strbuf req_buf = STRBUF_INIT;
struct ref *ref;
int new_refs;
- int ask_for_status_report = 0;
int allow_deleting_refs = 0;
- int expect_status_report = 0;
+ int status_report = 0;
+ int use_sideband = 0;
+ unsigned cmds_sent = 0;
int ret;
+ struct async demux;
/* Does the other end support the reporting? */
if (server_supports("report-status"))
- ask_for_status_report = 1;
+ status_report = 1;
if (server_supports("delete-refs"))
allow_deleting_refs = 1;
if (server_supports("ofs-delta"))
args->use_ofs_delta = 1;
+ if (server_supports("side-band-64k"))
+ use_sideband = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -426,28 +289,30 @@ int send_pack(struct send_pack_args *args,
if (!ref->deletion)
new_refs++;
- if (!args->dry_run) {
+ if (args->dry_run) {
+ ref->status = REF_STATUS_OK;
+ } else {
char *old_hex = sha1_to_hex(ref->old_sha1);
char *new_hex = sha1_to_hex(ref->new_sha1);
- if (ask_for_status_report) {
- packet_buf_write(&req_buf, "%s %s %s%c%s",
+ if (!cmds_sent && (status_report || use_sideband)) {
+ packet_buf_write(&req_buf, "%s %s %s%c%s%s",
old_hex, new_hex, ref->name, 0,
- "report-status");
- ask_for_status_report = 0;
- expect_status_report = 1;
+ status_report ? " report-status" : "",
+ use_sideband ? " side-band-64k" : "");
}
else
packet_buf_write(&req_buf, "%s %s %s",
old_hex, new_hex, ref->name);
+ ref->status = status_report ?
+ REF_STATUS_EXPECTING_REPORT :
+ REF_STATUS_OK;
+ cmds_sent++;
}
- ref->status = expect_status_report ?
- REF_STATUS_EXPECTING_REPORT :
- REF_STATUS_OK;
}
if (args->stateless_rpc) {
- if (!args->dry_run) {
+ if (!args->dry_run && cmds_sent) {
packet_buf_flush(&req_buf);
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
}
@@ -457,23 +322,43 @@ int send_pack(struct send_pack_args *args,
}
strbuf_release(&req_buf);
- if (new_refs && !args->dry_run) {
+ if (use_sideband && cmds_sent) {
+ memset(&demux, 0, sizeof(demux));
+ demux.proc = sideband_demux;
+ demux.data = fd;
+ demux.out = -1;
+ if (start_async(&demux))
+ die("receive-pack: unable to fork off sideband demultiplexer");
+ in = demux.out;
+ }
+
+ if (new_refs && cmds_sent) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
for (ref = remote_refs; ref; ref = ref->next)
ref->status = REF_STATUS_NONE;
+ if (use_sideband)
+ finish_async(&demux);
return -1;
}
}
- if (args->stateless_rpc && !args->dry_run)
+ if (args->stateless_rpc && cmds_sent)
packet_flush(out);
- if (expect_status_report)
+ if (status_report && cmds_sent)
ret = receive_status(in, remote_refs);
else
ret = 0;
if (args->stateless_rpc)
packet_flush(out);
+ if (use_sideband && cmds_sent) {
+ if (finish_async(&demux)) {
+ error("error in sideband demultiplexer");
+ ret = -1;
+ }
+ close(demux.out);
+ }
+
if (ret < 0)
return ret;
for (ref = remote_refs; ref; ref = ref->next) {
@@ -489,37 +374,6 @@ int send_pack(struct send_pack_args *args,
return 0;
}
-static void verify_remote_names(int nr_heads, const char **heads)
-{
- int i;
-
- for (i = 0; i < nr_heads; i++) {
- const char *local = heads[i];
- const char *remote = strrchr(heads[i], ':');
-
- if (*local == '+')
- local++;
-
- /* A matching refspec is okay. */
- if (remote == local && remote[1] == '\0')
- continue;
-
- remote = remote ? (remote + 1) : local;
- switch (check_ref_format(remote)) {
- case 0: /* ok */
- case CHECK_REF_FORMAT_ONELEVEL:
- /* ok but a single level -- that is fine for
- * a match pattern.
- */
- case CHECK_REF_FORMAT_WILDCARD:
- /* ok but ends with a pattern-match character */
- continue;
- }
- die("remote part of refspec is not a valid name in %s",
- heads[i]);
- }
-}
-
int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
int i, nr_refspecs = 0;
@@ -536,6 +390,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int send_all = 0;
const char *receivepack = "git-receive-pack";
int flags;
+ int nonfastforward = 0;
argv++;
for (i = 1; i < argc; i++, argv++) {
@@ -628,7 +483,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
&extra_have);
- verify_remote_names(nr_refspecs, refspecs);
+ transport_verify_remote_names(nr_refspecs, refspecs);
local_refs = get_local_heads();
@@ -657,15 +512,15 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
ret |= finish_connect(conn);
if (!helper_status)
- print_push_status(dest, remote_refs);
+ transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
if (!args.dry_run && remote) {
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next)
- update_tracking_ref(remote, ref);
+ transport_update_tracking_ref(remote, ref, args.verbose);
}
- if (!ret && !refs_pushed(remote_refs))
+ if (!ret && !transport_refs_pushed(remote_refs))
fprintf(stderr, "Everything up-to-date\n");
return ret;