@matheusbsbs / matheus-bagliano / commits / bc14fac825
Fork 0

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>

Jay Soffian committed Feb 25, 2009 at 03:32 UTC bc14fac825d9728c311aaa9d0aecf4960d4a3103
4 files changed +129 -3
Documentation/git-remote.txt
+26 -2
@@ -13,6 +13,7 @@ SYNOPSIS
13 'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
14 'git remote rename' <old> <new>
15 'git remote rm' <name>
16 +'git remote set-head' <name> [-a | -d | <branch>]
17 'git remote show' [-n] <name>
18 'git remote prune' [-n | --dry-run] <name>
19 'git remote update' [group]
@@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track
54 multiple branches without grabbing all branches.
55 +
56 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.
58 +
59 In mirror mode, enabled with `\--mirror`, the refs will not be stored
60 in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
@@ -76,6 +76,30 @@ the configuration file format.
76 Remove the remote named <name>. All remote tracking branches and
77 configuration settings for the remote are removed.
78
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 +
103 'show'::
104
105 Gives some information about the remote <name>.
builtin-remote.c
+62
@@ -12,6 +12,7 @@ static const char * const builtin_remote_usage[] = {
12 "git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
13 "git remote rename <old> <new>",
14 "git remote rm <name>",
15 + "git remote set-head <name> [-a | -d | <branch>]",
16 "git remote show [-n] <name>",
17 "git remote prune [-n | --dry-run] <name>",
18 "git remote [-v | --verbose] update [group]",
@@ -792,6 +793,65 @@ static int show(int argc, const char **argv)
793 return result;
794 }
795
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 +
855 static int prune(int argc, const char **argv)
856 {
857 int dry_run = 0, result = 0;
@@ -962,6 +1022,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
1022 result = mv(argc, argv);
1023 else if (!strcmp(argv[0], "rm"))
1024 result = rm(argc, argv);
1025 + else if (!strcmp(argv[0], "set-head"))
1026 + result = set_head(argc, argv);
1027 else if (!strcmp(argv[0], "show"))
1028 result = show(argc, argv);
1029 else if (!strcmp(argv[0], "prune"))
contrib/completion/git-completion.bash
+1 -1
@@ -1443,7 +1443,7 @@ _git_config ()
1443
1444 _git_remote ()
1445 {
1446 - local subcommands="add rename rm show prune update"
1446 + local subcommands="add rename rm show prune update set-head"
1447 local subcommand="$(__git_find_subcommand "$subcommands")"
1448 if [ -z "$subcommand" ]; then
1449 __gitcomp "$subcommands"
t/t5505-remote.sh
+40
@@ -205,6 +205,46 @@ test_expect_success 'prune' '
205 test_must_fail git rev-parse refs/remotes/origin/side)
206 '
207
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 +
248 cat > test/expect << EOF
249 Pruning origin
250 URL: $(pwd)/one