Skip to content

Commit 433f2be

Browse files
Ilari Liusvaaragitster
authored andcommitted
Add git remote set-url
Add 'git remote set-url' for changing URL of remote repository with one "porcelain-level" command. Signed-off-by: Ilari Liusvaara <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ff6d26a commit 433f2be

File tree

3 files changed

+330
-1
lines changed

3 files changed

+330
-1
lines changed

Documentation/git-remote.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ SYNOPSIS
1414
'git remote rename' <old> <new>
1515
'git remote rm' <name>
1616
'git remote set-head' <name> (-a | -d | <branch>)
17+
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
18+
'git remote set-url --add' [--push] <name> <newurl>
19+
'git remote set-url --delete' [--push] <name> <url>
1720
'git remote' [-v | --verbose] 'show' [-n] <name>
1821
'git remote prune' [-n | --dry-run] <name>
1922
'git remote' [-v | --verbose] 'update' [-p | --prune] [group | remote]...
@@ -101,6 +104,20 @@ remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
101104
`refs/remotes/origin/master` already exists; if not it must be fetched first.
102105
+
103106

107+
'set-url'::
108+
109+
Changes URL remote points to. Sets first URL remote points to matching
110+
regex <oldurl> (first URL if no <oldurl> is given) to <newurl>. If
111+
<oldurl> doesn't match any URL, error occurs and nothing is changed.
112+
+
113+
With '--push', push URLs are manipulated instead of fetch URLs.
114+
+
115+
With '--add', instead of changing some URL, new URL is added.
116+
+
117+
With '--delete', instead of changing some URL, all URLs matching
118+
regex <url> are deleted. Trying to delete all non-push URLs is an
119+
error.
120+
104121
'show'::
105122

106123
Gives some information about the remote <name>.

builtin-remote.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ static const char * const builtin_remote_usage[] = {
1616
"git remote [-v | --verbose] show [-n] <name>",
1717
"git remote prune [-n | --dry-run] <name>",
1818
"git remote [-v | --verbose] update [-p | --prune] [group | remote]",
19+
"git remote set-url <name> <newurl> [<oldurl>]",
20+
"git remote set-url --add <name> <newurl>",
21+
"git remote set-url --delete <name> <url>",
1922
NULL
2023
};
2124

@@ -54,6 +57,13 @@ static const char * const builtin_remote_update_usage[] = {
5457
NULL
5558
};
5659

60+
static const char * const builtin_remote_seturl_usage[] = {
61+
"git remote set-url [--push] <name> <newurl> [<oldurl>]",
62+
"git remote set-url --add <name> <newurl>",
63+
"git remote set-url --delete <name> <url>",
64+
NULL
65+
};
66+
5767
#define GET_REF_STATES (1<<0)
5868
#define GET_HEAD_NAMES (1<<1)
5969
#define GET_PUSH_REF_STATES (1<<2)
@@ -1255,6 +1265,92 @@ static int update(int argc, const char **argv)
12551265
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
12561266
}
12571267

