builtin-remote: add set-head subcommand
Provide a porcelain command for setting and deleting $GIT_DIR/remotes/<remote>/HEAD. While we're at it, document what $GIT_DIR/remotes/<remote>/HEAD is all about. Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
e61e0cc6b7
commit
bc14fac825
@ -13,6 +13,7 @@ SYNOPSIS
|
|||||||
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
||||||
'git remote rename' <old> <new>
|
'git remote rename' <old> <new>
|
||||||
'git remote rm' <name>
|
'git remote rm' <name>
|
||||||
|
'git remote set-head' <name> [-a | -d | <branch>]
|
||||||
'git remote show' [-n] <name>
|
'git remote show' [-n] <name>
|
||||||
'git remote prune' [-n | --dry-run] <name>
|
'git remote prune' [-n | --dry-run] <name>
|
||||||
'git remote update' [group]
|
'git remote update' [group]
|
||||||
@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track
|
|||||||
multiple branches without grabbing all branches.
|
multiple branches without grabbing all branches.
|
||||||
+
|
+
|
||||||
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
|
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
|
||||||
up to point at remote's `<master>` branch instead of whatever
|
up to point at remote's `<master>` branch. See also the set-head command.
|
||||||
branch the `HEAD` at the remote repository actually points at.
|
|
||||||
+
|
+
|
||||||
In mirror mode, enabled with `\--mirror`, the refs will not be stored
|
In mirror mode, enabled with `\--mirror`, the refs will not be stored
|
||||||
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
|
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
|
||||||
@ -76,6 +76,30 @@ the configuration file format.
|
|||||||
Remove the remote named <name>. All remote tracking branches and
|
Remove the remote named <name>. All remote tracking branches and
|
||||||
configuration settings for the remote are removed.
|
configuration settings for the remote are removed.
|
||||||
|
|
||||||
|
'set-head'::
|
||||||
|
|
||||||
|
Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for
|
||||||
|
the named remote. Having a default branch for a remote is not required,
|
||||||
|
but allows the name of the remote to be specified in lieu of a specific
|
||||||
|
branch. For example, if the default branch for `origin` is set to
|
||||||
|
`master`, then `origin` may be specified wherever you would normally
|
||||||
|
specify `origin/master`.
|
||||||
|
+
|
||||||
|
With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted.
|
||||||
|
+
|
||||||
|
With `-a`, the remote is queried to determine its `HEAD`, then
|
||||||
|
`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
|
||||||
|
`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
|
||||||
|
`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
|
||||||
|
only work if `refs/remotes/origin/next` already exists; if not it must be
|
||||||
|
fetched first.
|
||||||
|
+
|
||||||
|
Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., "git
|
||||||
|
remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
|
||||||
|
`refs/remotes/origin/master`. This will only work if
|
||||||
|
`refs/remotes/origin/master` already exists; if not it must be fetched first.
|
||||||
|
+
|
||||||
|
|
||||||
'show'::
|
'show'::
|
||||||
|
|
||||||
Gives some information about the remote <name>.
|
Gives some information about the remote <name>.
|
||||||
|
@ -12,6 +12,7 @@ static const char * const builtin_remote_usage[] = {
|
|||||||
"git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
|
"git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
|
||||||
"git remote rename <old> <new>",
|
"git remote rename <old> <new>",
|
||||||
"git remote rm <name>",
|
"git remote rm <name>",
|
||||||
|
"git remote set-head <name> [-a | -d | <branch>]",
|
||||||
"git remote show [-n] <name>",
|
"git remote show [-n] <name>",
|
||||||
"git remote prune [-n | --dry-run] <name>",
|
"git remote prune [-n | --dry-run] <name>",
|
||||||
"git remote [-v | --verbose] update [group]",
|
"git remote [-v | --verbose] update [group]",
|
||||||
@ -792,6 +793,65 @@ static int show(int argc, const char **argv)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_head(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
int i, opt_a = 0, opt_d = 0, result = 0;
|
||||||
|
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
|
||||||
|
char *head_name = NULL;
|
||||||
|
|
||||||
|
struct option options[] = {
|
||||||
|
OPT_GROUP("set-head specific options"),
|
||||||
|
OPT_BOOLEAN('a', "auto", &opt_a,
|
||||||
|
"set refs/remotes/<name>/HEAD according to remote"),
|
||||||
|
OPT_BOOLEAN('d', "delete", &opt_d,
|
||||||
|
"delete refs/remotes/<name>/HEAD"),
|
||||||
|
OPT_END()
|
||||||
|
};
|
||||||
|
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
|
||||||
|
if (argc)
|
||||||
|
strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
|
||||||
|
|
||||||
|
if (!opt_a && !opt_d && argc == 2) {
|
||||||
|
head_name = xstrdup(argv[1]);
|
||||||
|
} else if (opt_a && !opt_d && argc == 1) {
|
||||||
|
struct ref_states states;
|
||||||
|
memset(&states, 0, sizeof(states));
|
||||||
|
get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
|
||||||
|
if (!states.heads.nr)
|
||||||
|
result |= error("Cannot determine remote HEAD");
|
||||||
|
else if (states.heads.nr > 1) {
|
||||||
|
result |= error("Multiple remote HEAD branches. "
|
||||||
|
"Please choose one explicitly with:");
|
||||||
|
for (i = 0; i < states.heads.nr; i++)
|
||||||
|
fprintf(stderr, " git remote set-head %s %s\n",
|
||||||
|
argv[0], states.heads.items[i].string);
|
||||||
|
} else
|
||||||
|
head_name = xstrdup(states.heads.items[0].string);
|
||||||
|
free_remote_ref_states(&states);
|
||||||
|
} else if (opt_d && !opt_a && argc == 1) {
|
||||||
|
if (delete_ref(buf.buf, NULL, REF_NODEREF))
|
||||||
|
result |= error("Could not delete %s", buf.buf);
|
||||||
|
} else
|
||||||
|
usage_with_options(builtin_remote_usage, options);
|
||||||
|
|
||||||
|
if (head_name) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
|
||||||
|
/* make sure it's valid */
|
||||||
|
if (!resolve_ref(buf2.buf, sha1, 1, NULL))
|
||||||
|
result |= error("Not a valid ref: %s", buf2.buf);
|
||||||
|
else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
|
||||||
|
result |= error("Could not setup %s", buf.buf);
|
||||||
|
if (opt_a)
|
||||||
|
printf("%s/HEAD set to %s\n", argv[0], head_name);
|
||||||
|
free(head_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&buf2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int prune(int argc, const char **argv)
|
static int prune(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
int dry_run = 0, result = 0;
|
int dry_run = 0, result = 0;
|
||||||
@ -962,6 +1022,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
|
|||||||
result = mv(argc, argv);
|
result = mv(argc, argv);
|
||||||
else if (!strcmp(argv[0], "rm"))
|
else if (!strcmp(argv[0], "rm"))
|
||||||
result = rm(argc, argv);
|
result = rm(argc, argv);
|
||||||
|
else if (!strcmp(argv[0], "set-head"))
|
||||||
|
result = set_head(argc, argv);
|
||||||
else if (!strcmp(argv[0], "show"))
|
else if (!strcmp(argv[0], "show"))
|
||||||
result = show(argc, argv);
|
result = show(argc, argv);
|
||||||
else if (!strcmp(argv[0], "prune"))
|
else if (!strcmp(argv[0], "prune"))
|
||||||
|
@ -1443,7 +1443,7 @@ _git_config ()
|
|||||||
|
|
||||||
_git_remote ()
|
_git_remote ()
|
||||||
{
|
{
|
||||||
local subcommands="add rename rm show prune update"
|
local subcommands="add rename rm show prune update set-head"
|
||||||
local subcommand="$(__git_find_subcommand "$subcommands")"
|
local subcommand="$(__git_find_subcommand "$subcommands")"
|
||||||
if [ -z "$subcommand" ]; then
|
if [ -z "$subcommand" ]; then
|
||||||
__gitcomp "$subcommands"
|
__gitcomp "$subcommands"
|
||||||
|
@ -205,6 +205,46 @@ test_expect_success 'prune' '
|
|||||||
test_must_fail git rev-parse refs/remotes/origin/side)
|
test_must_fail git rev-parse refs/remotes/origin/side)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'set-head --delete' '
|
||||||
|
(cd test &&
|
||||||
|
git symbolic-ref refs/remotes/origin/HEAD &&
|
||||||
|
git remote set-head --delete origin &&
|
||||||
|
test_must_fail git symbolic-ref refs/remotes/origin/HEAD)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'set-head --auto' '
|
||||||
|
(cd test &&
|
||||||
|
git remote set-head --auto origin &&
|
||||||
|
echo refs/remotes/origin/master >expect &&
|
||||||
|
git symbolic-ref refs/remotes/origin/HEAD >output &&
|
||||||
|
test_cmp expect output
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >test/expect <<EOF
|
||||||
|
error: Multiple remote HEAD branches. Please choose one explicitly with:
|
||||||
|
git remote set-head two another
|
||||||
|
git remote set-head two master
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'set-head --auto fails w/multiple HEADs' '
|
||||||
|
(cd test &&
|
||||||
|
test_must_fail git remote set-head --auto two >output 2>&1 &&
|
||||||
|
test_cmp expect output)
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >test/expect <<EOF
|
||||||
|
refs/remotes/origin/side2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'set-head explicit' '
|
||||||
|
(cd test &&
|
||||||
|
git remote set-head origin side2 &&
|
||||||
|
git symbolic-ref refs/remotes/origin/HEAD >output &&
|
||||||
|
git remote set-head origin master &&
|
||||||
|
test_cmp expect output)
|
||||||
|
'
|
||||||
|
|
||||||
cat > test/expect << EOF
|
cat > test/expect << EOF
|
||||||
Pruning origin
|
Pruning origin
|
||||||
URL: $(pwd)/one
|
URL: $(pwd)/one
|
||||||
|
Reference in New Issue
Block a user