diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 43d4502..d93a18f 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -64,9 +64,21 @@ 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 and use it. The algorithm will remove a
+prefixed refs/ and the part after refs/ up to a slash (that part
+usually being a branch namespace, which makes it confusing to use for
+branch names). If the part after refs/ was remotes/, than a part past
+it is stripped too (it is expected to be the name of remote system).
+Otherwise, the part up to the first slash is removed.
+The algorithm aborts either if the given name has no slashes in it or
+if the part left after stripping the prefixes is empty. In this case,
+the name should be provided with '-b'.
++
+For example, if you called 'git checkout --track origin/next', the
+branch name will be 'next', as it will for 'git checkout --track
+remotes/origin/next'.
--no-track::
Ignore the branch.autosetupmerge configuration variable.
diff --git a/builtin-checkout.c b/builtin-checkout.c
index e95eab9..214b0b2 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -445,12 +445,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
/* --track without -b should DWIM */
if (opts.track && opts.track != -1 && !opts.new_branch) {
char *slash;
- if (!argc || !strcmp(argv[0], "--"))
+ 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(argv0, '/');
+ if (slash && !prefixcmp(argv0, "refs/")) {
+ argv0 = slash + 1;
+ slash = strchr(argv0, '/');
+ }
+ if (slash && !prefixcmp(argv0, "remotes/"))
slash = strchr(slash + 1, '/');
if (!slash || !slash[1])
die ("Missing branch name; try -b");diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 943dd57..1dff84d 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -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' '--
1.6.0.59.g8ae62