Skip to content

Commit 1c5d6b2

Browse files
committed
Merge branch 'jn/remote-set-branches'
* jn/remote-set-branches: Add git remote set-branches Conflicts: builtin/remote.c
2 parents 199d4c0 + 3d8b694 commit 1c5d6b2

File tree

3 files changed

+192
-11
lines changed

3 files changed

+192
-11
lines changed

Documentation/git-remote.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ 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-branches' <name> [--add] <branch>...
1718
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
1819
'git remote set-url --add' [--push] <name> <newurl>
1920
'git remote set-url --delete' [--push] <name> <url>
@@ -110,6 +111,18 @@ remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
110111
`refs/remotes/origin/master` already exists; if not it must be fetched first.
111112
+
112113

114+
'set-branches'::
115+
116+
Changes the list of branches tracked by the named remote.
117+
This can be used to track a subset of the available remote branches
118+
after the initial setup for a remote.
119+
+
120+
The named branches will be interpreted as if specified with the
121+
`-t` option on the 'git remote add' command line.
122+
+
123+
With `--add`, instead of replacing the list of currently tracked
124+
branches, adds to that list.
125+
113126
'set-url'::
114127

115128
Changes URL remote points to. Sets first URL remote points to matching

builtin/remote.c

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ 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-branches <name> [--add] <branch>...",
1920
"git remote set-url <name> <newurl> [<oldurl>]",
2021
"git remote set-url --add <name> <newurl>",
2122
"git remote set-url --delete <name> <url>",
@@ -42,6 +43,12 @@ static const char * const builtin_remote_sethead_usage[] = {
4243
NULL
4344
};
4445

46+
static const char * const builtin_remote_setbranches_usage[] = {
47+
"git remote set-branches <name> <branch>...",
48+
"git remote set-branches --add <name> <branch>...",
49+
NULL
50+
};
51+
4552
static const char * const builtin_remote_show_usage[] = {
4653
"git remote show [<options>] <name>",
4754
NULL
@@ -110,6 +117,20 @@ enum {
110117
TAGS_SET = 2
111118
};
112119

120+
static int add_branch(const char *key, const char *branchname,
121+
const char *remotename, int mirror, struct strbuf *tmp)
122+
{
123+
strbuf_reset(tmp);
124+
strbuf_addch(tmp, '+');
125+
if (mirror)
126+
strbuf_addf(tmp, "refs/%s:refs/%s",
127+
branchname, branchname);
128+
else
129+
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
130+
branchname, remotename, branchname);
131+
return git_config_set_multivar(key, tmp->buf, "^$", 0);
132+
}
133+
113134
static int add(int argc, const char **argv)
114135
{
115136
int fetch = 0, mirror = 0, fetch_tags = TAGS_DEFAULT;
@@ -162,17 +183,8 @@ static int add(int argc, const char **argv)
162183
if (track.nr == 0)
163184
string_list_append("*", &track);
164185
for (i = 0; i < track.nr; i++) {
165-
struct string_list_item *item = track.items + i;
166-
167-
strbuf_reset(&buf2);
168-
strbuf_addch(&buf2, '+');
169-
if (mirror)
170-
strbuf_addf(&buf2, "refs/%s:refs/%s",
171-
item->string, item->string);
172-
else
173-
strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
174-
item->string, name, item->string);
175-
if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
186+
if (add_branch(buf.buf, track.items[i].string,
187+
name, mirror, &buf2))
176188
return 1;
177189
}
178190

@@ -1284,6 +1296,72 @@ static int update(int argc, const char **argv)
12841296
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
12851297
}
12861298

1299+
static int remove_all_fetch_refspecs(const char *remote, const char *key)
1300+
{
1301+
return git_config_set_multivar(key, NULL, NULL, 1);
1302+
}
1303+
1304+
static int add_branches(struct remote *remote, const char **branches,
1305+
const char *key)
1306+
{
1307+
const char *remotename = remote->name;
1308+
int mirror = remote->mirror;
1309+
struct strbuf refspec = STRBUF_INIT;
1310+
1311+
for (; *branches; branches++)
1312+
if (add_branch(key, *branches, remotename, mirror, &refspec)) {
1313+
strbuf_release(&refspec);
1314+
return 1;
1315+
}
1316+
1317+
strbuf_release(&refspec);
1318+
return 0;
1319+
}
1320+
1321+
static int set_remote_branches(const char *remotename, const char **branches,
1322+
int add_mode)
1323+
{
1324+
struct strbuf key = STRBUF_INIT;
1325+
struct remote *remote;
1326+
1327+
strbuf_addf(&key, "remote.%s.fetch", remotename);
1328+
1329+
if (!remote_is_configured(remotename))
1330+
die("No such remote '%s'", remotename);
1331+
remote = remote_get(remotename);
1332+
1333+
if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) {
1334+
strbuf_release(&key);
1335+
return 1;
1336+
}
1337+
if (add_branches(remote, branches, key.buf)) {
1338+
strbuf_release(&key);
1339+
return 1;
1340+
}
1341+
1342+
strbuf_release(&key);
1343+
return 0;
1344+
}
1345+
1346+
static int set_branches(int argc, const char **argv)
1347+
{
1348+
int add_mode = 0;
1349+
struct option options[] = {
1350+
OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
1351+
OPT_END()
1352+
};
1353+
1354+
argc = parse_options(argc, argv, NULL, options,
1355+
builtin_remote_setbranches_usage, 0);
1356+
if (argc == 0) {
1357+
error("no remote specified");
1358+
usage_with_options(builtin_remote_seturl_usage, options);
1359+
}
1360+
argv[argc] = NULL;
1361+
1362+
return set_remote_branches(argv[0], argv + 1, add_mode);
1363+
}
1364+
12871365
static int set_url(int argc, const char **argv)
12881366
{
12891367
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
@@ -1449,6 +1527,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
14491527
result = rm(argc, argv);
14501528
else if (!strcmp(argv[0], "set-head"))
14511529
result = set_head(argc, argv);
1530+
else if (!strcmp(argv[0], "set-branches"))
1531+
result = set_branches(argc, argv);
14521532
else if (!strcmp(argv[0], "set-url"))
14531533
result = set_url(argc, argv);
14541534
else if (!strcmp(argv[0], "show"))

t/t5505-remote.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,94 @@ test_expect_success 'show empty remote' '
597597
)
598598
'
599599

