Move push matching and reporting logic into transport.c
For native-protocol pushes (and other protocols as they are converted to the new method), this moves the refspec match, tracking update, and report message out of send-pack() and into transport_push(), where it can be shared completely with other protocols. This also makes fetch and push more similar in terms of what code is in what file. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
a9c37a72c4
commit
64fcef2daa
@ -11,7 +11,6 @@ static const char send_pack_usage[] =
|
|||||||
" --all and explicit <ref> specification are mutually exclusive.";
|
" --all and explicit <ref> specification are mutually exclusive.";
|
||||||
|
|
||||||
static struct send_pack_args args = {
|
static struct send_pack_args args = {
|
||||||
/* .receivepack = */ "git-receive-pack",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int feed_object(const unsigned char *sha1, int fd, int negative)
|
static int feed_object(const unsigned char *sha1, int fd, int negative)
|
||||||
@ -31,7 +30,7 @@ static int feed_object(const unsigned char *sha1, int fd, int negative)
|
|||||||
/*
|
/*
|
||||||
* Make a pack stream and spit it out into file descriptor fd
|
* Make a pack stream and spit it out into file descriptor fd
|
||||||
*/
|
*/
|
||||||
static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
|
static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The child becomes pack-objects --revs; we feed
|
* The child becomes pack-objects --revs; we feed
|
||||||
@ -49,7 +48,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
|
|||||||
struct child_process po;
|
struct child_process po;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (args.use_thin_pack)
|
if (args->use_thin_pack)
|
||||||
argv[4] = "--thin";
|
argv[4] = "--thin";
|
||||||
memset(&po, 0, sizeof(po));
|
memset(&po, 0, sizeof(po));
|
||||||
po.argv = argv;
|
po.argv = argv;
|
||||||
@ -83,8 +82,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ref *remote_refs, **remote_tail;
|
|
||||||
|
|
||||||
static int receive_status(int in, struct ref *refs)
|
static int receive_status(int in, struct ref *refs)
|
||||||
{
|
{
|
||||||
struct ref *hint;
|
struct ref *hint;
|
||||||
@ -300,27 +297,19 @@ static int refs_pushed(struct ref *ref)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec)
|
int send_pack(struct send_pack_args *args,
|
||||||
|
int fd[], struct child_process *conn,
|
||||||
|
struct ref *remote_refs,
|
||||||
|
struct extra_have_objects *extra_have)
|
||||||
{
|
{
|
||||||
struct ref *ref, *local_refs;
|
int in = fd[0];
|
||||||
|
int out = fd[1];
|
||||||
|
struct ref *ref;
|
||||||
int new_refs;
|
int new_refs;
|
||||||
int ask_for_status_report = 0;
|
int ask_for_status_report = 0;
|
||||||
int allow_deleting_refs = 0;
|
int allow_deleting_refs = 0;
|
||||||
int expect_status_report = 0;
|
int expect_status_report = 0;
|
||||||
int flags = MATCH_REFS_NONE;
|
|
||||||
int ret;
|
int ret;
|
||||||
struct extra_have_objects extra_have;
|
|
||||||
|
|
||||||
memset(&extra_have, 0, sizeof(extra_have));
|
|
||||||
if (args.send_all)
|
|
||||||
flags |= MATCH_REFS_ALL;
|
|
||||||
if (args.send_mirror)
|
|
||||||
flags |= MATCH_REFS_MIRROR;
|
|
||||||
|
|
||||||
/* No funny business with the matcher */
|
|
||||||
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
|
|
||||||
&extra_have);
|
|
||||||
local_refs = get_local_heads();
|
|
||||||
|
|
||||||
/* Does the other end support the reporting? */
|
/* Does the other end support the reporting? */
|
||||||
if (server_supports("report-status"))
|
if (server_supports("report-status"))
|
||||||
@ -328,19 +317,9 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
|||||||
if (server_supports("delete-refs"))
|
if (server_supports("delete-refs"))
|
||||||
allow_deleting_refs = 1;
|
allow_deleting_refs = 1;
|
||||||
|
|
||||||
/* match them up */
|
|
||||||
if (!remote_tail)
|
|
||||||
remote_tail = &remote_refs;
|
|
||||||
if (match_refs(local_refs, remote_refs, &remote_tail,
|
|
||||||
nr_refspec, refspec, flags)) {
|
|
||||||
close(out);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!remote_refs) {
|
if (!remote_refs) {
|
||||||
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
|
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
|
||||||
"Perhaps you should specify a branch such as 'master'.\n");
|
"Perhaps you should specify a branch such as 'master'.\n");
|
||||||
close(out);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +331,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
|||||||
|
|
||||||
if (ref->peer_ref)
|
if (ref->peer_ref)
|
||||||
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
|
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
|
||||||
else if (!args.send_mirror)
|
else if (!args->send_mirror)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ref->deletion = is_null_sha1(ref->new_sha1);
|
ref->deletion = is_null_sha1(ref->new_sha1);
|
||||||
@ -391,7 +370,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
|||||||
(!has_sha1_file(ref->old_sha1)
|
(!has_sha1_file(ref->old_sha1)
|
||||||
|| !ref_newer(ref->new_sha1, ref->old_sha1));
|
|| !ref_newer(ref->new_sha1, ref->old_sha1));
|
||||||
|
|
||||||
if (ref->nonfastforward && !ref->force && !args.force_update) {
|
if (ref->nonfastforward && !ref->force && !args->force_update) {
|
||||||
ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
|
ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -399,7 +378,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
|||||||
if (!ref->deletion)
|
if (!ref->deletion)
|
||||||
new_refs++;
|
new_refs++;
|
||||||
|
|
||||||
if (!args.dry_run) {
|
if (!args->dry_run) {
|
||||||
char *old_hex = sha1_to_hex(ref->old_sha1);
|
char *old_hex = sha1_to_hex(ref->old_sha1);
|
||||||
char *new_hex = sha1_to_hex(ref->new_sha1);
|
char *new_hex = sha1_to_hex(ref->new_sha1);
|
||||||
|
|
||||||
@ -420,27 +399,19 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
|||||||
}
|
}
|
||||||
|
|
||||||
packet_flush(out);
|
packet_flush(out);
|
||||||
if (new_refs && !args.dry_run) {
|
if (new_refs && !args->dry_run) {
|
||||||
if (pack_objects(out, remote_refs, &extra_have) < 0)
|
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
|
||||||
|
for (ref = remote_refs; ref; ref = ref->next)
|
||||||
|
ref->status = REF_STATUS_NONE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
close(out);
|
|
||||||
|
|
||||||
if (expect_status_report)
|
if (expect_status_report)
|
||||||
ret = receive_status(in, remote_refs);
|
ret = receive_status(in, remote_refs);
|
||||||
else
|
else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
print_push_status(dest, remote_refs);
|
|
||||||
|
|
||||||
if (!args.dry_run && remote) {
|
|
||||||
for (ref = remote_refs; ref; ref = ref->next)
|
|
||||||
update_tracking_ref(remote, ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!refs_pushed(remote_refs))
|
|
||||||
fprintf(stderr, "Everything up-to-date\n");
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
for (ref = remote_refs; ref; ref = ref->next) {
|
for (ref = remote_refs; ref; ref = ref->next) {
|
||||||
@ -489,11 +460,19 @@ static void verify_remote_names(int nr_heads, const char **heads)
|
|||||||
|
|
||||||
int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i, nr_heads = 0;
|
int i, nr_refspecs = 0;
|
||||||
const char **heads = NULL;
|
const char **refspecs = NULL;
|
||||||
const char *remote_name = NULL;
|
const char *remote_name = NULL;
|
||||||
struct remote *remote = NULL;
|
struct remote *remote = NULL;
|
||||||
const char *dest = NULL;
|
const char *dest = NULL;
|
||||||
|
int fd[2];
|
||||||
|
struct child_process *conn;
|
||||||
|
struct extra_have_objects extra_have;
|
||||||
|
struct ref *remote_refs, **remote_tail, *local_refs;
|
||||||
|
int ret;
|
||||||
|
int send_all = 0;
|
||||||
|
const char *receivepack = "git-receive-pack";
|
||||||
|
int flags;
|
||||||
|
|
||||||
argv++;
|
argv++;
|
||||||
for (i = 1; i < argc; i++, argv++) {
|
for (i = 1; i < argc; i++, argv++) {
|
||||||
@ -501,11 +480,11 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
if (*arg == '-') {
|
if (*arg == '-') {
|
||||||
if (!prefixcmp(arg, "--receive-pack=")) {
|
if (!prefixcmp(arg, "--receive-pack=")) {
|
||||||
args.receivepack = arg + 15;
|
receivepack = arg + 15;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!prefixcmp(arg, "--exec=")) {
|
if (!prefixcmp(arg, "--exec=")) {
|
||||||
args.receivepack = arg + 7;
|
receivepack = arg + 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!prefixcmp(arg, "--remote=")) {
|
if (!prefixcmp(arg, "--remote=")) {
|
||||||
@ -513,7 +492,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--all")) {
|
if (!strcmp(arg, "--all")) {
|
||||||
args.send_all = 1;
|
send_all = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--dry-run")) {
|
if (!strcmp(arg, "--dry-run")) {
|
||||||
@ -542,8 +521,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
|||||||
dest = arg;
|
dest = arg;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
heads = (const char **) argv;
|
refspecs = (const char **) argv;
|
||||||
nr_heads = argc - i;
|
nr_refspecs = argc - i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!dest)
|
if (!dest)
|
||||||
@ -552,8 +531,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
|||||||
* --all and --mirror are incompatible; neither makes sense
|
* --all and --mirror are incompatible; neither makes sense
|
||||||
* with any refspecs.
|
* with any refspecs.
|
||||||
*/
|
*/
|
||||||
if ((heads && (args.send_all || args.send_mirror)) ||
|
if ((refspecs && (send_all || args.send_mirror)) ||
|
||||||
(args.send_all && args.send_mirror))
|
(send_all && args.send_mirror))
|
||||||
usage(send_pack_usage);
|
usage(send_pack_usage);
|
||||||
|
|
||||||
if (remote_name) {
|
if (remote_name) {
|
||||||
@ -564,24 +543,50 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return send_pack(&args, dest, remote, nr_heads, heads);
|
conn = git_connect(fd, dest, receivepack, args.verbose ? CONNECT_VERBOSE : 0);
|
||||||
}
|
|
||||||
|
|
||||||
int send_pack(struct send_pack_args *my_args,
|
memset(&extra_have, 0, sizeof(extra_have));
|
||||||
const char *dest, struct remote *remote,
|
|
||||||
int nr_heads, const char **heads)
|
|
||||||
{
|
|
||||||
int fd[2], ret;
|
|
||||||
struct child_process *conn;
|
|
||||||
|
|
||||||
memcpy(&args, my_args, sizeof(args));
|
get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
|
||||||
|
&extra_have);
|
||||||
|
|
||||||
verify_remote_names(nr_heads, heads);
|
verify_remote_names(nr_refspecs, refspecs);
|
||||||
|
|
||||||
conn = git_connect(fd, dest, args.receivepack, args.verbose ? CONNECT_VERBOSE : 0);
|
local_refs = get_local_heads();
|
||||||
ret = do_send_pack(fd[0], fd[1], remote, dest, nr_heads, heads);
|
|
||||||
|
flags = MATCH_REFS_NONE;
|
||||||
|
|
||||||
|
if (send_all)
|
||||||
|
flags |= MATCH_REFS_ALL;
|
||||||
|
if (args.send_mirror)
|
||||||
|
flags |= MATCH_REFS_MIRROR;
|
||||||
|
|
||||||
|
/* match them up */
|
||||||
|
remote_tail = &remote_refs;
|
||||||
|
while (*remote_tail)
|
||||||
|
remote_tail = &((*remote_tail)->next);
|
||||||
|
if (match_refs(local_refs, remote_refs, &remote_tail,
|
||||||
|
nr_refspecs, refspecs, flags)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
|
||||||
|
|
||||||
|
close(fd[1]);
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
/* do_send_pack always closes fd[1] */
|
|
||||||
ret |= finish_connect(conn);
|
ret |= finish_connect(conn);
|
||||||
return !!ret;
|
|
||||||
|
print_push_status(dest, remote_refs);
|
||||||
|
|
||||||
|
if (!args.dry_run && remote) {
|
||||||
|
struct ref *ref;
|
||||||
|
for (ref = remote_refs; ref; ref = ref->next)
|
||||||
|
update_tracking_ref(remote, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret && !refs_pushed(remote_refs))
|
||||||
|
fprintf(stderr, "Everything up-to-date\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
#define SEND_PACK_H
|
#define SEND_PACK_H
|
||||||
|
|
||||||
struct send_pack_args {
|
struct send_pack_args {
|
||||||
const char *receivepack;
|
|
||||||
unsigned verbose:1,
|
unsigned verbose:1,
|
||||||
send_all:1,
|
|
||||||
send_mirror:1,
|
send_mirror:1,
|
||||||
force_update:1,
|
force_update:1,
|
||||||
use_thin_pack:1,
|
use_thin_pack:1,
|
||||||
@ -12,7 +10,7 @@ struct send_pack_args {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int send_pack(struct send_pack_args *args,
|
int send_pack(struct send_pack_args *args,
|
||||||
const char *dest, struct remote *remote,
|
int fd[], struct child_process *conn,
|
||||||
int nr_heads, const char **heads);
|
struct ref *remote_refs, struct extra_have_objects *extra_have);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
281
transport.c
281
transport.c
@ -138,7 +138,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ref *get_refs_via_rsync(struct transport *transport)
|
static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
|
||||||
struct ref dummy, *tail = &dummy;
|
struct ref dummy, *tail = &dummy;
|
||||||
@ -146,6 +146,9 @@ static struct ref *get_refs_via_rsync(struct transport *transport)
|
|||||||
const char *args[5];
|
const char *args[5];
|
||||||
int temp_dir_len;
|
int temp_dir_len;
|
||||||
|
|
||||||
|
if (for_push)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* copy the refs to the temporary directory */
|
/* copy the refs to the temporary directory */
|
||||||
|
|
||||||
strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
|
strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
|
||||||
@ -422,7 +425,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
|
|||||||
return !!err;
|
return !!err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ref *get_refs_via_curl(struct transport *transport)
|
static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
|
||||||
{
|
{
|
||||||
struct strbuf buffer = STRBUF_INIT;
|
struct strbuf buffer = STRBUF_INIT;
|
||||||
char *data, *start, *mid;
|
char *data, *start, *mid;
|
||||||
@ -439,6 +442,9 @@ static struct ref *get_refs_via_curl(struct transport *transport)
|
|||||||
|
|
||||||
struct walker *walker;
|
struct walker *walker;
|
||||||
|
|
||||||
|
if (for_push)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (!transport->data)
|
if (!transport->data)
|
||||||
transport->data = get_http_walker(transport->url,
|
transport->data = get_http_walker(transport->url,
|
||||||
transport->remote);
|
transport->remote);
|
||||||
@ -525,12 +531,15 @@ struct bundle_transport_data {
|
|||||||
struct bundle_header header;
|
struct bundle_header header;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ref *get_refs_from_bundle(struct transport *transport)
|
static struct ref *get_refs_from_bundle(struct transport *transport, int for_push)
|
||||||
{
|
{
|
||||||
struct bundle_transport_data *data = transport->data;
|
struct bundle_transport_data *data = transport->data;
|
||||||
struct ref *result = NULL;
|
struct ref *result = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (for_push)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (data->fd > 0)
|
if (data->fd > 0)
|
||||||
close(data->fd);
|
close(data->fd);
|
||||||
data->fd = read_bundle_header(transport->url, &data->header);
|
data->fd = read_bundle_header(transport->url, &data->header);
|
||||||
@ -571,6 +580,7 @@ struct git_transport_data {
|
|||||||
int fd[2];
|
int fd[2];
|
||||||
const char *uploadpack;
|
const char *uploadpack;
|
||||||
const char *receivepack;
|
const char *receivepack;
|
||||||
|
struct extra_have_objects extra_have;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int set_git_option(struct transport *connection,
|
static int set_git_option(struct transport *connection,
|
||||||
@ -602,20 +612,23 @@ static int set_git_option(struct transport *connection,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int connect_setup(struct transport *transport)
|
static int connect_setup(struct transport *transport, int for_push, int verbose)
|
||||||
{
|
{
|
||||||
struct git_transport_data *data = transport->data;
|
struct git_transport_data *data = transport->data;
|
||||||
data->conn = git_connect(data->fd, transport->url, data->uploadpack, 0);
|
data->conn = git_connect(data->fd, transport->url,
|
||||||
|
for_push ? data->receivepack : data->uploadpack,
|
||||||
|
verbose ? CONNECT_VERBOSE : 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ref *get_refs_via_connect(struct transport *transport)
|
static struct ref *get_refs_via_connect(struct transport *transport, int for_push)
|
||||||
{
|
{
|
||||||
struct git_transport_data *data = transport->data;
|
struct git_transport_data *data = transport->data;
|
||||||
struct ref *refs;
|
struct ref *refs;
|
||||||
|
|
||||||
connect_setup(transport);
|
connect_setup(transport, for_push, 0);
|
||||||
get_remote_heads(data->fd[0], &refs, 0, NULL, 0, NULL);
|
get_remote_heads(data->fd[0], &refs, 0, NULL,
|
||||||
|
for_push ? REF_NORMAL : 0, &data->extra_have);
|
||||||
|
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
@ -647,7 +660,7 @@ static int fetch_refs_via_pack(struct transport *transport,
|
|||||||
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
|
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
|
||||||
|
|
||||||
if (!data->conn) {
|
if (!data->conn) {
|
||||||
connect_setup(transport);
|
connect_setup(transport, 0, 0);
|
||||||
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
|
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,20 +683,216 @@ static int fetch_refs_via_pack(struct transport *transport,
|
|||||||
return (refs ? 0 : -1);
|
return (refs ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
|
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 update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
|
||||||
|
{
|
||||||
|
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 (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_ref(from), prettify_ref(to));
|
||||||
|
else
|
||||||
|
fputs(prettify_ref(to), 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, int verbose)
|
||||||
|
{
|
||||||
|
struct ref *ref;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (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 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags)
|
||||||
{
|
{
|
||||||
struct git_transport_data *data = transport->data;
|
struct git_transport_data *data = transport->data;
|
||||||
struct send_pack_args args;
|
struct send_pack_args args;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!data->conn) {
|
||||||
|
struct ref *tmp_refs;
|
||||||
|
connect_setup(transport, 1, 0);
|
||||||
|
|
||||||
|
get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
args.receivepack = data->receivepack;
|
|
||||||
args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
|
|
||||||
args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
|
args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
|
||||||
args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
|
args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
|
||||||
args.use_thin_pack = data->thin;
|
args.use_thin_pack = data->thin;
|
||||||
args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
|
args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
|
||||||
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
|
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
|
||||||
|
|
||||||
return send_pack(&args, transport->url, transport->remote, refspec_nr, refspec);
|
ret = send_pack(&args, data->fd, data->conn, remote_refs,
|
||||||
|
&data->extra_have);
|
||||||
|
|
||||||
|
close(data->fd[1]);
|
||||||
|
close(data->fd[0]);
|
||||||
|
ret |= finish_connect(data->conn);
|
||||||
|
data->conn = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int disconnect_git(struct transport *transport)
|
static int disconnect_git(struct transport *transport)
|
||||||
@ -753,7 +962,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
|||||||
ret->set_option = set_git_option;
|
ret->set_option = set_git_option;
|
||||||
ret->get_refs_list = get_refs_via_connect;
|
ret->get_refs_list = get_refs_via_connect;
|
||||||
ret->fetch = fetch_refs_via_pack;
|
ret->fetch = fetch_refs_via_pack;
|
||||||
ret->push = git_transport_push;
|
ret->push_refs = git_transport_push;
|
||||||
ret->disconnect = disconnect_git;
|
ret->disconnect = disconnect_git;
|
||||||
|
|
||||||
data->thin = 1;
|
data->thin = 1;
|
||||||
@ -780,15 +989,53 @@ int transport_set_option(struct transport *transport,
|
|||||||
int transport_push(struct transport *transport,
|
int transport_push(struct transport *transport,
|
||||||
int refspec_nr, const char **refspec, int flags)
|
int refspec_nr, const char **refspec, int flags)
|
||||||
{
|
{
|
||||||
if (!transport->push)
|
verify_remote_names(refspec_nr, refspec);
|
||||||
return 1;
|
|
||||||
|
if (transport->push)
|
||||||
return transport->push(transport, refspec_nr, refspec, flags);
|
return transport->push(transport, refspec_nr, refspec, flags);
|
||||||
|
if (transport->push_refs) {
|
||||||
|
struct ref *remote_refs =
|
||||||
|
transport->get_refs_list(transport, 1);
|
||||||
|
struct ref **remote_tail;
|
||||||
|
struct ref *local_refs = get_local_heads();
|
||||||
|
int match_flags = MATCH_REFS_NONE;
|
||||||
|
int verbose = flags & TRANSPORT_PUSH_VERBOSE;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (flags & TRANSPORT_PUSH_ALL)
|
||||||
|
match_flags |= MATCH_REFS_ALL;
|
||||||
|
if (flags & TRANSPORT_PUSH_MIRROR)
|
||||||
|
match_flags |= MATCH_REFS_MIRROR;
|
||||||
|
|
||||||
|
remote_tail = &remote_refs;
|
||||||
|
while (*remote_tail)
|
||||||
|
remote_tail = &((*remote_tail)->next);
|
||||||
|
if (match_refs(local_refs, remote_refs, &remote_tail,
|
||||||
|
refspec_nr, refspec, match_flags)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = transport->push_refs(transport, remote_refs, flags);
|
||||||
|
|
||||||
|
print_push_status(transport->url, remote_refs, verbose);
|
||||||
|
|
||||||
|
if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
|
||||||
|
struct ref *ref;
|
||||||
|
for (ref = remote_refs; ref; ref = ref->next)
|
||||||
|
update_tracking_ref(transport->remote, ref, verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret && !refs_pushed(remote_refs))
|
||||||
|
fprintf(stderr, "Everything up-to-date\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct ref *transport_get_remote_refs(struct transport *transport)
|
const struct ref *transport_get_remote_refs(struct transport *transport)
|
||||||
{
|
{
|
||||||
if (!transport->remote_refs)
|
if (!transport->remote_refs)
|
||||||
transport->remote_refs = transport->get_refs_list(transport);
|
transport->remote_refs = transport->get_refs_list(transport, 0);
|
||||||
return transport->remote_refs;
|
return transport->remote_refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,9 @@ struct transport {
|
|||||||
int (*set_option)(struct transport *connection, const char *name,
|
int (*set_option)(struct transport *connection, const char *name,
|
||||||
const char *value);
|
const char *value);
|
||||||
|
|
||||||
struct ref *(*get_refs_list)(struct transport *transport);
|
struct ref *(*get_refs_list)(struct transport *transport, int for_push);
|
||||||
int (*fetch)(struct transport *transport, int refs_nr, const struct ref **refs);
|
int (*fetch)(struct transport *transport, int refs_nr, const struct ref **refs);
|
||||||
|
int (*push_refs)(struct transport *transport, struct ref *refs, int flags);
|
||||||
int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
|
int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
|
||||||
|
|
||||||
int (*disconnect)(struct transport *connection);
|
int (*disconnect)(struct transport *connection);
|
||||||
|
Loading…
Reference in New Issue
Block a user