{"thread":{"id":"40131","subject":"[PATCH v2 0/9] Flags and config to sign pushes by default","startedAt":"2015-08-19T15:26:38Z","lastAt":"2015-09-11T16:22:11Z","messageCount":19,"participants":["Dave Borowitz","Stefan Beller","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":2,"patchTotal":9},"messages":[{"id":"268310","messageId":"1439998007-28719-1-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":null,"subject":"[PATCH v2 0/9] Flags and config to sign pushes by default","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:38Z","receivedAt":"2015-08-19T15:26:38Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Changes since v1:\n - Rebased on 44e02239\n - Use options --[no-]signed|--signed=(yes|no|if-asked)\n - Support general yes/true/1/etc. option parsing.\n - Convert builtin/send-pack.c to use option parsing API for better code\n   reuse.\n - Various cleanups as suggested by Junio.\n\nv1 can be found at:\nhttp://thread.gmane.org/gmane.comp.version-control.git/275881\n\nDave Borowitz (9):\n  Documentation/git-push.txt: Document when --signed may fail\n  Documentation/git-send-pack.txt: Flow long synopsis line\n  Documentation/git-send-pack.txt: Document --signed\n  gitremote-helpers.txt: Document pushcert option\n  transport: Remove git_transport_options.push_cert\n  config.c: Expose git_parse_maybe_bool\n  builtin/send-pack.c: Use option parsing API\n  Support signing pushes iff the server supports it\n  Add a config option push.gpgSign for default signed pushes\n\n Documentation/config.txt            |   8 ++\n Documentation/git-push.txt          |  15 ++-\n Documentation/git-send-pack.txt     |  16 ++-\n Documentation/gitremote-helpers.txt |   3 +\n builtin/push.c                      |  42 +++++++-\n builtin/send-pack.c                 | 192 ++++++++++++++++--------------------\n cache.h                             |   1 +\n config.c                            |   6 +-\n remote-curl.c                       |  16 ++-\n send-pack.c                         |  43 ++++++--\n send-pack.h                         |  12 ++-\n transport-helper.c                  |  34 +++----\n transport.c                         |  11 ++-\n transport.h                         |   6 +-\n 14 files changed, 253 insertions(+), 152 deletions(-)\n\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268312","messageId":"1439998007-28719-2-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 1/9] Documentation/git-push.txt: Document when --signed may fail","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:39Z","receivedAt":"2015-08-19T15:26:39Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Like --atomic, --signed will fail if the server does not advertise the\nnecessary capability. In addition, it requires gpg on the client side.\n\nSigned-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/git-push.txt | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 135d810..da0a98d 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -137,7 +137,9 @@ already exists on the remote side.\n \tGPG-sign the push request to update refs on the receiving\n \tside, to allow it to be checked by the hooks and/or be\n \tlogged.  See linkgit:git-receive-pack[1] for the details\n-\ton the receiving end.\n+\ton the receiving end.  If the attempt to sign with `gpg` fails,\n+\tor if the server does not support signed pushes, the push will\n+\tfail.\n \n --[no-]atomic::\n \tUse an atomic transaction on the remote side if available.\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268315","messageId":"1439998007-28719-3-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 2/9] Documentation/git-send-pack.txt: Flow long synopsis line","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:40Z","receivedAt":"2015-08-19T15:26:40Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Signed-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/git-send-pack.txt | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\nindex b5d09f7..6affff6 100644\n--- a/Documentation/git-send-pack.txt\n+++ b/Documentation/git-send-pack.txt\n@@ -9,7 +9,8 @@ git-send-pack - Push objects over Git protocol to another repository\n SYNOPSIS\n --------\n [verse]\n-'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n+'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]\n+\t\t[--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n \n DESCRIPTION\n -----------\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268318","messageId":"1439998007-28719-4-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 3/9] Documentation/git-send-pack.txt: Document --signed","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:41Z","receivedAt":"2015-08-19T15:26:41Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Signed-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/git-send-pack.txt | 11 ++++++++++-\n 1 file changed, 10 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\nindex 6affff6..0a0a3fb 100644\n--- a/Documentation/git-send-pack.txt\n+++ b/Documentation/git-send-pack.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n --------\n [verse]\n 'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]\n-\t\t[--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n+\t\t[--verbose] [--thin] [--atomic] [--signed]\n+\t\t[<host>:]<directory> [<ref>...]\n \n DESCRIPTION\n -----------\n@@ -68,6 +69,14 @@ be in a separate packet, and the list must end with a flush packet.\n \tfails to update then the entire push will fail without changing any\n \trefs.\n \n+--signed::\n+\tGPG-sign the push request to update refs on the receiving\n+\tside, to allow it to be checked by the hooks and/or be\n+\tlogged.  See linkgit:git-receive-pack[1] for the details\n+\ton the receiving end.  If the attempt to sign with `gpg` fails,\n+\tor if the server does not support signed pushes, the push will\n+\tfail.\n+\n <host>::\n \tA remote host to house the repository.  When this\n \tpart is specified, 'git-receive-pack' is invoked via\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268314","messageId":"1439998007-28719-5-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 4/9] gitremote-helpers.txt: Document pushcert option","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:42Z","receivedAt":"2015-08-19T15:26:42Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Signed-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/gitremote-helpers.txt | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 82e2d15..78e0b27 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -448,6 +448,9 @@ set by Git if the remote helper has the 'option' capability.\n 'option update-shallow {'true'|'false'}::\n \tAllow to extend .git/shallow if the new refs require it.\n \n+'option pushcert {'true'|'false'}::\n+\tGPG sign pushes.\n+\n SEE ALSO\n --------\n linkgit:git-remote[1]\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268319","messageId":"1439998007-28719-6-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 5/9] transport: Remove git_transport_options.push_cert","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:43Z","receivedAt":"2015-08-19T15:26:43Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"This field was set in transport_set_option, but never read in the push\ncode. The push code basically ignores the smart_options field\nentirely, and derives its options from the flags arguments to the\npush* callbacks. Note that in git_transport_push there are already\nseveral args set from flags that have no corresponding field in\ngit_transport_options; after this change, push_cert is just like\nthose.\n\nSigned-off-by: Dave Borowitz <dborowitz@google.com>\n---\n transport.c | 3 ---\n transport.h | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex 40692f8..3dd6e30 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -476,9 +476,6 @@ static int set_git_option(struct git_transport_options *opts,\n \t\t\t\tdie(\"transport: invalid depth option '%s'\", value);\n \t\t}\n \t\treturn 0;\n-\t} else if (!strcmp(name, TRANS_OPT_PUSH_CERT)) {\n-\t\topts->push_cert = !!value;\n-\t\treturn 0;\n \t}\n \treturn 1;\n }\ndiff --git a/transport.h b/transport.h\nindex 18d2cf8..79190df 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -12,7 +12,6 @@ struct git_transport_options {\n \tunsigned check_self_contained_and_connected : 1;\n \tunsigned self_contained_and_connected : 1;\n \tunsigned update_shallow : 1;\n-\tunsigned push_cert : 1;\n \tint depth;\n \tconst char *uploadpack;\n \tconst char *receivepack;\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268313","messageId":"1439998007-28719-7-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 6/9] config.c: Expose git_parse_maybe_bool","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:44Z","receivedAt":"2015-08-19T15:26:44Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Signed-off-by: Dave Borowitz <dborowitz@google.com>\n---\n cache.h  | 1 +\n config.c | 6 +++---\n 2 files changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 6bb7119..95d9594 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1392,6 +1392,7 @@ extern int git_config_with_options(config_fn_t fn, void *,\n \t\t\t\t   int respect_includes);\n extern int git_config_early(config_fn_t fn, void *, const char *repo_config);\n extern int git_parse_ulong(const char *, unsigned long *);\n+extern int git_parse_maybe_bool(const char *);\n extern int git_config_int(const char *, const char *);\n extern int64_t git_config_int64(const char *, const char *);\n extern unsigned long git_config_ulong(const char *, const char *);\ndiff --git a/config.c b/config.c\nindex 9fd275f..e5d7959 100644\n--- a/config.c\n+++ b/config.c\n@@ -618,7 +618,7 @@ unsigned long git_config_ulong(const char *name, const char *value)\n \treturn ret;\n }\n \n-static int git_config_maybe_bool_text(const char *name, const char *value)\n+int git_parse_maybe_bool(const char *value)\n {\n \tif (!value)\n \t\treturn 1;\n@@ -637,7 +637,7 @@ static int git_config_maybe_bool_text(const char *name, const char *value)\n \n int git_config_maybe_bool(const char *name, const char *value)\n {\n-\tint v = git_config_maybe_bool_text(name, value);\n+\tint v = git_parse_maybe_bool(value);\n \tif (0 <= v)\n \t\treturn v;\n \tif (git_parse_int(value, &v))\n@@ -647,7 +647,7 @@ int git_config_maybe_bool(const char *name, const char *value)\n \n int git_config_bool_or_int(const char *name, const char *value, int *is_bool)\n {\n-\tint v = git_config_maybe_bool_text(name, value);\n+\tint v = git_parse_maybe_bool(value);\n \tif (0 <= v) {\n \t\t*is_bool = 1;\n \t\treturn v;\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268317","messageId":"1439998007-28719-8-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 7/9] builtin/send-pack.c: Use option parsing API","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:45Z","receivedAt":"2015-08-19T15:26:45Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"The old option parsing code in this plumbing command predates this\nAPI, so option parsing was done more manually. Using the new API\nbrings send-pack more in line with push, and accepts new variants\nlike --no-* for negating options.\n\nSigned-off-by: Dave Borowitz <dborowitz@google.com>\n---\n builtin/send-pack.c | 163 +++++++++++++++++++---------------------------------\n 1 file changed, 59 insertions(+), 104 deletions(-)\n\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex 23b2962..5f2c744 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -12,10 +12,15 @@\n #include \"version.h\"\n #include \"sha1-array.h\"\n #include \"gpg-interface.h\"\n+#include \"gettext.h\"\n \n-static const char send_pack_usage[] =\n-\"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\\n\"\n-\"  --all and explicit <ref> specification are mutually exclusive.\";\n+static const char * const send_pack_usage[] = {\n+\tN_(\"git send-pack [--all | --mirror] [--dry-run] [--force] \"\n+\t  \"[--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] \"\n+\t  \"[<host>:]<directory> [<ref>...]\\n\"\n+\t  \"  --all and explicit <ref> specification are mutually exclusive.\"),\n+\tNULL,\n+};\n \n static struct send_pack_args args;\n \n@@ -107,116 +112,66 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \tint ret;\n \tint helper_status = 0;\n \tint send_all = 0;\n+\tint verbose = 0;\n \tconst char *receivepack = \"git-receive-pack\";\n+\tunsigned dry_run = 0;\n+\tunsigned send_mirror = 0;\n+\tunsigned force_update = 0;\n+\tunsigned quiet = 0;\n+\tunsigned push_cert = 0;\n+\tunsigned use_thin_pack = 0;\n+\tunsigned atomic = 0;\n+\tunsigned stateless_rpc = 0;\n \tint flags;\n \tunsigned int reject_reasons;\n \tint progress = -1;\n \tint from_stdin = 0;\n \tstruct push_cas_option cas = {0};\n \n-\tgit_config(git_gpg_config, NULL);\n+\tstruct option options[] = {\n+\t\tOPT__VERBOSITY(&verbose),\n+\t\tOPT_STRING(0, \"receive-pack\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n+\t\tOPT_STRING(0, \"exec\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n+\t\tOPT_STRING(0, \"remote\", &remote_name, \"remote\", N_(\"remote name\")),\n+\t\tOPT_BOOL(0, \"all\", &send_all, N_(\"push all refs\")),\n+\t\tOPT_BOOL('n' , \"dry-run\", &dry_run, N_(\"dry run\")),\n+\t\tOPT_BOOL(0, \"mirror\", &send_mirror, N_(\"mirror all refs\")),\n+\t\tOPT_BOOL('f', \"force\", &force_update, N_(\"force updates\")),\n+\t\tOPT_BOOL(0, \"signed\", &push_cert, N_(\"GPG sign the push\")),\n+\t\tOPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n+\t\tOPT_BOOL(0, \"thin\", &use_thin_pack, N_(\"use thin pack\")),\n+\t\tOPT_BOOL(0, \"atomic\", &atomic, N_(\"request atomic transaction on remote side\")),\n+\t\tOPT_BOOL(0, \"stateless-rpc\", &stateless_rpc, N_(\"use stateless RPC protocol\")),\n+\t\tOPT_BOOL(0, \"stdin\", &from_stdin, N_(\"read refs from stdin\")),\n+\t\tOPT_BOOL(0, \"helper-status\", &helper_status, N_(\"print status from remote helper\")),\n+\t\t{ OPTION_CALLBACK,\n+\t\t  0, CAS_OPT_NAME, &cas, N_(\"refname>:<expect\"),\n+\t\t  N_(\"require old value of ref to be at this value\"),\n+\t\t  PARSE_OPT_OPTARG, parseopt_push_cas_option },\n+\t\tOPT_END()\n+\t};\n \n-\targv++;\n-\tfor (i = 1; i < argc; i++, argv++) {\n-\t\tconst char *arg = *argv;\n-\n-\t\tif (*arg == '-') {\n-\t\t\tif (starts_with(arg, \"--receive-pack=\")) {\n-\t\t\t\treceivepack = arg + 15;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (starts_with(arg, \"--exec=\")) {\n-\t\t\t\treceivepack = arg + 7;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (starts_with(arg, \"--remote=\")) {\n-\t\t\t\tremote_name = arg + 9;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--all\")) {\n-\t\t\t\tsend_all = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--dry-run\")) {\n-\t\t\t\targs.dry_run = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--mirror\")) {\n-\t\t\t\targs.send_mirror = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--force\")) {\n-\t\t\t\targs.force_update = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--quiet\")) {\n-\t\t\t\targs.quiet = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--verbose\")) {\n-\t\t\t\targs.verbose = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--signed\")) {\n-\t\t\t\targs.push_cert = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--progress\")) {\n-\t\t\t\tprogress = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--no-progress\")) {\n-\t\t\t\tprogress = 0;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--thin\")) {\n-\t\t\t\targs.use_thin_pack = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--atomic\")) {\n-\t\t\t\targs.atomic = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--stateless-rpc\")) {\n-\t\t\t\targs.stateless_rpc = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--stdin\")) {\n-\t\t\t\tfrom_stdin = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--helper-status\")) {\n-\t\t\t\thelper_status = 1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--\" CAS_OPT_NAME)) {\n-\t\t\t\tif (parse_push_cas_option(&cas, NULL, 0) < 0)\n-\t\t\t\t\texit(1);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!strcmp(arg, \"--no-\" CAS_OPT_NAME)) {\n-\t\t\t\tif (parse_push_cas_option(&cas, NULL, 1) < 0)\n-\t\t\t\t\texit(1);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (starts_with(arg, \"--\" CAS_OPT_NAME \"=\")) {\n-\t\t\t\tif (parse_push_cas_option(&cas,\n-\t\t\t\t\t\t\t  strchr(arg, '=') + 1, 0) < 0)\n-\t\t\t\t\texit(1);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tusage(send_pack_usage);\n-\t\t}\n-\t\tif (!dest) {\n-\t\t\tdest = arg;\n-\t\t\tcontinue;\n-\t\t}\n-\t\trefspecs = (const char **) argv;\n-\t\tnr_refspecs = argc - i;\n-\t\tbreak;\n+\tgit_config(git_gpg_config, NULL);\n+\targc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);\n+\tif (argc > 0) {\n+\t\tdest = argv[0];\n+\t\trefspecs = (const char **)(argv + 1);\n+\t\tnr_refspecs = argc - 1;\n \t}\n+\n \tif (!dest)\n-\t\tusage(send_pack_usage);\n+\t\tusage_with_options(send_pack_usage, options);\n+\n+\targs.verbose = verbose;\n+\targs.dry_run = dry_run;\n+\targs.send_mirror = send_mirror;\n+\targs.force_update = force_update;\n+\targs.quiet = quiet;\n+\targs.push_cert = push_cert;\n+\targs.progress = progress;\n+\targs.use_thin_pack = use_thin_pack;\n+\targs.atomic = atomic;\n+\targs.stateless_rpc = stateless_rpc;\n \n \tif (from_stdin) {\n \t\tstruct argv_array all_refspecs = ARGV_ARRAY_INIT;\n@@ -245,7 +200,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t */\n \tif ((refspecs && (send_all || args.send_mirror)) ||\n \t    (send_all && args.send_mirror))\n-\t\tusage(send_pack_usage);\n+\t\tusage_with_options(send_pack_usage, options);\n \n \tif (remote_name) {\n \t\tremote = remote_get(remote_name);\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268316","messageId":"1439998007-28719-9-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 8/9] Support signing pushes iff the server supports it","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:46Z","receivedAt":"2015-08-19T15:26:46Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Add a new flag --signed-if-possible to push and send-pack that sends a\npush certificate if and only if the server advertised a push cert\nnonce. If not, at least warn the user that their push may not be as\nsecure as they thought.\n\nSigned-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/git-push.txt      | 17 +++++++++-------\n Documentation/git-send-pack.txt | 16 +++++++++------\n builtin/push.c                  | 20 ++++++++++++++++++-\n builtin/send-pack.c             |  6 ++++--\n remote-curl.c                   | 16 ++++++++++-----\n send-pack.c                     | 43 ++++++++++++++++++++++++++++++++++-------\n send-pack.h                     | 12 +++++++++++-\n transport-helper.c              | 34 ++++++++++++++++----------------\n transport.c                     |  8 +++++++-\n transport.h                     |  5 +++--\n 10 files changed, 128 insertions(+), 49 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex da0a98d..1495e34 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -11,7 +11,8 @@ SYNOPSIS\n [verse]\n 'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]\n \t   [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose]\n-\t   [-u | --set-upstream] [--signed]\n+\t   [-u | --set-upstream]\n+\t   [--[no-]signed|--sign=(true|false|if-asked)]\n \t   [--force-with-lease[=<refname>[:<expect>]]]\n \t   [--no-verify] [<repository> [<refspec>...]]\n \n@@ -132,14 +133,16 @@ already exists on the remote side.\n \twith configuration variable 'push.followTags'.  For more\n \tinformation, see 'push.followTags' in linkgit:git-config[1].\n \n-\n---signed::\n+--[no-]signed::\n+--sign=(true|false|if-asked)::\n \tGPG-sign the push request to update refs on the receiving\n \tside, to allow it to be checked by the hooks and/or be\n-\tlogged.  See linkgit:git-receive-pack[1] for the details\n-\ton the receiving end.  If the attempt to sign with `gpg` fails,\n-\tor if the server does not support signed pushes, the push will\n-\tfail.\n+\tlogged.  If `false` or `--no-signed`, no signing will be\n+\tattempted.  If `true` or `--signed`, the push will fail if the\n+\tserver does not support signed pushes.  If set to `if-asked`,\n+\tsign if and only if the server supports signed pushes.  The push\n+\twill also fail if the actual call to `gpg --sign` fails.  See\n+\tlinkgit:git-receive-pack[1] for the details on the receiving end.\n \n --[no-]atomic::\n \tUse an atomic transaction on the remote side if available.\ndiff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\nindex 0a0a3fb..6aa91e8 100644\n--- a/Documentation/git-send-pack.txt\n+++ b/Documentation/git-send-pack.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n --------\n [verse]\n 'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]\n-\t\t[--verbose] [--thin] [--atomic] [--signed]\n+\t\t[--verbose] [--thin] [--atomic]\n+\t\t[--[no-]signed|--sign=(true|false|if-asked)]\n \t\t[<host>:]<directory> [<ref>...]\n \n DESCRIPTION\n@@ -69,13 +70,16 @@ be in a separate packet, and the list must end with a flush packet.\n \tfails to update then the entire push will fail without changing any\n \trefs.\n \n---signed::\n+--[no-]signed::\n+--sign=(true|false|if-asked)::\n \tGPG-sign the push request to update refs on the receiving\n \tside, to allow it to be checked by the hooks and/or be\n-\tlogged.  See linkgit:git-receive-pack[1] for the details\n-\ton the receiving end.  If the attempt to sign with `gpg` fails,\n-\tor if the server does not support signed pushes, the push will\n-\tfail.\n+\tlogged.  If `false` or `--no-signed`, no signing will be\n+\tattempted.  If `true` or `--signed`, the push will fail if the\n+\tserver does not support signed pushes.  If set to `if-asked`,\n+\tsign if and only if the server supports signed pushes.  The push\n+\twill also fail if the actual call to `gpg --sign` fails.  See\n+\tlinkgit:git-receive-pack[1] for the details on the receiving end.\n \n <host>::\n \tA remote host to house the repository.  When this\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 57c138b..85a82cd 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -9,6 +9,7 @@\n #include \"transport.h\"\n #include \"parse-options.h\"\n #include \"submodule.h\"\n+#include \"send-pack.h\"\n \n static const char * const push_usage[] = {\n \tN_(\"git push [<options>] [<repository> [<refspec>...]]\"),\n@@ -495,6 +496,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n {\n \tint flags = 0;\n \tint tags = 0;\n+\tint push_cert = -1;\n \tint rc;\n \tconst char *repo = NULL;\t/* default repository */\n \tstruct option options[] = {\n@@ -526,7 +528,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"no-verify\", &flags, N_(\"bypass pre-push hook\"), TRANSPORT_PUSH_NO_HOOK),\n \t\tOPT_BIT(0, \"follow-tags\", &flags, N_(\"push missing but relevant tags\"),\n \t\t\tTRANSPORT_PUSH_FOLLOW_TAGS),\n-\t\tOPT_BIT(0, \"signed\", &flags, N_(\"GPG sign the push\"), TRANSPORT_PUSH_CERT),\n+\t\t{ OPTION_CALLBACK,\n+\t\t  0, \"signed\", &push_cert, \"yes|no|if-asked\", N_(\"GPG sign the push\"),\n+\t\t  PARSE_OPT_OPTARG, option_parse_push_signed },\n \t\tOPT_BIT(0, \"atomic\", &flags, N_(\"request atomic transaction on remote side\"), TRANSPORT_PUSH_ATOMIC),\n \t\tOPT_END()\n \t};\n@@ -548,6 +552,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tset_refspecs(argv + 1, argc - 1, repo);\n \t}\n \n+\tswitch (push_cert) {\n+\tcase SEND_PACK_PUSH_CERT_NEVER:\n+\t\tflags &= ~(TRANSPORT_PUSH_CERT_ALWAYS | TRANSPORT_PUSH_CERT_IF_ASKED);\n+\t\tbreak;\n+\tcase SEND_PACK_PUSH_CERT_ALWAYS:\n+\t\tflags |= TRANSPORT_PUSH_CERT_ALWAYS;\n+\t\tflags &= ~TRANSPORT_PUSH_CERT_IF_ASKED;\n+\t\tbreak;\n+\tcase SEND_PACK_PUSH_CERT_IF_ASKED:\n+\t\tflags |= TRANSPORT_PUSH_CERT_IF_ASKED;\n+\t\tflags &= ~TRANSPORT_PUSH_CERT_ALWAYS;\n+\t\tbreak;\n+\t}\n+\n \trc = do_push(repo, flags);\n \tif (rc == -1)\n \t\tusage_with_options(push_usage, options);\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex 5f2c744..0ce3bc8 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -118,7 +118,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \tunsigned send_mirror = 0;\n \tunsigned force_update = 0;\n \tunsigned quiet = 0;\n-\tunsigned push_cert = 0;\n+\tint push_cert = 0;\n \tunsigned use_thin_pack = 0;\n \tunsigned atomic = 0;\n \tunsigned stateless_rpc = 0;\n@@ -137,7 +137,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL('n' , \"dry-run\", &dry_run, N_(\"dry run\")),\n \t\tOPT_BOOL(0, \"mirror\", &send_mirror, N_(\"mirror all refs\")),\n \t\tOPT_BOOL('f', \"force\", &force_update, N_(\"force updates\")),\n-\t\tOPT_BOOL(0, \"signed\", &push_cert, N_(\"GPG sign the push\")),\n+\t\t{ OPTION_CALLBACK,\n+\t\t  0, \"signed\", &push_cert, \"yes|no|if-asked\", N_(\"GPG sign the push\"),\n+\t\t  PARSE_OPT_OPTARG, option_parse_push_signed },\n \t\tOPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n \t\tOPT_BOOL(0, \"thin\", &use_thin_pack, N_(\"use thin pack\")),\n \t\tOPT_BOOL(0, \"atomic\", &atomic, N_(\"request atomic transaction on remote side\")),\ndiff --git a/remote-curl.c b/remote-curl.c\nindex af7b678..71fbbb6 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -11,6 +11,7 @@\n #include \"argv-array.h\"\n #include \"credential.h\"\n #include \"sha1-array.h\"\n+#include \"send-pack.h\"\n \n static struct remote *remote;\n /* always ends with a trailing slash */\n@@ -26,7 +27,8 @@ struct options {\n \t\tfollowtags : 1,\n \t\tdry_run : 1,\n \t\tthin : 1,\n-\t\tpush_cert : 1;\n+\t\t/* One of the SEND_PACK_PUSH_CERT_* constants. */\n+\t\tpush_cert : 2;\n };\n static struct options options;\n static struct string_list cas_options = STRING_LIST_INIT_DUP;\n@@ -109,9 +111,11 @@ static int set_option(const char *name, const char *value)\n \t\treturn 0;\n \t} else if (!strcmp(name, \"pushcert\")) {\n \t\tif (!strcmp(value, \"true\"))\n-\t\t\toptions.push_cert = 1;\n+\t\t\toptions.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;\n \t\telse if (!strcmp(value, \"false\"))\n-\t\t\toptions.push_cert = 0;\n+\t\t\toptions.push_cert = SEND_PACK_PUSH_CERT_NEVER;\n+\t\telse if (!strcmp(value, \"if-asked\"))\n+\t\t\toptions.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;\n \t\telse\n \t\t\treturn -1;\n \t\treturn 0;\n@@ -880,8 +884,10 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)\n \t\targv_array_push(&args, \"--thin\");\n \tif (options.dry_run)\n \t\targv_array_push(&args, \"--dry-run\");\n-\tif (options.push_cert)\n-\t\targv_array_push(&args, \"--signed\");\n+\tif (options.push_cert == SEND_PACK_PUSH_CERT_ALWAYS)\n+\t\targv_array_push(&args, \"--signed=yes\");\n+\telse if (options.push_cert == SEND_PACK_PUSH_CERT_IF_ASKED)\n+\t\targv_array_push(&args, \"--signed=if-asked\");\n \tif (options.verbosity == 0)\n \t\targv_array_push(&args, \"--quiet\");\n \telse if (options.verbosity > 1)\ndiff --git a/send-pack.c b/send-pack.c\nindex 2a64fec..c6a4030 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -12,6 +12,29 @@\n #include \"version.h\"\n #include \"sha1-array.h\"\n #include \"gpg-interface.h\"\n+#include \"cache.h\"\n+\n+int option_parse_push_signed(const struct option *opt,\n+\t\t\t     const char *arg, int unset)\n+{\n+\tif (unset) {\n+\t\t*(int *)(opt->value) = SEND_PACK_PUSH_CERT_NEVER;\n+\t\treturn 0;\n+\t}\n+\tswitch (git_parse_maybe_bool(arg)) {\n+\tcase 1:\n+\t\t*(int *)(opt->value) = SEND_PACK_PUSH_CERT_ALWAYS;\n+\t\treturn 0;\n+\tcase 0:\n+\t\t*(int *)(opt->value) = SEND_PACK_PUSH_CERT_NEVER;\n+\t\treturn 0;\n+\t}\n+\tif (!strcasecmp(\"if-asked\", arg)) {\n+\t\t*(int *)(opt->value) = SEND_PACK_PUSH_CERT_IF_ASKED;\n+\t\treturn 0;\n+\t}\n+\tdie(\"bad %s argument: %s\", opt->long_name, arg);\n+}\n \n static int feed_object(const unsigned char *sha1, int fd, int negative)\n {\n@@ -370,14 +393,20 @@ int send_pack(struct send_pack_args *args,\n \t\targs->use_thin_pack = 0;\n \tif (server_supports(\"atomic\"))\n \t\tatomic_supported = 1;\n-\tif (args->push_cert) {\n-\t\tint len;\n \n+\tif (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {\n+\t\tint len;\n \t\tpush_cert_nonce = server_feature_value(\"push-cert\", &len);\n-\t\tif (!push_cert_nonce)\n+\t\tif (push_cert_nonce) {\n+\t\t\treject_invalid_nonce(push_cert_nonce, len);\n+\t\t\tpush_cert_nonce = xmemdupz(push_cert_nonce, len);\n+\t\t} else if (args->push_cert == SEND_PACK_PUSH_CERT_ALWAYS) {\n \t\t\tdie(_(\"the receiving end does not support --signed push\"));\n-\t\treject_invalid_nonce(push_cert_nonce, len);\n-\t\tpush_cert_nonce = xmemdupz(push_cert_nonce, len);\n+\t\t} else if (args->push_cert == SEND_PACK_PUSH_CERT_IF_ASKED) {\n+\t\t\twarning(_(\"not sending a push certificate since the\"\n+\t\t\t\t  \" receiving end does not support --signed\"\n+\t\t\t\t  \" push\"));\n+\t\t}\n \t}\n \n \tif (!remote_refs) {\n@@ -413,7 +442,7 @@ int send_pack(struct send_pack_args *args,\n \tif (!args->dry_run)\n \t\tadvertise_shallow_grafts_buf(&req_buf);\n \n-\tif (!args->dry_run && args->push_cert)\n+\tif (!args->dry_run && push_cert_nonce)\n \t\tcmds_sent = generate_push_cert(&req_buf, remote_refs, args,\n \t\t\t\t\t       cap_buf.buf, push_cert_nonce);\n \n@@ -452,7 +481,7 @@ int send_pack(struct send_pack_args *args,\n \tfor (ref = remote_refs; ref; ref = ref->next) {\n \t\tchar *old_hex, *new_hex;\n \n-\t\tif (args->dry_run || args->push_cert)\n+\t\tif (args->dry_run || push_cert_nonce)\n \t\t\tcontinue;\n \n \t\tif (check_to_send_update(ref, args) < 0)\ndiff --git a/send-pack.h b/send-pack.h\nindex b664648..57f222a 100644\n--- a/send-pack.h\n+++ b/send-pack.h\n@@ -1,6 +1,11 @@\n #ifndef SEND_PACK_H\n #define SEND_PACK_H\n \n+/* Possible values for push_cert field in send_pack_args. */\n+#define SEND_PACK_PUSH_CERT_NEVER 0\n+#define SEND_PACK_PUSH_CERT_IF_ASKED 1\n+#define SEND_PACK_PUSH_CERT_ALWAYS 2\n+\n struct send_pack_args {\n \tconst char *url;\n \tunsigned verbose:1,\n@@ -12,11 +17,16 @@ struct send_pack_args {\n \t\tuse_thin_pack:1,\n \t\tuse_ofs_delta:1,\n \t\tdry_run:1,\n-\t\tpush_cert:1,\n+\t\t/* One of the SEND_PACK_PUSH_CERT_* constants. */\n+\t\tpush_cert:2,\n \t\tstateless_rpc:1,\n \t\tatomic:1;\n };\n \n+struct option;\n+int option_parse_push_signed(const struct option *opt,\n+\t\t\t     const char *arg, int unset);\n+\n int send_pack(struct send_pack_args *args,\n \t      int fd[], struct child_process *conn,\n \t      struct ref *remote_refs, struct sha1_array *extra_have);\ndiff --git a/transport-helper.c b/transport-helper.c\nindex 5d99a6b..fd5723f 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -257,7 +257,6 @@ static const char *boolean_options[] = {\n \tTRANS_OPT_THIN,\n \tTRANS_OPT_KEEP,\n \tTRANS_OPT_FOLLOWTAGS,\n-\tTRANS_OPT_PUSH_CERT\n \t};\n \n static int set_helper_option(struct transport *transport,\n@@ -763,6 +762,21 @@ static int push_update_refs_status(struct helper_data *data,\n \treturn ret;\n }\n \n+static void set_common_push_options(struct transport *transport,\n+\t\t\t\t   const char *name, int flags)\n+{\n+\tif (flags & TRANSPORT_PUSH_DRY_RUN) {\n+\t\tif (set_helper_option(transport, \"dry-run\", \"true\") != 0)\n+\t\t\tdie(\"helper %s does not support dry-run\", name);\n+\t} else if (flags & TRANSPORT_PUSH_CERT_ALWAYS) {\n+\t\tif (set_helper_option(transport, TRANS_OPT_PUSH_CERT, \"true\") != 0)\n+\t\t\tdie(\"helper %s does not support --signed\", name);\n+\t} else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED) {\n+\t\tif (set_helper_option(transport, TRANS_OPT_PUSH_CERT, \"if-asked\") != 0)\n+\t\t\tdie(\"helper %s does not support --signed=if-asked\", name);\n+\t}\n+}\n+\n static int push_refs_with_push(struct transport *transport,\n \t\t\t       struct ref *remote_refs, int flags)\n {\n@@ -830,14 +844,7 @@ static int push_refs_with_push(struct transport *transport,\n \n \tfor_each_string_list_item(cas_option, &cas_options)\n \t\tset_helper_option(transport, \"cas\", cas_option->string);\n-\n-\tif (flags & TRANSPORT_PUSH_DRY_RUN) {\n-\t\tif (set_helper_option(transport, \"dry-run\", \"true\") != 0)\n-\t\t\tdie(\"helper %s does not support dry-run\", data->name);\n-\t} else if (flags & TRANSPORT_PUSH_CERT) {\n-\t\tif (set_helper_option(transport, TRANS_OPT_PUSH_CERT, \"true\") != 0)\n-\t\t\tdie(\"helper %s does not support --signed\", data->name);\n-\t}\n+\tset_common_push_options(transport, data->name, flags);\n \n \tstrbuf_addch(&buf, '\\n');\n \tsendline(data, &buf);\n@@ -858,14 +865,7 @@ static int push_refs_with_export(struct transport *transport,\n \tif (!data->refspecs)\n \t\tdie(\"remote-helper doesn't support push; refspec needed\");\n \n-\tif (flags & TRANSPORT_PUSH_DRY_RUN) {\n-\t\tif (set_helper_option(transport, \"dry-run\", \"true\") != 0)\n-\t\t\tdie(\"helper %s does not support dry-run\", data->name);\n-\t} else if (flags & TRANSPORT_PUSH_CERT) {\n-\t\tif (set_helper_option(transport, TRANS_OPT_PUSH_CERT, \"true\") != 0)\n-\t\t\tdie(\"helper %s does not support --signed\", data->name);\n-\t}\n-\n+\tset_common_push_options(transport, data->name, flags);\n \tif (flags & TRANSPORT_PUSH_FORCE) {\n \t\tif (set_helper_option(transport, \"force\", \"true\") != 0)\n \t\t\twarning(\"helper %s does not support 'force'\", data->name);\ndiff --git a/transport.c b/transport.c\nindex 3dd6e30..ebe3b3b 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -826,10 +826,16 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re\n \targs.progress = transport->progress;\n \targs.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);\n \targs.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);\n-\targs.push_cert = !!(flags & TRANSPORT_PUSH_CERT);\n \targs.atomic = !!(flags & TRANSPORT_PUSH_ATOMIC);\n \targs.url = transport->url;\n \n+\tif (flags & TRANSPORT_PUSH_CERT_ALWAYS)\n+\t\targs.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;\n+\telse if (flags & TRANSPORT_PUSH_CERT_IF_ASKED)\n+\t\targs.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;\n+\telse\n+\t\targs.push_cert = SEND_PACK_PUSH_CERT_NEVER;\n+\n \tret = send_pack(&args, data->fd, data->conn, remote_refs,\n \t\t\t&data->extra_have);\n \ndiff --git a/transport.h b/transport.h\nindex 79190df..d682b77 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -123,8 +123,9 @@ struct transport {\n #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256\n #define TRANSPORT_PUSH_NO_HOOK 512\n #define TRANSPORT_PUSH_FOLLOW_TAGS 1024\n-#define TRANSPORT_PUSH_CERT 2048\n-#define TRANSPORT_PUSH_ATOMIC 4096\n+#define TRANSPORT_PUSH_CERT_ALWAYS 2048\n+#define TRANSPORT_PUSH_CERT_IF_ASKED 4096\n+#define TRANSPORT_PUSH_ATOMIC 8192\n \n #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)\n #define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268311","messageId":"1439998007-28719-10-git-send-email-dborowitz@google.com","threadId":"40131","inReplyTo":"1439998007-28719-1-git-send-email-dborowitz@google.com","subject":"[PATCH v2 9/9] Add a config option push.gpgSign for default signed pushes","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T15:26:47Z","receivedAt":"2015-08-19T15:26:47Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"Signed-off-by: Dave Borowitz <dborowitz@google.com>\n---\n Documentation/config.txt |  8 ++++++++\n builtin/push.c           | 50 ++++++++++++++++++++++++++++++++++--------------\n builtin/send-pack.c      | 27 +++++++++++++++++++++++++-\n 3 files changed, 70 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 016f6e9..4ba0e4b 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2178,6 +2178,14 @@ push.followTags::\n \tmay override this configuration at time of push by specifying\n \t'--no-follow-tags'.\n \n+push.gpgSign::\n+\tMay be set to a boolean value, or the string 'if-asked'. A true\n+\tvalue causes all pushes to be GPG signed, as if '--signed' is\n+\tpassed to linkgit:git-push[1]. The string 'if-asked' causes\n+\tpushes to be signed if the server supports it, as if\n+\t'--signed=if-asked' is passed to 'git push'. A false value may\n+\toverride a value from a lower-priority config file. An explicit\n+\tcommand-line flag always overrides this config option.\n \n rebase.stat::\n \tWhether to show a diffstat of what changed upstream since the last\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 85a82cd..3bda430 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -472,6 +472,24 @@ static int option_parse_recurse_submodules(const struct option *opt,\n \treturn 0;\n }\n \n+static void set_push_cert_flags(int *flags, int v)\n+{\n+\tswitch (v) {\n+\tcase SEND_PACK_PUSH_CERT_NEVER:\n+\t\t*flags &= ~(TRANSPORT_PUSH_CERT_ALWAYS | TRANSPORT_PUSH_CERT_IF_ASKED);\n+\t\tbreak;\n+\tcase SEND_PACK_PUSH_CERT_ALWAYS:\n+\t\t*flags |= TRANSPORT_PUSH_CERT_ALWAYS;\n+\t\t*flags &= ~TRANSPORT_PUSH_CERT_IF_ASKED;\n+\t\tbreak;\n+\tcase SEND_PACK_PUSH_CERT_IF_ASKED:\n+\t\t*flags |= TRANSPORT_PUSH_CERT_IF_ASKED;\n+\t\t*flags &= ~TRANSPORT_PUSH_CERT_ALWAYS;\n+\t\tbreak;\n+\t}\n+}\n+\n+\n static int git_push_config(const char *k, const char *v, void *cb)\n {\n \tint *flags = cb;\n@@ -487,6 +505,23 @@ static int git_push_config(const char *k, const char *v, void *cb)\n \t\telse\n \t\t\t*flags &= ~TRANSPORT_PUSH_FOLLOW_TAGS;\n \t\treturn 0;\n+\t} else if (!strcmp(k, \"push.gpgsign\")) {\n+\t\tconst char *value;\n+\t\tif (!git_config_get_value(\"push.gpgsign\", &value)) {\n+\t\t\tswitch (git_config_maybe_bool(\"push.gpgsign\", value)) {\n+\t\t\tcase 0:\n+\t\t\t\tset_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);\n+\t\t\t\tbreak;\n+\t\t\tcase 1:\n+\t\t\t\tset_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tif (value && !strcasecmp(value, \"if-asked\"))\n+\t\t\t\t\tset_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);\n+\t\t\t\telse\n+\t\t\t\t\treturn error(\"Invalid value for '%s'\", k);\n+\t\t\t}\n+\t\t}\n \t}\n \n \treturn git_default_config(k, v, NULL);\n@@ -538,6 +573,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \tpacket_trace_identity(\"push\");\n \tgit_config(git_push_config, &flags);\n \targc = parse_options(argc, argv, prefix, options, push_usage, 0);\n+\tset_push_cert_flags(&flags, push_cert);\n \n \tif (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))\n \t\tdie(_(\"--delete is incompatible with --all, --mirror and --tags\"));\n@@ -552,20 +588,6 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tset_refspecs(argv + 1, argc - 1, repo);\n \t}\n \n-\tswitch (push_cert) {\n-\tcase SEND_PACK_PUSH_CERT_NEVER:\n-\t\tflags &= ~(TRANSPORT_PUSH_CERT_ALWAYS | TRANSPORT_PUSH_CERT_IF_ASKED);\n-\t\tbreak;\n-\tcase SEND_PACK_PUSH_CERT_ALWAYS:\n-\t\tflags |= TRANSPORT_PUSH_CERT_ALWAYS;\n-\t\tflags &= ~TRANSPORT_PUSH_CERT_IF_ASKED;\n-\t\tbreak;\n-\tcase SEND_PACK_PUSH_CERT_IF_ASKED:\n-\t\tflags |= TRANSPORT_PUSH_CERT_IF_ASKED;\n-\t\tflags &= ~TRANSPORT_PUSH_CERT_ALWAYS;\n-\t\tbreak;\n-\t}\n-\n \trc = do_push(repo, flags);\n \tif (rc == -1)\n \t\tusage_with_options(push_usage, options);\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex 0ce3bc8..f6e5d64 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -97,6 +97,31 @@ static void print_helper_status(struct ref *ref)\n \tstrbuf_release(&buf);\n }\n \n+static int send_pack_config(const char *k, const char *v, void *cb)\n+{\n+\tgit_gpg_config(k, v, NULL);\n+\n+\tif (!strcmp(k, \"push.gpgsign\")) {\n+\t\tconst char *value;\n+\t\tif (!git_config_get_value(\"push.gpgsign\", &value)) {\n+\t\t\tswitch (git_config_maybe_bool(\"push.gpgsign\", value)) {\n+\t\t\tcase 0:\n+\t\t\t\targs.push_cert = SEND_PACK_PUSH_CERT_NEVER;\n+\t\t\t\tbreak;\n+\t\t\tcase 1:\n+\t\t\t\targs.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tif (value && !strcasecmp(value, \"if-asked\"))\n+\t\t\t\t\targs.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;\n+\t\t\t\telse\n+\t\t\t\t\treturn error(\"Invalid value for '%s'\", k);\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n int cmd_send_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, nr_refspecs = 0;\n@@ -153,7 +178,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_gpg_config, NULL);\n+\tgit_config(send_pack_config, NULL);\n \targc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);\n \tif (argc > 0) {\n \t\tdest = argv[0];\n-- \n2.5.0.276.gf5e568e\n"},{"id":"268332","messageId":"CAGZ79kYSNAqsaj-rWvt1fSbNd+LPpeSSACcX5kHNZPe9+brLiw@mail.gmail.com","threadId":"40131","inReplyTo":"1439998007-28719-8-git-send-email-dborowitz@google.com","subject":"Re: [PATCH v2 7/9] builtin/send-pack.c: Use option parsing API","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2015-08-19T18:00:07Z","receivedAt":"2015-08-19T18:00:07Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Aug 19, 2015 at 8:26 AM, Dave Borowitz <dborowitz@google.com> wrote:\n> The old option parsing code in this plumbing command predates this\n> API, so option parsing was done more manually. Using the new API\n> brings send-pack more in line with push, and accepts new variants\n> like --no-* for negating options.\n>\n> Signed-off-by: Dave Borowitz <dborowitz@google.com>\n> ---\n>  builtin/send-pack.c | 163 +++++++++++++++++++---------------------------------\n>  1 file changed, 59 insertions(+), 104 deletions(-)\n>\n> diff --git a/builtin/send-pack.c b/builtin/send-pack.c\n> index 23b2962..5f2c744 100644\n> --- a/builtin/send-pack.c\n> +++ b/builtin/send-pack.c\n> @@ -12,10 +12,15 @@\n>  #include \"version.h\"\n>  #include \"sha1-array.h\"\n>  #include \"gpg-interface.h\"\n> +#include \"gettext.h\"\n>\n> -static const char send_pack_usage[] =\n> -\"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\\n\"\n> -\"  --all and explicit <ref> specification are mutually exclusive.\";\n> +static const char * const send_pack_usage[] = {\n> +       N_(\"git send-pack [--all | --mirror] [--dry-run] [--force] \"\n> +         \"[--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] \"\n> +         \"[<host>:]<directory> [<ref>...]\\n\"\n> +         \"  --all and explicit <ref> specification are mutually exclusive.\"),\n> +       NULL,\n> +};\n>\n>  static struct send_pack_args args;\n>\n> @@ -107,116 +112,66 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n>         int ret;\n>         int helper_status = 0;\n>         int send_all = 0;\n> +       int verbose = 0;\n>         const char *receivepack = \"git-receive-pack\";\n> +       unsigned dry_run = 0;\n> +       unsigned send_mirror = 0;\n> +       unsigned force_update = 0;\n> +       unsigned quiet = 0;\n> +       unsigned push_cert = 0;\n> +       unsigned use_thin_pack = 0;\n> +       unsigned atomic = 0;\n> +       unsigned stateless_rpc = 0;\n\nFirst I thought:\n    You could write to the args flags directly from the options. No\nneed to have (most of)\n    the variables around here and copy over the values. You'd need to\nuse OPT_BIT instead\n    for setting a specific bit though\nbut then I realized we do not have a direct bit field in args, which\nwould make it a bit unreadable.\n\n>         int flags;\n>         unsigned int reject_reasons;\n>         int progress = -1;\n>         int from_stdin = 0;\n>         struct push_cas_option cas = {0};\n>\n> -       git_config(git_gpg_config, NULL);\n> +       struct option options[] = {\n> +               OPT__VERBOSITY(&verbose),\n> +               OPT_STRING(0, \"receive-pack\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n> +               OPT_STRING(0, \"exec\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n> +               OPT_STRING(0, \"remote\", &remote_name, \"remote\", N_(\"remote name\")),\n> +               OPT_BOOL(0, \"all\", &send_all, N_(\"push all refs\")),\n> +               OPT_BOOL('n' , \"dry-run\", &dry_run, N_(\"dry run\")),\n> +               OPT_BOOL(0, \"mirror\", &send_mirror, N_(\"mirror all refs\")),\n> +               OPT_BOOL('f', \"force\", &force_update, N_(\"force updates\")),\n\n-f and -n are new here now?\n\n> +               OPT_BOOL(0, \"signed\", &push_cert, N_(\"GPG sign the push\")),\n> +               OPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n> +               OPT_BOOL(0, \"thin\", &use_thin_pack, N_(\"use thin pack\")),\n> +               OPT_BOOL(0, \"atomic\", &atomic, N_(\"request atomic transaction on remote side\")),\n> +               OPT_BOOL(0, \"stateless-rpc\", &stateless_rpc, N_(\"use stateless RPC protocol\")),\n> +               OPT_BOOL(0, \"stdin\", &from_stdin, N_(\"read refs from stdin\")),\n> +               OPT_BOOL(0, \"helper-status\", &helper_status, N_(\"print status from remote helper\")),\n> +               { OPTION_CALLBACK,\n> +                 0, CAS_OPT_NAME, &cas, N_(\"refname>:<expect\"),\n> +                 N_(\"require old value of ref to be at this value\"),\n> +                 PARSE_OPT_OPTARG, parseopt_push_cas_option },\n> +               OPT_END()\n> +       };\n>\n> -       argv++;\n> -       for (i = 1; i < argc; i++, argv++) {\n> -               const char *arg = *argv;\n> -\n> -               if (*arg == '-') {\n> -                       if (starts_with(arg, \"--receive-pack=\")) {\n> -                               receivepack = arg + 15;\n> -                               continue;\n> -                       }\n> -                       if (starts_with(arg, \"--exec=\")) {\n> -                               receivepack = arg + 7;\n> -                               continue;\n> -                       }\n> -                       if (starts_with(arg, \"--remote=\")) {\n> -                               remote_name = arg + 9;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--all\")) {\n> -                               send_all = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--dry-run\")) {\n> -                               args.dry_run = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--mirror\")) {\n> -                               args.send_mirror = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--force\")) {\n> -                               args.force_update = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--quiet\")) {\n> -                               args.quiet = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--verbose\")) {\n> -                               args.verbose = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--signed\")) {\n> -                               args.push_cert = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--progress\")) {\n> -                               progress = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--no-progress\")) {\n> -                               progress = 0;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--thin\")) {\n> -                               args.use_thin_pack = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--atomic\")) {\n> -                               args.atomic = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--stateless-rpc\")) {\n> -                               args.stateless_rpc = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--stdin\")) {\n> -                               from_stdin = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--helper-status\")) {\n> -                               helper_status = 1;\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--\" CAS_OPT_NAME)) {\n> -                               if (parse_push_cas_option(&cas, NULL, 0) < 0)\n> -                                       exit(1);\n> -                               continue;\n> -                       }\n> -                       if (!strcmp(arg, \"--no-\" CAS_OPT_NAME)) {\n> -                               if (parse_push_cas_option(&cas, NULL, 1) < 0)\n> -                                       exit(1);\n> -                               continue;\n> -                       }\n> -                       if (starts_with(arg, \"--\" CAS_OPT_NAME \"=\")) {\n> -                               if (parse_push_cas_option(&cas,\n> -                                                         strchr(arg, '=') + 1, 0) < 0)\n> -                                       exit(1);\n> -                               continue;\n> -                       }\n> -                       usage(send_pack_usage);\n> -               }\n> -               if (!dest) {\n> -                       dest = arg;\n> -                       continue;\n> -               }\n> -               refspecs = (const char **) argv;\n> -               nr_refspecs = argc - i;\n> -               break;\n> +       git_config(git_gpg_config, NULL);\n> +       argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);\n> +       if (argc > 0) {\n> +               dest = argv[0];\n> +               refspecs = (const char **)(argv + 1);\n> +               nr_refspecs = argc - 1;\n>         }\n> +\n>         if (!dest)\n> -               usage(send_pack_usage);\n> +               usage_with_options(send_pack_usage, options);\n> +\n> +       args.verbose = verbose;\n> +       args.dry_run = dry_run;\n> +       args.send_mirror = send_mirror;\n> +       args.force_update = force_update;\n> +       args.quiet = quiet;\n> +       args.push_cert = push_cert;\n> +       args.progress = progress;\n> +       args.use_thin_pack = use_thin_pack;\n> +       args.atomic = atomic;\n> +       args.stateless_rpc = stateless_rpc;\n>\n>         if (from_stdin) {\n>                 struct argv_array all_refspecs = ARGV_ARRAY_INIT;\n> @@ -245,7 +200,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n>          */\n>         if ((refspecs && (send_all || args.send_mirror)) ||\n>             (send_all && args.send_mirror))\n> -               usage(send_pack_usage);\n> +               usage_with_options(send_pack_usage, options);\n>\n>         if (remote_name) {\n>                 remote = remote_get(remote_name);\n> --\n> 2.5.0.276.gf5e568e\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"268341","messageId":"CAD0k6qSp5af+N9QvjAxw1M19ytzh_n4repFA1+5Nq6v+px+fPw@mail.gmail.com","threadId":"40131","inReplyTo":"CAGZ79kYSNAqsaj-rWvt1fSbNd+LPpeSSACcX5kHNZPe9+brLiw@mail.gmail.com","subject":"Re: [PATCH v2 7/9] builtin/send-pack.c: Use option parsing API","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T19:46:25Z","receivedAt":"2015-08-19T19:46:25Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"On Wed, Aug 19, 2015 at 2:00 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Wed, Aug 19, 2015 at 8:26 AM, Dave Borowitz <dborowitz@google.com> wrote:\n>> The old option parsing code in this plumbing command predates this\n>> API, so option parsing was done more manually. Using the new API\n>> brings send-pack more in line with push, and accepts new variants\n>> like --no-* for negating options.\n>>\n>> Signed-off-by: Dave Borowitz <dborowitz@google.com>\n>> ---\n>>  builtin/send-pack.c | 163 +++++++++++++++++++---------------------------------\n>>  1 file changed, 59 insertions(+), 104 deletions(-)\n>>\n>> diff --git a/builtin/send-pack.c b/builtin/send-pack.c\n>> index 23b2962..5f2c744 100644\n>> --- a/builtin/send-pack.c\n>> +++ b/builtin/send-pack.c\n>> @@ -12,10 +12,15 @@\n>>  #include \"version.h\"\n>>  #include \"sha1-array.h\"\n>>  #include \"gpg-interface.h\"\n>> +#include \"gettext.h\"\n>>\n>> -static const char send_pack_usage[] =\n>> -\"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\\n\"\n>> -\"  --all and explicit <ref> specification are mutually exclusive.\";\n>> +static const char * const send_pack_usage[] = {\n>> +       N_(\"git send-pack [--all | --mirror] [--dry-run] [--force] \"\n>> +         \"[--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] \"\n>> +         \"[<host>:]<directory> [<ref>...]\\n\"\n>> +         \"  --all and explicit <ref> specification are mutually exclusive.\"),\n>> +       NULL,\n>> +};\n>>\n>>  static struct send_pack_args args;\n>>\n>> @@ -107,116 +112,66 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n>>         int ret;\n>>         int helper_status = 0;\n>>         int send_all = 0;\n>> +       int verbose = 0;\n>>         const char *receivepack = \"git-receive-pack\";\n>> +       unsigned dry_run = 0;\n>> +       unsigned send_mirror = 0;\n>> +       unsigned force_update = 0;\n>> +       unsigned quiet = 0;\n>> +       unsigned push_cert = 0;\n>> +       unsigned use_thin_pack = 0;\n>> +       unsigned atomic = 0;\n>> +       unsigned stateless_rpc = 0;\n>\n> First I thought:\n>     You could write to the args flags directly from the options. No\n> need to have (most of)\n>     the variables around here and copy over the values. You'd need to\n> use OPT_BIT instead\n>     for setting a specific bit though\n> but then I realized we do not have a direct bit field in args, which\n> would make it a bit unreadable.\n\nRight, and &args->push_cert etc. is invalid, and I didn't know if it\nwas ok to expand the args struct to be several words longer. But I'm\nnot a C programmer so I'm happy to take suggestions how to make this\nmore idiomatic.\n\n>>         int flags;\n>>         unsigned int reject_reasons;\n>>         int progress = -1;\n>>         int from_stdin = 0;\n>>         struct push_cas_option cas = {0};\n>>\n>> -       git_config(git_gpg_config, NULL);\n>> +       struct option options[] = {\n>> +               OPT__VERBOSITY(&verbose),\n>> +               OPT_STRING(0, \"receive-pack\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n>> +               OPT_STRING(0, \"exec\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n>> +               OPT_STRING(0, \"remote\", &remote_name, \"remote\", N_(\"remote name\")),\n>> +               OPT_BOOL(0, \"all\", &send_all, N_(\"push all refs\")),\n>> +               OPT_BOOL('n' , \"dry-run\", &dry_run, N_(\"dry run\")),\n>> +               OPT_BOOL(0, \"mirror\", &send_mirror, N_(\"mirror all refs\")),\n>> +               OPT_BOOL('f', \"force\", &force_update, N_(\"force updates\")),\n>\n> -f and -n are new here now?\n\nYeah, I was going for consistency with push.c (and also just copy/pasted ;)\n\n>> +               OPT_BOOL(0, \"signed\", &push_cert, N_(\"GPG sign the push\")),\n>> +               OPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n>> +               OPT_BOOL(0, \"thin\", &use_thin_pack, N_(\"use thin pack\")),\n>> +               OPT_BOOL(0, \"atomic\", &atomic, N_(\"request atomic transaction on remote side\")),\n>> +               OPT_BOOL(0, \"stateless-rpc\", &stateless_rpc, N_(\"use stateless RPC protocol\")),\n>> +               OPT_BOOL(0, \"stdin\", &from_stdin, N_(\"read refs from stdin\")),\n>> +               OPT_BOOL(0, \"helper-status\", &helper_status, N_(\"print status from remote helper\")),\n>> +               { OPTION_CALLBACK,\n>> +                 0, CAS_OPT_NAME, &cas, N_(\"refname>:<expect\"),\n>> +                 N_(\"require old value of ref to be at this value\"),\n>> +                 PARSE_OPT_OPTARG, parseopt_push_cas_option },\n>> +               OPT_END()\n>> +       };\n>>\n>> -       argv++;\n>> -       for (i = 1; i < argc; i++, argv++) {\n>> -               const char *arg = *argv;\n>> -\n>> -               if (*arg == '-') {\n>> -                       if (starts_with(arg, \"--receive-pack=\")) {\n>> -                               receivepack = arg + 15;\n>> -                               continue;\n>> -                       }\n>> -                       if (starts_with(arg, \"--exec=\")) {\n>> -                               receivepack = arg + 7;\n>> -                               continue;\n>> -                       }\n>> -                       if (starts_with(arg, \"--remote=\")) {\n>> -                               remote_name = arg + 9;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--all\")) {\n>> -                               send_all = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--dry-run\")) {\n>> -                               args.dry_run = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--mirror\")) {\n>> -                               args.send_mirror = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--force\")) {\n>> -                               args.force_update = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--quiet\")) {\n>> -                               args.quiet = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--verbose\")) {\n>> -                               args.verbose = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--signed\")) {\n>> -                               args.push_cert = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--progress\")) {\n>> -                               progress = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--no-progress\")) {\n>> -                               progress = 0;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--thin\")) {\n>> -                               args.use_thin_pack = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--atomic\")) {\n>> -                               args.atomic = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--stateless-rpc\")) {\n>> -                               args.stateless_rpc = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--stdin\")) {\n>> -                               from_stdin = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--helper-status\")) {\n>> -                               helper_status = 1;\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--\" CAS_OPT_NAME)) {\n>> -                               if (parse_push_cas_option(&cas, NULL, 0) < 0)\n>> -                                       exit(1);\n>> -                               continue;\n>> -                       }\n>> -                       if (!strcmp(arg, \"--no-\" CAS_OPT_NAME)) {\n>> -                               if (parse_push_cas_option(&cas, NULL, 1) < 0)\n>> -                                       exit(1);\n>> -                               continue;\n>> -                       }\n>> -                       if (starts_with(arg, \"--\" CAS_OPT_NAME \"=\")) {\n>> -                               if (parse_push_cas_option(&cas,\n>> -                                                         strchr(arg, '=') + 1, 0) < 0)\n>> -                                       exit(1);\n>> -                               continue;\n>> -                       }\n>> -                       usage(send_pack_usage);\n>> -               }\n>> -               if (!dest) {\n>> -                       dest = arg;\n>> -                       continue;\n>> -               }\n>> -               refspecs = (const char **) argv;\n>> -               nr_refspecs = argc - i;\n>> -               break;\n>> +       git_config(git_gpg_config, NULL);\n>> +       argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);\n>> +       if (argc > 0) {\n>> +               dest = argv[0];\n>> +               refspecs = (const char **)(argv + 1);\n>> +               nr_refspecs = argc - 1;\n>>         }\n>> +\n>>         if (!dest)\n>> -               usage(send_pack_usage);\n>> +               usage_with_options(send_pack_usage, options);\n>> +\n>> +       args.verbose = verbose;\n>> +       args.dry_run = dry_run;\n>> +       args.send_mirror = send_mirror;\n>> +       args.force_update = force_update;\n>> +       args.quiet = quiet;\n>> +       args.push_cert = push_cert;\n>> +       args.progress = progress;\n>> +       args.use_thin_pack = use_thin_pack;\n>> +       args.atomic = atomic;\n>> +       args.stateless_rpc = stateless_rpc;\n>>\n>>         if (from_stdin) {\n>>                 struct argv_array all_refspecs = ARGV_ARRAY_INIT;\n>> @@ -245,7 +200,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n>>          */\n>>         if ((refspecs && (send_all || args.send_mirror)) ||\n>>             (send_all && args.send_mirror))\n>> -               usage(send_pack_usage);\n>> +               usage_with_options(send_pack_usage, options);\n>>\n>>         if (remote_name) {\n>>                 remote = remote_get(remote_name);\n>> --\n>> 2.5.0.276.gf5e568e\n>>\n>> --\n>> To unsubscribe from this list: send the line \"unsubscribe git\" in\n>> the body of a message to majordomo@vger.kernel.org\n>> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"268343","messageId":"xmqqtwrv8328.fsf@gitster.dls.corp.google.com","threadId":"40131","inReplyTo":"1439998007-28719-3-git-send-email-dborowitz@google.com","subject":"Re: [PATCH v2 2/9] Documentation/git-send-pack.txt: Flow long synopsis line","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-19T19:56:47Z","receivedAt":"2015-08-19T19:56:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Dave Borowitz <dborowitz@google.com> writes:\n\n> Signed-off-by: Dave Borowitz <dborowitz@google.com>\n> ---\n>  Documentation/git-send-pack.txt | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\n> index b5d09f7..6affff6 100644\n> --- a/Documentation/git-send-pack.txt\n> +++ b/Documentation/git-send-pack.txt\n> @@ -9,7 +9,8 @@ git-send-pack - Push objects over Git protocol to another repository\n>  SYNOPSIS\n>  --------\n>  [verse]\n> -'git send-pack' [--all] [--dry-run] [--force]\n> [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic]\n> [<host>:]<directory> [<ref>...]\n> +'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]\n> +\t\t[--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n>  \n>  DESCRIPTION\n>  -----------\n\nAs can be expected from the Subject: line, this patch is\nline-wrapped and does not apply ;-)\n\nI've done a trivial fix-up and took the liberty of making the result\nof this step into three lines, not two.  That would make 3/9 look\nmore trivial.\n\nThanks.\n"},{"id":"268345","messageId":"xmqqpp2j82z7.fsf@gitster.dls.corp.google.com","threadId":"40131","inReplyTo":"1439998007-28719-9-git-send-email-dborowitz@google.com","subject":"Re: [PATCH v2 8/9] Support signing pushes iff the server supports it","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-19T19:58:36Z","receivedAt":"2015-08-19T19:58:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Dave Borowitz <dborowitz@google.com> writes:\n\n> Add a new flag --signed-if-possible to push and send-pack that sends a\n> push certificate if and only if the server advertised a push cert\n> nonce. If not, at least warn the user that their push may not be as\n> secure as they thought.\n>\n> Signed-off-by: Dave Borowitz <dborowitz@google.com>\n> ---\n\nObviously, the above description needs updating.  Here is what I've\nqueued tentatively.\n\nThanks.\n\ncommit 32d273dfabb0a70b2839971f5afff7fa86a8f4c2\nAuthor: Dave Borowitz <dborowitz@google.com>\nDate:   Wed Aug 19 11:26:46 2015 -0400\n\n    push: support signing pushes iff the server supports it\n    \n    Add a new flag --sign=true (or --sign=false), which means the same\n    thing as the original --signed (or --no-signed).  Give it a third\n    value --sign=if-asked to tell push and send-pack to send a push\n    certificate if and only if the server advertised a push cert nonce.\n    \n    If not, warn the user that their push may not be as secure as they\n    thought.\n    \n    Signed-off-by: Dave Borowitz <dborowitz@google.com>\n    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n"},{"id":"268346","messageId":"CAD0k6qRtXX3OqeQF_USwiNYA-y+92X65MSJqPKjhNjGka9QXBw@mail.gmail.com","threadId":"40131","inReplyTo":"xmqqtwrv8328.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 2/9] Documentation/git-send-pack.txt: Flow long synopsis line","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T19:59:45Z","receivedAt":"2015-08-19T19:59:45Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"On Wed, Aug 19, 2015 at 3:56 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Dave Borowitz <dborowitz@google.com> writes:\n>\n>> Signed-off-by: Dave Borowitz <dborowitz@google.com>\n>> ---\n>>  Documentation/git-send-pack.txt | 3 ++-\n>>  1 file changed, 2 insertions(+), 1 deletion(-)\n>>\n>> diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\n>> index b5d09f7..6affff6 100644\n>> --- a/Documentation/git-send-pack.txt\n>> +++ b/Documentation/git-send-pack.txt\n>> @@ -9,7 +9,8 @@ git-send-pack - Push objects over Git protocol to another repository\n>>  SYNOPSIS\n>>  --------\n>>  [verse]\n>> -'git send-pack' [--all] [--dry-run] [--force]\n>> [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic]\n>> [<host>:]<directory> [<ref>...]\n>> +'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]\n>> +             [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n>>\n>>  DESCRIPTION\n>>  -----------\n>\n> As can be expected from the Subject: line, this patch is\n> line-wrapped and does not apply ;-)\n\nI produced the patch with \"git format-patch --subject-prefix='PATCH\nv2' --cover-letter @{u}..\" and mailed with \"git send-email\n--to=git@vger.kernel.org,gitster@pobox.com 0*.patch\"; is there a way\nthat would have preserved whitespace better?\n\n> I've done a trivial fix-up and took the liberty of making the result\n> of this step into three lines, not two.  That would make 3/9 look\n> more trivial.\n\nOk by me.\n\n> Thanks.\n"},{"id":"268347","messageId":"CAD0k6qT8azfV296wx-Q1AAjbT1fcVjZBQCuK515DYv_ZfefzdQ@mail.gmail.com","threadId":"40131","inReplyTo":"xmqqpp2j82z7.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 8/9] Support signing pushes iff the server supports it","fromName":"Dave Borowitz","fromEmail":"dborowitz@google.com","sentAt":"2015-08-19T20:00:30Z","receivedAt":"2015-08-19T20:00:30Z","isPatch":true,"sender":{"key":"dborowitz@google.com","avatar":"https://avatars.githubusercontent.com/u/194927?v=4"},"body":"On Wed, Aug 19, 2015 at 3:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Dave Borowitz <dborowitz@google.com> writes:\n>\n>> Add a new flag --signed-if-possible to push and send-pack that sends a\n>> push certificate if and only if the server advertised a push cert\n>> nonce. If not, at least warn the user that their push may not be as\n>> secure as they thought.\n>>\n>> Signed-off-by: Dave Borowitz <dborowitz@google.com>\n>> ---\n>\n> Obviously, the above description needs updating.  Here is what I've\n> queued tentatively.\n\nSound good.\n\n> Thanks.\n>\n> commit 32d273dfabb0a70b2839971f5afff7fa86a8f4c2\n> Author: Dave Borowitz <dborowitz@google.com>\n> Date:   Wed Aug 19 11:26:46 2015 -0400\n>\n>     push: support signing pushes iff the server supports it\n>\n>     Add a new flag --sign=true (or --sign=false), which means the same\n>     thing as the original --signed (or --no-signed).  Give it a third\n>     value --sign=if-asked to tell push and send-pack to send a push\n>     certificate if and only if the server advertised a push cert nonce.\n>\n>     If not, warn the user that their push may not be as secure as they\n>     thought.\n>\n>     Signed-off-by: Dave Borowitz <dborowitz@google.com>\n>     Signed-off-by: Junio C Hamano <gitster@pobox.com>\n"},{"id":"268350","messageId":"xmqqlhd782fp.fsf@gitster.dls.corp.google.com","threadId":"40131","inReplyTo":"CAD0k6qRtXX3OqeQF_USwiNYA-y+92X65MSJqPKjhNjGka9QXBw@mail.gmail.com","subject":"Re: [PATCH v2 2/9] Documentation/git-send-pack.txt: Flow long synopsis line","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-19T20:10:18Z","receivedAt":"2015-08-19T20:10:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Dave Borowitz <dborowitz@google.com> writes:\n\n> I produced the patch with \"git format-patch --subject-prefix='PATCH\n> v2' --cover-letter @{u}..\" and mailed with \"git send-email\n> --to=git@vger.kernel.org,gitster@pobox.com 0*.patch\"; is there a way\n> that would have preserved whitespace better?\n\nNo need to worry, I suspect that this is a local Emacs/GNUS glitch\non the receiving end.  Sorry for a noise.\n"},{"id":"268426","messageId":"20150821150613.GB565@sigill.intra.peff.net","threadId":"40131","inReplyTo":"CAD0k6qSp5af+N9QvjAxw1M19ytzh_n4repFA1+5Nq6v+px+fPw@mail.gmail.com","subject":"Re: [PATCH v2 7/9] builtin/send-pack.c: Use option parsing API","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-21T15:06:14Z","receivedAt":"2015-08-21T15:06:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Aug 19, 2015 at 03:46:25PM -0400, Dave Borowitz wrote:\n\n> >> +       unsigned dry_run = 0;\n> >> +       unsigned send_mirror = 0;\n> >> +       unsigned force_update = 0;\n> >> +       unsigned quiet = 0;\n> >> +       unsigned push_cert = 0;\n> >> +       unsigned use_thin_pack = 0;\n> >> +       unsigned atomic = 0;\n> >> +       unsigned stateless_rpc = 0;\n> >\n> > First I thought:\n> >     You could write to the args flags directly from the options. No\n> > need to have (most of)\n> >     the variables around here and copy over the values. You'd need to\n> > use OPT_BIT instead\n> >     for setting a specific bit though\n> > but then I realized we do not have a direct bit field in args, which\n> > would make it a bit unreadable.\n> \n> Right, and &args->push_cert etc. is invalid, and I didn't know if it\n> was ok to expand the args struct to be several words longer. But I'm\n> not a C programmer so I'm happy to take suggestions how to make this\n> more idiomatic.\n\nI think it would be fine to expand it. The reason to use bitfields is to\nsave memory, and there is literally only one of these structs per\nprogram. I'm sure we can afford the extra dozen bytes.\n\nMaking the struct members single-bits also communicates to readers that\nthey are true booleans, but I think a comment in the declaration of\nsend_pack_args could do the same.\n\n-Peff\n"},{"id":"269778","messageId":"xmqqfv2l0vv0.fsf@gitster.mtv.corp.google.com","threadId":"40131","inReplyTo":"xmqqlhd782fp.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 2/9] Documentation/git-send-pack.txt: Flow long synopsis line","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-11T16:22:11Z","receivedAt":"2015-09-11T16:22:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Dave Borowitz <dborowitz@google.com> writes:\n>\n>> I produced the patch with \"git format-patch --subject-prefix='PATCH\n>> v2' --cover-letter @{u}..\" and mailed with \"git send-email\n>> --to=git@vger.kernel.org,gitster@pobox.com 0*.patch\"; is there a way\n>> that would have preserved whitespace better?\n>\n> No need to worry, I suspect that this is a local Emacs/GNUS glitch\n> on the receiving end.  Sorry for a noise.\n\nPSA, as I figured this out.\n\nIt turns out that gnus-treat-fill-long-lines was set to (typep\n\"text/plain\"), which meant that I cannot trust what I see in my MUA\nas an exact copy of the patch the sender intended to give me.\n\nHere is what \"Describe variable\" gave me (after I fixed it, that is).\n\n    ---\n    gnus-treat-fill-long-lines's value is nil\n    Original value was \n    (typep \"text/plain\")\n\n\n    Documentation:\n    Fill long lines.\n    Valid values are nil, t, `head', `first', `last', an integer or a\n    predicate.  See Info node `(gnus)Customizing Articles'.\n\n    You can customize this variable.\n\n    This variable was introduced, or its default value was changed, in\n    version 24.1 of Emacs.\n    ---\n"}]}