600+
test_expect_success 'remote set-branches requires a remote' '
601+
test_must_fail git remote set-branches &&
602+
test_must_fail git remote set-branches --add
603+
'
604+
605+
test_expect_success 'remote set-branches' '
606+
echo "+refs/heads/*:refs/remotes/scratch/*" >expect.initial &&
607+
sort <<-\EOF >expect.add &&
608+
+refs/heads/*:refs/remotes/scratch/*
609+
+refs/heads/other:refs/remotes/scratch/other
610+
EOF
611+
sort <<-\EOF >expect.replace &&
612+
+refs/heads/maint:refs/remotes/scratch/maint
613+
+refs/heads/master:refs/remotes/scratch/master
614+
+refs/heads/next:refs/remotes/scratch/next
615+
EOF
616+
sort <<-\EOF >expect.add-two &&
617+
+refs/heads/maint:refs/remotes/scratch/maint
618+
+refs/heads/master:refs/remotes/scratch/master
619+
+refs/heads/next:refs/remotes/scratch/next
620+
+refs/heads/pu:refs/remotes/scratch/pu
621+
+refs/heads/t/topic:refs/remotes/scratch/t/topic
622+
EOF
623+
sort <<-\EOF >expect.setup-ffonly &&
624+
refs/heads/master:refs/remotes/scratch/master
625+
+refs/heads/next:refs/remotes/scratch/next
626+
EOF
627+
sort <<-\EOF >expect.respect-ffonly &&
628+
refs/heads/master:refs/remotes/scratch/master
629+
+refs/heads/next:refs/remotes/scratch/next
630+
+refs/heads/pu:refs/remotes/scratch/pu
631+
EOF
632+
633+
git clone .git/ setbranches &&
634+
(
635+
cd setbranches &&
636+
git remote rename origin scratch &&
637+
git config --get-all remote.scratch.fetch >config-result &&
638+
sort <config-result >../actual.initial &&
639+
640+
git remote set-branches scratch --add other &&
641+
git config --get-all remote.scratch.fetch >config-result &&
642+
sort <config-result >../actual.add &&
643+
644+
git remote set-branches scratch maint master next &&
645+
git config --get-all remote.scratch.fetch >config-result &&
646+
sort <config-result >../actual.replace &&
647+
648+
git remote set-branches --add scratch pu t/topic &&
649+
git config --get-all remote.scratch.fetch >config-result &&
650+
sort <config-result >../actual.add-two &&
651+
652+
git config --unset-all remote.scratch.fetch &&
653+
git config remote.scratch.fetch \
654+
refs/heads/master:refs/remotes/scratch/master &&
655+
git config --add remote.scratch.fetch \
656+
+refs/heads/next:refs/remotes/scratch/next &&
657+
git config --get-all remote.scratch.fetch >config-result &&
658+
sort <config-result >../actual.setup-ffonly &&
659+
660+
git remote set-branches --add scratch pu &&
661+
git config --get-all remote.scratch.fetch >config-result &&
662+
sort <config-result >../actual.respect-ffonly
663+
) &&
664+
test_cmp expect.initial actual.initial &&
665+
test_cmp expect.add actual.add &&
666+
test_cmp expect.replace actual.replace &&
667+
test_cmp expect.add-two actual.add-two &&
668+
test_cmp expect.setup-ffonly actual.setup-ffonly &&
669+
test_cmp expect.respect-ffonly actual.respect-ffonly
670+
'
671+
672+
test_expect_success 'remote set-branches with --mirror' '
673+
echo "+refs/*:refs/*" >expect.initial &&
674+
echo "+refs/heads/master:refs/heads/master" >expect.replace &&
675+
git clone --mirror .git/ setbranches-mirror &&
676+
(
677+
cd setbranches-mirror &&
678+
git remote rename origin scratch &&
679+
git config --get-all remote.scratch.fetch >../actual.initial &&
680+
681+
git remote set-branches scratch heads/master &&
682+
git config --get-all remote.scratch.fetch >../actual.replace
683+
) &&
684+
test_cmp expect.initial actual.initial &&
685+
test_cmp expect.replace actual.replace
686+
'
687+
600688
test_expect_success 'new remote' '
601689
git remote add someremote foo &&
602690
echo foo >expect &&

0 commit comments

Comments
 (0)