diff options
author | Junio C Hamano <gitster@pobox.com> | 2020-09-26 00:25:39 +0200 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2020-09-26 00:25:39 +0200 |
commit | 6c430a647cb990fc856d328733fa59e1fafadb97 (patch) | |
tree | 09bf6873a1b13f2f0178d864a09a30f9fe3cf09a /transport-helper.c | |
parent | Merge branch 'ds/maintenance-part-1' (diff) | |
parent | doc: add documentation for the proc-receive hook (diff) | |
download | git-6c430a647cb990fc856d328733fa59e1fafadb97.tar.xz git-6c430a647cb990fc856d328733fa59e1fafadb97.zip |
Merge branch 'jx/proc-receive-hook'
"git receive-pack" that accepts requests by "git push" learned to
outsource most of the ref updates to the new "proc-receive" hook.
* jx/proc-receive-hook:
doc: add documentation for the proc-receive hook
transport: parse report options for tracking refs
t5411: test updates of remote-tracking branches
receive-pack: new config receive.procReceiveRefs
doc: add document for capability report-status-v2
New capability "report-status-v2" for git-push
receive-pack: feed report options to post-receive
receive-pack: add new proc-receive hook
t5411: add basic test cases for proc-receive hook
transport: not report a non-head push as a branch
Diffstat (limited to 'transport-helper.c')
-rw-r--r-- | transport-helper.c | 128 |
1 files changed, 99 insertions, 29 deletions
diff --git a/transport-helper.c b/transport-helper.c index c52c99d829..b573b6c730 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -723,13 +723,61 @@ static int fetch(struct transport *transport, return -1; } +struct push_update_ref_state { + struct ref *hint; + struct ref_push_report *report; + int new_report; +}; + static int push_update_ref_status(struct strbuf *buf, - struct ref **ref, + struct push_update_ref_state *state, struct ref *remote_refs) { char *refname, *msg; int status, forced = 0; + if (starts_with(buf->buf, "option ")) { + struct object_id old_oid, new_oid; + const char *key, *val; + char *p; + + if (!state->hint || !(state->report || state->new_report)) + die(_("'option' without a matching 'ok/error' directive")); + if (state->new_report) { + if (!state->hint->report) { + state->hint->report = xcalloc(1, sizeof(struct ref_push_report)); + state->report = state->hint->report; + } else { + state->report = state->hint->report; + while (state->report->next) + state->report = state->report->next; + state->report->next = xcalloc(1, sizeof(struct ref_push_report)); + state->report = state->report->next; + } + state->new_report = 0; + } + key = buf->buf + 7; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + state->report->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + state->report->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + state->report->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + state->report->forced_update = 1; + /* Not update remote namespace again. */ + return 1; + } + + state->report = NULL; + state->new_report = 0; + if (starts_with(buf->buf, "ok ")) { status = REF_STATUS_OK; refname = buf->buf + 3; @@ -785,16 +833,16 @@ static int push_update_ref_status(struct strbuf *buf, } } - if (*ref) - *ref = find_ref_by_name(*ref, refname); - if (!*ref) - *ref = find_ref_by_name(remote_refs, refname); - if (!*ref) { + if (state->hint) + state->hint = find_ref_by_name(state->hint, refname); + if (!state->hint) + state->hint = find_ref_by_name(remote_refs, refname); + if (!state->hint) { warning(_("helper reported unexpected status of %s"), refname); return 1; } - if ((*ref)->status != REF_STATUS_NONE) { + if (state->hint->status != REF_STATUS_NONE) { /* * Earlier, the ref was marked not to be pushed, so ignore the ref * status reported by the remote helper if the latter is 'no match'. @@ -803,9 +851,11 @@ static int push_update_ref_status(struct strbuf *buf, return 1; } - (*ref)->status = status; - (*ref)->forced_update |= forced; - (*ref)->remote_status = msg; + if (status == REF_STATUS_OK) + state->new_report = 1; + state->hint->status = status; + state->hint->forced_update |= forced; + state->hint->remote_status = msg; return !(status == REF_STATUS_OK); } @@ -813,37 +863,57 @@ static int push_update_refs_status(struct helper_data *data, struct ref *remote_refs, int flags) { + struct ref *ref; + struct ref_push_report *report; struct strbuf buf = STRBUF_INIT; - struct ref *ref = remote_refs; - int ret = 0; + struct push_update_ref_state state = { remote_refs, NULL, 0 }; for (;;) { - char *private; - if (recvline(data, &buf)) { - ret = 1; - break; + strbuf_release(&buf); + return 1; } - if (!buf.len) break; + push_update_ref_status(&buf, &state, remote_refs); + } + strbuf_release(&buf); - if (push_update_ref_status(&buf, &ref, remote_refs)) - continue; + if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update) + return 0; - if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update) - continue; + /* propagate back the update to the remote namespace */ + for (ref = remote_refs; ref; ref = ref->next) { + char *private; - /* propagate back the update to the remote namespace */ - private = apply_refspecs(&data->rs, ref->name); - if (!private) + if (ref->status != REF_STATUS_OK) continue; - update_ref("update by helper", private, &ref->new_oid, NULL, - 0, 0); - free(private); + + if (!ref->report) { + private = apply_refspecs(&data->rs, ref->name); + if (!private) + continue; + update_ref("update by helper", private, &(ref->new_oid), + NULL, 0, 0); + free(private); + } else { + for (report = ref->report; report; report = report->next) { + private = apply_refspecs(&data->rs, + report->ref_name + ? report->ref_name + : ref->name); + if (!private) + continue; + update_ref("update by helper", private, + report->new_oid + ? report->new_oid + : &(ref->new_oid), + NULL, 0, 0); + free(private); + } + } } - strbuf_release(&buf); - return ret; + return 0; } static void set_common_push_options(struct transport *transport, |