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 <madduck@debian.org> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jonathan Nieder committed
May 19, 2010 at 13:38 UTC
3d8b69495fd1132d5af6d7f46425cca97a937d97
3 files changed
+192
-11
Documentation/git-remote.txt
+13
@@ -14,6 +14,7 @@ SYNOPSIS
14
'git remote rename' <old> <new>
15
'git remote rm' <name>
16
'git remote set-head' <name> (-a | -d | <branch>)
17
+'git remote set-branches' <name> [--add] <branch>...
18
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
19
'git remote set-url --add' [--push] <name> <newurl>
20
'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
105
`refs/remotes/origin/master` already exists; if not it must be fetched first.
106
+
107
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
+
120
'set-url'::
121
122
Changes URL remote points to. Sets first URL remote points to matching
builtin/remote.c
+91
-11
@@ -16,6 +16,7 @@ static const char * const builtin_remote_usage[] = {
16
"git remote [-v | --verbose] show [-n] <name>",
17
"git remote prune [-n | --dry-run] <name>",
18
"git remote [-v | --verbose] update [-p | --prune] [group | remote]",
19
+ "git remote set-branches <name> [--add] <branch>...",
20
"git remote set-url <name> <newurl> [<oldurl>]",
21
"git remote set-url --add <name> <newurl>",
22
"git remote set-url --delete <name> <url>",
@@ -42,6 +43,12 @@ static const char * const builtin_remote_sethead_usage[] = {
43
NULL
44
};
45
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
+
52
static const char * const builtin_remote_show_usage[] = {
53
"git remote show [<options>] <name>",
54
NULL
@@ -104,6 +111,20 @@ static int fetch_remote(const char *name)
111
return 0;
112
}
113
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
+
128
static int add(int argc, const char **argv)
129
{
130
int fetch = 0, mirror = 0;
@@ -151,17 +172,8 @@ static int add(int argc, const char **argv)
172
if (track.nr == 0)
173
string_list_append("*", &track);
174
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))
177
return 1;
178
}
179
@@ -1265,6 +1277,72 @@ static int update(int argc, const char **argv)
1277
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
1278
}
1279
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
+
1346
static int set_url(int argc, const char **argv)
1347
{
1348
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)
1508
result = rm(argc, argv);
1509
else if (!strcmp(argv[0], "set-head"))
1510
result = set_head(argc, argv);
1511
+ else if (!strcmp(argv[0], "set-branches"))
1512
+ result = set_branches(argc, argv);
1513
else if (!strcmp(argv[0], "set-url"))
1514
result = set_url(argc, argv);
1515
else if (!strcmp(argv[0], "show"))
t/t5505-remote.sh
+88
@@ -534,6 +534,94 @@ test_expect_success 'show empty remote' '
534
)
535
'
536
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
+
625
test_expect_success 'new remote' '
626
git remote add someremote foo &&
627
echo foo >expect &&