{"thread":{"id":"22269","subject":"[PATCH] Add git remote set-url","startedAt":"2010-01-18T17:18:02Z","lastAt":"2010-01-18T17:18:02Z","messageCount":1,"participants":["Ilari Liusvaara"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"132036","messageId":"1263835082-21506-1-git-send-email-ilari.liusvaara@elisanet.fi","threadId":"22269","inReplyTo":null,"subject":"[PATCH] Add git remote set-url","fromName":"Ilari Liusvaara","fromEmail":"ilari.liusvaara@elisanet.fi","sentAt":"2010-01-18T17:18:02Z","receivedAt":"2010-01-18T17:18:02Z","isPatch":true,"sender":{"key":"ilari.liusvaara@elisanet.fi","avatar":null},"body":"Add 'git remote set-url' for changing URL of remote repository with\none \"porcelain-level\" command.\n\nSigned-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>\n---\nBuilt atop master. Another one from my TODO list.\n\n Documentation/git-remote.txt |   17 ++++\n builtin-remote.c             |  100 +++++++++++++++++++\n t/t5505-remote.sh            |  216 +++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 332 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex c272c92..35d32f7 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -14,6 +14,9 @@ SYNOPSIS\n 'git remote rename' <old> <new>\n 'git remote rm' <name>\n 'git remote set-head' <name> (-a | -d | <branch>)\n+'git remote set-url' [--push] <name> <newurl> [<oldurl>]\n+'git remote set-url --add' [--push] <name> <newurl>\n+'git remote set-url --delete' [--push] <name> <url>\n 'git remote' [-v | --verbose] 'show' [-n] <name>\n 'git remote prune' [-n | --dry-run] <name>\n 'git remote' [-v | --verbose] 'update' [-p | --prune] [group | remote]...\n@@ -101,6 +104,20 @@ remote set-head origin master\" will set `$GIT_DIR/refs/remotes/origin/HEAD` to\n `refs/remotes/origin/master` already exists; if not it must be fetched first.\n +\n \n+'set-url'::\n+\n+Changes URL remote points to. Sets first URL remote points to matching\n+regex <oldurl> (first URL if no <oldurl> is given) to <newurl>. If\n+<oldurl> doesn't match any URL, error occurs and nothing is changed.\n++\n+With '--push', push URLs are manipulated instead of fetch URLs.\n++\n+With '--add', instead of changing some URL, new URL is added.\n++\n+With '--delete', instead of changing some URL, all URLs matching\n+regex <url> are deleted. Trying to delete all non-push URLs is an\n+error.\n+\n 'show'::\n \n Gives some information about the remote <name>.\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex c4945b8..03ac7ee 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -16,6 +16,9 @@ static const char * const builtin_remote_usage[] = {\n \t\"git remote [-v | --verbose] show [-n] <name>\",\n \t\"git remote prune [-n | --dry-run] <name>\",\n \t\"git remote [-v | --verbose] update [-p | --prune] [group | remote]\",\n+\t\"git remote set-url <name> <newurl> [<oldurl>]\",\n+\t\"git remote set-url --add <name> <newurl>\",\n+\t\"git remote set-url --delete <name> <url>\",\n \tNULL\n };\n \n@@ -54,12 +57,21 @@ static const char * const builtin_remote_update_usage[] = {\n \tNULL\n };\n \n+static const char * const builtin_remote_seturl_usage[] = {\n+\t\"git remote set-url [--push] <name> <newurl> [<oldurl>]\",\n+\t\"git remote set-url --add <name> <newurl>\",\n+\t\"git remote set-url --delete <name> <url>\",\n+\tNULL\n+};\n+\n #define GET_REF_STATES (1<<0)\n #define GET_HEAD_NAMES (1<<1)\n #define GET_PUSH_REF_STATES (1<<2)\n \n static int verbose;\n \n+\n+\n static int show_all(void);\n static int prune_remote(const char *remote, int dry_run);\n \n@@ -1255,6 +1267,92 @@ static int update(int argc, const char **argv)\n \treturn run_command_v_opt(fetch_argv, RUN_GIT_CMD);\n }\n \n+static int set_url(int argc, const char **argv)\n+{\n+\tint i, push_mode = 0, add_mode = 0, delete_mode = 0;\n+\tint matches = 0, negative_matches = 0;\n+\tconst char *remotename = NULL;\n+\tconst char *newurl = NULL;\n+\tconst char *oldurl = NULL;\n+\tstruct remote *remote;\n+\tregex_t old_regex;\n+\tconst char **urlset;\n+\tint urlset_nr;\n+\tstruct strbuf name_buf = STRBUF_INIT;\n+\tstruct option options[] = {\n+\t\tOPT_BOOLEAN('\\0', \"push\", &push_mode,\n+\t\t\t    \"manipulate push URLs\"),\n+\t\tOPT_BOOLEAN('\\0', \"add\", &add_mode,\n+\t\t\t    \"add URL\"),\n+\t\tOPT_BOOLEAN('\\0', \"delete\", &delete_mode,\n+\t\t\t    \"delete URLs\"),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,\n+\t\t\t     PARSE_OPT_KEEP_ARGV0);\n+\n+\tif (add_mode && delete_mode)\n+\t\tdie(\"--add --delete doesn't make sense\");\n+\n+\tif (argc < 3 || argc > 4 || ((add_mode || delete_mode) && argc != 3))\n+\t\tusage_with_options(builtin_remote_seturl_usage, options);\n+\n+\tremotename = argv[1];\n+\tnewurl = argv[2];\n+\tif (argc > 3)\n+\t\toldurl = argv[3];\n+\n+\tif (delete_mode)\n+\t\toldurl = newurl;\n+\n+\tif (!remote_is_configured(remotename))\n+\t\tdie(\"No such remote '%s'\", remotename);\n+\tremote = remote_get(remotename);\n+\n+\tif (push_mode) {\n+\t\tstrbuf_addf(&name_buf, \"remote.%s.pushurl\", remotename);\n+\t\turlset = remote->pushurl;\n+\t\turlset_nr = remote->pushurl_nr;\n+\t} else {\n+\t\tstrbuf_addf(&name_buf, \"remote.%s.url\", remotename);\n+\t\turlset = remote->url;\n+\t\turlset_nr = remote->url_nr;\n+\t}\n+\n+\t/* Special cases that add new entry. */\n+\tif ((!oldurl && !delete_mode) || add_mode) {\n+\t\tif (add_mode)\n+\t\t\tgit_config_set_multivar(name_buf.buf, newurl,\n+\t\t\t\t\"^$\", 0);\n+\t\telse\n+\t\t\tgit_config_set(name_buf.buf, newurl);\n+\t\tstrbuf_release(&name_buf);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Old URL specified. Demand that one matches. */\n+\tif (regcomp(&old_regex, oldurl, REG_EXTENDED))\n+\t\tdie(\"Invalid old URL pattern: %s\", oldurl);\n+\n+\tfor (i = 0; i < urlset_nr; i++)\n+\t\tif (!regexec(&old_regex, urlset[i], 0, NULL, 0))\n+\t\t\tmatches++;\n+\t\telse\n+\t\t\tnegative_matches++;\n+\tif (!delete_mode && !matches)\n+\t\tdie(\"No such URL found: %s\", oldurl);\n+\tif (delete_mode && !negative_matches && !push_mode)\n+\t\tdie(\"Will not delete all non-push URLs\");\n+\n+\tregfree(&old_regex);\n+\n+\tif (!delete_mode)\n+\t\tgit_config_set_multivar(name_buf.buf, newurl, oldurl, 0);\n+\telse\n+\t\tgit_config_set_multivar(name_buf.buf, NULL, oldurl, 1);\n+\treturn 0;\n+}\n+\n static int get_one_entry(struct remote *remote, void *priv)\n {\n \tstruct string_list *list = priv;\n@@ -1334,6 +1432,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)\n \t\tresult = rm(argc, argv);\n \telse if (!strcmp(argv[0], \"set-head\"))\n \t\tresult = set_head(argc, argv);\n+\telse if (!strcmp(argv[0], \"set-url\"))\n+\t\tresult = set_url(argc, argv);\n \telse if (!strcmp(argv[0], \"show\"))\n \t\tresult = show(argc, argv);\n \telse if (!strcmp(argv[0], \"prune\"))\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 936fe0a..a82c5ff 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -533,5 +533,219 @@ test_expect_success 'show empty remote' '\n \t)\n '\n \n-test_done\n+test_expect_success 'new remote' '\n+(\n+\tgit remote add someremote foo &&\n+\techo foo >expect &&\n+\tgit config --get-all remote.someremote.url >actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url bar' '\n+(\n+\tgit remote set-url someremote bar &&\n+\techo bar >expect &&\n+\tgit config --get-all remote.someremote.url >actual &&\n+\tcmp expect actual\n+)\n+'\n \n+test_expect_success 'remote set-url baz bar' '\n+(\n+\tgit remote set-url someremote baz bar &&\n+\techo baz >expect &&\n+\tgit config --get-all remote.someremote.url >actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url zot bar' '\n+(\n+\ttest_must_fail git remote set-url someremote zot bar &&\n+\techo baz >expect &&\n+\tgit config --get-all remote.someremote.url >actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push zot baz' '\n+(\n+\ttest_must_fail git remote set-url --push someremote zot baz &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push zot' '\n+(\n+\tgit remote set-url --push someremote zot &&\n+\techo zot >expect &&\n+\techo \"YYY\" >>expect &&\n+\techo baz >>expect &&\n+\tgit config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push qux zot' '\n+(\n+\tgit remote set-url --push someremote qux zot &&\n+\techo qux >expect &&\n+\techo \"YYY\" >>expect &&\n+\techo baz >>expect &&\n+\tgit config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push foo qu+x' '\n+(\n+\tgit remote set-url --push someremote foo qu+x &&\n+\techo foo >expect &&\n+\techo \"YYY\" >>expect &&\n+\techo baz >>expect &&\n+\tgit config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push --add aaa' '\n+(\n+\tgit remote set-url --push --add someremote aaa &&\n+\techo foo >expect &&\n+\techo aaa >>expect &&\n+\techo \"YYY\" >>expect &&\n+\techo baz >>expect &&\n+\tgit config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push bar aaa' '\n+(\n+\tgit remote set-url --push someremote bar aaa &&\n+\techo foo >expect &&\n+\techo bar >>expect &&\n+\techo \"YYY\" >>expect &&\n+\techo baz >>expect &&\n+\tgit config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push --delete bar' '\n+(\n+\tgit remote set-url --push --delete someremote bar &&\n+\techo foo >expect &&\n+\techo \"YYY\" >>expect &&\n+\techo baz >>expect &&\n+\tgit config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --push --delete foo' '\n+(\n+\tgit remote set-url --push --delete someremote foo &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --add bbb' '\n+(\n+\tgit remote set-url --add someremote bbb &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\techo bbb >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --delete .*' '\n+(\n+\ttest_must_fail git remote set-url --delete someremote .* &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\techo bbb >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --delete bbb' '\n+(\n+\tgit remote set-url --delete someremote bbb &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --delete baz' '\n+(\n+\ttest_must_fail git remote set-url --delete someremote baz &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --add ccc' '\n+(\n+\tgit remote set-url --add someremote ccc &&\n+\techo \"YYY\" >expect &&\n+\techo baz >>expect &&\n+\techo ccc >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_expect_success 'remote set-url --delete baz' '\n+(\n+\tgit remote set-url --delete someremote baz &&\n+\techo \"YYY\" >expect &&\n+\techo ccc >>expect &&\n+\ttest_must_fail git config --get-all remote.someremote.pushurl >actual &&\n+\techo \"YYY\" >>actual &&\n+\tgit config --get-all remote.someremote.url >>actual &&\n+\tcmp expect actual\n+)\n+'\n+\n+test_done\n-- \n1.6.6.199.gff4b0\n"}]}