Skip to content

Commit f6a4e61

Browse files
stefanbellergitster
authored andcommitted
push: accept push options
This implements everything that is required on the client side to make use of push options from the porcelain push command. Signed-off-by: Stefan Beller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c714e45 commit f6a4e61

File tree

6 files changed

+63
-4
lines changed

6 files changed

+63
-4
lines changed

Documentation/git-push.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ SYNOPSIS
1111
[verse]
1212
'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
1313
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
14-
[-u | --set-upstream]
14+
[-u | --set-upstream] [--push-option=<string>]
1515
[--[no-]signed|--sign=(true|false|if-asked)]
1616
[--force-with-lease[=<refname>[:<expect>]]]
1717
[--no-verify] [<repository> [<refspec>...]]
@@ -156,6 +156,12 @@ already exists on the remote side.
156156
Either all refs are updated, or on error, no refs are updated.
157157
If the server does not support atomic pushes the push will fail.
158158

159+
-o::
160+
--push-option::
161+
Transmit the given string to the server, which passes them to
162+
the pre-receive as well as the post-receive hook. The given string
163+
must not contain a NUL or LF character.
164+
159165
--receive-pack=<git-receive-pack>::
160166
--exec=<git-receive-pack>::
161167
Path to the 'git-receive-pack' program on the remote

builtin/push.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ static int push_with_options(struct transport *transport, int flags)
353353
return 1;
354354
}
355355

356-
static int do_push(const char *repo, int flags)
356+
static int do_push(const char *repo, int flags,
357+
const struct string_list *push_options)
357358
{
358359
int i, errs;
359360
struct remote *remote = pushremote_get(repo);
@@ -376,6 +377,9 @@ static int do_push(const char *repo, int flags)
376377
if (remote->mirror)
377378
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
378379

380+
if (push_options->nr)
381+
flags |= TRANSPORT_PUSH_OPTIONS;
382+
379383
if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
380384
if (!strcmp(*refspec, "refs/tags/*"))
381385
return error(_("--all and --tags are incompatible"));
@@ -406,13 +410,16 @@ static int do_push(const char *repo, int flags)
406410
for (i = 0; i < url_nr; i++) {
407411
struct transport *transport =
408412
transport_get(remote, url[i]);
413+
if (flags & TRANSPORT_PUSH_OPTIONS)
414+
transport->push_options = push_options;
409415
if (push_with_options(transport, flags))
410416
errs++;
411417
}
412418
} else {
413419
struct transport *transport =
414420
transport_get(remote, NULL);
415-
421+
if (flags & TRANSPORT_PUSH_OPTIONS)
422+
transport->push_options = push_options;
416423
if (push_with_options(transport, flags))
417424
errs++;
418425
}
@@ -500,6 +507,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
500507
int push_cert = -1;
501508
int rc;
502509
const char *repo = NULL; /* default repository */
510+
static struct string_list push_options = STRING_LIST_INIT_DUP;
511+
static struct string_list_item *item;
512+
503513
struct option options[] = {
504514
OPT__VERBOSITY(&verbosity),
505515
OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
@@ -533,6 +543,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
533543
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
534544
PARSE_OPT_OPTARG, option_parse_push_signed },
535545
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
546+
OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
536547
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
537548
TRANSPORT_FAMILY_IPV4),
538549
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
@@ -563,7 +574,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
563574
set_refspecs(argv + 1, argc - 1, repo);
564575
}
565576

566-
rc = do_push(repo, flags);
577+
for_each_string_list_item(item, &push_options)
578+
if (strchr(item->string, '\n'))
579+
die(_("push options must not have new line characters"));
580+
581+
rc = do_push(repo, flags, &push_options);
567582
if (rc == -1)
568583
usage_with_options(push_usage, options);
569584
else

