summaryrefslogtreecommitdiff
path: root/transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'transport.c')
-rw-r--r--transport.c111
1 files changed, 92 insertions, 19 deletions
diff --git a/transport.c b/transport.c
index 1811b500d9..886ffd8b1e 100644
--- a/transport.c
+++ b/transport.c
@@ -518,8 +518,7 @@ static int fetch_refs_via_pack(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
struct git_transport_data *data = transport->data;
- char **heads = xmalloc(nr_heads * sizeof(*heads));
- char **origh = xmalloc(nr_heads * sizeof(*origh));
+ struct string_list sought = STRING_LIST_INIT_DUP;
const struct ref *refs;
char *dest = xstrdup(transport->url);
struct fetch_pack_args args;
@@ -538,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport,
args.depth = data->options.depth;
for (i = 0; i < nr_heads; i++)
- origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
+ string_list_append(&sought, to_fetch[i]->name);
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
@@ -548,7 +547,7 @@ static int fetch_refs_via_pack(struct transport *transport,
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
- dest, nr_heads, heads, &transport->pack_lockfile);
+ dest, &sought, &transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
if (finish_connect(data->conn))
@@ -558,10 +557,7 @@ static int fetch_refs_via_pack(struct transport *transport,
free_refs(refs_tmp);
- for (i = 0; i < nr_heads; i++)
- free(origh[i]);
- free(origh);
- free(heads);
+ string_list_clear(&sought, 0);
free(dest);
return (refs ? 0 : -1);
}
@@ -663,7 +659,7 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
const char *msg;
strcpy(quickref, status_abbrev(ref->old_sha1));
- if (ref->nonfastforward) {
+ if (ref->forced_update) {
strcat(quickref, "...");
type = '+';
msg = "forced update";
@@ -699,6 +695,18 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"non-fast-forward", porcelain);
break;
+ case REF_STATUS_REJECT_ALREADY_EXISTS:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "already exists", porcelain);
+ break;
+ case REF_STATUS_REJECT_FETCH_FIRST:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "fetch first", porcelain);
+ break;
+ case REF_STATUS_REJECT_NEEDS_FORCE:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "needs force", porcelain);
+ break;
case REF_STATUS_REMOTE_REJECT:
print_ref_status('!', "[remote rejected]", ref,
ref->deletion ? NULL : ref->peer_ref,
@@ -718,7 +726,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
}
void transport_print_push_status(const char *dest, struct ref *refs,
- int verbose, int porcelain, int *nonfastforward)
+ int verbose, int porcelain, unsigned int *reject_reasons)
{
struct ref *ref;
int n = 0;
@@ -737,18 +745,23 @@ void transport_print_push_status(const char *dest, struct ref *refs,
if (ref->status == REF_STATUS_OK)
n += print_one_push_status(ref, dest, n, porcelain);
- *nonfastforward = 0;
+ *reject_reasons = 0;
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, porcelain);
- if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD &&
- *nonfastforward != NON_FF_HEAD) {
- if (!strcmp(head, ref->name))
- *nonfastforward = NON_FF_HEAD;
+ if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD) {
+ if (head != NULL && !strcmp(head, ref->name))
+ *reject_reasons |= REJECT_NON_FF_HEAD;
else
- *nonfastforward = NON_FF_OTHER;
+ *reject_reasons |= REJECT_NON_FF_OTHER;
+ } else if (ref->status == REF_STATUS_REJECT_ALREADY_EXISTS) {
+ *reject_reasons |= REJECT_ALREADY_EXISTS;
+ } else if (ref->status == REF_STATUS_REJECT_FETCH_FIRST) {
+ *reject_reasons |= REJECT_FETCH_FIRST;
+ } else if (ref->status == REF_STATUS_REJECT_NEEDS_FORCE) {
+ *reject_reasons |= REJECT_NEEDS_FORCE;
}
}
}
@@ -1033,11 +1046,67 @@ static void die_with_unpushed_submodules(struct string_list *needs_pushing)
die("Aborting.");
}
+static int run_pre_push_hook(struct transport *transport,
+ struct ref *remote_refs)
+{
+ int ret = 0, x;
+ struct ref *r;
+ struct child_process proc;
+ struct strbuf buf;
+ const char *argv[4];
+
+ if (!(argv[0] = find_hook("pre-push")))
+ return 0;
+
+ argv[1] = transport->remote->name;
+ argv[2] = transport->url;
+ argv[3] = NULL;
+
+ memset(&proc, 0, sizeof(proc));
+ proc.argv = argv;
+ proc.in = -1;
+
+ if (start_command(&proc)) {
+ finish_command(&proc);
+ return -1;
+ }
+
+ strbuf_init(&buf, 256);
+
+ for (r = remote_refs; r; r = r->next) {
+ if (!r->peer_ref) continue;
+ if (r->status == REF_STATUS_REJECT_NONFASTFORWARD) continue;
+ if (r->status == REF_STATUS_UPTODATE) continue;
+
+ strbuf_reset(&buf);
+ strbuf_addf( &buf, "%s %s %s %s\n",
+ r->peer_ref->name, sha1_to_hex(r->new_sha1),
+ r->name, sha1_to_hex(r->old_sha1));
+
+ if (write_in_full(proc.in, buf.buf, buf.len) != buf.len) {
+ ret = -1;
+ break;
+ }
+ }
+
+ strbuf_release(&buf);
+
+ x = close(proc.in);
+ if (!ret)
+ ret = x;
+
+ x = finish_command(&proc);
+ if (!ret)
+ ret = x;
+
+ return ret;
+}
+
int transport_push(struct transport *transport,
int refspec_nr, const char **refspec, int flags,
- int *nonfastforward)
+ unsigned int *reject_reasons)
{
- *nonfastforward = 0;
+ *reject_reasons = 0;
transport_verify_remote_names(refspec_nr, refspec);
if (transport->push) {
@@ -1073,6 +1142,10 @@ int transport_push(struct transport *transport,
flags & TRANSPORT_PUSH_MIRROR,
flags & TRANSPORT_PUSH_FORCE);
+ if (!(flags & TRANSPORT_PUSH_NO_HOOK))
+ if (run_pre_push_hook(transport, remote_refs))
+ return -1;
+
if ((flags & TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND) && !is_bare_repository()) {
struct ref *ref = remote_refs;
for (; ref; ref = ref->next)
@@ -1103,7 +1176,7 @@ int transport_push(struct transport *transport,
if (!quiet || err)
transport_print_push_status(transport->url, remote_refs,
verbose | porcelain, porcelain,
- nonfastforward);
+ reject_reasons);
if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
set_upstreams(transport, remote_refs, pretend);