1#include "builtin.h"2#include "commit.h"3#include "refs.h"4#include "pkt-line.h"5#include "sideband.h"6#include "run-command.h"7#include "remote.h"8#include "send-pack.h"9#include "quote.h"10#include "transport.h"11#include "version.h"1213static const char send_pack_usage[] =14"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"15" --all and explicit <ref> specification are mutually exclusive.";1617static struct send_pack_args args;1819static void print_helper_status(struct ref *ref)20{21struct strbuf buf = STRBUF_INIT;2223for (; ref; ref = ref->next) {24const char *msg = NULL;25const char *res;2627switch(ref->status) {28case REF_STATUS_NONE:29res = "error";30msg = "no match";31break;3233case REF_STATUS_OK:34res = "ok";35break;3637case REF_STATUS_UPTODATE:38res = "ok";39msg = "up to date";40break;4142case REF_STATUS_REJECT_NONFASTFORWARD:43res = "error";44msg = "non-fast forward";45break;4647case REF_STATUS_REJECT_ALREADY_EXISTS:48res = "error";49msg = "already exists";50break;5152case REF_STATUS_REJECT_NODELETE:53case REF_STATUS_REMOTE_REJECT:54res = "error";55break;5657case REF_STATUS_EXPECTING_REPORT:58default:59continue;60}6162strbuf_reset(&buf);63strbuf_addf(&buf, "%s %s", res, ref->name);64if (ref->remote_status)65msg = ref->remote_status;66if (msg) {67strbuf_addch(&buf, ' ');68quote_two_c_style(&buf, "", msg, 0);69}70strbuf_addch(&buf, '\n');7172safe_write(1, buf.buf, buf.len);73}74strbuf_release(&buf);75}7677int cmd_send_pack(int argc, const char **argv, const char *prefix)78{79int i, nr_refspecs = 0;80const char **refspecs = NULL;81const char *remote_name = NULL;82struct remote *remote = NULL;83const char *dest = NULL;84int fd[2];85struct child_process *conn;86struct extra_have_objects extra_have;87struct ref *remote_refs, *local_refs;88int ret;89int helper_status = 0;90int send_all = 0;91const char *receivepack = "git-receive-pack";92int flags;93unsigned int reject_reasons;94int progress = -1;9596argv++;97for (i = 1; i < argc; i++, argv++) {98const char *arg = *argv;99100if (*arg == '-') {101if (!prefixcmp(arg, "--receive-pack=")) {102receivepack = arg + 15;103continue;104}105if (!prefixcmp(arg, "--exec=")) {106receivepack = arg + 7;107continue;108}109if (!prefixcmp(arg, "--remote=")) {110remote_name = arg + 9;111continue;112}113if (!strcmp(arg, "--all")) {114send_all = 1;115continue;116}117if (!strcmp(arg, "--dry-run")) {118args.dry_run = 1;119continue;120}121if (!strcmp(arg, "--mirror")) {122args.send_mirror = 1;123continue;124}125if (!strcmp(arg, "--force")) {126args.force_update = 1;127continue;128}129if (!strcmp(arg, "--quiet")) {130args.quiet = 1;131continue;132}133if (!strcmp(arg, "--verbose")) {134args.verbose = 1;135continue;136}137if (!strcmp(arg, "--progress")) {138progress = 1;139continue;140}141if (!strcmp(arg, "--no-progress")) {142progress = 0;143continue;144}145if (!strcmp(arg, "--thin")) {146args.use_thin_pack = 1;147continue;148}149if (!strcmp(arg, "--stateless-rpc")) {150args.stateless_rpc = 1;151continue;152}153if (!strcmp(arg, "--helper-status")) {154helper_status = 1;155continue;156}157usage(send_pack_usage);158}159if (!dest) {160dest = arg;161continue;162}163refspecs = (const char **) argv;164nr_refspecs = argc - i;165break;166}167if (!dest)168usage(send_pack_usage);169/*170* --all and --mirror are incompatible; neither makes sense171* with any refspecs.172*/173if ((refspecs && (send_all || args.send_mirror)) ||174(send_all && args.send_mirror))175usage(send_pack_usage);176177if (remote_name) {178remote = remote_get(remote_name);179if (!remote_has_url(remote, dest)) {180die("Destination %s is not a uri for %s",181dest, remote_name);182}183}184185if (progress == -1)186progress = !args.quiet && isatty(2);187args.progress = progress;188189if (args.stateless_rpc) {190conn = NULL;191fd[0] = 0;192fd[1] = 1;193} else {194conn = git_connect(fd, dest, receivepack,195args.verbose ? CONNECT_VERBOSE : 0);196}197198memset(&extra_have, 0, sizeof(extra_have));199200get_remote_heads(fd[0], &remote_refs, REF_NORMAL, &extra_have);201202transport_verify_remote_names(nr_refspecs, refspecs);203204local_refs = get_local_heads();205206flags = MATCH_REFS_NONE;207208if (send_all)209flags |= MATCH_REFS_ALL;210if (args.send_mirror)211flags |= MATCH_REFS_MIRROR;212213/* match them up */214if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))215return -1;216217set_ref_status_for_push(remote_refs, args.send_mirror,218args.force_update);219220ret = send_pack(&args, fd, conn, remote_refs, &extra_have);221222if (helper_status)223print_helper_status(remote_refs);224225close(fd[1]);226close(fd[0]);227228ret |= finish_connect(conn);229230if (!helper_status)231transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);232233if (!args.dry_run && remote) {234struct ref *ref;235for (ref = remote_refs; ref; ref = ref->next)236transport_update_tracking_ref(remote, ref, args.verbose);237}238239if (!ret && !transport_refs_pushed(remote_refs))240fprintf(stderr, "Everything up-to-date\n");241242return ret;243}