send-pack.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ static int generate_push_cert(struct strbuf *req_buf,
260260
const char *push_cert_nonce)
261261
{
262262
const struct ref *ref;
263+
struct string_list_item *item;
263264
char *signing_key = xstrdup(get_signing_key());
264265
const char *cp, *np;
265266
struct strbuf cert = STRBUF_INIT;
@@ -276,6 +277,9 @@ static int generate_push_cert(struct strbuf *req_buf,
276277
}
277278
if (push_cert_nonce[0])
278279
strbuf_addf(&cert, "nonce %s\n", push_cert_nonce);
280+
if (args->push_options)
281+
for_each_string_list_item(item, args->push_options)
282+
strbuf_addf(&cert, "push-option %s\n", item->string);
279283
strbuf_addstr(&cert, "\n");
280284

281285
for (ref = remote_refs; ref; ref = ref->next) {
@@ -370,6 +374,8 @@ int send_pack(struct send_pack_args *args,
370374
int agent_supported = 0;
371375
int use_atomic = 0;
372376
int atomic_supported = 0;
377+
int use_push_options = 0;
378+
int push_options_supported = 0;
373379
unsigned cmds_sent = 0;
374380
int ret;
375381
struct async demux;
@@ -392,6 +398,8 @@ int send_pack(struct send_pack_args *args,
392398
args->use_thin_pack = 0;
393399
if (server_supports("atomic"))
394400
atomic_supported = 1;
401+
if (server_supports("push-options"))
402+
push_options_supported = 1;
395403

396404
if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
397405
int len;
@@ -418,6 +426,11 @@ int send_pack(struct send_pack_args *args,
418426

419427
use_atomic = atomic_supported && args->atomic;
420428

429+
if (args->push_options && !push_options_supported)
430+
die(_("the receiving end does not support push options"));
431+
432+
use_push_options = push_options_supported && args->push_options;
433+
421434
if (status_report)
422435
strbuf_addstr(&cap_buf, " report-status");
423436
if (use_sideband)
@@ -426,6 +439,8 @@ int send_pack(struct send_pack_args *args,
426439
strbuf_addstr(&cap_buf, " quiet");
427440
if (use_atomic)
428441
strbuf_addstr(&cap_buf, " atomic");
442+
if (use_push_options)
443+
strbuf_addstr(&cap_buf, " push-options");
429444
if (agent_supported)
430445
strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
431446

@@ -512,6 +527,18 @@ int send_pack(struct send_pack_args *args,
512527
strbuf_release(&req_buf);
513528
strbuf_release(&cap_buf);
514529

530+
if (use_push_options) {
531+
struct string_list_item *item;
532+
struct strbuf sb = STRBUF_INIT;
533+
534+
for_each_string_list_item(item, args->push_options)
535+
packet_buf_write(&sb, "%s", item->string);
536+
537+
write_or_die(out, sb.buf, sb.len);
538+
packet_flush(out);
539+
strbuf_release(&sb);
540+
}
541+
515542
if (use_sideband && cmds_sent) {
516543
memset(&demux, 0, sizeof(demux));
517544
demux.proc = sideband_demux;

send-pack.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef SEND_PACK_H
22
#define SEND_PACK_H
33

4+
#include "string-list.h"
5+
46
/* Possible values for push_cert field in send_pack_args. */
57
#define SEND_PACK_PUSH_CERT_NEVER 0
68
#define SEND_PACK_PUSH_CERT_IF_ASKED 1
@@ -21,6 +23,7 @@ struct send_pack_args {
2123
push_cert:2,
2224
stateless_rpc:1,
2325
atomic:1;
26+
const struct string_list *push_options;
2427
};
2528

2629
struct option;

transport.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
510510
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
511511
args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);
512512
args.atomic = !!(flags & TRANSPORT_PUSH_ATOMIC);
513+
args.push_options = transport->push_options;
513514
args.url = transport->url;
514515

515516
if (flags & TRANSPORT_PUSH_CERT_ALWAYS)

transport.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ struct transport {
4848
*/
4949
unsigned cloning : 1;
5050

51+
/*
52+
* These strings will be passed to the {pre, post}-receive hook,
53+
* on the remote side, if both sides support the push options capability.
54+
*/
55+
const struct string_list *push_options;
56+
5157
/**
5258
* Returns 0 if successful, positive if the option is not
5359
* recognized or is inapplicable, and negative if the option
@@ -134,6 +140,7 @@ struct transport {
134140
#define TRANSPORT_PUSH_CERT_ALWAYS 2048
135141
#define TRANSPORT_PUSH_CERT_IF_ASKED 4096
136142
#define TRANSPORT_PUSH_ATOMIC 8192
143+
#define TRANSPORT_PUSH_OPTIONS 16384
137144

138145
#define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
139146
#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)

0 commit comments

Comments
 (0)