Skip to content

Commit 3d8b694

Browse files
jrngitster
authored andcommitted
Add git remote set-branches
Add ‘git remote set-branches’ for changing the list of tracked refs for a remote repository with one "porcelain-level" command. This complements the longstanding ‘git remote add --track’ option. The interface is based on the ‘git remote set-url’ subcommand. git remote set-branches base --add C git remote set-branches base A B D git remote set-branches base --delete D; # not implemented Suggested-by: martin f. krafft <[email protected]> Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 636e87d commit 3d8b694

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>
@@ -104,6 +105,18 @@ remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
104105
`refs/remotes/origin/master` already exists; if not it must be fetched first.
105106
+
106107

108+
'set-branches'::
109+
110+
Changes the list of branches tracked by the named remote.
111+
This can be used to track a subset of the available remote branches
112+
after the initial setup for a remote.
113+
+
114+
The named branches will be interpreted as if specified with the
115+
`-t` option on the 'git remote add' command line.
116+
+
117+
With `--add`, instead of replacing the list of currently tracked
118+
branches, adds to that list.
119+
107120
'set-url'::
108121

109122
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
@@ -104,6 +111,20 @@ static int fetch_remote(const char *name)
104111
return 0;
105112
}
106113

114+
static int add_branch(const char *key, const char *branchname,
115+
const char *remotename, int mirror, struct strbuf *tmp)
116+
{
117+
strbuf_reset(tmp);
118+
strbuf_addch(tmp, '+');
119+
if (mirror)
120+
strbuf_addf(tmp, "refs/%s:refs/%s",
121+
branchname, branchname);
122+
else
123+
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
124+
branchname, remotename, branchname);
125+
return git_config_set_multivar(key, tmp->buf, "^$", 0);
126+
}
127+
107128
static int add(int argc, const char **argv)
108129
{
109130
int fetch = 0, mirror = 0;
@@ -151,17 +172,8 @@ static int add(int argc, const char **argv)
151172
if (track.nr == 0)
152173
string_list_append("*", &track);
153174
for (i = 0; i < track.nr; i++) {
154-
struct string_list_item *item = track.items + i;
155-
156-
strbuf_reset(&buf2);
157-
strbuf_addch(&buf2, '+');
158-
if (mirror)
159-
strbuf_addf(&buf2, "refs/%s:refs/%s",
160-
item->string, item->string);
161-
else
162-
strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
163-
item->string, name, item->string);
164-
if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
175+
if (add_branch(buf.buf, track.items[i].string,
176+
name, mirror, &buf2))
165177
return 1;
166178
}
167179

@@ -1265,6 +1277,72 @@ static int update(int argc, const char **argv)
12651277
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
12661278
}
12671279

1280+
static int remove_all_fetch_refspecs(const char *remote, const char *key)
1281+
{
1282+
return git_config_set_multivar(key, NULL, NULL, 1);
1283+
}
1284+
1285+
static int add_branches(struct remote *remote, const char **branches,
1286+
const char *key)
1287+
{
1288+
const char *remotename = remote->name;
1289+
int mirror = remote->mirror;
1290+
struct strbuf refspec = STRBUF_INIT;
1291+
1292+
for (; *branches; branches++)
1293+
if (add_branch(key, *branches, remotename, mirror, &refspec)) {
1294+
strbuf_release(&refspec);
1295+
return 1;
1296+
}
1297+
1298+
strbuf_release(&refspec);
1299+
return 0;
1300+
}
1301+
1302+
static int set_remote_branches(const char *remotename, const char **branches,
1303+
int add_mode)
1304+
{
1305+
struct strbuf key = STRBUF_INIT;
1306+
struct remote *remote;
1307+
1308+
strbuf_addf(&key, "remote.%s.fetch", remotename);
1309+
1310+
if (!remote_is_configured(remotename))
1311+
die("No such remote '%s'", remotename);
1312+
remote = remote_get(remotename);
1313+
1314+
if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) {
1315+
strbuf_release(&key);
1316+
return 1;
1317+
}
1318+
if (add_branches(remote, branches, key.buf)) {
1319+
strbuf_release(&key);
1320+
return 1;
1321+
}
1322+
1323+
strbuf_release(&key);
1324+
return 0;
1325+
}
1326+
1327+
static int set_branches(int argc, const char **argv)
1328+
{
1329+
int add_mode = 0;
1330+
struct option options[] = {
1331+
OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
1332+
OPT_END()
1333+
};
1334+
1335+
argc = parse_options(argc, argv, NULL, options,
1336+
builtin_remote_setbranches_usage, 0);
1337+
if (argc == 0) {
1338+
error("no remote specified");
1339+
usage_with_options(builtin_remote_seturl_usage, options);
1340+
}
1341+
argv[argc] = NULL;
1342+
1343+
return set_remote_branches(argv[0], argv + 1, add_mode);
1344+
}
1345+
12681346
static int set_url(int argc, const char **argv)
12691347
{
12701348
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
@@ -1430,6 +1508,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
14301508
result = rm(argc, argv);
14311509
else if (!strcmp(argv[0], "set-head"))
14321510
result = set_head(argc, argv);
1511+
else if (!strcmp(argv[0], "set-branches"))
1512+
result = set_branches(argc, argv);
14331513
else if (!strcmp(argv[0], "set-url"))
14341514
result = set_url(argc, argv);
14351515
else if (!strcmp(argv[0], "show"))

t/t5505-remote.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,94 @@ test_expect_success 'show empty remote' '
534534
)
535535
'
536536

