{"thread":{"id":"20863","subject":"[PATCH 0/2] Add url.<base>.pushInsteadOf: URL rewriting for push only","startedAt":"2009-09-07T06:59:28Z","lastAt":"2009-09-07T08:19:52Z","messageCount":5,"participants":["Josh Triplett","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"122584","messageId":"cover.1252306396.git.josh@joshtriplett.org","threadId":"20863","inReplyTo":null,"subject":"[PATCH 0/2] Add url.<base>.pushInsteadOf: URL rewriting for push only","fromName":"Josh Triplett","fromEmail":"josh@joshtriplett.org","sentAt":"2009-09-07T06:59:28Z","receivedAt":"2009-09-07T06:59:28Z","isPatch":true,"sender":{"key":"josh@joshtriplett.org","avatar":"https://avatars.githubusercontent.com/u/162737?v=4"},"body":"Many sites host repositories via both git:// for fetch-only anonymous\naccess and ssh:// for push-capable access.  The \"insteadOf\" mechanism\nmakes it straightforward to substitute the push-capable URLs for the\npull-only URLs, which proves convenient when the site hosts many\nrepositories using the same URL scheme.  However, if you use such a\nsubstitution and you cannot use the ssh:// URLs (either because you\ndon't have SSH access or you don't have permission to a particular\nrepository), you cannot clone or fetch either, even though you could do\nso via the git:// URLs.  A situation like this arises when sharing git\nconfiguration files between systems, of which only a few have SSH access\nto repositories.\n\n\"pushurl\" provides a way to specify URLs used only for push, but this\nrequires configuring a pushurl for each such repository.  As in the\nrationale for insteadOf, it makes sense to configure this for all\nrepositories hosted on a given system at once.\n\nThis patch series adds a new \"pushInsteadOf\" option to go with\n\"insteadOf\".  pushInsteadOf allows systematically rewriting fetch-only\nURLs to push-capable URLs when used with push.  For instance:\n\n[url \"ssh://example.org/\"]\n    pushInsteadOf = \"git://example.org/\"\n\nThis will allow clones of \"git://example.org/path/to/repo\" to\nsubsequently push to \"ssh://example.org/path/to/repo\", without manually\nconfiguring pushurl for that remote.\n\nIncludes documentation for the new option, bash completion updates, and\ntest cases (both that pushInsteadOf applies to push and that it does\n*not* apply to fetch).\n\n\nJosh Triplett (2):\n  Wrap rewrite globals in a struct in preparation for adding another set\n  Add url.<base>.pushInsteadOf: URL rewriting for push only\n\n Documentation/config.txt               |   12 +++++\n Documentation/urls.txt                 |   18 +++++++\n contrib/completion/git-completion.bash |    2 +-\n remote.c                               |   80 +++++++++++++++++++------------\n t/t5516-fetch-push.sh                  |   31 ++++++++++++\n 5 files changed, 111 insertions(+), 32 deletions(-)\n"},{"id":"122585","messageId":"bdf2f41d610eb68d335bfd02c9bf4638a02a225a.1252306396.git.josh@joshtriplett.org","threadId":"20863","inReplyTo":"cover.1252306396.git.josh@joshtriplett.org","subject":"[PATCH 1/2] Wrap rewrite globals in a struct in preparation for adding another set","fromName":"Josh Triplett","fromEmail":"josh@joshtriplett.org","sentAt":"2009-09-07T07:00:00Z","receivedAt":"2009-09-07T07:00:00Z","isPatch":true,"sender":{"key":"josh@joshtriplett.org","avatar":"https://avatars.githubusercontent.com/u/162737?v=4"},"body":"remote.c has a global set of URL rewrites, accessed by alias_url and\nmake_rewrite.  Wrap them in a new \"struct rewrites\", passed to alias_url\nand make_rewrite.  This allows adding other sets of rewrites.\n\nSigned-off-by: Josh Triplett <josh@joshtriplett.org>\n---\n remote.c |   53 ++++++++++++++++++++++++++++-------------------------\n 1 files changed, 28 insertions(+), 25 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 4b5b905..ff8e71f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -28,6 +28,11 @@ struct rewrite {\n \tint instead_of_nr;\n \tint instead_of_alloc;\n };\n+struct rewrites {\n+\tstruct rewrite **rewrite;\n+\tint rewrite_alloc;\n+\tint rewrite_nr;\n+};\n \n static struct remote **remotes;\n static int remotes_alloc;\n@@ -41,14 +46,12 @@ static struct branch *current_branch;\n static const char *default_remote_name;\n static int explicit_default_remote_name;\n \n-static struct rewrite **rewrite;\n-static int rewrite_alloc;\n-static int rewrite_nr;\n+static struct rewrites rewrites;\n \n #define BUF_SIZE (2048)\n static char buffer[BUF_SIZE];\n \n-static const char *alias_url(const char *url)\n+static const char *alias_url(const char *url, struct rewrites *r)\n {\n \tint i, j;\n \tchar *ret;\n@@ -57,14 +60,14 @@ static const char *alias_url(const char *url)\n \n \tlongest = NULL;\n \tlongest_i = -1;\n-\tfor (i = 0; i < rewrite_nr; i++) {\n-\t\tif (!rewrite[i])\n+\tfor (i = 0; i < r->rewrite_nr; i++) {\n+\t\tif (!r->rewrite[i])\n \t\t\tcontinue;\n-\t\tfor (j = 0; j < rewrite[i]->instead_of_nr; j++) {\n-\t\t\tif (!prefixcmp(url, rewrite[i]->instead_of[j].s) &&\n+\t\tfor (j = 0; j < r->rewrite[i]->instead_of_nr; j++) {\n+\t\t\tif (!prefixcmp(url, r->rewrite[i]->instead_of[j].s) &&\n \t\t\t    (!longest ||\n-\t\t\t     longest->len < rewrite[i]->instead_of[j].len)) {\n-\t\t\t\tlongest = &(rewrite[i]->instead_of[j]);\n+\t\t\t     longest->len < r->rewrite[i]->instead_of[j].len)) {\n+\t\t\t\tlongest = &(r->rewrite[i]->instead_of[j]);\n \t\t\t\tlongest_i = i;\n \t\t\t}\n \t\t}\n@@ -72,10 +75,10 @@ static const char *alias_url(const char *url)\n \tif (!longest)\n \t\treturn url;\n \n-\tret = xmalloc(rewrite[longest_i]->baselen +\n+\tret = xmalloc(r->rewrite[longest_i]->baselen +\n \t\t     (strlen(url) - longest->len) + 1);\n-\tstrcpy(ret, rewrite[longest_i]->base);\n-\tstrcpy(ret + rewrite[longest_i]->baselen, url + longest->len);\n+\tstrcpy(ret, r->rewrite[longest_i]->base);\n+\tstrcpy(ret + r->rewrite[longest_i]->baselen, url + longest->len);\n \treturn ret;\n }\n \n@@ -103,7 +106,7 @@ static void add_url(struct remote *remote, const char *url)\n \n static void add_url_alias(struct remote *remote, const char *url)\n {\n-\tadd_url(remote, alias_url(url));\n+\tadd_url(remote, alias_url(url, &rewrites));\n }\n \n static void add_pushurl(struct remote *remote, const char *pushurl)\n@@ -169,22 +172,22 @@ static struct branch *make_branch(const char *name, int len)\n \treturn ret;\n }\n \n-static struct rewrite *make_rewrite(const char *base, int len)\n+static struct rewrite *make_rewrite(struct rewrites *r, const char *base, int len)\n {\n \tstruct rewrite *ret;\n \tint i;\n \n-\tfor (i = 0; i < rewrite_nr; i++) {\n+\tfor (i = 0; i < r->rewrite_nr; i++) {\n \t\tif (len\n-\t\t    ? (len == rewrite[i]->baselen &&\n-\t\t       !strncmp(base, rewrite[i]->base, len))\n-\t\t    : !strcmp(base, rewrite[i]->base))\n-\t\t\treturn rewrite[i];\n+\t\t    ? (len == r->rewrite[i]->baselen &&\n+\t\t       !strncmp(base, r->rewrite[i]->base, len))\n+\t\t    : !strcmp(base, r->rewrite[i]->base))\n+\t\t\treturn r->rewrite[i];\n \t}\n \n-\tALLOC_GROW(rewrite, rewrite_nr + 1, rewrite_alloc);\n+\tALLOC_GROW(r->rewrite, r->rewrite_nr + 1, r->rewrite_alloc);\n \tret = xcalloc(1, sizeof(struct rewrite));\n-\trewrite[rewrite_nr++] = ret;\n+\tr->rewrite[r->rewrite_nr++] = ret;\n \tif (len) {\n \t\tret->base = xstrndup(base, len);\n \t\tret->baselen = len;\n@@ -355,7 +358,7 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\tsubkey = strrchr(name, '.');\n \t\tif (!subkey)\n \t\t\treturn 0;\n-\t\trewrite = make_rewrite(name, subkey - name);\n+\t\trewrite = make_rewrite(&rewrites, name, subkey - name);\n \t\tif (!strcmp(subkey, \".insteadof\")) {\n \t\t\tif (!value)\n \t\t\t\treturn config_error_nonbool(key);\n@@ -433,10 +436,10 @@ static void alias_all_urls(void)\n \t\tif (!remotes[i])\n \t\t\tcontinue;\n \t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n-\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j]);\n+\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n \t\t}\n \t\tfor (j = 0; j < remotes[i]->pushurl_nr; j++) {\n-\t\t\tremotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j]);\n+\t\t\tremotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites);\n \t\t}\n \t}\n }\n-- \n1.6.3.3\n"},{"id":"122586","messageId":"0be9995dcd7d48c918fa75f4d9e557a6144a047c.1252306396.git.josh@joshtriplett.org","threadId":"20863","inReplyTo":"cover.1252306396.git.josh@joshtriplett.org","subject":"[PATCH 2/2] Add url.<base>.pushInsteadOf: URL rewriting for push only","fromName":"Josh Triplett","fromEmail":"josh@joshtriplett.org","sentAt":"2009-09-07T07:00:20Z","receivedAt":"2009-09-07T07:00:20Z","isPatch":true,"sender":{"key":"josh@joshtriplett.org","avatar":"https://avatars.githubusercontent.com/u/162737?v=4"},"body":"This configuration option allows systematically rewriting fetch-only\nURLs to push-capable URLs when used with push.  For instance:\n\n[url \"ssh://example.org/\"]\n    pushInsteadOf = \"git://example.org/\"\n\nThis will allow clones of \"git://example.org/path/to/repo\" to\nsubsequently push to \"ssh://example.org/path/to/repo\", without manually\nconfiguring pushurl for that remote.\n\nIncludes documentation for the new option, bash completion updates, and\ntest cases (both that pushInsteadOf applies to push and that it does\n*not* apply to fetch).\n\nSigned-off-by: Josh Triplett <josh@joshtriplett.org>\n---\n Documentation/config.txt               |   12 +++++++++++\n Documentation/urls.txt                 |   18 +++++++++++++++++\n contrib/completion/git-completion.bash |    2 +-\n remote.c                               |   33 +++++++++++++++++++++++--------\n t/t5516-fetch-push.sh                  |   31 ++++++++++++++++++++++++++++++\n 5 files changed, 86 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5256c7f..726aa89 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1500,6 +1500,18 @@ url.<base>.insteadOf::\n \tnever-before-seen repository on the site.  When more than one\n \tinsteadOf strings match a given URL, the longest match is used.\n \n+url.<base>.pushInsteadOf::\n+\tAny URL that starts with this value will not be pushed to;\n+\tinstead, it will be rewritten to start with <base>, and the\n+\tresulting URL will be pushed to. In cases where some site serves\n+\ta large number of repositories, and serves them with multiple\n+\taccess methods, some of which do not allow push, this feature\n+\tallows people to specify a pull-only URL and have git\n+\tautomatically use an appropriate URL to push, even for a\n+\tnever-before-seen repository on the site.  When more than one\n+\tpushInsteadOf strings match a given URL, the longest match is\n+\tused.\n+\n user.email::\n \tYour email address to be recorded in any newly created commits.\n \tCan be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and\ndiff --git a/Documentation/urls.txt b/Documentation/urls.txt\nindex 5355ebc..d813ceb 100644\n--- a/Documentation/urls.txt\n+++ b/Documentation/urls.txt\n@@ -67,3 +67,21 @@ For example, with this:\n a URL like \"work:repo.git\" or like \"host.xz:/path/to/repo.git\" will be\n rewritten in any context that takes a URL to be \"git://git.host.xz/repo.git\".\n \n+If you want to rewrite URLs for push only, you can create a\n+configuration section of the form:\n+\n+------------\n+\t[url \"<actual url base>\"]\n+\t\tpushInsteadOf = <other url base>\n+------------\n+\n+For example, with this:\n+\n+------------\n+\t[url \"ssh://example.org/\"]\n+\t\tpushInsteadOf = git://example.org/\n+------------\n+\n+a URL like \"git://example.org/path/to/repo.git\" will be rewritten to\n+\"ssh://example.org/path/to/repo.git\" for pushes, but pulls will still\n+use the original URL.\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex bf688e1..9859204 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1532,7 +1532,7 @@ _git_config ()\n \turl.*.*)\n \t\tlocal pfx=\"${cur%.*}.\"\n \t\tcur=\"${cur##*.}\"\n-\t\t__gitcomp \"insteadof\" \"$pfx\" \"$cur\"\n+\t\t__gitcomp \"insteadOf pushInsteadOf\" \"$pfx\" \"$cur\"\n \t\treturn\n \t\t;;\n \tesac\ndiff --git a/remote.c b/remote.c\nindex ff8e71f..6789786 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -47,6 +47,7 @@ static const char *default_remote_name;\n static int explicit_default_remote_name;\n \n static struct rewrites rewrites;\n+static struct rewrites rewrites_push;\n \n #define BUF_SIZE (2048)\n static char buffer[BUF_SIZE];\n@@ -104,17 +105,25 @@ static void add_url(struct remote *remote, const char *url)\n \tremote->url[remote->url_nr++] = url;\n }\n \n-static void add_url_alias(struct remote *remote, const char *url)\n-{\n-\tadd_url(remote, alias_url(url, &rewrites));\n-}\n-\n static void add_pushurl(struct remote *remote, const char *pushurl)\n {\n \tALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc);\n \tremote->pushurl[remote->pushurl_nr++] = pushurl;\n }\n \n+static void add_pushurl_alias(struct remote *remote, const char *url)\n+{\n+\tconst char *pushurl = alias_url(url, &rewrites_push);\n+\tif (pushurl != url)\n+\t\tadd_pushurl(remote, pushurl);\n+}\n+\n+static void add_url_alias(struct remote *remote, const char *url)\n+{\n+\tadd_url(remote, alias_url(url, &rewrites));\n+\tadd_pushurl_alias(remote, url);\n+}\n+\n static struct remote *make_remote(const char *name, int len)\n {\n \tstruct remote *ret;\n@@ -358,8 +367,13 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\tsubkey = strrchr(name, '.');\n \t\tif (!subkey)\n \t\t\treturn 0;\n-\t\trewrite = make_rewrite(&rewrites, name, subkey - name);\n \t\tif (!strcmp(subkey, \".insteadof\")) {\n+\t\t\trewrite = make_rewrite(&rewrites, name, subkey - name);\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(key);\n+\t\t\tadd_instead_of(rewrite, xstrdup(value));\n+\t\t} else if (!strcmp(subkey, \".pushinsteadof\")) {\n+\t\t\trewrite = make_rewrite(&rewrites_push, name, subkey - name);\n \t\t\tif (!value)\n \t\t\t\treturn config_error_nonbool(key);\n \t\t\tadd_instead_of(rewrite, xstrdup(value));\n@@ -435,12 +449,13 @@ static void alias_all_urls(void)\n \tfor (i = 0; i < remotes_nr; i++) {\n \t\tif (!remotes[i])\n \t\t\tcontinue;\n-\t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n-\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n-\t\t}\n \t\tfor (j = 0; j < remotes[i]->pushurl_nr; j++) {\n \t\t\tremotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites);\n \t\t}\n+\t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n+\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n+\t\t\tadd_pushurl_alias(remotes[i], remotes[i]->url[j]);\n+\t\t}\n \t}\n }\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 2d2633f..8f455c7 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -122,6 +122,23 @@ test_expect_success 'fetch with insteadOf' '\n \t)\n '\n \n+test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '\n+\tmk_empty &&\n+\t(\n+\t\tTRASH=$(pwd)/ &&\n+\t\tcd testrepo &&\n+\t\tgit config \"url.trash/.pushInsteadOf\" \"$TRASH\" &&\n+\t\tgit config remote.up.url \"$TRASH.\" &&\n+\t\tgit config remote.up.fetch \"refs/heads/*:refs/remotes/origin/*\" &&\n+\t\tgit fetch up &&\n+\n+\t\tr=$(git show-ref -s --verify refs/remotes/origin/master) &&\n+\t\ttest \"z$r\" = \"z$the_commit\" &&\n+\n+\t\ttest 1 = $(git for-each-ref refs/remotes/origin | wc -l)\n+\t)\n+'\n+\n test_expect_success 'push without wildcard' '\n \tmk_empty &&\n \n@@ -162,6 +179,20 @@ test_expect_success 'push with insteadOf' '\n \t)\n '\n \n+test_expect_success 'push with pushInsteadOf' '\n+\tmk_empty &&\n+\tTRASH=\"$(pwd)/\" &&\n+\tgit config \"url.$TRASH.pushInsteadOf\" trash/ &&\n+\tgit push trash/testrepo refs/heads/master:refs/remotes/origin/master &&\n+\t(\n+\t\tcd testrepo &&\n+\t\tr=$(git show-ref -s --verify refs/remotes/origin/master) &&\n+\t\ttest \"z$r\" = \"z$the_commit\" &&\n+\n+\t\ttest 1 = $(git for-each-ref refs/remotes/origin | wc -l)\n+\t)\n+'\n+\n test_expect_success 'push with matching heads' '\n \n \tmk_test heads/master &&\n-- \n1.6.3.3\n"},{"id":"122591","messageId":"7vljkr2ntd.fsf@alter.siamese.dyndns.org","threadId":"20863","inReplyTo":"0be9995dcd7d48c918fa75f4d9e557a6144a047c.1252306396.git.josh@joshtriplett.org","subject":"Re: [PATCH 2/2] Add url.<base>.pushInsteadOf: URL rewriting for push only","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-09-07T07:53:18Z","receivedAt":"2009-09-07T07:53:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josh Triplett <josh@joshtriplett.org> writes:\n\n> This configuration option allows systematically rewriting fetch-only\n> URLs to push-capable URLs when used with push.  For instance:\n>\n> [url \"ssh://example.org/\"]\n>     pushInsteadOf = \"git://example.org/\"\n>\n> This will allow clones of \"git://example.org/path/to/repo\" to\n> subsequently push to \"ssh://example.org/path/to/repo\", without manually\n> configuring pushurl for that remote.\n\nNice.\n\n> @@ -435,12 +449,13 @@ static void alias_all_urls(void)\n>  \tfor (i = 0; i < remotes_nr; i++) {\n>  \t\tif (!remotes[i])\n>  \t\t\tcontinue;\n> -\t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n> -\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n> -\t\t}\n>  \t\tfor (j = 0; j < remotes[i]->pushurl_nr; j++) {\n>  \t\t\tremotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites);\n>  \t\t}\n> +\t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n> +\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n> +\t\t\tadd_pushurl_alias(remotes[i], remotes[i]->url[j]);\n> +\t\t}\n\nEven if you have URL but not pushURL, now you get a corresponding pushURL\nfor free by just adding pushinsteadof mapping that covers the URL without\nhaving to configue pushURL for each of them.\n\nWhat happens if you already had a pair of concrete url and pushurl defined\nfor one of your repositories (say git://git.kernel.org/pub/scm/git/git.git\nfor fetch, ssh://x.kernel.org/pub/scm/git/git.git for push) at a site, and\nthen upon seeing this new feature, added a pushinsteadof pattern that also\ncovers the URL side of that pair (e.g. everything in git://git.kernel.org/\nis mapped to x.kernel.org:/ namespsace)?\n\nDo you end up pushing to both (e.g. ssh://x.kernel.org/pub/scm/git/git.git\nand x.kernel.org:/pub/scm/git/git.git), or in such a case, the pushURL you\ngave explicitly prevents the pushinsteadof to give unexpected duplicates?\n"},{"id":"122597","messageId":"20090907081952.GA21550@feather","threadId":"20863","inReplyTo":"7vljkr2ntd.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/2] Add url.<base>.pushInsteadOf: URL rewriting for push only","fromName":"Josh Triplett","fromEmail":"josh@joshtriplett.org","sentAt":"2009-09-07T08:19:52Z","receivedAt":"2009-09-07T08:19:52Z","isPatch":true,"sender":{"key":"josh@joshtriplett.org","avatar":"https://avatars.githubusercontent.com/u/162737?v=4"},"body":"On Mon, Sep 07, 2009 at 12:53:18AM -0700, Junio C Hamano wrote:\n> Josh Triplett <josh@joshtriplett.org> writes:\n> > This configuration option allows systematically rewriting fetch-only\n> > URLs to push-capable URLs when used with push.  For instance:\n> >\n> > [url \"ssh://example.org/\"]\n> >     pushInsteadOf = \"git://example.org/\"\n> >\n> > This will allow clones of \"git://example.org/path/to/repo\" to\n> > subsequently push to \"ssh://example.org/path/to/repo\", without manually\n> > configuring pushurl for that remote.\n> \n> Nice.\n\nThanks.\n\n> > @@ -435,12 +449,13 @@ static void alias_all_urls(void)\n> >  \tfor (i = 0; i < remotes_nr; i++) {\n> >  \t\tif (!remotes[i])\n> >  \t\t\tcontinue;\n> > -\t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n> > -\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n> > -\t\t}\n> >  \t\tfor (j = 0; j < remotes[i]->pushurl_nr; j++) {\n> >  \t\t\tremotes[i]->pushurl[j] = alias_url(remotes[i]->pushurl[j], &rewrites);\n> >  \t\t}\n> > +\t\tfor (j = 0; j < remotes[i]->url_nr; j++) {\n> > +\t\t\tremotes[i]->url[j] = alias_url(remotes[i]->url[j], &rewrites);\n> > +\t\t\tadd_pushurl_alias(remotes[i], remotes[i]->url[j]);\n> > +\t\t}\n> \n> Even if you have URL but not pushURL, now you get a corresponding pushURL\n> for free by just adding pushinsteadof mapping that covers the URL without\n> having to configue pushURL for each of them.\n\nYes, exactly.\n\n> What happens if you already had a pair of concrete url and pushurl defined\n> for one of your repositories (say git://git.kernel.org/pub/scm/git/git.git\n> for fetch, ssh://x.kernel.org/pub/scm/git/git.git for push) at a site, and\n> then upon seeing this new feature, added a pushinsteadof pattern that also\n> covers the URL side of that pair (e.g. everything in git://git.kernel.org/\n> is mapped to x.kernel.org:/ namespsace)?\n> \n> Do you end up pushing to both (e.g. ssh://x.kernel.org/pub/scm/git/git.git\n> and x.kernel.org:/pub/scm/git/git.git), or in such a case, the pushURL you\n> gave explicitly prevents the pushinsteadof to give unexpected duplicates?\n\nYou get a duplicate:\n\n~$ grep -B1 steadOf .gitconfig\n[url \"ssh://joshtriplett.org/\"]\n        pushInsteadOf=\"git://joshtriplett.org/\"\n~$ grep -B1 url .git/config\n[remote \"origin\"]\n        url = git://joshtriplett.org/git/home.git\n        pushurl = ssh://joshtriplett.org/git/home.git\n~$ ~/src/git/git push\nEverything up-to-date\nEverything up-to-date\n\nInitially, that behavior seemed pretty reasonable to me; nothing else in\nthe remotes handling attempts to remove duplicates, and they seem\nharmless enough and easily resolved by removing one or the other.  Now\nthat I think about it, though, an explicit pushurl should definitely\ndisable pushInsteadOf's implicit pushurls.  If you explicitly configure\na *different* pushurl for a remote, you may not *want* the default\npushurl that corresponds to your url.  For instance, consider what would\nhappen if you configure url to point to the main public repository and\npushurl to point to a private repository.  In this case, you definitely\ndon't want \"git push\" to helpfully push to the public repository as\nwell; if you do, you can easily enough add a second pushurl for that.\n\nI can easily change the patch to make an explicit pushurl disable\npushInsteadOf.  Expect v2 shortly.\n\n- Josh Triplett\n"}]}