{"thread":{"id":"32855","subject":"[RFC/PATCH] Introduce branch.<name>.pushremote","startedAt":"2013-02-08T07:19:42Z","lastAt":"2013-03-18T09:02:46Z","messageCount":18,"participants":["Ramkumar Ramachandra","Junio C Hamano","Blind","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"208983","messageId":"1360307982-20027-1-git-send-email-artagnon@gmail.com","threadId":"32855","inReplyTo":null,"subject":"[RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-08T07:19:42Z","receivedAt":"2013-02-08T07:19:42Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"This new configuration variable overrides the remote in\n`branch.<name>.remote` for pushes.  It is useful in the typical\nscenario, where the remote I'm pulling from is not the remote I'm\npushing to.  Although `remote.<name>.pushurl` is similar, it does not\nserve the purpose as the URL would lack corresponding remote tracking\nbranches.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n This is a first cut.  There's code duplication at the moment, but I'm\n currently trying to figure out which other remote_get() calls to\n replace with pushremote_get().  Comments are welcome.\n\n I will leave it to future patches to do the following things:\n 1. Fix the status output to be more meaningful when pushremote is\n set.  At the moment, I'm thinking statuses like [pull: 4 behind,\n push: 3 ahead] will make sense.\n 2. Introduce a remote.pushDefault (peff)\n 3. Introduce a remote.default (peff)\n\n Documentation/config.txt |  6 ++++++\n builtin/push.c           |  2 +-\n remote.c                 | 41 +++++++++++++++++++++++++++++++++++++++++\n remote.h                 |  2 ++\n 4 files changed, 50 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 9b11597..0b3b1f8 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -727,6 +727,12 @@ branch.<name>.remote::\n \tremote to fetch from/push to.  It defaults to `origin` if no remote is\n \tconfigured. `origin` is also used if you are not on any branch.\n \n+branch.<name>.pushremote::\n+\tWhen in branch <name>, it tells 'git push' which remote to\n+\tpush to.  It falls back to `branch.<name>.remote`, and\n+\tdefaults to `origin` if no remote is configured. `origin` is\n+\talso used if you are not on any branch.\n+\n branch.<name>.merge::\n \tDefines, together with branch.<name>.remote, the upstream branch\n \tfor the given branch. It tells 'git fetch'/'git pull'/'git rebase' which\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 42b129d..d447a80 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)\n static int do_push(const char *repo, int flags)\n {\n \tint i, errs;\n-\tstruct remote *remote = remote_get(repo);\n+\tstruct remote *remote = pushremote_get(repo);\n \tconst char **url;\n \tint url_nr;\n \ndiff --git a/remote.c b/remote.c\nindex e53a6eb..d6fcfc0 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -48,6 +48,7 @@ static int branches_nr;\n \n static struct branch *current_branch;\n static const char *default_remote_name;\n+static const char *pushremote_name;\n static int explicit_default_remote_name;\n \n static struct rewrites rewrites;\n@@ -363,6 +364,12 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\t\tdefault_remote_name = branch->remote_name;\n \t\t\t\texplicit_default_remote_name = 1;\n \t\t\t}\n+\t\t} else if (!strcmp(subkey, \".pushremote\")) {\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(key);\n+\t\t\tbranch->pushremote_name = xstrdup(value);\n+\t\t\tif (branch == current_branch)\n+\t\t\t\tpushremote_name = branch->pushremote_name;\n \t\t} else if (!strcmp(subkey, \".merge\")) {\n \t\t\tif (!value)\n \t\t\t\treturn config_error_nonbool(key);\n@@ -700,6 +707,40 @@ struct remote *remote_get(const char *name)\n \treturn ret;\n }\n \n+struct remote *pushremote_get(const char *name)\n+{\n+\tstruct remote *ret;\n+\tint name_given = 0;\n+\n+\tread_config();\n+\tif (name)\n+\t\tname_given = 1;\n+\telse {\n+\t\tif (pushremote_name) {\n+\t\t\tname = pushremote_name;\n+\t\t\tname_given = 1;\n+\t\t} else {\n+\t\t\tname = default_remote_name;\n+\t\t\tname_given = explicit_default_remote_name;\n+\t\t}\n+\t}\n+\n+\tret = make_remote(name, 0);\n+\tif (valid_remote_nick(name)) {\n+\t\tif (!valid_remote(ret))\n+\t\t\tread_remotes_file(ret);\n+\t\tif (!valid_remote(ret))\n+\t\t\tread_branches_file(ret);\n+\t}\n+\tif (name_given && !valid_remote(ret))\n+\t\tadd_url_alias(ret, name);\n+\tif (!valid_remote(ret))\n+\t\treturn NULL;\n+\tret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);\n+\tret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);\n+\treturn ret;\n+}\n+\n int remote_is_configured(const char *name)\n {\n \tint i;\ndiff --git a/remote.h b/remote.h\nindex 251d8fd..aa42ff5 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -51,6 +51,7 @@ struct remote {\n };\n \n struct remote *remote_get(const char *name);\n+struct remote *pushremote_get(const char *name);\n int remote_is_configured(const char *name);\n \n typedef int each_remote_fn(struct remote *remote, void *priv);\n@@ -130,6 +131,7 @@ struct branch {\n \tconst char *refname;\n \n \tconst char *remote_name;\n+\tconst char *pushremote_name;\n \tstruct remote *remote;\n \n \tconst char **merge_name;\n-- \n1.8.1.2.545.g2f19ada.dirty\n"},{"id":"208987","messageId":"7v1ucr43mk.fsf@alter.siamese.dyndns.org","threadId":"32855","inReplyTo":"1360307982-20027-1-git-send-email-artagnon@gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-02-08T08:21:55Z","receivedAt":"2013-02-08T08:21:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n>  Comments are welcome.\n\nAs the first cut, I would have expected the series to start from\nmore general (not \"only this branch\"), with later follow-up to let\nmore specific configuration.\n\nAlso I'd prefer to see the \"push\" semantics (e.g. \"what does\nupstream mean in this new world order?\") designed better first.\n"},{"id":"208988","messageId":"1360314123-1259-1-git-send-email-artagnon@gmail.com","threadId":"32855","inReplyTo":"7v1ucr43mk.fsf@alter.siamese.dyndns.org","subject":"[RFC/PATCH] Introduce remote.pushdefault","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-08T09:02:03Z","receivedAt":"2013-02-08T09:02:03Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"This new configuration variable overrides branch-specific\nconfiguration `branch.<name>.remote` for pushes.  It is useful in the\ntypical scenario, where the remote I'm pulling from is not the remote\nI'm pushing to.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Junio C Hamano wrote:\n > As the first cut, I would have expected the series to start from\n > more general (not \"only this branch\"), with later follow-up to let\n > more specific configuration.\n\n Doesn't that follow trivially from my previous patch?  I'm looking\n for comments on how best to share code between pushremote_get()/\n remote_get(), and on other remote_get() callsites.\n\n > Also I'd prefer to see the \"push\" semantics (e.g. \"what does\n > upstream mean in this new world order?\") designed better first.\n\n Why should the meaning of upstream change?  We'd probably like to\n introduce something like a branch@{downstream} pointing to the push\n remote ref sometime in the future though.  Wait, should it always be\n called downstream?\n\n Documentation/config.txt |  4 ++++\n builtin/push.c           |  2 +-\n remote.c                 | 45 +++++++++++++++++++++++++++++++++++++++++++--\n remote.h                 |  1 +\n 4 files changed, 49 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 9b11597..82a4a78 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1884,6 +1884,10 @@ receive.updateserverinfo::\n \tIf set to true, git-receive-pack will run git-update-server-info\n \tafter receiving data from git-push and updating refs.\n \n+remote.pushdefault::\n+\tThe remote to push to by default.  Overrides the\n+\tbranch-specific configuration `branch.<name>.remote`.\n+\n remote.<name>.url::\n \tThe URL of a remote repository.  See linkgit:git-fetch[1] or\n \tlinkgit:git-push[1].\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 42b129d..d447a80 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)\n static int do_push(const char *repo, int flags)\n {\n \tint i, errs;\n-\tstruct remote *remote = remote_get(repo);\n+\tstruct remote *remote = pushremote_get(repo);\n \tconst char **url;\n \tint url_nr;\n \ndiff --git a/remote.c b/remote.c\nindex e53a6eb..08bb803 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -48,6 +48,7 @@ static int branches_nr;\n \n static struct branch *current_branch;\n static const char *default_remote_name;\n+static const char *pushremote_name;\n static int explicit_default_remote_name;\n \n static struct rewrites rewrites;\n@@ -349,6 +350,14 @@ static int handle_config(const char *key, const char *value, void *cb)\n \tconst char *subkey;\n \tstruct remote *remote;\n \tstruct branch *branch;\n+\tif (!prefixcmp(key,  \"remote.\")) {\n+\t\tname = key + 7;\n+\t\tif (!strcmp(name, \"pushdefault\")) {\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(key);\n+\t\t\tpushremote_name = xstrdup(value);\n+\t\t}\n+\t}\n \tif (!prefixcmp(key, \"branch.\")) {\n \t\tname = key + 7;\n \t\tsubkey = strrchr(name, '.');\n@@ -388,8 +397,6 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\tadd_instead_of(rewrite, xstrdup(value));\n \t\t}\n \t}\n-\tif (prefixcmp(key,  \"remote.\"))\n-\t\treturn 0;\n \tname = key + 7;\n \tif (*name == '/') {\n \t\twarning(\"Config remote shorthand cannot begin with '/': %s\",\n@@ -700,6 +707,40 @@ struct remote *remote_get(const char *name)\n \treturn ret;\n }\n \n+struct remote *pushremote_get(const char *name)\n+{\n+\tstruct remote *ret;\n+\tint name_given = 0;\n+\n+\tread_config();\n+\tif (name)\n+\t\tname_given = 1;\n+\telse {\n+\t\tif (pushremote_name) {\n+\t\t\tname = pushremote_name;\n+\t\t\tname_given = 1;\n+\t\t} else {\n+\t\t\tname = default_remote_name;\n+\t\t\tname_given = explicit_default_remote_name;\n+\t\t}\n+\t}\n+\n+\tret = make_remote(name, 0);\n+\tif (valid_remote_nick(name)) {\n+\t\tif (!valid_remote(ret))\n+\t\t\tread_remotes_file(ret);\n+\t\tif (!valid_remote(ret))\n+\t\t\tread_branches_file(ret);\n+\t}\n+\tif (name_given && !valid_remote(ret))\n+\t\tadd_url_alias(ret, name);\n+\tif (!valid_remote(ret))\n+\t\treturn NULL;\n+\tret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);\n+\tret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);\n+\treturn ret;\n+}\n+\n int remote_is_configured(const char *name)\n {\n \tint i;\ndiff --git a/remote.h b/remote.h\nindex 251d8fd..99a437f 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -51,6 +51,7 @@ struct remote {\n };\n \n struct remote *remote_get(const char *name);\n+struct remote *pushremote_get(const char *name);\n int remote_is_configured(const char *name);\n \n typedef int each_remote_fn(struct remote *remote, void *priv);\n-- \n1.8.1.3.535.ga923c31.dirty\n"},{"id":"209029","messageId":"7v8v6y1sih.fsf@alter.siamese.dyndns.org","threadId":"32855","inReplyTo":"1360307982-20027-1-git-send-email-artagnon@gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-02-08T20:04:54Z","receivedAt":"2013-02-08T20:04:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 9b11597..0b3b1f8 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -727,6 +727,12 @@ branch.<name>.remote::\n>  \tremote to fetch from/push to.  It defaults to `origin` if no remote is\n>  \tconfigured. `origin` is also used if you are not on any branch.\n>  \n> +branch.<name>.pushremote::\n> +\tWhen in branch <name>, it tells 'git push' which remote to\n> +\tpush to.  It falls back to `branch.<name>.remote`, and\n> +\tdefaults to `origin` if no remote is configured. `origin` is\n> +\talso used if you are not on any branch.\n\nSounds sensible (modulo the missing \"default location to push to\nthat is not per remote\" bit, obviously).  I think \"When _on_ branch\"\nis more correct, to match \"if you are not on any branch\" at the end,\nthough.\n\n> diff --git a/remote.c b/remote.c\n> index e53a6eb..d6fcfc0 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -48,6 +48,7 @@ static int branches_nr;\n>  \n>  static struct branch *current_branch;\n>  static const char *default_remote_name;\n> +static const char *pushremote_name;\n>  static int explicit_default_remote_name;\n>  \n>  static struct rewrites rewrites;\n> @@ -363,6 +364,12 @@ static int handle_config(const char *key, const char *value, void *cb)\n>  \t\t\t\tdefault_remote_name = branch->remote_name;\n>  \t\t\t\texplicit_default_remote_name = 1;\n>  \t\t\t}\n> +\t\t} else if (!strcmp(subkey, \".pushremote\")) {\n> +\t\t\tif (!value)\n> +\t\t\t\treturn config_error_nonbool(key);\n> +\t\t\tbranch->pushremote_name = xstrdup(value);\n\nPerhaps use git_config_string()?\n\nI also notice that git_config_string() should free (*dest) if there\nalready is some value, and that has to be done after auditing all\nexisting callers.\n\n> +\t\t\tif (branch == current_branch)\n> +\t\t\t\tpushremote_name = branch->pushremote_name;\n\nWhy is this global only when current_branch is involved?\n\nIn other words, does it make sense to read branch.$name.pushremote\nfor all the other irrelevant branches?  \n\nIn yet other words, perhaps adding pushremote_name to the branch\nstructure is unneeded, and you only need this single global\nvariable?\n\n(The remainder of the patch unsnipped for others' reference.)\n\n> @@ -700,6 +707,40 @@ struct remote *remote_get(const char *name)\n>  \treturn ret;\n>  }\n>  \n> +struct remote *pushremote_get(const char *name)\n> +{\n> +\tstruct remote *ret;\n> +\tint name_given = 0;\n> +\n> +\tread_config();\n> +\tif (name)\n> +\t\tname_given = 1;\n> +\telse {\n> +\t\tif (pushremote_name) {\n> +\t\t\tname = pushremote_name;\n> +\t\t\tname_given = 1;\n> +\t\t} else {\n> +\t\t\tname = default_remote_name;\n> +\t\t\tname_given = explicit_default_remote_name;\n> +\t\t}\n> +\t}\n> +\n> +\tret = make_remote(name, 0);\n> +\tif (valid_remote_nick(name)) {\n> +\t\tif (!valid_remote(ret))\n> +\t\t\tread_remotes_file(ret);\n> +\t\tif (!valid_remote(ret))\n> +\t\t\tread_branches_file(ret);\n> +\t}\n> +\tif (name_given && !valid_remote(ret))\n> +\t\tadd_url_alias(ret, name);\n> +\tif (!valid_remote(ret))\n> +\t\treturn NULL;\n> +\tret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);\n> +\tret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);\n> +\treturn ret;\n> +}\n> +\n>  int remote_is_configured(const char *name)\n>  {\n>  \tint i;\n> diff --git a/remote.h b/remote.h\n> index 251d8fd..aa42ff5 100644\n> --- a/remote.h\n> +++ b/remote.h\n> @@ -51,6 +51,7 @@ struct remote {\n>  };\n>  \n>  struct remote *remote_get(const char *name);\n> +struct remote *pushremote_get(const char *name);\n>  int remote_is_configured(const char *name);\n>  \n>  typedef int each_remote_fn(struct remote *remote, void *priv);\n> @@ -130,6 +131,7 @@ struct branch {\n>  \tconst char *refname;\n>  \n>  \tconst char *remote_name;\n> +\tconst char *pushremote_name;\n>  \tstruct remote *remote;\n>  \n>  \tconst char **merge_name;\n"},{"id":"209030","messageId":"7v4nhm1s85.fsf@alter.siamese.dyndns.org","threadId":"32855","inReplyTo":"1360314123-1259-1-git-send-email-artagnon@gmail.com","subject":"Re: [RFC/PATCH] Introduce remote.pushdefault","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-02-08T20:11:06Z","receivedAt":"2013-02-08T20:11:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 9b11597..82a4a78 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -1884,6 +1884,10 @@ receive.updateserverinfo::\n>  \tIf set to true, git-receive-pack will run git-update-server-info\n>  \tafter receiving data from git-push and updating refs.\n>  \n> +remote.pushdefault::\n> +\tThe remote to push to by default.  Overrides the\n> +\tbranch-specific configuration `branch.<name>.remote`.\n\nIt feels unexpected to see \"I may have said while on this branch I\npush there and on that branch I push somewhere else, but no, with\nthis single configuration I'm invalidating all these previous\nstatements, and all pushes go to this new place\".\n\nShouldn't the default be the default that is to be overridden by\nother configuration that is more specific?  That is, \"I would\nnormally push to this remote and unless I say otherwise that is all\nI have to say, but for this particular branch, I push to somehwere\nelse\".\n\n> diff --git a/builtin/push.c b/builtin/push.c\n> index 42b129d..d447a80 100644\n> --- a/builtin/push.c\n> +++ b/builtin/push.c\n> @@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)\n>  static int do_push(const char *repo, int flags)\n>  {\n>  \tint i, errs;\n> -\tstruct remote *remote = remote_get(repo);\n> +\tstruct remote *remote = pushremote_get(repo);\n>  \tconst char **url;\n>  \tint url_nr;\n>  \n> diff --git a/remote.c b/remote.c\n> index e53a6eb..08bb803 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -48,6 +48,7 @@ static int branches_nr;\n>  \n>  static struct branch *current_branch;\n>  static const char *default_remote_name;\n> +static const char *pushremote_name;\n>  static int explicit_default_remote_name;\n>  \n>  static struct rewrites rewrites;\n> @@ -349,6 +350,14 @@ static int handle_config(const char *key, const char *value, void *cb)\n>  \tconst char *subkey;\n>  \tstruct remote *remote;\n>  \tstruct branch *branch;\n> +\tif (!prefixcmp(key,  \"remote.\")) {\n> +\t\tname = key + 7;\n> +\t\tif (!strcmp(name, \"pushdefault\")) {\n> +\t\t\tif (!value)\n> +\t\t\t\treturn config_error_nonbool(key);\n> +\t\t\tpushremote_name = xstrdup(value);\n> +\t\t}\n> +\t}\n>  \tif (!prefixcmp(key, \"branch.\")) {\n>  \t\tname = key + 7;\n>  \t\tsubkey = strrchr(name, '.');\n> @@ -388,8 +397,6 @@ static int handle_config(const char *key, const char *value, void *cb)\n>  \t\t\tadd_instead_of(rewrite, xstrdup(value));\n>  \t\t}\n>  \t}\n> -\tif (prefixcmp(key,  \"remote.\"))\n> -\t\treturn 0;\n\nWhy is this no longer needed?\n\nAll the remainder of this function is about \"remote.*\" config and\nthis rejects other keys, like \"user.name\", etc.\n\nI'm a bit confused....\n\n>  \tname = key + 7;\n>  \tif (*name == '/') {\n>  \t\twarning(\"Config remote shorthand cannot begin with '/': %s\",\n"},{"id":"209073","messageId":"CALkWK0kp5SvbeTQgLRKWUAT_koSi0wyp6iPTC324iH8+D8oeJg@mail.gmail.com","threadId":"32855","inReplyTo":"7v8v6y1sih.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-09T07:46:38Z","receivedAt":"2013-02-09T07:46:38Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Junio C Hamano wrote:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>\n>> diff --git a/remote.c b/remote.c\n>> index e53a6eb..d6fcfc0 100644\n>> --- a/remote.c\n>> +++ b/remote.c\n>> @@ -48,6 +48,7 @@ static int branches_nr;\n>>\n>>  static struct branch *current_branch;\n>>  static const char *default_remote_name;\n>> +static const char *pushremote_name;\n>>  static int explicit_default_remote_name;\n>>\n>>  static struct rewrites rewrites;\n>> @@ -363,6 +364,12 @@ static int handle_config(const char *key, const char *value, void *cb)\n>>                               default_remote_name = branch->remote_name;\n>>                               explicit_default_remote_name = 1;\n>>                       }\n>> +             } else if (!strcmp(subkey, \".pushremote\")) {\n>> +                     if (!value)\n>> +                             return config_error_nonbool(key);\n>> +                     branch->pushremote_name = xstrdup(value);\n>\n> Perhaps use git_config_string()?\n\nI was just following the style of the surrounding code without\nthinking.  However, it looks like the surrounding code may be dated,\nso I'll include a patch to update it to use git_config_string() before\nmaking the change here.\n\n>> +                     if (branch == current_branch)\n>> +                             pushremote_name = branch->pushremote_name;\n>\n> Why is this global only when current_branch is involved?\n>\n> In other words, does it make sense to read branch.$name.pushremote\n> for all the other irrelevant branches?\n>\n> In yet other words, perhaps adding pushremote_name to the branch\n> structure is unneeded, and you only need this single global\n> variable?\n\nFrankly, I'm unhappy with this global.  Setting a global here and\nsubsequently reading it in pushremote_get() feels flaky.  Why use it\nat all when we have branch->remote_name, branch->remote, and (the now\nintroduced) branch->pushremote_name?  I left the pushremote_name field\naround, with the expectation that other codepaths that use the\nremote_name field might be able to use it.\n\nThanks.\n"},{"id":"209074","messageId":"CALkWK0nq9Nir9NA9CxyajazrTxNURA_6r4kN6c3v+G8MtQtqsg@mail.gmail.com","threadId":"32855","inReplyTo":"7v4nhm1s85.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] Introduce remote.pushdefault","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-09T07:50:31Z","receivedAt":"2013-02-09T07:50:31Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Junio C Hamano wrote:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>\n>> diff --git a/Documentation/config.txt b/Documentation/config.txt\n>> index 9b11597..82a4a78 100644\n>> --- a/Documentation/config.txt\n>> +++ b/Documentation/config.txt\n>> @@ -1884,6 +1884,10 @@ receive.updateserverinfo::\n>>       If set to true, git-receive-pack will run git-update-server-info\n>>       after receiving data from git-push and updating refs.\n>>\n>> +remote.pushdefault::\n>> +     The remote to push to by default.  Overrides the\n>> +     branch-specific configuration `branch.<name>.remote`.\n>\n> It feels unexpected to see \"I may have said while on this branch I\n> push there and on that branch I push somewhere else, but no, with\n> this single configuration I'm invalidating all these previous\n> statements, and all pushes go to this new place\".\n>\n> Shouldn't the default be the default that is to be overridden by\n> other configuration that is more specific?  That is, \"I would\n> normally push to this remote and unless I say otherwise that is all\n> I have to say, but for this particular branch, I push to somehwere\n> else\".\n\nOops, I meant to have it overriden by branch-specific configuration.  Fixed now.\n\n>> diff --git a/builtin/push.c b/builtin/push.c\n>> index 42b129d..d447a80 100644\n>> --- a/builtin/push.c\n>> +++ b/builtin/push.c\n>> @@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)\n>>  static int do_push(const char *repo, int flags)\n>>  {\n>>       int i, errs;\n>> -     struct remote *remote = remote_get(repo);\n>> +     struct remote *remote = pushremote_get(repo);\n>>       const char **url;\n>>       int url_nr;\n>>\n>> diff --git a/remote.c b/remote.c\n>> index e53a6eb..08bb803 100644\n>> --- a/remote.c\n>> +++ b/remote.c\n>> @@ -48,6 +48,7 @@ static int branches_nr;\n>>\n>>  static struct branch *current_branch;\n>>  static const char *default_remote_name;\n>> +static const char *pushremote_name;\n>>  static int explicit_default_remote_name;\n>>\n>>  static struct rewrites rewrites;\n>> @@ -349,6 +350,14 @@ static int handle_config(const char *key, const char *value, void *cb)\n>>       const char *subkey;\n>>       struct remote *remote;\n>>       struct branch *branch;\n>> +     if (!prefixcmp(key,  \"remote.\")) {\n>> +             name = key + 7;\n>> +             if (!strcmp(name, \"pushdefault\")) {\n>> +                     if (!value)\n>> +                             return config_error_nonbool(key);\n>> +                     pushremote_name = xstrdup(value);\n>> +             }\n>> +     }\n>>       if (!prefixcmp(key, \"branch.\")) {\n>>               name = key + 7;\n>>               subkey = strrchr(name, '.');\n>> @@ -388,8 +397,6 @@ static int handle_config(const char *key, const char *value, void *cb)\n>>                       add_instead_of(rewrite, xstrdup(value));\n>>               }\n>>       }\n>> -     if (prefixcmp(key,  \"remote.\"))\n>> -             return 0;\n>\n> Why is this no longer needed?\n>\n> All the remainder of this function is about \"remote.*\" config and\n> this rejects other keys, like \"user.name\", etc.\n\nI'm sorry.  I read that as if (!prefixcmp(key, \"remote.\")), which is\nan entirely different thing.  Fixed now.\n\nThanks.\n"},{"id":"209090","messageId":"7vhallw946.fsf@alter.siamese.dyndns.org","threadId":"32855","inReplyTo":"CALkWK0kp5SvbeTQgLRKWUAT_koSi0wyp6iPTC324iH8+D8oeJg@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-02-09T20:00:25Z","receivedAt":"2013-02-09T20:00:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>\n>> In other words, does it make sense to read branch.$name.pushremote\n>> for all the other irrelevant branches?\n>>\n>> In yet other words, perhaps adding pushremote_name to the branch\n>> structure is unneeded, and you only need this single global\n>> variable?\n>\n> Frankly, I'm unhappy with this global.  Setting a global here and\n> subsequently reading it in pushremote_get() feels flaky.\n\nWhy unhappy?\n\nThis is expressed as a per-branch configuration, but in realitiy the\nconfiguration on any branch that is not the current one does *not*\nmatter an iota.\n\nAn API call find_pushremote_for_branch() that takes a branch name\nand returns the pushremote for that arbitrary branch has no use in\nyour designed feature.  find_pushremote() that tells you where a\nlazy \"git push\" goes under the conditoin is the only thing you need\nin your design.  You can still implement it without globals, e.g.\n\n\tstruct bp { const char *branch; const char *remotename; };\n\n        static int pushremote(const char *var, const char *val, void *cb)\n\t{\n\t\tstruct bp *bp = cb;\n\t        const char *name, *key;\n                int namelen;\n\n\t\tif (!parse_config_key(var, \"branch\", &name, &namelen, &key) &&\n                    namelen == strlen(bp->branch) &&\n                    !memcmp(name, bp->branch, name, namelen) &&\n\t\t    !strcmp(key, \"remotepush\")) {\n\t\t\tgit_config_string(&bp->remotename, var, val);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tchar *find_pushremote(void) {\n\t\tstruct bp bp;\n\n                bp.branch = get_current_branch();\n                bp.remotename = NULL;\n                git_config(pushremote, &bp);\n                return bp.remotename;\n\t}\n\n\nAnd if you want to take default.pushremote that changes a lazy \"git\npush\" to go to somewhere other than \"origin\", you make the\npushremote() callback notice that variable, add one element\n\"defaultremote\" to struct \"bp\" to record that value, and then make\nfind_pushremote() do\n\n\treturn bp.remotename ? bp.remotename : bp.defaultremote;\n\nSometimes \"global variable\" feels disturbing because then we cannot\nrun more than one user at the same time.  One caller may want to\nknow the value for \"foo\" branch while another want it for \"bar\"\nbranch.\n\nBut there is no reason for anybody to want to know the value for the\nvariables branch.$name.pushremote for all defined $name's at the\nsame time, exactly because this matters only for the current branch,\nno?\n\t\t\t\n"},{"id":"209140","messageId":"CALkWK0mjEmErd2A5qb8qdfNMSXG1L0dt8A=ecbSVFGPEg5MxkA@mail.gmail.com","threadId":"32855","inReplyTo":"7vhallw946.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-10T15:41:59Z","receivedAt":"2013-02-10T15:41:59Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Junio C Hamano wrote:\n>         struct bp { const char *branch; const char *remotename; };\n>\n>         static int pushremote(const char *var, const char *val, void *cb)\n>         {\n>                 struct bp *bp = cb;\n>                 const char *name, *key;\n>                 int namelen;\n>\n>                 if (!parse_config_key(var, \"branch\", &name, &namelen, &key) &&\n>                     namelen == strlen(bp->branch) &&\n>                     !memcmp(name, bp->branch, name, namelen) &&\n>                     !strcmp(key, \"remotepush\")) {\n>                         git_config_string(&bp->remotename, var, val);\n>                 }\n>                 return 0;\n>         }\n>\n>         char *find_pushremote(void) {\n>                 struct bp bp;\n>\n>                 bp.branch = get_current_branch();\n>                 bp.remotename = NULL;\n>                 git_config(pushremote, &bp);\n>                 return bp.remotename;\n>         }\n\nI don't get the point of your illustration.  First, we never deal with\na char * branch anywhere: handle_config() immediately calls\nmake_branch() as soon as it parses the name from the config.  Second,\nremote_name is already bundled with the branch struct: why do you need\na new bp struct?  This is how I would do it without relying on a\nglobal:\n\n\tstatic int handle_config(const char *key, const char *value, void *cb) {\n\t\t/* parse branch name here */\n\t\t/* ... */\n\t\tbranch = make_branch(name);\n\t\tif (!strcmp(subkey, \".pushremote\"))\n\t\t\tbranch->pushremote_name = xstrdup(value);\n\t}\n\n\tstruct remote *pushremote_get(struct branch *this_branch)\n\t{\n\t\tif (this_branch == get_current_branch())\n\t\t\tname = this_branch->pushremote_name;\n\t\t/* ... */\n\t\treturn make_remote(name);\n\t}\n\nEssentially, I need to know for which branch we're trying to get the\npushremote: hence the parameter this_branch to pushremote_get().\n\n> But there is no reason for anybody to want to know the value for the\n> variables branch.$name.pushremote for all defined $name's at the\n> same time, exactly because this matters only for the current branch,\n> no?\n\nAh, yes.  You are right.  There's no harm in having globals because\nthere can really be only one current branch, and only one pushremote\ncorresponding to that.  It's just that globals tend to confuse me in\ngeneral, because I have to keep track of a maze of functions that are\ngetting/ setting them.\n"},{"id":"209219","messageId":"CAGL0X-rKnWBy-Ff=YmEdqgo8RFb40FXTxvUM5X77YaQvhAGHYg@mail.gmail.com","threadId":"32855","inReplyTo":"1360307982-20027-1-git-send-email-artagnon@gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Blind","fromEmail":"stoycho.sleptsov@gmail.com","sentAt":"2013-02-11T06:16:50Z","receivedAt":"2013-02-11T06:16:50Z","isPatch":true,"sender":{"key":"stoycho.sleptsov@gmail.com","avatar":null},"body":"If I understand correctly,\nin your scenario the branches with branch.<name>.pushremote\nwill be still included in the $git push <remote> --all?\nAre you considering some way to exclude a branch from \"push --all\"\n(branch.<name>.push = always, explicit, never... for example)?\nOr maybe, if the branch is already marked as special\nwith branch.<name>.pushremote,\nthen it could be logical to push it only when is explicitly specified\non the command line (excluded from --all)?\n\nThanks,\nBlind.\n\n2013/2/8 Ramkumar Ramachandra <artagnon@gmail.com>:\n> This new configuration variable overrides the remote in\n> `branch.<name>.remote` for pushes.  It is useful in the typical\n> scenario, where the remote I'm pulling from is not the remote I'm\n> pushing to.  Although `remote.<name>.pushurl` is similar, it does not\n> serve the purpose as the URL would lack corresponding remote tracking\n> branches.\n>\n> Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n> ---\n>  This is a first cut.  There's code duplication at the moment, but I'm\n>  currently trying to figure out which other remote_get() calls to\n>  replace with pushremote_get().  Comments are welcome.\n>\n>  I will leave it to future patches to do the following things:\n>  1. Fix the status output to be more meaningful when pushremote is\n>  set.  At the moment, I'm thinking statuses like [pull: 4 behind,\n>  push: 3 ahead] will make sense.\n>  2. Introduce a remote.pushDefault (peff)\n>  3. Introduce a remote.default (peff)\n>\n>  Documentation/config.txt |  6 ++++++\n>  builtin/push.c           |  2 +-\n>  remote.c                 | 41 +++++++++++++++++++++++++++++++++++++++++\n>  remote.h                 |  2 ++\n>  4 files changed, 50 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 9b11597..0b3b1f8 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -727,6 +727,12 @@ branch.<name>.remote::\n>         remote to fetch from/push to.  It defaults to `origin` if no remote is\n>         configured. `origin` is also used if you are not on any branch.\n>\n> +branch.<name>.pushremote::\n> +       When in branch <name>, it tells 'git push' which remote to\n> +       push to.  It falls back to `branch.<name>.remote`, and\n> +       defaults to `origin` if no remote is configured. `origin` is\n> +       also used if you are not on any branch.\n> +\n>  branch.<name>.merge::\n>         Defines, together with branch.<name>.remote, the upstream branch\n>         for the given branch. It tells 'git fetch'/'git pull'/'git rebase' which\n> diff --git a/builtin/push.c b/builtin/push.c\n> index 42b129d..d447a80 100644\n> --- a/builtin/push.c\n> +++ b/builtin/push.c\n> @@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)\n>  static int do_push(const char *repo, int flags)\n>  {\n>         int i, errs;\n> -       struct remote *remote = remote_get(repo);\n> +       struct remote *remote = pushremote_get(repo);\n>         const char **url;\n>         int url_nr;\n>\n> diff --git a/remote.c b/remote.c\n> index e53a6eb..d6fcfc0 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -48,6 +48,7 @@ static int branches_nr;\n>\n>  static struct branch *current_branch;\n>  static const char *default_remote_name;\n> +static const char *pushremote_name;\n>  static int explicit_default_remote_name;\n>\n>  static struct rewrites rewrites;\n> @@ -363,6 +364,12 @@ static int handle_config(const char *key, const char *value, void *cb)\n>                                 default_remote_name = branch->remote_name;\n>                                 explicit_default_remote_name = 1;\n>                         }\n> +               } else if (!strcmp(subkey, \".pushremote\")) {\n> +                       if (!value)\n> +                               return config_error_nonbool(key);\n> +                       branch->pushremote_name = xstrdup(value);\n> +                       if (branch == current_branch)\n> +                               pushremote_name = branch->pushremote_name;\n>                 } else if (!strcmp(subkey, \".merge\")) {\n>                         if (!value)\n>                                 return config_error_nonbool(key);\n> @@ -700,6 +707,40 @@ struct remote *remote_get(const char *name)\n>         return ret;\n>  }\n>\n> +struct remote *pushremote_get(const char *name)\n> +{\n> +       struct remote *ret;\n> +       int name_given = 0;\n> +\n> +       read_config();\n> +       if (name)\n> +               name_given = 1;\n> +       else {\n> +               if (pushremote_name) {\n> +                       name = pushremote_name;\n> +                       name_given = 1;\n> +               } else {\n> +                       name = default_remote_name;\n> +                       name_given = explicit_default_remote_name;\n> +               }\n> +       }\n> +\n> +       ret = make_remote(name, 0);\n> +       if (valid_remote_nick(name)) {\n> +               if (!valid_remote(ret))\n> +                       read_remotes_file(ret);\n> +               if (!valid_remote(ret))\n> +                       read_branches_file(ret);\n> +       }\n> +       if (name_given && !valid_remote(ret))\n> +               add_url_alias(ret, name);\n> +       if (!valid_remote(ret))\n> +               return NULL;\n> +       ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);\n> +       ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);\n> +       return ret;\n> +}\n> +\n>  int remote_is_configured(const char *name)\n>  {\n>         int i;\n> diff --git a/remote.h b/remote.h\n> index 251d8fd..aa42ff5 100644\n> --- a/remote.h\n> +++ b/remote.h\n> @@ -51,6 +51,7 @@ struct remote {\n>  };\n>\n>  struct remote *remote_get(const char *name);\n> +struct remote *pushremote_get(const char *name);\n>  int remote_is_configured(const char *name);\n>\n>  typedef int each_remote_fn(struct remote *remote, void *priv);\n> @@ -130,6 +131,7 @@ struct branch {\n>         const char *refname;\n>\n>         const char *remote_name;\n> +       const char *pushremote_name;\n>         struct remote *remote;\n>\n>         const char **merge_name;\n> --\n> 1.8.1.2.545.g2f19ada.dirty\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":"209784","messageId":"CALkWK0kBjsHtK1_7imJx-7CATSKFzpUgGzH6Hs9DAQ8c7jRUPw@mail.gmail.com","threadId":"32855","inReplyTo":"CAGL0X-rKnWBy-Ff=YmEdqgo8RFb40FXTxvUM5X77YaQvhAGHYg@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-19T09:27:47Z","receivedAt":"2013-02-19T09:27:47Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Blind wrote:\n> If I understand correctly,\n> in your scenario the branches with branch.<name>.pushremote\n> will be still included in the $git push <remote> --all?\n\nYes, this is correct.\n\n> Are you considering some way to exclude a branch from \"push --all\"\n> (branch.<name>.push = always, explicit, never... for example)?\n\nNo.  I don't see why push.default is limiting.\n\n> Or maybe, if the branch is already marked as special\n> with branch.<name>.pushremote,\n> then it could be logical to push it only when is explicitly specified\n> on the command line (excluded from --all)?\n\nHuh?  Why would I treat this as a special case?\n"},{"id":"209809","messageId":"CAGL0X-qLikj3bKervpASEixnEVLjBGDN=8QX8K6SG-A2Z_dVUg@mail.gmail.com","threadId":"32855","inReplyTo":"CALkWK0kBjsHtK1_7imJx-7CATSKFzpUgGzH6Hs9DAQ8c7jRUPw@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Blind","fromEmail":"stoycho.sleptsov@gmail.com","sentAt":"2013-02-19T11:18:10Z","receivedAt":"2013-02-19T11:18:10Z","isPatch":true,"sender":{"key":"stoycho.sleptsov@gmail.com","avatar":null},"body":"2013/2/19 Ramkumar Ramachandra:\n> No.  I don't see why push.default is limiting.\n\nI just want to find a way to exclude a branch (or infact a group of\nbranches) from $git push --all.\nso when I read your thing, I thought for a second that it could be a\npossibility... But seems its not the case.\n\n... or branch.<name>.pushremote can support some kind of a \"none\" value?\n\nBlind.\n"},{"id":"209811","messageId":"CALkWK0nJbbA_wjo--LW9v7pP35LS4SUOhZjHVh4dbZqDjSJnew@mail.gmail.com","threadId":"32855","inReplyTo":"CAGL0X-qLikj3bKervpASEixnEVLjBGDN=8QX8K6SG-A2Z_dVUg@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-02-19T11:30:20Z","receivedAt":"2013-02-19T11:30:20Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Blind wrote:\n> 2013/2/19 Ramkumar Ramachandra:\n>> No.  I don't see why push.default is limiting.\n>\n> I just want to find a way to exclude a branch (or infact a group of\n> branches) from $git push --all.\n> so when I read your thing, I thought for a second that it could be a\n> possibility... But seems its not the case.\n\nWhat is your usecase?  If you have a local branch with the same name\nas on the remote, why wouldn't you want to push-to-update it when you\nmake changes in the branch?  In other words, why doesn't push.default\n= matching suffice for most practical purposes.\n\n> ... or branch.<name>.pushremote can support some kind of a \"none\" value?\n\nNot a bad idea at all, provided you tell me your usecase.\n"},{"id":"209812","messageId":"CAGL0X-ocNDea_iRB8-ZjoSXqSkXn-V9F1Tz51GgpzqtLdg5t5Q@mail.gmail.com","threadId":"32855","inReplyTo":"CALkWK0nJbbA_wjo--LW9v7pP35LS4SUOhZjHVh4dbZqDjSJnew@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce branch.<name>.pushremote","fromName":"Blind","fromEmail":"stoycho.sleptsov@gmail.com","sentAt":"2013-02-19T11:51:33Z","receivedAt":"2013-02-19T11:51:33Z","isPatch":true,"sender":{"key":"stoycho.sleptsov@gmail.com","avatar":null},"body":"2013/2/19 Ramkumar Ramachandra:\n>\n> What is your usecase?  If you have a local branch with the same name\n> as on the remote, why wouldn't you want to push-to-update it when you\n> make changes in the branch?  In other words, why doesn't push.default\n> = matching suffice for most practical purposes.\n>\n>> ... or branch.<name>.pushremote can support some kind of a \"none\" value?\n>\n> Not a bad idea at all, provided you tell me your usecase.\n\nThe question is infact about branches who are not on the remote.\npush.default=matching wouldn't upload the branches which are not there already.\npush --all on other hand pushes .. all (as expected :-))...\n\nIts difficult for me to manage quickly, lets say, \"news-to-push/*\" and\n\"crazy-ideas/*\" branches ...\n\nBlind.\n"},{"id":"211475","messageId":"CALkWK0m2N=D47WJLk1F4j1GsGGWHyfxVF_WGXBbG3vyrfQ-oLA@mail.gmail.com","threadId":"32855","inReplyTo":"7v4nhm1s85.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH] Introduce remote.pushdefault","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-17T00:30:08Z","receivedAt":"2013-03-17T00:30:08Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Sorry about the horribly late response- I just got around to\nre-rolling this, and had a doubt.\n\nJunio C Hamano <gitster@pobox.com> wrote:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>\n>> diff --git a/Documentation/config.txt b/Documentation/config.txt\n>> index 9b11597..82a4a78 100644\n>> --- a/Documentation/config.txt\n>> +++ b/Documentation/config.txt\n>> @@ -1884,6 +1884,10 @@ receive.updateserverinfo::\n>>       If set to true, git-receive-pack will run git-update-server-info\n>>       after receiving data from git-push and updating refs.\n>>\n>> +remote.pushdefault::\n>> +     The remote to push to by default.  Overrides the\n>> +     branch-specific configuration `branch.<name>.remote`.\n>\n> It feels unexpected to see \"I may have said while on this branch I\n> push there and on that branch I push somewhere else, but no, with\n> this single configuration I'm invalidating all these previous\n> statements, and all pushes go to this new place\".\n>\n> Shouldn't the default be the default that is to be overridden by\n> other configuration that is more specific?  That is, \"I would\n> normally push to this remote and unless I say otherwise that is all\n> I have to say, but for this particular branch, I push to somehwere\n> else\".\n\nI'm a little confused as to where this configuration variable will be\nuseful.  On a fresh clone from Github, I get branch.master.remote\nconfigured to \"origin\".  How will adding remote.pushdefault have any\nimpact, unless I explicitly remove this branch-specific remote\nconfiguration?  Besides, without branch.<name>.remote configured, I\ncan't even pull and expect changes to be merged.  So, really: what is\nthe use of remote.pushdefault?\n\nI'm dropping this patch, and just going with branch.<name>.pushremote,\nunless you convince me otherwise.\n"},{"id":"211489","messageId":"20130317054803.GB16070@sigill.intra.peff.net","threadId":"32855","inReplyTo":"CALkWK0m2N=D47WJLk1F4j1GsGGWHyfxVF_WGXBbG3vyrfQ-oLA@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce remote.pushdefault","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-03-17T05:48:03Z","receivedAt":"2013-03-17T05:48:03Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Mar 17, 2013 at 06:00:08AM +0530, Ramkumar Ramachandra wrote:\n\n> >> +remote.pushdefault::\n> >> +     The remote to push to by default.  Overrides the\n> >> +     branch-specific configuration `branch.<name>.remote`.\n> >\n> > It feels unexpected to see \"I may have said while on this branch I\n> > push there and on that branch I push somewhere else, but no, with\n> > this single configuration I'm invalidating all these previous\n> > statements, and all pushes go to this new place\".\n> >\n> > Shouldn't the default be the default that is to be overridden by\n> > other configuration that is more specific?  That is, \"I would\n> > normally push to this remote and unless I say otherwise that is all\n> > I have to say, but for this particular branch, I push to somehwere\n> > else\".\n> \n> I'm a little confused as to where this configuration variable will be\n> useful.  On a fresh clone from Github, I get branch.master.remote\n> configured to \"origin\".  How will adding remote.pushdefault have any\n> impact, unless I explicitly remove this branch-specific remote\n> configuration?  Besides, without branch.<name>.remote configured, I\n> can't even pull and expect changes to be merged.  So, really: what is\n> the use of remote.pushdefault?\n> \n> I'm dropping this patch, and just going with branch.<name>.pushremote,\n> unless you convince me otherwise.\n\nThat is why I described the scheme I did in [1]. It uses the following\ntwo general rules:\n\n  1. Per-branch config trumps repo-wide config.\n\n  2. Push-specific config (e.g., \"remote.pushdefault\") trumps\n     non-specific config (e.g., \"remote.default\") for pushing.\n\nSo the push lookup list is (in order of precedence):\n\n  1. branch.*.pushremote\n  2. remote.pushdefault\n  3. branch.*.remote\n  4. remote.default\n  5. origin\n\nand it solves Junio's issue because the way to say \"override my\nremote.pushdefault for this branch\" is not to set \"branch.*.remote\", but\nto set \"branch.*.pushremote\".\n\n-Peff\n\n[1] http://article.gmane.org/gmane.comp.version-control.git/215751\n"},{"id":"211494","messageId":"7vobeisgip.fsf@alter.siamese.dyndns.org","threadId":"32855","inReplyTo":"CALkWK0m2N=D47WJLk1F4j1GsGGWHyfxVF_WGXBbG3vyrfQ-oLA@mail.gmail.com","subject":"Re: [RFC/PATCH] Introduce remote.pushdefault","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-17T06:10:38Z","receivedAt":"2013-03-17T06:10:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> How will adding remote.pushdefault have any\n> impact, unless I explicitly remove this branch-specific remote\n> configuration?  Besides, without branch.<name>.remote configured, I\n> can't even pull and expect changes to be merged.\n\nIf the triangle topology is the norm for your project, I would\nexpect that it would be pretty common to have all of your branches\npull from one place and have all of them push to another place.  In\nthe central repository workflow, it is very common that all of your\nbranches pull from one place and all of them push to the same place.\n\nIn the bigger picture, forcing to set the branch specific remote is\na mistake in the first place; in the longer term, you should be able\nto say \"My project uses the central repository workflow\" once and\nyou should be able to pull without branch.master.remote; just record\nwhere the default \"origin\" for all branches is.\n\nI think the per-branch branch.*.pushremote is actively making things\nworse by repeating the same mistake for the triangle topology.  You\nshould be able to say \"My project uses the triangle workflow\" once\nand specify two remotes, where you pull from and where you push to,\nno?\n\nA per-branch override, be it branch.*.remote or brnach.*.pushremote,\nis useful to give an escape hatch in order to handle special cases\nwith additional flexibility.  But making it the sole mechanism and\nforcing the user to repeat the same \"which remote does it use\" all\nover the place does not sound like a solid engineering.\n"},{"id":"211553","messageId":"CALkWK0niFD81e_GnMDf-bY89J=GdyNbyi9sr-BruHs9wTzsZEg@mail.gmail.com","threadId":"32855","inReplyTo":"20130317054803.GB16070@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] Introduce remote.pushdefault","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-18T09:02:46Z","receivedAt":"2013-03-18T09:02:46Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Jeff King wrote:\n> So the push lookup list is (in order of precedence):\n>\n>   1. branch.*.pushremote\n>   2. remote.pushdefault\n>   3. branch.*.remote\n>   4. remote.default\n>   5. origin\n>\n> and it solves Junio's issue because the way to say \"override my\n> remote.pushdefault for this branch\" is not to set \"branch.*.remote\", but\n> to set \"branch.*.pushremote\".\n\nRight, thanks for clearing that up Jeff.  I'll re-roll with\nremote.pushdefault overriding branch.<name>.remote.\n\nRam\n"}]}