1268+
static int set_url(int argc, const char **argv)
1269+
{
1270+
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
1271+
int matches = 0, negative_matches = 0;
1272+
const char *remotename = NULL;
1273+
const char *newurl = NULL;
1274+
const char *oldurl = NULL;
1275+
struct remote *remote;
1276+
regex_t old_regex;
1277+
const char **urlset;
1278+
int urlset_nr;
1279+
struct strbuf name_buf = STRBUF_INIT;
1280+
struct option options[] = {
1281+
OPT_BOOLEAN('\0', "push", &push_mode,
1282+
"manipulate push URLs"),
1283+
OPT_BOOLEAN('\0', "add", &add_mode,
1284+
"add URL"),
1285+
OPT_BOOLEAN('\0', "delete", &delete_mode,
1286+
"delete URLs"),
1287+
OPT_END()
1288+
};
1289+
argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
1290+
PARSE_OPT_KEEP_ARGV0);
1291+
1292+
if (add_mode && delete_mode)
1293+
die("--add --delete doesn't make sense");
1294+
1295+
if (argc < 3 || argc > 4 || ((add_mode || delete_mode) && argc != 3))
1296+
usage_with_options(builtin_remote_seturl_usage, options);
1297+
1298+
remotename = argv[1];
1299+
newurl = argv[2];
1300+
if (argc > 3)
1301+
oldurl = argv[3];
1302+
1303+
if (delete_mode)
1304+
oldurl = newurl;
1305+
1306+
if (!remote_is_configured(remotename))
1307+
die("No such remote '%s'", remotename);
1308+
remote = remote_get(remotename);
1309+
1310+
if (push_mode) {
1311+
strbuf_addf(&name_buf, "remote.%s.pushurl", remotename);
1312+
urlset = remote->pushurl;
1313+
urlset_nr = remote->pushurl_nr;
1314+
} else {
1315+
strbuf_addf(&name_buf, "remote.%s.url", remotename);
1316+
urlset = remote->url;
1317+
urlset_nr = remote->url_nr;
1318+
}
1319+
1320+
/* Special cases that add new entry. */
1321+
if ((!oldurl && !delete_mode) || add_mode) {
1322+
if (add_mode)
1323+
git_config_set_multivar(name_buf.buf, newurl,
1324+
"^$", 0);
1325+
else
1326+
git_config_set(name_buf.buf, newurl);
1327+
strbuf_release(&name_buf);
1328+
return 0;
1329+
}
1330+
1331+
/* Old URL specified. Demand that one matches. */
1332+
if (regcomp(&old_regex, oldurl, REG_EXTENDED))
1333+
die("Invalid old URL pattern: %s", oldurl);
1334+
1335+
for (i = 0; i < urlset_nr; i++)
1336+
if (!regexec(&old_regex, urlset[i], 0, NULL, 0))
1337+
matches++;
1338+
else
1339+
negative_matches++;
1340+
if (!delete_mode && !matches)
1341+
die("No such URL found: %s", oldurl);
1342+
if (delete_mode && !negative_matches && !push_mode)
1343+
die("Will not delete all non-push URLs");
1344+
1345+
regfree(&old_regex);
1346+
1347+
if (!delete_mode)
1348+
git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
1349+
else
1350+
git_config_set_multivar(name_buf.buf, NULL, oldurl, 1);
1351+
return 0;
1352+
}
1353+
12581354
static int get_one_entry(struct remote *remote, void *priv)
12591355
{
12601356
struct string_list *list = priv;
@@ -1334,6 +1430,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
13341430
result = rm(argc, argv);
13351431
else if (!strcmp(argv[0], "set-head"))
13361432
result = set_head(argc, argv);
1433+
else if (!strcmp(argv[0], "set-url"))
1434+
result = set_url(argc, argv);
13371435
else if (!strcmp(argv[0], "show"))
13381436
result = show(argc, argv);
13391437
else if (!strcmp(argv[0], "prune"))

t/t5505-remote.sh

Lines changed: 215 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,5 +533,219 @@ test_expect_success 'show empty remote' '
533533
)
534534
'
535535

536-
test_done
536+
test_expect_success 'new remote' '
537+
(
538+
git remote add someremote foo &&
539+
echo foo >expect &&
540+
git config --get-all remote.someremote.url >actual &&
541+
cmp expect actual
542+
)
543+
'
544+
545+
test_expect_success 'remote set-url bar' '
546+
(
547+
git remote set-url someremote bar &&
548+
echo bar >expect &&
549+
git config --get-all remote.someremote.url >actual &&
550+
cmp expect actual
551+
)
552+
'
537553

