Merge branch 'jn/remote-set-branches'
* jn/remote-set-branches: Add git remote set-branches Conflicts: builtin/remote.c
This commit is contained in:
commit
1c5d6b2a40
@ -14,6 +14,7 @@ SYNOPSIS
|
||||
'git remote rename' <old> <new>
|
||||
'git remote rm' <name>
|
||||
'git remote set-head' <name> (-a | -d | <branch>)
|
||||
'git remote set-branches' <name> [--add] <branch>...
|
||||
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
|
||||
'git remote set-url --add' [--push] <name> <newurl>
|
||||
'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
|
||||
`refs/remotes/origin/master` already exists; if not it must be fetched first.
|
||||
+
|
||||
|
||||
'set-branches'::
|
||||
|
||||
Changes the list of branches tracked by the named remote.
|
||||
This can be used to track a subset of the available remote branches
|
||||
after the initial setup for a remote.
|
||||
+
|
||||
The named branches will be interpreted as if specified with the
|
||||
`-t` option on the 'git remote add' command line.
|
||||
+
|
||||
With `--add`, instead of replacing the list of currently tracked
|
||||
branches, adds to that list.
|
||||
|
||||
'set-url'::
|
||||
|
||||
Changes URL remote points to. Sets first URL remote points to matching
|
||||
|
102
builtin/remote.c
102
builtin/remote.c
@ -16,6 +16,7 @@ static const char * const builtin_remote_usage[] = {
|
||||
"git remote [-v | --verbose] show [-n] <name>",
|
||||
"git remote prune [-n | --dry-run] <name>",
|
||||
"git remote [-v | --verbose] update [-p | --prune] [group | remote]",
|
||||
"git remote set-branches <name> [--add] <branch>...",
|
||||
"git remote set-url <name> <newurl> [<oldurl>]",
|
||||
"git remote set-url --add <name> <newurl>",
|
||||
"git remote set-url --delete <name> <url>",
|
||||
@ -42,6 +43,12 @@ static const char * const builtin_remote_sethead_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const builtin_remote_setbranches_usage[] = {
|
||||
"git remote set-branches <name> <branch>...",
|
||||
"git remote set-branches --add <name> <branch>...",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const builtin_remote_show_usage[] = {
|
||||
"git remote show [<options>] <name>",
|
||||
NULL
|
||||
@ -110,6 +117,20 @@ enum {
|
||||
TAGS_SET = 2
|
||||
};
|
||||
|
||||
static int add_branch(const char *key, const char *branchname,
|
||||
const char *remotename, int mirror, struct strbuf *tmp)
|
||||
{
|
||||
strbuf_reset(tmp);
|
||||
strbuf_addch(tmp, '+');
|
||||
if (mirror)
|
||||
strbuf_addf(tmp, "refs/%s:refs/%s",
|
||||
branchname, branchname);
|
||||
else
|
||||
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
|
||||
branchname, remotename, branchname);
|
||||
return git_config_set_multivar(key, tmp->buf, "^$", 0);
|
||||
}
|
||||
|
||||
static int add(int argc, const char **argv)
|
||||
{
|
||||
int fetch = 0, mirror = 0, fetch_tags = TAGS_DEFAULT;
|
||||
@ -162,17 +183,8 @@ static int add(int argc, const char **argv)
|
||||
if (track.nr == 0)
|
||||
string_list_append("*", &track);
|
||||
for (i = 0; i < track.nr; i++) {
|
||||
struct string_list_item *item = track.items + i;
|
||||
|
||||
strbuf_reset(&buf2);
|
||||
strbuf_addch(&buf2, '+');
|
||||
if (mirror)
|
||||
strbuf_addf(&buf2, "refs/%s:refs/%s",
|
||||
item->string, item->string);
|
||||
else
|
||||
strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
|
||||
item->string, name, item->string);
|
||||
if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
|
||||
if (add_branch(buf.buf, track.items[i].string,
|
||||
name, mirror, &buf2))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1284,6 +1296,72 @@ static int update(int argc, const char **argv)
|
||||
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
|
||||
}
|
||||
|
||||
static int remove_all_fetch_refspecs(const char *remote, const char *key)
|
||||
{
|
||||
return git_config_set_multivar(key, NULL, NULL, 1);
|
||||
}
|
||||
|
||||
static int add_branches(struct remote *remote, const char **branches,
|
||||
const char *key)
|
||||
{
|
||||
const char *remotename = remote->name;
|
||||
int mirror = remote->mirror;
|
||||
struct strbuf refspec = STRBUF_INIT;
|
||||
|
||||
for (; *branches; branches++)
|
||||
if (add_branch(key, *branches, remotename, mirror, &refspec)) {
|
||||
strbuf_release(&refspec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
strbuf_release(&refspec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_remote_branches(const char *remotename, const char **branches,
|
||||
int add_mode)
|
||||
{
|
||||
struct strbuf key = STRBUF_INIT;
|
||||
struct remote *remote;
|
||||
|
||||
strbuf_addf(&key, "remote.%s.fetch", remotename);
|
||||
|
||||
if (!remote_is_configured(remotename))
|
||||
die("No such remote '%s'", remotename);
|
||||
remote = remote_get(remotename);
|
||||
|
||||
if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) {
|
||||
strbuf_release(&key);
|
||||
return 1;
|
||||
}
|
||||
if (add_branches(remote, branches, key.buf)) {
|
||||
strbuf_release(&key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
strbuf_release(&key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_branches(int argc, const char **argv)
|
||||
{
|
||||
int add_mode = 0;
|
||||
struct option options[] = {
|
||||
OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options,
|
||||
builtin_remote_setbranches_usage, 0);
|
||||
if (argc == 0) {
|
||||
error("no remote specified");
|
||||
usage_with_options(builtin_remote_seturl_usage, options);
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
return set_remote_branches(argv[0], argv + 1, add_mode);
|
||||
}
|
||||
|
||||
static int set_url(int argc, const char **argv)
|
||||
{
|
||||
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)
|
||||
result = rm(argc, argv);
|
||||
else if (!strcmp(argv[0], "set-head"))
|
||||
result = set_head(argc, argv);
|
||||
else if (!strcmp(argv[0], "set-branches"))
|
||||
result = set_branches(argc, argv);
|
||||
else if (!strcmp(argv[0], "set-url"))
|
||||
result = set_url(argc, argv);
|
||||
else if (!strcmp(argv[0], "show"))
|
||||
|
@ -597,6 +597,94 @@ test_expect_success 'show empty remote' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'remote set-branches requires a remote' '
|
||||
test_must_fail git remote set-branches &&
|
||||
test_must_fail git remote set-branches --add
|
||||
'
|
||||
|
||||
test_expect_success 'remote set-branches' '
|
||||
echo "+refs/heads/*:refs/remotes/scratch/*" >expect.initial &&
|
||||
sort <<-\EOF >expect.add &&
|
||||
+refs/heads/*:refs/remotes/scratch/*
|
||||
+refs/heads/other:refs/remotes/scratch/other
|
||||
EOF
|
||||
sort <<-\EOF >expect.replace &&
|
||||
+refs/heads/maint:refs/remotes/scratch/maint
|
||||
+refs/heads/master:refs/remotes/scratch/master
|
||||
+refs/heads/next:refs/remotes/scratch/next
|
||||
EOF
|
||||
sort <<-\EOF >expect.add-two &&
|
||||
+refs/heads/maint:refs/remotes/scratch/maint
|
||||
+refs/heads/master:refs/remotes/scratch/master
|
||||
+refs/heads/next:refs/remotes/scratch/next
|
||||
+refs/heads/pu:refs/remotes/scratch/pu
|
||||
+refs/heads/t/topic:refs/remotes/scratch/t/topic
|
||||
EOF
|
||||
sort <<-\EOF >expect.setup-ffonly &&
|
||||
refs/heads/master:refs/remotes/scratch/master
|
||||
+refs/heads/next:refs/remotes/scratch/next
|
||||
EOF
|
||||
sort <<-\EOF >expect.respect-ffonly &&
|
||||
refs/heads/master:refs/remotes/scratch/master
|
||||
+refs/heads/next:refs/remotes/scratch/next
|
||||
+refs/heads/pu:refs/remotes/scratch/pu
|
||||
EOF
|
||||
|
||||
git clone .git/ setbranches &&
|
||||
(
|
||||
cd setbranches &&
|
||||
git remote rename origin scratch &&
|
||||
git config --get-all remote.scratch.fetch >config-result &&
|
||||
sort <config-result >../actual.initial &&
|
||||
|
||||
git remote set-branches scratch --add other &&
|
||||
git config --get-all remote.scratch.fetch >config-result &&
|
||||
sort <config-result >../actual.add &&
|
||||
|
||||
git remote set-branches scratch maint master next &&
|
||||
git config --get-all remote.scratch.fetch >config-result &&
|
||||
sort <config-result >../actual.replace &&
|
||||
|
||||
git remote set-branches --add scratch pu t/topic &&
|
||||
git config --get-all remote.scratch.fetch >config-result &&
|
||||
sort <config-result >../actual.add-two &&
|
||||
|
||||
git config --unset-all remote.scratch.fetch &&
|
||||
git config remote.scratch.fetch \
|
||||
refs/heads/master:refs/remotes/scratch/master &&
|
||||
git config --add remote.scratch.fetch \
|
||||
+refs/heads/next:refs/remotes/scratch/next &&
|
||||
git config --get-all remote.scratch.fetch >config-result &&
|
||||
sort <config-result >../actual.setup-ffonly &&
|
||||
|
||||
git remote set-branches --add scratch pu &&
|
||||
git config --get-all remote.scratch.fetch >config-result &&
|
||||
sort <config-result >../actual.respect-ffonly
|
||||
) &&
|
||||
test_cmp expect.initial actual.initial &&
|
||||
test_cmp expect.add actual.add &&
|
||||
test_cmp expect.replace actual.replace &&
|
||||
test_cmp expect.add-two actual.add-two &&
|
||||
test_cmp expect.setup-ffonly actual.setup-ffonly &&
|
||||
test_cmp expect.respect-ffonly actual.respect-ffonly
|
||||
'
|
||||
|
||||
test_expect_success 'remote set-branches with --mirror' '
|
||||
echo "+refs/*:refs/*" >expect.initial &&
|
||||
echo "+refs/heads/master:refs/heads/master" >expect.replace &&
|
||||
git clone --mirror .git/ setbranches-mirror &&
|
||||
(
|
||||
cd setbranches-mirror &&
|
||||
git remote rename origin scratch &&
|
||||
git config --get-all remote.scratch.fetch >../actual.initial &&
|
||||
|
||||
git remote set-branches scratch heads/master &&
|
||||
git config --get-all remote.scratch.fetch >../actual.replace
|
||||
) &&
|
||||
test_cmp expect.initial actual.initial &&
|
||||
test_cmp expect.replace actual.replace
|
||||
'
|
||||
|
||||
test_expect_success 'new remote' '
|
||||
git remote add someremote foo &&
|
||||
echo foo >expect &&
|
||||
|
Loading…
Reference in New Issue
Block a user