Skip to content

Commit bc14fac

Browse files
jaysoffiangitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e61e0cc commit bc14fac

File tree

4 files changed

+129
-3
lines changed

4 files changed

+129
-3
lines changed

Documentation/git-remote.txt

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SYNOPSIS
1313
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
1414
'git remote rename' <old> <new>
1515
'git remote rm' <name>
16+
'git remote set-head' <name> [-a | -d | <branch>]
1617
'git remote show' [-n] <name>
1718
'git remote prune' [-n | --dry-run] <name>
1819
'git remote update' [group]
@@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track
5354
multiple branches without grabbing all branches.
5455
+
5556
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
56-
up to point at remote's `<master>` branch instead of whatever
57-
branch the `HEAD` at the remote repository actually points at.
57+
up to point at remote's `<master>` branch. See also the set-head command.
5858
+
5959
In mirror mode, enabled with `\--mirror`, the refs will not be stored
6060
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
@@ -76,6 +76,30 @@ the configuration file format.
7676
Remove the remote named <name>. All remote tracking branches and
7777
configuration settings for the remote are removed.
7878

79+
'set-head'::
80+
81+
Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for
82+
the named remote. Having a default branch for a remote is not required,
83+
but allows the name of the remote to be specified in lieu of a specific
84+
branch. For example, if the default branch for `origin` is set to
85+
`master`, then `origin` may be specified wherever you would normally
86+
specify `origin/master`.
87+
+
88+
With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted.
89+
+
90+
With `-a`, the remote is queried to determine its `HEAD`, then
91+
`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
92+
`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
93+
`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
94+
only work if `refs/remotes/origin/next` already exists; if not it must be
95+
fetched first.
96+
+
97+
Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., "git
98+
remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
99+
`refs/remotes/origin/master`. This will only work if
100+
`refs/remotes/origin/master` already exists; if not it must be fetched first.
101+
+
102+
79103
'show'::
80104

81105
Gives some information about the remote <name>.

builtin-remote.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static const char * const builtin_remote_usage[] = {
1212
"git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
1313
"git remote rename <old> <new>",
1414
"git remote rm <name>",
15+
"git remote set-head <name> [-a | -d | <branch>]",
1516
"git remote show [-n] <name>",
1617
"git remote prune [-n | --dry-run] <name>",
1718
"git remote [-v | --verbose] update [group]",
@@ -792,6 +793,65 @@ static int show(int argc, const char **argv)
792793
return result;
793794
}
794795

796+
static int set_head(int argc, const char **argv)
797+
{
798+
int i, opt_a = 0, opt_d = 0, result = 0;
799+
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
800+
char *head_name = NULL;
801+
802+
struct option options[] = {
803+
OPT_GROUP("set-head specific options"),
804+
OPT_BOOLEAN('a', "auto", &opt_a,
805+
"set refs/remotes/<name>/HEAD according to remote"),
806+
OPT_BOOLEAN('d', "delete", &opt_d,
807+
"delete refs/remotes/<name>/HEAD"),
808+
OPT_END()
809+
};
810+
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
811+
if (argc)
812+
strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
813+
814+
if (!opt_a && !opt_d && argc == 2) {
815+
head_name = xstrdup(argv[1]);
816+
} else if (opt_a && !opt_d && argc == 1) {
817+
struct ref_states states;
818+
memset(&states, 0, sizeof(states));
819+
get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
820+
if (!states.heads.nr)
821+
result |= error("Cannot determine remote HEAD");
822+
else if (states.heads.nr > 1) {
823+
result |= error("Multiple remote HEAD branches. "
824+
"Please choose one explicitly with:");
825+
for (i = 0; i < states.heads.nr; i++)
826+
fprintf(stderr, " git remote set-head %s %s\n",
827+
argv[0], states.heads.items[i].string);
828+
} else
829+
head_name = xstrdup(states.heads.items[0].string);
830+
free_remote_ref_states(&states);
831+
} else if (opt_d && !opt_a && argc == 1) {
832+
if (delete_ref(buf.buf, NULL, REF_NODEREF))
833+
result |= error("Could not delete %s", buf.buf);
834+
} else
835+
usage_with_options(builtin_remote_usage, options);
836+
837+
if (head_name) {
838+
unsigned char sha1[20];
839+
strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
840+
/* make sure it's valid */
841+
if (!resolve_ref(buf2.buf, sha1, 1, NULL))
842+
result |= error("Not a valid ref: %s", buf2.buf);
843+
else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
844+
result |= error("Could not setup %s", buf.buf);
845+
if (opt_a)
846+
printf("%s/HEAD set to %s\n", argv[0], head_name);
847+
free(head_name);
848+
}
849+
850+
strbuf_release(&buf);
851+
strbuf_release(&buf2);
852+
return result;
853+
}
854+
795855
static int prune(int argc, const char **argv)
796856
{
797857
int dry_run = 0, result = 0;
@@ -962,6 +1022,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
9621022
result = mv(argc, argv);
9631023
else if (!strcmp(argv[0], "rm"))
9641024
result = rm(argc, argv);
1025+
else if (!strcmp(argv[0], "set-head"))
1026+
result = set_head(argc, argv);
9651027
else if (!strcmp(argv[0], "show"))
9661028
result = show(argc, argv);
9671029
else if (!strcmp(argv[0], "prune"))

contrib/completion/git-completion.bash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1443,7 +1443,7 @@ _git_config ()
14431443

14441444
_git_remote ()
14451445
{
1446-
local subcommands="add rename rm show prune update"
1446+
local subcommands="add rename rm show prune update set-head"
14471447
local subcommand="$(__git_find_subcommand "$subcommands")"
14481448
if [ -z "$subcommand" ]; then
14491449
__gitcomp "$subcommands"

t/t5505-remote.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,46 @@ test_expect_success 'prune' '
205205
test_must_fail git rev-parse refs/remotes/origin/side)
206206
'
207207

208+
test_expect_success 'set-head --delete' '
209+
(cd test &&
210+
git symbolic-ref refs/remotes/origin/HEAD &&
211+
git remote set-head --delete origin &&
212+
test_must_fail git symbolic-ref refs/remotes/origin/HEAD)
213+
'
214+
215+
test_expect_success 'set-head --auto' '
216+
(cd test &&
217+
git remote set-head --auto origin &&
218+
echo refs/remotes/origin/master >expect &&
219+
git symbolic-ref refs/remotes/origin/HEAD >output &&
220+
test_cmp expect output
221+
)
222+
'
223+
224+
cat >test/expect <<EOF
225+
error: Multiple remote HEAD branches. Please choose one explicitly with:
226+
git remote set-head two another
227+
git remote set-head two master
228+
EOF
229+
230+
test_expect_success 'set-head --auto fails w/multiple HEADs' '
231+
(cd test &&
232+
test_must_fail git remote set-head --auto two >output 2>&1 &&
233+
test_cmp expect output)
234+
'
235+
236+
cat >test/expect <<EOF
237+
refs/remotes/origin/side2
238+
EOF
239+
240+
test_expect_success 'set-head explicit' '
241+
(cd test &&
242+
git remote set-head origin side2 &&
243+
git symbolic-ref refs/remotes/origin/HEAD >output &&
244+
git remote set-head origin master &&
245+
test_cmp expect output)
246+
'
247+
208248
cat > test/expect << EOF
209249
Pruning origin
210250
URL: $(pwd)/one

0 commit comments

Comments
 (0)