554+
test_expect_success 'remote set-url baz bar' '
555+
(
556+
git remote set-url someremote baz bar &&
557+
echo baz >expect &&
558+
git config --get-all remote.someremote.url >actual &&
559+
cmp expect actual
560+
)
561+
'
562+
563+
test_expect_success 'remote set-url zot bar' '
564+
(
565+
test_must_fail git remote set-url someremote zot bar &&
566+
echo baz >expect &&
567+
git config --get-all remote.someremote.url >actual &&
568+
cmp expect actual
569+
)
570+
'
571+
572+
test_expect_success 'remote set-url --push zot baz' '
573+
(
574+
test_must_fail git remote set-url --push someremote zot baz &&
575+
echo "YYY" >expect &&
576+
echo baz >>expect &&
577+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
578+
echo "YYY" >>actual &&
579+
git config --get-all remote.someremote.url >>actual &&
580+
cmp expect actual
581+
)
582+
'
583+
584+
test_expect_success 'remote set-url --push zot' '
585+
(
586+
git remote set-url --push someremote zot &&
587+
echo zot >expect &&
588+
echo "YYY" >>expect &&
589+
echo baz >>expect &&
590+
git config --get-all remote.someremote.pushurl >actual &&
591+
echo "YYY" >>actual &&
592+
git config --get-all remote.someremote.url >>actual &&
593+
cmp expect actual
594+
)
595+
'
596+
597+
test_expect_success 'remote set-url --push qux zot' '
598+
(
599+
git remote set-url --push someremote qux zot &&
600+
echo qux >expect &&
601+
echo "YYY" >>expect &&
602+
echo baz >>expect &&
603+
git config --get-all remote.someremote.pushurl >actual &&
604+
echo "YYY" >>actual &&
605+
git config --get-all remote.someremote.url >>actual &&
606+
cmp expect actual
607+
)
608+
'
609+
610+
test_expect_success 'remote set-url --push foo qu+x' '
611+
(
612+
git remote set-url --push someremote foo qu+x &&
613+
echo foo >expect &&
614+
echo "YYY" >>expect &&
615+
echo baz >>expect &&
616+
git config --get-all remote.someremote.pushurl >actual &&
617+
echo "YYY" >>actual &&
618+
git config --get-all remote.someremote.url >>actual &&
619+
cmp expect actual
620+
)
621+
'
622+
623+
test_expect_success 'remote set-url --push --add aaa' '
624+
(
625+
git remote set-url --push --add someremote aaa &&
626+
echo foo >expect &&
627+
echo aaa >>expect &&
628+
echo "YYY" >>expect &&
629+
echo baz >>expect &&
630+
git config --get-all remote.someremote.pushurl >actual &&
631+
echo "YYY" >>actual &&
632+
git config --get-all remote.someremote.url >>actual &&
633+
cmp expect actual
634+
)
635+
'
636+
637+
test_expect_success 'remote set-url --push bar aaa' '
638+
(
639+
git remote set-url --push someremote bar aaa &&
640+
echo foo >expect &&
641+
echo bar >>expect &&
642+
echo "YYY" >>expect &&
643+
echo baz >>expect &&
644+
git config --get-all remote.someremote.pushurl >actual &&
645+
echo "YYY" >>actual &&
646+
git config --get-all remote.someremote.url >>actual &&
647+
cmp expect actual
648+
)
649+
'
650+
651+
test_expect_success 'remote set-url --push --delete bar' '
652+
(
653+
git remote set-url --push --delete someremote bar &&
654+
echo foo >expect &&
655+
echo "YYY" >>expect &&
656+
echo baz >>expect &&
657+
git config --get-all remote.someremote.pushurl >actual &&
658+
echo "YYY" >>actual &&
659+
git config --get-all remote.someremote.url >>actual &&
660+
cmp expect actual
661+
)
662+
'
663+
664+
test_expect_success 'remote set-url --push --delete foo' '
665+
(
666+
git remote set-url --push --delete someremote foo &&
667+
echo "YYY" >expect &&
668+
echo baz >>expect &&
669+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
670+
echo "YYY" >>actual &&
671+
git config --get-all remote.someremote.url >>actual &&
672+
cmp expect actual
673+
)
674+
'
675+
676+
test_expect_success 'remote set-url --add bbb' '
677+
(
678+
git remote set-url --add someremote bbb &&
679+
echo "YYY" >expect &&
680+
echo baz >>expect &&
681+
echo bbb >>expect &&
682+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
683+
echo "YYY" >>actual &&
684+
git config --get-all remote.someremote.url >>actual &&
685+
cmp expect actual
686+
)
687+
'
688+
689+
test_expect_success 'remote set-url --delete .*' '
690+
(
691+
test_must_fail git remote set-url --delete someremote .* &&
692+
echo "YYY" >expect &&
693+
echo baz >>expect &&
694+
echo bbb >>expect &&
695+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
696+
echo "YYY" >>actual &&
697+
git config --get-all remote.someremote.url >>actual &&
698+
cmp expect actual
699+
)
700+
'
701+
702+
test_expect_success 'remote set-url --delete bbb' '
703+
(
704+
git remote set-url --delete someremote bbb &&
705+
echo "YYY" >expect &&
706+
echo baz >>expect &&
707+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
708+
echo "YYY" >>actual &&
709+
git config --get-all remote.someremote.url >>actual &&
710+
cmp expect actual
711+
)
712+
'
713+
714+
test_expect_success 'remote set-url --delete baz' '
715+
(
716+
test_must_fail git remote set-url --delete someremote baz &&
717+
echo "YYY" >expect &&
718+
echo baz >>expect &&
719+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
720+
echo "YYY" >>actual &&
721+
git config --get-all remote.someremote.url >>actual &&
722+
cmp expect actual
723+
)
724+
'
725+
726+
test_expect_success 'remote set-url --add ccc' '
727+
(
728+
git remote set-url --add someremote ccc &&
729+
echo "YYY" >expect &&
730+
echo baz >>expect &&
731+
echo ccc >>expect &&
732+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
733+
echo "YYY" >>actual &&
734+
git config --get-all remote.someremote.url >>actual &&
735+
cmp expect actual
736+
)
737+
'
738+
739+
test_expect_success 'remote set-url --delete baz' '
740+
(
741+
git remote set-url --delete someremote baz &&
742+
echo "YYY" >expect &&
743+
echo ccc >>expect &&
744+
test_must_fail git config --get-all remote.someremote.pushurl >actual &&
745+
echo "YYY" >>actual &&
746+
git config --get-all remote.someremote.url >>actual &&
747+
cmp expect actual
748+
)
749+
'
750+
751+
test_done

0 commit comments

Comments
 (0)