537+
test_expect_success 'remote set-branches requires a remote' '
538+
test_must_fail git remote set-branches &&
539+
test_must_fail git remote set-branches --add
540+
'
541+
542+
test_expect_success 'remote set-branches' '
543+
echo "+refs/heads/*:refs/remotes/scratch/*" >expect.initial &&
544+
sort <<-\EOF >expect.add &&
545+
+refs/heads/*:refs/remotes/scratch/*
546+
+refs/heads/other:refs/remotes/scratch/other
547+
EOF
548+
sort <<-\EOF >expect.replace &&
549+
+refs/heads/maint:refs/remotes/scratch/maint
550+
+refs/heads/master:refs/remotes/scratch/master
551+
+refs/heads/next:refs/remotes/scratch/next
552+
EOF
553+
sort <<-\EOF >expect.add-two &&
554+
+refs/heads/maint:refs/remotes/scratch/maint
555+
+refs/heads/master:refs/remotes/scratch/master
556+
+refs/heads/next:refs/remotes/scratch/next
557+
+refs/heads/pu:refs/remotes/scratch/pu
558+
+refs/heads/t/topic:refs/remotes/scratch/t/topic
559+
EOF
560+
sort <<-\EOF >expect.setup-ffonly &&
561+
refs/heads/master:refs/remotes/scratch/master
562+
+refs/heads/next:refs/remotes/scratch/next
563+
EOF
564+
sort <<-\EOF >expect.respect-ffonly &&
565+
refs/heads/master:refs/remotes/scratch/master
566+
+refs/heads/next:refs/remotes/scratch/next
567+
+refs/heads/pu:refs/remotes/scratch/pu
568+
EOF
569+
570+
git clone .git/ setbranches &&
571+
(
572+
cd setbranches &&
573+
git remote rename origin scratch &&
574+
git config --get-all remote.scratch.fetch >config-result &&
575+
sort <config-result >../actual.initial &&
576+
577+
git remote set-branches scratch --add other &&
578+
git config --get-all remote.scratch.fetch >config-result &&
579+
sort <config-result >../actual.add &&
580+
581+
git remote set-branches scratch maint master next &&
582+
git config --get-all remote.scratch.fetch >config-result &&
583+
sort <config-result >../actual.replace &&
584+
585+
git remote set-branches --add scratch pu t/topic &&
586+
git config --get-all remote.scratch.fetch >config-result &&
587+
sort <config-result >../actual.add-two &&
588+
589+
git config --unset-all remote.scratch.fetch &&
590+
git config remote.scratch.fetch \
591+
refs/heads/master:refs/remotes/scratch/master &&
592+
git config --add remote.scratch.fetch \
593+
+refs/heads/next:refs/remotes/scratch/next &&
594+
git config --get-all remote.scratch.fetch >config-result &&
595+
sort <config-result >../actual.setup-ffonly &&
596+
597+
git remote set-branches --add scratch pu &&
598+
git config --get-all remote.scratch.fetch >config-result &&
599+
sort <config-result >../actual.respect-ffonly
600+
) &&
601+
test_cmp expect.initial actual.initial &&
602+
test_cmp expect.add actual.add &&
603+
test_cmp expect.replace actual.replace &&
604+
test_cmp expect.add-two actual.add-two &&
605+
test_cmp expect.setup-ffonly actual.setup-ffonly &&
606+
test_cmp expect.respect-ffonly actual.respect-ffonly
607+
'
608+
609+
test_expect_success 'remote set-branches with --mirror' '
610+
echo "+refs/*:refs/*" >expect.initial &&
611+
echo "+refs/heads/master:refs/heads/master" >expect.replace &&
612+
git clone --mirror .git/ setbranches-mirror &&
613+
(
614+
cd setbranches-mirror &&
615+
git remote rename origin scratch &&
616+
git config --get-all remote.scratch.fetch >../actual.initial &&
617+
618+
git remote set-branches scratch heads/master &&
619+
git config --get-all remote.scratch.fetch >../actual.replace
620+
) &&
621+
test_cmp expect.initial actual.initial &&
622+
test_cmp expect.replace actual.replace
623+
'
624+
537625
test_expect_success 'new remote' '
538626
git remote add someremote foo &&
539627
echo foo >expect &&

0 commit comments

Comments
 (0)