Extend "checkout --track" DWIM to support more cases
authorAlex Riesen <raa.lkml@gmail.com>
Thu, 21 Aug 2008 17:23:20 +0000 (19:23 +0200)
committerJunio C Hamano <gitster@pobox.com>
Sat, 23 Aug 2008 00:18:26 +0000 (17:18 -0700)
The code handles additionally "refs/remotes/<something>/name",
"remotes/<something>/name", and "refs/<namespace>/name".

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-checkout.txt
builtin-checkout.c
cache.h
t/t7201-co.sh

index 43d4502547128c3155f598ae9c00b18d17c1ec2c..be54a0299fb2b6849993aa27d18c829ce91e7e00 100644 (file)
@@ -64,9 +64,16 @@ OPTIONS
        given. Set it to `always` if you want this behavior when the
        start-point is either a local or remote branch.
 +
-If no '-b' option was given, a name will be made up for you, by stripping
-the part up to the first slash of the tracked branch.  For example, if you
-called 'git checkout --track origin/next', the branch name will be 'next'.
+If no '-b' option was given, the name of the new branch will be
+derived from the remote branch, by attempting to guess the name
+of the branch on remote system.  If "remotes/" or "refs/remotes/"
+are prefixed, it is stripped away, and then the part up to the
+next slash (which would be the nickname of the remote) is removed.
+This would tell us to use "hack" as the local branch when branching
+off of "origin/hack" (or "remotes/origin/hack", or even
+"refs/remotes/origin/hack").  If the given name has no slash, or the above
+guessing results in an empty name, the guessing is aborted.  You can
+exlicitly give a name with '-b' in such a case.
 
 --no-track::
        Ignore the branch.autosetupmerge configuration variable.
index e95eab9b1b1f068e432c4106d603becaa8f0d1f6..b380ad6e80046e77ed78a438c26f507da2737b0e 100644 (file)
@@ -157,7 +157,7 @@ struct checkout_opts {
        int force;
        int writeout_error;
 
-       char *new_branch;
+       const char *new_branch;
        int new_branch_log;
        enum branch_track track;
 };
@@ -437,27 +437,27 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 
        git_config(git_default_config, NULL);
 
-       opts.track = -1;
+       opts.track = BRANCH_TRACK_UNSPECIFIED;
 
        argc = parse_options(argc, argv, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
 
        /* --track without -b should DWIM */
-       if (opts.track && opts.track != -1 && !opts.new_branch) {
-               char *slash;
-               if (!argc || !strcmp(argv[0], "--"))
+       if (0 < opts.track && !opts.new_branch) {
+               const char *argv0 = argv[0];
+               if (!argc || !strcmp(argv0, "--"))
                        die ("--track needs a branch name");
-               slash = strchr(argv[0], '/');
-               if (slash && !prefixcmp(argv[0], "refs/"))
-                       slash = strchr(slash + 1, '/');
-               if (slash && !prefixcmp(argv[0], "remotes/"))
-                       slash = strchr(slash + 1, '/');
-               if (!slash || !slash[1])
+               if (!prefixcmp(argv0, "refs/"))
+                       argv0 += 5;
+               if (!prefixcmp(argv0, "remotes/"))
+                       argv0 += 8;
+               argv0 = strchr(argv0, '/');
+               if (!argv0 || !argv0[1])
                        die ("Missing branch name; try -b");
-               opts.new_branch = slash + 1;
+               opts.new_branch = argv0 + 1;
        }
 
-       if (opts.track == -1)
+       if (opts.track == BRANCH_TRACK_UNSPECIFIED)
                opts.track = git_branch_track;
 
        if (opts.force && opts.merge)
diff --git a/cache.h b/cache.h
index 928ae9f148dae6361b6300aea9e76f22e0c23e60..a097a959bd4279e61eebd4f20589d337c8ec977b 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -451,6 +451,7 @@ enum safe_crlf {
 extern enum safe_crlf safe_crlf;
 
 enum branch_track {
+       BRANCH_TRACK_UNSPECIFIED = -1,
        BRANCH_TRACK_NEVER = 0,
        BRANCH_TRACK_REMOTE,
        BRANCH_TRACK_ALWAYS,
index 943dd57aacd379868687637fc9b2770b6ebc46d8..1dff84d2fd9ef665a9db314819152fcb94d17974 100755 (executable)
@@ -340,9 +340,30 @@ test_expect_success \
 test_expect_success \
     'checkout with --track fakes a sensible -b <name>' '
     git update-ref refs/remotes/origin/koala/bear renamer &&
+    git update-ref refs/new/koala/bear renamer &&
+
     git checkout --track origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"'
+    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
+
+    git checkout master && git branch -D koala/bear &&
+
+    git checkout --track refs/remotes/origin/koala/bear &&
+    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
+    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
+
+    git checkout master && git branch -D koala/bear &&
+
+    git checkout --track remotes/origin/koala/bear &&
+    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
+    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
+
+    git checkout master && git branch -D koala/bear &&
+
+    git checkout --track refs/new/koala/bear &&
+    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
+    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
+'
 
 test_expect_success \
     'checkout with --track, but without -b, fails with too short tracked name' '