{"thread":{"id":"20162","subject":"[PATCH 0/3] add push --current and remote.*.pushHeadOnly","startedAt":"2009-07-20T06:36:57Z","lastAt":"2009-07-20T11:50:53Z","messageCount":9,"participants":["Paolo Bonzini","Björn Steinbrink","Tay Ray Chuan","demerphq"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"118283","messageId":"1248071820-18289-1-git-send-email-bonzini@gnu.org","threadId":"20162","inReplyTo":null,"subject":"[PATCH 0/3] add push --current and remote.*.pushHeadOnly","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2009-07-20T06:36:57Z","receivedAt":"2009-07-20T06:36:57Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"This second series is gets rid of the most annoying part\n(IMHO) of push.default = tracking, i.e. the fact that its\nbehavior cannot be achieved using git's ordinary tools.\nWhile autosetuppush is enough to set the refspecs correctly,\npush.tracking does not push _all_ tracked branches, but\nonly the current one (because it implicitly adds only\none refspec, while autosetuppush places them all in the\nconfiguration).\n\nWhat I introduce here is \"git push --current\" and a companion\nremote.*.pushHeadOnly option to make it the default.  The\ndifference between \"git push HEAD\" and \"git push --current\"\nis that the latter will still walk the remote.*.push refspecs,\nbut honor only the one matching HEAD.\n\nTogether with autosetuppush, this more or less achieves the\nsame result as push.tracking, at least for newly created\nremotes.  A subsequent series will handle the transition.\n\nv2 integrates changes from Nanako's review.  Patch 1 is new\nand partially reverts bba0fd2 (push: do not give big warning\nwhen no preference is configured, 2009-07-18).  Patch 2 is the\nmeat of the implementation.  Most of it actually touches the\ntransport mechanism, not builtin-push.c (which covers only\none detail about how to handle \"git push --current\" when\nthe remote does not have a corresponding push refspec).\nPatch 3 adds remote.*.pushHeadOnly.\n\nPaolo Bonzini (3):\n      reintroduce PUSH_DEFAULT_UNSPECIFIED\n      push: add --current\n      push: add remote.*.pushHeadOnly configuration\n\n Documentation/config.txt   |    6 ++++\n Documentation/git-push.txt |   18 +++++++++++-\n builtin-push.c             |   17 +++++++++--\n cache.h                    |    1 +\n environment.c              |    2 +-\n http-push.c                |   27 ++++++++++++++----\n remote.c                   |   42 ++++++++++++++++++++++++-----\n remote.h                   |    3 ++\n t/t5516-fetch-push.sh      |   64 ++++++++++++++++++++++++++++++++++++++++++++\n transport.c                |   22 ++++++++++++++-\n transport.h                |    1 +\n 11 files changed, 183 insertions(+), 20 deletions(-)\n"},{"id":"118284","messageId":"1248071820-18289-2-git-send-email-bonzini@gnu.org","threadId":"20162","inReplyTo":"1248071820-18289-1-git-send-email-bonzini@gnu.org","subject":"[PATCH 1/3] reintroduce PUSH_DEFAULT_UNSPECIFIED","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2009-07-20T06:36:58Z","receivedAt":"2009-07-20T06:36:58Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"With the next patch, the default refspec for push will depend on\nwhether --current is being used.  Revert part of bba0fd2 (push:\ndo not give big warning when no preference is configured, 2009-07-18)\nto simplify the code.\n\nSigned-off-by: Paolo Bonzini <bonzini@gnu.org>\n---\n builtin-push.c |    1 +\n cache.h        |    1 +\n environment.c  |    2 +-\n 3 files changed, 3 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 1d92e22..e678a9d 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -69,6 +69,7 @@ static void setup_default_push_refspecs(void)\n \tgit_config(git_default_config, NULL);\n \tswitch (push_default) {\n \tdefault:\n+\tcase PUSH_DEFAULT_UNSPECIFIED:\n \tcase PUSH_DEFAULT_MATCHING:\n \t\tadd_refspec(\":\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex c72f125..f1e5ede 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -543,6 +543,7 @@ enum rebase_setup_type {\n };\n \n enum push_default_type {\n+\tPUSH_DEFAULT_UNSPECIFIED = -1,\n \tPUSH_DEFAULT_NOTHING = 0,\n \tPUSH_DEFAULT_MATCHING,\n \tPUSH_DEFAULT_TRACKING,\ndiff --git a/environment.c b/environment.c\nindex 720f26b..801a005 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN;\n unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;\n enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;\n enum rebase_setup_type autorebase = AUTOREBASE_NEVER;\n-enum push_default_type push_default = PUSH_DEFAULT_MATCHING;\n+enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #ifndef OBJECT_CREATION_MODE\n #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS\n #endif\n-- \n1.6.2.5\n"},{"id":"118286","messageId":"1248071820-18289-3-git-send-email-bonzini@gnu.org","threadId":"20162","inReplyTo":"1248071820-18289-1-git-send-email-bonzini@gnu.org","subject":"[PATCH 2/3] push: add --current","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2009-07-20T06:36:59Z","receivedAt":"2009-07-20T06:36:59Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"This patch adds the --current option to git-push.  The option restricts\npushing to the current HEAD, even in the presence of wildcard refspecs\nin the configuration.  This achieves an effect similar to the \"tracking\"\nvalue of push.default, in that git push only pushes a subset of the\nentire push possibilities (the difference, of course, is that these\nare implicitly taken from remote.*.merge in the case of push.default =\ntracking).\n\nA secondary effect of --head is that, if there is no push.default\nspecified, I make the default push refspec \"HEAD\".  This conforms to the\nidea of pushing the current branch only and is in general more intuitive.\nFor example in a normal configuration, \"git push --current FOO\" would give\nan error when pushing to an empty destination if this special behavior\nwas not there.\n\nThe option does not make sense, and is thus disabled, if explicit refspecs\nare given on the command line.\n\nSigned-off-by: Paolo Bonzini <bonzini@gnu.org>\n---\n Documentation/git-push.txt |   18 ++++++++++++++-\n builtin-push.c             |   16 ++++++++++---\n http-push.c                |   27 ++++++++++++++++++-----\n remote.c                   |   40 +++++++++++++++++++++++++++++------\n remote.h                   |    2 +\n t/t5516-fetch-push.sh      |   50 ++++++++++++++++++++++++++++++++++++++++++++\n transport.c                |   22 ++++++++++++++++++-\n transport.h                |    1 +\n 8 files changed, 156 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 2653388..8d03ea7 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -9,8 +9,9 @@ git-push - Update remote refs along with associated objects\n SYNOPSIS\n --------\n [verse]\n-'git push' [--all | --mirror | --tags] [--dry-run] [--receive-pack=<git-receive-pack>]\n-\t   [--repo=<repository>] [-f | --force] [-v | --verbose]\n+'git push' [--all | --mirror | --tags | --current] [--dry-run]\n+\t   [--receive-pack=<git-receive-pack>] [--repo=<repository>]\n+\t   [-f | --force] [-v | --verbose]\n \t   [<repository> <refspec>...]\n \n DESCRIPTION\n@@ -71,6 +72,19 @@ nor in any Push line of the corresponding remotes file---see below).\n \tInstead of naming each ref to push, specifies that all\n \trefs under `$GIT_DIR/refs/heads/` be pushed.\n \n+--current::\n+\tIndependent of the other options, restrict pushing to the current\n+\tHEAD.\n++\n+Refspecs given in the configuration are still used to find the\n+destination name of the current branch.  However, this option cannot\n+be specified if an explicit refspec is given on the command line,\n+because it would be useless and possibly confusing.\n++\n+Additionally, if there is no refspec in the configuration and no\n+`push.default` configuration either, with this option git will use a\n+default refspec of `HEAD` rather than `:`.\n+\n --mirror::\n \tInstead of naming each ref to push, specifies that all\n \trefs under `$GIT_DIR/refs/` (which includes but is not\ndiff --git a/builtin-push.c b/builtin-push.c\nindex e678a9d..71d94a5 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,7 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git push [--all | --mirror] [--current] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n \tNULL,\n };\n \n@@ -64,12 +64,17 @@ static void setup_push_tracking(void)\n \tadd_refspec(refspec.buf);\n }\n \n-static void setup_default_push_refspecs(void)\n+static void setup_default_push_refspecs(int flags)\n {\n+\tpush_default = PUSH_DEFAULT_UNSPECIFIED;\n \tgit_config(git_default_config, NULL);\n+\tif (push_default == PUSH_DEFAULT_UNSPECIFIED)\n+\t\tpush_default = (flags & TRANSPORT_PUSH_CURRENT\n+\t\t\t\t? PUSH_DEFAULT_CURRENT\n+\t\t\t\t: PUSH_DEFAULT_MATCHING);\n+\n \tswitch (push_default) {\n \tdefault:\n-\tcase PUSH_DEFAULT_UNSPECIFIED:\n \tcase PUSH_DEFAULT_MATCHING:\n \t\tadd_refspec(\":\");\n \t\tbreak;\n@@ -127,7 +132,7 @@ static int do_push(const char *repo, int flags)\n \t\t\trefspec = remote->push_refspec;\n \t\t\trefspec_nr = remote->push_refspec_nr;\n \t\t} else if (!(flags & TRANSPORT_PUSH_MIRROR))\n-\t\t\tsetup_default_push_refspecs();\n+\t\t\tsetup_default_push_refspecs(flags);\n \t}\n \terrs = 0;\n \tif (remote->pushurl_nr) {\n@@ -175,6 +180,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT( 0 , \"mirror\", &flags, \"mirror all refs\",\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n+\t\tOPT_BIT( 0 , \"current\", &flags, \"push current HEAD only\", TRANSPORT_PUSH_CURRENT),\n \t\tOPT_BIT( 0 , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n \t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n \t\tOPT_BIT('f', \"force\", &flags, \"force updates\", TRANSPORT_PUSH_FORCE),\n@@ -186,6 +192,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, push_usage, 0);\n \n+\tif ((argc > 1 || tags) && (flags & TRANSPORT_PUSH_CURRENT))\n+\t\treturn error (\"Cannot give --current together with --tags or a refspec.\");\n \tif (tags)\n \t\tadd_refspec(\"refs/tags/*\");\n \ndiff --git a/http-push.c b/http-push.c\nindex 00e83dc..9c93e91 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -14,7 +14,7 @@\n #include <expat.h>\n \n static const char http_push_usage[] =\n-\"git http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\\n\";\n+\"git http-push [--all] [--current] [--dry-run] [--force] [--verbose] <remote> [<head>...]\\n\";\n \n #ifndef XML_STATUS_OK\n enum XML_Status {\n@@ -75,7 +75,7 @@ static int aborted;\n static signed char remote_dir_exists[256];\n \n static int push_verbosely;\n-static int push_all = MATCH_REFS_NONE;\n+static int match_flags = MATCH_REFS_NONE;\n static int force_all;\n static int dry_run;\n \n@@ -1802,7 +1802,11 @@ int main(int argc, char **argv)\n \n \t\tif (*arg == '-') {\n \t\t\tif (!strcmp(arg, \"--all\")) {\n-\t\t\t\tpush_all = MATCH_REFS_ALL;\n+\t\t\t\tmatch_flags |= MATCH_REFS_ALL;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--current\")) {\n+\t\t\t\tmatch_flags |= MATCH_REFS_HEAD_ONLY;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--force\")) {\n@@ -1904,7 +1908,17 @@ int main(int argc, char **argv)\n \t\tfetch_indices();\n \n \t/* Get a list of all local and remote heads to validate refspecs */\n-\tlocal_refs = get_local_heads();\n+\tif (match_flags && MATCH_REFS_HEAD_ONLY) {\n+\t\tlocal_refs = get_current_head();\n+\t\tif (!local_refs) {\n+\t\t\tfprintf(stderr, \"--current specified with no current branch.\\n\");\n+\t\t\trc = -1;\n+\t\t\tgoto cleanup;\n+\t\t}\n+\t}\n+\telse\n+\t\tlocal_refs = get_local_heads();\n+\n \tfprintf(stderr, \"Fetching remote heads...\\n\");\n \tget_dav_remote_heads();\n \trun_request_queue();\n@@ -1919,7 +1933,7 @@ int main(int argc, char **argv)\n \n \t/* match them up */\n \tif (match_refs(local_refs, &remote_refs,\n-\t\t       nr_refspec, (const char **) refspec, push_all)) {\n+\t\t       nr_refspec, (const char **) refspec, match_flags)) {\n \t\trc = -1;\n \t\tgoto cleanup;\n \t}\n@@ -2005,7 +2019,8 @@ int main(int argc, char **argv)\n \t\told_sha1_hex = NULL;\n \t\tcommit_argv[1] = \"--objects\";\n \t\tcommit_argv[2] = new_sha1_hex;\n-\t\tif (!push_all && !is_null_sha1(ref->old_sha1)) {\n+\t\tif (!(match_flags & MATCH_REFS_ALL)\n+\t\t    && !is_null_sha1(ref->old_sha1)) {\n \t\t\told_sha1_hex = xmalloc(42);\n \t\t\tsprintf(old_sha1_hex, \"^%s\",\n \t\t\t\tsha1_to_hex(ref->old_sha1));\ndiff --git a/remote.c b/remote.c\nindex c3ada2d..b5bf9a6 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -990,7 +990,7 @@ static char *guess_ref(const char *name, struct ref *peer)\n \n static int match_explicit(struct ref *src, struct ref *dst,\n \t\t\t  struct ref ***dst_tail,\n-\t\t\t  struct refspec *rs)\n+\t\t\t  struct refspec *rs, int head_only)\n {\n \tstruct ref *matched_src, *matched_dst;\n \tint copy_src;\n@@ -1007,14 +1007,26 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\tcopy_src = 1;\n \t\tbreak;\n \tcase 0:\n-\t\t/* The source could be in the get_sha1() format\n+\t\t/*\n+\t\t * The source could be in the get_sha1() format\n \t\t * not a reference name.  :refs/other is a\n \t\t * way to delete 'other' ref at the remote end.\n+\t\t * This case however could cause unwanted references\n+\t\t * to be stored in matched_dst->peer_ref for --current.\n+\t\t * In that case, all we can/want handle is HEAD.\n \t\t */\n-\t\tmatched_src = try_explicit_object_name(rs->src);\n+\t\tif (head_only) {\n+\t\t\tassert (!src->next);\n+\t\t\tif (strcmp(rs->src, \"HEAD\"))\n+\t\t\t\treturn 0;\n+\t\t\tmatched_src = src;\n+\t\t\tcopy_src = 1;\n+\t\t} else {\n+\t\t\tmatched_src = try_explicit_object_name(rs->src);\n+\t\t\tcopy_src = 0;\n+\t\t}\n \t\tif (!matched_src)\n \t\t\treturn error(\"src refspec %s does not match any.\", rs->src);\n-\t\tcopy_src = 0;\n \t\tbreak;\n \tdefault:\n \t\treturn error(\"src refspec %s matches more than one.\", rs->src);\n@@ -1068,11 +1080,11 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \n static int match_explicit_refs(struct ref *src, struct ref *dst,\n \t\t\t       struct ref ***dst_tail, struct refspec *rs,\n-\t\t\t       int rs_nr)\n+\t\t\t       int rs_nr, int head_only)\n {\n \tint i, errs;\n \tfor (i = errs = 0; i < rs_nr; i++)\n-\t\terrs += match_explicit(src, dst, dst_tail, &rs[i]);\n+\t\terrs += match_explicit(src, dst, dst_tail, &rs[i], head_only);\n \treturn errs;\n }\n \n@@ -1118,6 +1130,7 @@ int match_refs(struct ref *src, struct ref **dst,\n \tstruct refspec *rs;\n \tint send_all = flags & MATCH_REFS_ALL;\n \tint send_mirror = flags & MATCH_REFS_MIRROR;\n+\tint head_only = flags & MATCH_REFS_HEAD_ONLY;\n \tint errs;\n \tstatic const char *default_refspec[] = { \":\", NULL };\n \tstruct ref **dst_tail = tail_ref(dst);\n@@ -1127,7 +1140,8 @@ int match_refs(struct ref *src, struct ref **dst,\n \t\trefspec = default_refspec;\n \t}\n \trs = parse_push_refspec(nr_refspec, (const char **) refspec);\n-\terrs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);\n+\terrs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec,\n+\t\t\t\t   head_only);\n \n \t/* pick the remainder */\n \tfor ( ; src; src = src->next) {\n@@ -1527,6 +1541,18 @@ struct ref *get_local_heads(void)\n \treturn local_refs;\n }\n \n+struct ref *get_current_head(void)\n+{\n+\tstruct ref *local_refs = NULL, **local_tail = &local_refs;\n+\tstruct branch *branch = branch_get(NULL);\n+\tunsigned char sha1[20];\n+\tif (branch) {\n+\t\tget_sha1(branch->refname, sha1);\n+\t\tone_local_ref(branch->refname, sha1, 0, &local_tail);\n+\t}\n+\treturn local_refs;\n+}\n+\n struct ref *guess_remote_head(const struct ref *head,\n \t\t\t      const struct ref *refs,\n \t\t\t      int all)\ndiff --git a/remote.h b/remote.h\nindex 5db8420..8e5d5b4 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -137,6 +137,7 @@ enum match_refs_flags {\n \tMATCH_REFS_NONE\t\t= 0,\n \tMATCH_REFS_ALL \t\t= (1 << 0),\n \tMATCH_REFS_MIRROR\t= (1 << 1),\n+\tMATCH_REFS_HEAD_ONLY\t= (1 << 2),\n };\n \n /* Reporting of tracking info */\n@@ -144,6 +145,7 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs);\n int format_tracking_info(struct branch *branch, struct strbuf *sb);\n \n struct ref *get_local_heads(void);\n+struct ref *get_current_head(void);\n /*\n  * Find refs from a list which are likely to be pointed to by the given HEAD\n  * ref. If 'all' is false, returns the most likely ref; otherwise, returns a\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 2d2633f..a480cb2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -586,4 +586,54 @@ test_expect_success 'push with branches containing #' '\n \tgit checkout master\n '\n \n+test_expect_success 'push --current succeeds on empty repository' '\n+\tgit init &&\n+\tmkdir b.git &&\n+\t(cd b.git && git init --bare) &&\n+\techo a > b &&\n+\tgit add b &&\n+\tgit commit -m a &&\n+\tgit checkout -b branch &&\n+\techo bb > b &&\n+\tgit add b &&\n+\tgit commit -m branch &&\n+\tgit checkout master &&\n+\tgit push --current b.git\n+\ttest $(git rev-parse master) = $(cd b.git && git rev-parse master)\n+'\n+\n+test_expect_success 'push --current always creates current branch' '\n+\tgit checkout branch &&\n+\tgit push --current b.git &&\n+\ttest $(git rev-parse branch) = $(cd b.git && git rev-parse branch)\n+'\n+\n+test_expect_success 'push --current does not push other branches' '\n+\tgit checkout master &&\n+\techo aa > b &&\n+\tgit commit -m master2 b &&\n+\tgit checkout branch &&\n+\tgit push --current b.git 2>&1 | grep \"Everything up-to-date\" &&\n+\ttest $(git rev-parse master^) = $(cd b.git && git rev-parse master)\n+'\n+\n+test_expect_success 'push --current does update the current branches' '\n+\techo cc > b &&\n+\tgit commit -m branch2 b &&\n+\tgit checkout master &&\n+\tgit push --current b.git &&\n+\ttest $(git rev-parse master) = $(cd b.git && git rev-parse master) &&\n+\ttest $(git rev-parse branch^) = $(cd b.git && git rev-parse branch)\n+'\n+\n+test_expect_success 'push --current respects configuration' '\n+\tgit config remote.bremote.url b.git &&\n+\tgit config remote.bremote.push refs/heads/master:refs/heads/master2 &&\n+\tgit push --current bremote &&\n+\ttest $(git rev-parse master) = $(cd b.git && git rev-parse master2)\n+\tgit checkout branch &&\n+\tgit push --current bremote 2>&1 | grep \"Everything up-to-date\" &&\n+\ttest $(git rev-parse branch^) = $(cd b.git && git rev-parse branch)\n+'\n+\n test_done\ndiff --git a/transport.c b/transport.c\nindex de0d587..c7b6aaa 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -327,6 +327,11 @@ static int rsync_transport_push(struct transport *transport,\n \tif (flags & TRANSPORT_PUSH_ALL) {\n \t\tif (for_each_ref(write_one_ref, &temp_dir))\n \t\t\treturn -1;\n+\t} else if (flags & TRANSPORT_PUSH_CURRENT) {\n+\t\tstruct branch *branch = branch_get(NULL);\n+\t\tunsigned char sha1[20];\n+\t\tget_sha1(branch->name, sha1);\n+\t\twrite_one_ref(branch->name, sha1, 0, &temp_dir);\n \t} else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec))\n \t\treturn -1;\n \n@@ -406,6 +411,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \targc = 1;\n \tif (flags & TRANSPORT_PUSH_ALL)\n \t\targv[argc++] = \"--all\";\n+\tif (flags & TRANSPORT_PUSH_CURRENT)\n+\t\targv[argc++] = \"--current\";\n \tif (flags & TRANSPORT_PUSH_FORCE)\n \t\targv[argc++] = \"--force\";\n \tif (flags & TRANSPORT_PUSH_DRY_RUN)\n@@ -1001,12 +1008,19 @@ int transport_push(struct transport *transport,\n {\n \tverify_remote_names(refspec_nr, refspec);\n \n+\tif (flags & TRANSPORT_PUSH_CURRENT) {\n+\t\tstruct branch *branch = branch_get(NULL);\n+\t\tif (!branch)\n+\t\t\treturn error(\"Tried to push current branch, but there \"\n+\t\t\t\t     \"is no current branch!\");\n+\t}\n+\n \tif (transport->push)\n \t\treturn transport->push(transport, refspec_nr, refspec, flags);\n \tif (transport->push_refs) {\n \t\tstruct ref *remote_refs =\n \t\t\ttransport->get_refs_list(transport, 1);\n-\t\tstruct ref *local_refs = get_local_heads();\n+\t\tstruct ref *local_refs;\n \t\tint match_flags = MATCH_REFS_NONE;\n \t\tint verbose = flags & TRANSPORT_PUSH_VERBOSE;\n \t\tint porcelain = flags & TRANSPORT_PUSH_PORCELAIN;\n@@ -1017,6 +1031,12 @@ int transport_push(struct transport *transport,\n \t\tif (flags & TRANSPORT_PUSH_MIRROR)\n \t\t\tmatch_flags |= MATCH_REFS_MIRROR;\n \n+\t\tif (flags & TRANSPORT_PUSH_CURRENT) {\n+\t\t\tlocal_refs = get_current_head();\n+\t\t\tmatch_flags |= MATCH_REFS_HEAD_ONLY;\n+\t\t} else\n+\t\t\tlocal_refs = get_local_heads();\n+\n \t\tif (match_refs(local_refs, &remote_refs,\n \t\t\t       refspec_nr, refspec, match_flags)) {\n \t\t\treturn -1;\ndiff --git a/transport.h b/transport.h\nindex 51b5397..62aa243 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -36,6 +36,7 @@ struct transport {\n #define TRANSPORT_PUSH_MIRROR 8\n #define TRANSPORT_PUSH_VERBOSE 16\n #define TRANSPORT_PUSH_PORCELAIN 32\n+#define TRANSPORT_PUSH_CURRENT 64\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n-- \n1.6.2.5\n"},{"id":"118285","messageId":"1248071820-18289-4-git-send-email-bonzini@gnu.org","threadId":"20162","inReplyTo":"1248071820-18289-1-git-send-email-bonzini@gnu.org","subject":"[PATCH 3/3] push: add remote.*.pushHeadOnly configuration","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2009-07-20T06:37:00Z","receivedAt":"2009-07-20T06:37:00Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"This patch adds a remote.*.pushHeadOnly configuration that automatically\nenables (when possible) the --current option to git push.\n\nSigned-off-by: Paolo Bonzini <bonzini@gnu.org>\n---\n Documentation/config.txt |    6 ++++++\n builtin-push.c           |    2 ++\n remote.c                 |    2 ++\n remote.h                 |    1 +\n t/t5516-fetch-push.sh    |   16 +++++++++++++++-\n 5 files changed, 26 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex cb6832b..4ab5593 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1359,6 +1359,12 @@ remote.<name>.uploadpack::\n \tThe default program to execute on the remote side when fetching.  See\n \toption \\--upload-pack of linkgit:git-fetch-pack[1].\n \n+remote.<name>.pushHeadOnly::\n+\tIf true, whenever `git push` is invoked without a refspec and\n+\tit will try pushing to this remote, `git push` will automatically\n+\tbehave as if the `\\--current` option was given on the command line.\n+\tIn other words, only the current branch is pushed to the remote.\n+\n remote.<name>.tagopt::\n \tSetting this value to \\--no-tags disables automatic tag following when\n \tfetching from remote <name>\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 71d94a5..8d5b054 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -109,6 +109,8 @@ static int do_push(const char *repo, int flags)\n \n \tif (remote->mirror)\n \t\tflags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);\n+\tif (remote->push_head_only && !refspec_nr)\n+\t\tflags |= TRANSPORT_PUSH_CURRENT;\n \n \tif ((flags & TRANSPORT_PUSH_ALL) && refspec) {\n \t\tif (!strcmp(*refspec, \"refs/tags/*\"))\ndiff --git a/remote.c b/remote.c\nindex b5bf9a6..d46dc0d 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -379,6 +379,8 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\tremote->mirror = git_config_bool(key, value);\n \telse if (!strcmp(subkey, \".skipdefaultupdate\"))\n \t\tremote->skip_default_update = git_config_bool(key, value);\n+\telse if (!strcmp(subkey, \".pushheadonly\"))\n+\t\tremote->push_head_only = git_config_bool(key, value);\n \n \telse if (!strcmp(subkey, \".url\")) {\n \t\tconst char *v;\ndiff --git a/remote.h b/remote.h\nindex 8e5d5b4..b1e3e99 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -36,6 +36,7 @@ struct remote {\n \t * 2 to always fetch tags\n \t */\n \tint fetch_tags;\n+\tint push_head_only;\n \tint skip_default_update;\n \tint mirror;\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex a480cb2..9d61ba0 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -631,9 +631,23 @@ test_expect_success 'push --current respects configuration' '\n \tgit config remote.bremote.push refs/heads/master:refs/heads/master2 &&\n \tgit push --current bremote &&\n \ttest $(git rev-parse master) = $(cd b.git && git rev-parse master2)\n+'\n+\n+test_expect_success 'remote.*.pushHeadOnly respects configuration' '\n+\techo xx > b &&\n+\tgit commit -mmaster3 b &&\n+\tgit config remote.bremote.pushHeadOnly true &&\n \tgit checkout branch &&\n-\tgit push --current bremote 2>&1 | grep \"Everything up-to-date\" &&\n+\tgit push bremote &&\n+\ttest $(git rev-parse master^) = $(cd b.git && git rev-parse master) &&\n \ttest $(git rev-parse branch^) = $(cd b.git && git rev-parse branch)\n '\n \n+test_expect_success 'remote.*.pushHeadOnly works' '\n+\tgit config --unset remote.bremote.push &&\n+\tgit push bremote &&\n+\ttest $(git rev-parse master^) = $(cd b.git && git rev-parse master) &&\n+\ttest $(git rev-parse branch) = $(cd b.git && git rev-parse branch)\n+'\n+\n test_done\n-- \n1.6.2.5\n"},{"id":"118287","messageId":"20090720071413.GA29915@atjola.homenet","threadId":"20162","inReplyTo":"1248071820-18289-3-git-send-email-bonzini@gnu.org","subject":"Re: [PATCH 2/3] push: add --current","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-07-20T07:14:13Z","receivedAt":"2009-07-20T07:14:13Z","isPatch":true,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.07.20 08:36:59 +0200, Paolo Bonzini wrote:\n> +--current::\n> +\tIndependent of the other options, restrict pushing to the current\n> +\tHEAD.\n\nTo me, this sounds like there are multiple HEADs and this selects the\ncurrent one to be pushed, which would be wrong. Maybe this could be\nwritten as:\n\n\tRestrict pushing to the currently checked out branch head.\n\nWhich is also in line with the error message that is produced when\nyou're on a detached HEAD.\n\n> +Refspecs given in the configuration are still used to find the\n> +destination name of the current branch.  However, this option cannot\n> +be specified if an explicit refspec is given on the command line,\n> +because it would be useless and possibly confusing.\n\nHm, this only talks about refspecs in the config, but your patch series\nis especially about push.default=tracking, which is not a refspec set in\nthe config, but causes a refspec to be generated on the fly. Maybe:\n\n\tWith this option, defaults given in the configuration, either as\n\tpush refspecs for the remote or as a global push default, are\n\tstill evaluated, but only the currently checked out branch is\n\tpushed. This means that this option, unlike the `HEAD` refspec,\n\tsupports a destination name that differs from the source name.\n\tHowever, this option cannot be specified if an explicit refspec\n\tis given on the command line, because it would be useless and\n\tpossibly confusing.\n\nWhich also explains a bit how this option differs from using the HEAD\nrefspec.\n\n> ++\n> +Additionally, if there is no refspec in the configuration and no\n> +`push.default` configuration either, with this option git will use a\n> +default refspec of `HEAD` rather than `:`.\n\nHm, this looks kind of funny with my rewrite of the previous paragraph,\nso:\n\n\tAdditionally, if there are no push defaults given in the\n\tconfiguration at all, this option makes git default to `HEAD`\n\tinstead of `:`.\n\nBjörn\n"},{"id":"118294","messageId":"4A643D7B.9090900@gmail.com","threadId":"20162","inReplyTo":"20090720071413.GA29915@atjola.homenet","subject":"Re: [PATCH 2/3] push: add --current","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@gmail.com","sentAt":"2009-07-20T09:48:43Z","receivedAt":"2009-07-20T09:48:43Z","isPatch":true,"sender":{"key":"paolo.bonzini@gmail.com","avatar":"https://gravatar.com/avatar/7817ef2e168b4ef0570c5bb5bdc1d4b44f34d3075fe32b871710dd942d0a89f5?d=mp&s=160"},"body":">> +--current::\n>> +\tIndependent of the other options, restrict pushing to the current\n>> +\tHEAD.\n>\n> To me, this sounds like there are multiple HEADs and this selects the\n> current one to be pushed, which would be wrong. Maybe this could be\n> written as:\n>\n> \tRestrict pushing to the currently checked out branch head.\n\nI wrote that referring to \"the branch currently pointed to by [the \nsymref] HEAD\".\n\n> Hm, this only talks about refspecs in the config, but your patch series\n> is especially about push.default=tracking, which is not a refspec set in\n> the config, but causes a refspec to be generated on the fly.\n\nNot really, as push.default=tracking and push.default=current would \nanyway push only the currently checked out branch.  \"git push --current\" \nwould have a visible effect only for push.default=matching (the effect \nwould be the same as push.default=current except that a new branch will \nnot be created remotely).\n\nIf you have creted all your tracking branches with autosetuppush, then \nin that case \"git push --current\" or pushHeadOnly will indeed achieve \nthe same effect as push.default=tracking; however, that would be with \nreal refspecs in the config rather than with one generated on the fly. \nAnd since in that case you have a push refspec in the configuration, \npush.default would not be used.\n\nPaolo\n"},{"id":"118295","messageId":"be6fef0d0907200315j14089edcv8baa997d2ec34f3f@mail.gmail.com","threadId":"20162","inReplyTo":"1248071820-18289-3-git-send-email-bonzini@gnu.org","subject":"Re: [PATCH 2/3] push: add --current","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-07-20T10:15:32Z","receivedAt":"2009-07-20T10:15:32Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"Hi,\n\nOn Mon, Jul 20, 2009 at 2:36 PM, Paolo Bonzini<bonzini@gnu.org> wrote:\n>  t/t5516-fetch-push.sh      |   50 ++++++++++++++++++++++++++++++++++++++++++++\n\nsince you're making modifications to pushing over HTTP, you should\nconsider making tests also for HTTP repositories, or else your changes\nin http-push.c won't be used.\n\n-- \nCheers,\nRay Chuan\n"},{"id":"118297","messageId":"9b18b3110907200417t2e916d9bqffdb168329d88bc4@mail.gmail.com","threadId":"20162","inReplyTo":"1248071820-18289-3-git-send-email-bonzini@gnu.org","subject":"Re: [PATCH 2/3] push: add --current","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2009-07-20T11:17:36Z","receivedAt":"2009-07-20T11:17:36Z","isPatch":true,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"2009/7/20 Paolo Bonzini <bonzini@gnu.org>:\n[snip]\n> A secondary effect of --head is that, if there is no push.default\n> specified, I make the default push refspec \"HEAD\".\n\nI think you mean something like:\n\n  A secondary effect of --current is that if there is no push.default\n  configuration setting specified the default push refspec will be \"HEAD\".\n\nThe important point being you talk about --current but then mention\n--head which I am guessing was a previous name for this option.\n\nBTW, I like this option and I can imagine it will be a popular alias.\nOne of the more common questions I get asked from people about git is\nwhat to do about all the \"error\" messages when pushing. I usually\nexplain that unless the error message concerns the current branch\nwhich you wanted to push that they can be ignored. I look forward to\npointing out this option instead. Thanks. :-)\n\nCheers,\nyves\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"118300","messageId":"4A645A1D.8010401@gnu.org","threadId":"20162","inReplyTo":"be6fef0d0907200315j14089edcv8baa997d2ec34f3f@mail.gmail.com","subject":"Re: [PATCH 2/3] push: add --current","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2009-07-20T11:50:53Z","receivedAt":"2009-07-20T11:50:53Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"On 07/20/2009 12:15 PM, Tay Ray Chuan wrote:\n> Hi,\n>\n> On Mon, Jul 20, 2009 at 2:36 PM, Paolo Bonzini<bonzini@gnu.org>  wrote:\n>>   t/t5516-fetch-push.sh      |   50 ++++++++++++++++++++++++++++++++++++++++++++\n>\n> since you're making modifications to pushing over HTTP, you should\n> consider making tests also for HTTP repositories, or else your changes\n> in http-push.c won't be used.\n\nYeah, I had tested them with a server I already had setup rather than \nwith the testsuite, because the default Apache setup of Fedora is not \ndetected correctly by lib-httpd.sh.  Any test I included would then be \nuntested, while http-push.c was tested. :-)\n\nHowever, I'll include the tests in v3 of the patch.\n\nPaolo\n"}]}