{"thread":{"id":"33562","subject":"[PATCHv3 0/8] Improving the search for remote-tracking branches","startedAt":"2013-04-21T21:51:58Z","lastAt":"2013-04-21T21:52:06Z","messageCount":9,"participants":["Johan Herland"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"215033","messageId":"1366581126-3880-1-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":null,"subject":"[PATCHv3 0/8] Improving the search for remote-tracking branches","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:51:58Z","receivedAt":"2013-04-21T21:51:58Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Hi,\n\nThis is third iteration of this series. The only difference from v2 is\nimproved test code (in patches #1 and #2) thanks to Jonathan Nieder,\nand Eric Wong's ACK to patch #6.\n\nHave fun! :)\n\n...Johan\n\n\nJohan Herland (8):\n  t2024: Add tests verifying current DWIM behavior of 'git checkout <branch>'\n  t2024: Show failure to use refspec when DWIMming remote branch names\n  checkout: Use remote refspecs when DWIMming tracking branches\n  t3200.39: tracking setup should fail if there is no matching refspec.\n  t7201.24: Add refspec to keep --track working\n  t9114.2: Don't use --track option against \"svn-remote\"-tracking branches\n  branch.c: Validate tracking branches with refspecs instead of refs/remotes/*\n  glossary: Update and rephrase the definition of a remote-tracking branch\n\n Documentation/git-checkout.txt     |   6 +-\n Documentation/glossary-content.txt |  13 +--\n branch.c                           |  17 +++-\n builtin/checkout.c                 |  42 +++++-----\n t/t2024-checkout-dwim.sh           | 167 +++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |   8 +-\n t/t7201-co.sh                      |   1 +\n t/t9114-git-svn-dcommit-merge.sh   |   2 +-\n 8 files changed, 221 insertions(+), 35 deletions(-)\n create mode 100755 t/t2024-checkout-dwim.sh\n\n-- \n1.8.1.3.704.g33f7d4f\n\n>From fcab754f6702ea2724258dacd40803943db1e172 Mon Sep 17 00:00:00 2001\nFrom: Johan Herland <johan@herland.net>\nDate: Sat, 20 Apr 2013 14:28:51 +0200\nSubject: [PATCHv2 0/8] Improving the search for remote-tracking branches\n\nHi,\n\nThis is second iteration of this series. The initial three patches are\nunchanged, although the commit message of #3 has been rephrased based\non Junio's comments.\n\nPatches #4-#6 fixes existing tests in preparation for patch #7, which\nchanges the validation of the remote-tracking branch passed to --track:\nWe now require the --track argument to refer to a ref that matches a\nconfigured refspec - otherwise, we can not reliably deduce the upstream\ninformation to store into branch.<name>.remote and branch.<name>.merge.\n\nFinally, patch #8 updates the paragraph on remote-tracking branches in\nthe glossary to be somewhat closer to the current state of things.\n\n\nHave fun! :)\n\n...Johan\n\n\nJohan Herland (8):\n  t2024: Add tests verifying current DWIM behavior of 'git checkout <branch>'\n  t2024: Show failure to use refspec when DWIMming remote branch names\n  checkout: Use remote refspecs when DWIMming tracking branches\n  t3200.39: tracking setup should fail if there is no matching refspec.\n  t7201.24: Add refspec to keep --track working\n  t9114.2: Don't use --track option against \"svn-remote\"-tracking branches\n  branch.c: Validate tracking branches with refspecs instead of refs/remotes/*\n  glossary: Update and rephrase the definition of a remote-tracking branch\n\n Documentation/git-checkout.txt     |   6 +-\n Documentation/glossary-content.txt |  13 +++--\n branch.c                           |  17 +++++-\n builtin/checkout.c                 |  42 +++++++-------\n t/t2024-checkout-dwim.sh           | 116 +++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |   8 +--\n t/t7201-co.sh                      |   1 +\n t/t9114-git-svn-dcommit-merge.sh   |   2 +-\n 8 files changed, 170 insertions(+), 35 deletions(-)\n create mode 100755 t/t2024-checkout-dwim.sh\n\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215035","messageId":"1366581126-3880-2-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 1/8] t2024: Add tests verifying current DWIM behavior of 'git checkout <branch>'","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:51:59Z","receivedAt":"2013-04-21T21:51:59Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"The DWIM mode of checkout allows you to run \"git checkout foo\" when there is\nno existing local ref or path called \"foo\", and there is exactly one remote\nwith a remote-tracking branch called \"foo\". Git will then automatically\ncreate a new local branch called \"foo\" using the remote-tracking \"foo\" as\nits starting point and configured upstream.\n\nImproved-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n t/t2024-checkout-dwim.sh | 99 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 99 insertions(+)\n create mode 100755 t/t2024-checkout-dwim.sh\n\ndiff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh\nnew file mode 100755\nindex 0000000..1452bea\n--- /dev/null\n+++ b/t/t2024-checkout-dwim.sh\n@@ -0,0 +1,99 @@\n+#!/bin/sh\n+\n+test_description='checkout <branch>\n+\n+Ensures that checkout on an unborn branch does what the user expects'\n+\n+. ./test-lib.sh\n+\n+# Is the current branch \"refs/heads/$1\"?\n+test_branch () {\n+\tprintf \"%s\\n\" \"refs/heads/$1\" >expect.HEAD &&\n+\tgit symbolic-ref HEAD >actual.HEAD &&\n+\ttest_cmp expect.HEAD actual.HEAD\n+}\n+\n+# Is branch \"refs/heads/$1\" set to pull from \"$2/$3\"?\n+test_branch_upstream () {\n+\tprintf \"%s\\n\" \"$2\" \"refs/heads/$3\" >expect.upstream &&\n+\t{\n+\t\tgit config \"branch.$1.remote\" &&\n+\t\tgit config \"branch.$1.merge\"\n+\t} >actual.upstream &&\n+\ttest_cmp expect.upstream actual.upstream\n+}\n+\n+test_expect_success 'setup' '\n+\tgit init repo_a &&\n+\t(\n+\t\tcd repo_a &&\n+\t\ttest_commit a_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit a_foo &&\n+\t\tgit checkout -b bar &&\n+\t\ttest_commit a_bar\n+\t) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit b_foo &&\n+\t\tgit checkout -b baz &&\n+\t\ttest_commit b_baz\n+\t) &&\n+\tgit remote add repo_a repo_a &&\n+\tgit remote add repo_b repo_b &&\n+\tgit config remote.repo_b.fetch \\\n+\t\t\"+refs/heads/*:refs/remotes/other_b/*\" &&\n+\tgit fetch --all\n+'\n+\n+test_expect_success 'checkout of non-existing branch fails' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D xyzzy &&\n+\n+\ttest_must_fail git checkout xyzzy &&\n+\ttest_must_fail git rev-parse --verify refs/heads/xyzzy &&\n+\ttest_branch master\n+'\n+\n+test_expect_success 'checkout of branch from multiple remotes fails' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D foo &&\n+\n+\ttest_must_fail git checkout foo &&\n+\ttest_must_fail git rev-parse --verify refs/heads/foo &&\n+\ttest_branch master\n+'\n+\n+test_expect_success 'checkout of branch from a single remote succeeds #1' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D bar &&\n+\n+\tgit checkout bar &&\n+\ttest_branch bar &&\n+\ttest_cmp_rev remotes/repo_a/bar HEAD &&\n+\ttest_branch_upstream bar repo_a bar\n+'\n+\n+test_expect_success 'checkout of branch from a single remote succeeds #2' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D baz &&\n+\n+\tgit checkout baz &&\n+\ttest_branch baz &&\n+\ttest_cmp_rev remotes/other_b/baz HEAD &&\n+\ttest_branch_upstream baz repo_b baz\n+'\n+\n+test_expect_success '--no-guess suppresses branch auto-vivification' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D bar &&\n+\n+\ttest_must_fail git checkout --no-guess bar &&\n+\ttest_must_fail git rev-parse --verify refs/heads/bar &&\n+\ttest_branch master\n+'\n+\n+test_done\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215034","messageId":"1366581126-3880-3-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 2/8] t2024: Show failure to use refspec when DWIMming remote branch names","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:00Z","receivedAt":"2013-04-21T21:52:00Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"When using \"git checkout foo\" to DWIM the creation of local \"foo\" from some\nexisting upstream \"foo\", we assume conventional refspecs as created by \"git\nclone\" or \"git remote add\", and fail to work correctly if the current\nrefspecs do not follow the conventional \"refs/remotes/$remote/*\" pattern.\n\nImproved-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n t/t2024-checkout-dwim.sh | 70 +++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 69 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh\nindex 1452bea..b1e3444 100755\n--- a/t/t2024-checkout-dwim.sh\n+++ b/t/t2024-checkout-dwim.sh\n@@ -24,6 +24,7 @@ test_branch_upstream () {\n }\n \n test_expect_success 'setup' '\n+\ttest_commit my_master &&\n \tgit init repo_a &&\n \t(\n \t\tcd repo_a &&\n@@ -58,7 +59,7 @@ test_expect_success 'checkout of non-existing branch fails' '\n \ttest_branch master\n '\n \n-test_expect_success 'checkout of branch from multiple remotes fails' '\n+test_expect_success 'checkout of branch from multiple remotes fails #1' '\n \tgit checkout -B master &&\n \ttest_might_fail git branch -D foo &&\n \n@@ -96,4 +97,71 @@ test_expect_success '--no-guess suppresses branch auto-vivification' '\n \ttest_branch master\n '\n \n+test_expect_success 'setup more remotes with unconventional refspecs' '\n+\tgit checkout -B master &&\n+\tgit init repo_c &&\n+\t(\n+\t\tcd repo_c &&\n+\t\ttest_commit c_master &&\n+\t\tgit checkout -b bar &&\n+\t\ttest_commit c_bar\n+\t\tgit checkout -b spam &&\n+\t\ttest_commit c_spam\n+\t) &&\n+\tgit init repo_d &&\n+\t(\n+\t\tcd repo_d &&\n+\t\ttest_commit d_master &&\n+\t\tgit checkout -b baz &&\n+\t\ttest_commit f_baz\n+\t\tgit checkout -b eggs &&\n+\t\ttest_commit c_eggs\n+\t) &&\n+\tgit remote add repo_c repo_c &&\n+\tgit config remote.repo_c.fetch \\\n+\t\t\"+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*\" &&\n+\tgit remote add repo_d repo_d &&\n+\tgit config remote.repo_d.fetch \\\n+\t\t\"+refs/heads/*:refs/repo_d/*\" &&\n+\tgit fetch --all\n+'\n+\n+test_expect_failure 'checkout of branch from multiple remotes fails #2' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D bar &&\n+\n+\ttest_must_fail git checkout bar &&\n+\ttest_must_fail git rev-parse --verify refs/heads/bar &&\n+\ttest_branch master\n+'\n+\n+test_expect_failure 'checkout of branch from multiple remotes fails #3' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D baz &&\n+\n+\ttest_must_fail git checkout baz &&\n+\ttest_must_fail git rev-parse --verify refs/heads/baz &&\n+\ttest_branch master\n+'\n+\n+test_expect_failure 'checkout of branch from a single remote succeeds #3' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D spam &&\n+\n+\tgit checkout spam &&\n+\ttest_branch spam &&\n+\ttest_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&\n+\ttest_branch_upstream spam repo_c spam\n+'\n+\n+test_expect_failure 'checkout of branch from a single remote succeeds #4' '\n+\tgit checkout -B master &&\n+\ttest_might_fail git branch -D eggs &&\n+\n+\tgit checkout eggs &&\n+\ttest_branch eggs &&\n+\ttest_cmp_rev refs/repo_d/eggs HEAD &&\n+\ttest_branch_upstream eggs repo_d eggs\n+'\n+\n test_done\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215037","messageId":"1366581126-3880-4-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 3/8] checkout: Use remote refspecs when DWIMming tracking branches","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:01Z","receivedAt":"2013-04-21T21:52:01Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"The DWIM mode of checkout allows you to run \"git checkout foo\" when there\nis no existing local ref or path called \"foo\", and there is exactly _one_\nremote with a remote-tracking branch called \"foo\". Git will automatically\ncreate a new local branch called \"foo\" using the remote-tracking \"foo\" as\nits starting point and configured upstream.\n\nFor example, consider the following unconventional (but perfectly valid)\nremote setup:\n\n\t[remote \"origin\"]\n\t\tfetch = refs/heads/*:refs/remotes/origin/*\n\t[remote \"frotz\"]\n\t\tfetch = refs/heads/*:refs/remotes/frotz/nitfol/*\n\nCase 1: Assume both \"origin\" and \"frotz\" have remote-tracking branches called\n\"foo\", at \"refs/remotes/origin/foo\" and \"refs/remotes/frotz/nitfol/foo\"\nrespectively. In this case \"git checkout foo\" should fail, because there is\nmore than one remote with a \"foo\" branch.\n\nCase 2: Assume only \"frotz\" have a remote-tracking branch called \"foo\". In\nthis case \"git checkout foo\" should succeed, and create a local branch \"foo\"\nfrom \"refs/remotes/frotz/nitfol/foo\", using remote branch \"foo\" from \"frotz\"\nas its upstream.\n\nThe current code hardcodes the assumption that all remote-tracking branches\nmust match the \"refs/remotes/$remote/*\" pattern (which is true for remotes\nwith \"conventional\" refspecs, but not true for the \"frotz\" remote above).\nWhen running \"git checkout foo\", the current code looks for exactly one ref\nmatching \"refs/remotes/*/foo\", hence in the above example, it fails to find\n\"refs/remotes/frotz/nitfol/foo\", which causes it to fail both case #1 and #2.\n\nThe better way to handle the above example is to actually study the fetch\nrefspecs to deduce the candidate remote-tracking branches for \"foo\"; i.e.\nassume \"foo\" is a remote branch being fetched, and then map \"refs/heads/foo\"\nthrough the refspecs in order to get the corresponding remote-tracking\nbranches \"refs/remotes/origin/foo\" and \"refs/remotes/frotz/nitfol/foo\".\nFinally we check which of these happens to exist in the local repo, and\nif there is exactly one, we have an unambiguous match for \"git checkout foo\",\nand may proceed.\n\nThis fixes most of the failing tests introduced in the previous patch.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n Documentation/git-checkout.txt |  6 +++---\n builtin/checkout.c             | 42 ++++++++++++++++++++++--------------------\n t/t2024-checkout-dwim.sh       |  6 +++---\n 3 files changed, 28 insertions(+), 26 deletions(-)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 8edcdca..bf0c99c 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -131,9 +131,9 @@ entries; instead, unmerged entries are ignored.\n \t\"--track\" in linkgit:git-branch[1] for details.\n +\n If no '-b' option is given, the name of the new branch will be\n-derived from the remote-tracking branch.  If \"remotes/\" or \"refs/remotes/\"\n-is prefixed it is stripped away, and then the part up to the\n-next slash (which would be the nickname of the remote) is removed.\n+derived from the remote-tracking branch, by looking at the local part of\n+the refspec configured for the corresponding remote, and then stripping\n+the initial part up to the \"*\".\n This would tell us to use \"hack\" as the local branch when branching\n off of \"origin/hack\" (or \"remotes/origin/hack\", or even\n \"refs/remotes/origin/hack\").  If the given name has no slash, or the above\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex eb51872..bcb18c8 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -822,38 +822,40 @@ static int git_checkout_config(const char *var, const char *value, void *cb)\n }\n \n struct tracking_name_data {\n-\tconst char *name;\n-\tchar *remote;\n+\t/* const */ char *src_ref;\n+\tchar *dst_ref;\n+\tunsigned char *dst_sha1;\n \tint unique;\n };\n \n-static int check_tracking_name(const char *refname, const unsigned char *sha1,\n-\t\t\t       int flags, void *cb_data)\n+static int check_tracking_name(struct remote *remote, void *cb_data)\n {\n \tstruct tracking_name_data *cb = cb_data;\n-\tconst char *slash;\n-\n-\tif (prefixcmp(refname, \"refs/remotes/\"))\n-\t\treturn 0;\n-\tslash = strchr(refname + 13, '/');\n-\tif (!slash || strcmp(slash + 1, cb->name))\n+\tstruct refspec query;\n+\tmemset(&query, 0, sizeof(struct refspec));\n+\tquery.src = cb->src_ref;\n+\tif (remote_find_tracking(remote, &query) ||\n+\t    get_sha1(query.dst, cb->dst_sha1))\n \t\treturn 0;\n-\tif (cb->remote) {\n+\tif (cb->dst_ref) {\n \t\tcb->unique = 0;\n \t\treturn 0;\n \t}\n-\tcb->remote = xstrdup(refname);\n+\tcb->dst_ref = xstrdup(query.dst);\n \treturn 0;\n }\n \n-static const char *unique_tracking_name(const char *name)\n+static const char *unique_tracking_name(const char *name, unsigned char *sha1)\n {\n-\tstruct tracking_name_data cb_data = { NULL, NULL, 1 };\n-\tcb_data.name = name;\n-\tfor_each_ref(check_tracking_name, &cb_data);\n+\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n+\tchar src_ref[PATH_MAX];\n+\tsnprintf(src_ref, PATH_MAX, \"refs/heads/%s\", name);\n+\tcb_data.src_ref = src_ref;\n+\tcb_data.dst_sha1 = sha1;\n+\tfor_each_remote(check_tracking_name, &cb_data);\n \tif (cb_data.unique)\n-\t\treturn cb_data.remote;\n-\tfree(cb_data.remote);\n+\t\treturn cb_data.dst_ref;\n+\tfree(cb_data.dst_ref);\n \treturn NULL;\n }\n \n@@ -916,8 +918,8 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t\tif (dwim_new_local_branch_ok &&\n \t\t    !check_filename(NULL, arg) &&\n \t\t    argc == 1) {\n-\t\t\tconst char *remote = unique_tracking_name(arg);\n-\t\t\tif (!remote || get_sha1(remote, rev))\n+\t\t\tconst char *remote = unique_tracking_name(arg, rev);\n+\t\t\tif (!remote)\n \t\t\t\treturn argcount;\n \t\t\t*new_branch = arg;\n \t\t\targ = remote;\ndiff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh\nindex b1e3444..31e3d47 100755\n--- a/t/t2024-checkout-dwim.sh\n+++ b/t/t2024-checkout-dwim.sh\n@@ -126,7 +126,7 @@ test_expect_success 'setup more remotes with unconventional refspecs' '\n \tgit fetch --all\n '\n \n-test_expect_failure 'checkout of branch from multiple remotes fails #2' '\n+test_expect_success 'checkout of branch from multiple remotes fails #2' '\n \tgit checkout -B master &&\n \ttest_might_fail git branch -D bar &&\n \n@@ -135,7 +135,7 @@ test_expect_failure 'checkout of branch from multiple remotes fails #2' '\n \ttest_branch master\n '\n \n-test_expect_failure 'checkout of branch from multiple remotes fails #3' '\n+test_expect_success 'checkout of branch from multiple remotes fails #3' '\n \tgit checkout -B master &&\n \ttest_might_fail git branch -D baz &&\n \n@@ -144,7 +144,7 @@ test_expect_failure 'checkout of branch from multiple remotes fails #3' '\n \ttest_branch master\n '\n \n-test_expect_failure 'checkout of branch from a single remote succeeds #3' '\n+test_expect_success 'checkout of branch from a single remote succeeds #3' '\n \tgit checkout -B master &&\n \ttest_might_fail git branch -D spam &&\n \n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215036","messageId":"1366581126-3880-5-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 4/8] t3200.39: tracking setup should fail if there is no matching refspec.","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:02Z","receivedAt":"2013-04-21T21:52:02Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"We are formalizing a requirement that any remote-tracking branch to be used\nas an upstream (i.e. as an argument to --track), _must_ \"belong\" to a\nconfigured remote by being matched by the \"dst\" side of a fetch refspec.\n\nThis patch encodes the new expected behavior of this test, and marks the\ntest with \"test_expect_failure\" in anticipation of a following patch to\nintroduce the new behavior.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n t/t3200-branch.sh | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex d969f0e..1bfdadc 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -317,13 +317,13 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '\n \ttest $(git config branch.my4.merge) = refs/heads/master\n '\n \n-test_expect_success 'test tracking setup (non-wildcard, not matching)' '\n+test_expect_failure 'tracking setup fails on non-matching refspec' '\n \tgit config remote.local.url . &&\n \tgit config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n \t(git show-ref -q refs/remotes/local/master || git fetch local) &&\n-\tgit branch --track my5 local/master &&\n-\t! test \"$(git config branch.my5.remote)\" = local &&\n-\t! test \"$(git config branch.my5.merge)\" = refs/heads/master\n+\ttest_must_fail git branch --track my5 local/master &&\n+\ttest_must_fail git config branch.my5.remote &&\n+\ttest_must_fail git config branch.my5.merge\n '\n \n test_expect_success 'test tracking setup via config' '\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215038","messageId":"1366581126-3880-6-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 5/8] t7201.24: Add refspec to keep --track working","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:03Z","receivedAt":"2013-04-21T21:52:03Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"We are formalizing a requirement that any remote-tracking branch to be used\nas an upstream (i.e. as an argument to --track), _must_ \"belong\" to a\nconfigured remote by being matched by the \"dst\" side of a fetch refspec.\n\nWithout this patch, this test would start failing when the new behavior is\nintroduced.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n t/t7201-co.sh | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex be9672e..0c9ec0a 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -431,6 +431,7 @@ test_expect_success 'detach a symbolic link HEAD' '\n \n test_expect_success \\\n     'checkout with --track fakes a sensible -b <name>' '\n+    git config remote.origin.fetch \"+refs/heads/*:refs/remotes/origin/*\" &&\n     git update-ref refs/remotes/origin/koala/bear renamer &&\n \n     git checkout --track origin/koala/bear &&\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215039","messageId":"1366581126-3880-7-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 6/8] t9114.2: Don't use --track option against \"svn-remote\"-tracking branches","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:04Z","receivedAt":"2013-04-21T21:52:04Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"We are formalizing a requirement that any remote-tracking branch to be used\nas an upstream (i.e. as an argument to --track), _must_ \"belong\" to a\nconfigured remote by being matched by the \"dst\" side of a fetch refspec.\n\nThis test uses --track against a \"remotes/trunk\" ref which does not belong\nto any configured (git) remotes, but is instead created by \"git svn fetch\"\noperating on an svn-remote. It does not make sense to use an svn-remote as\nan upstream for a local branch, as a regular \"git pull\" from (or \"git push\"\nto) it would obviously fail (instead you would need to use \"git svn\" to\ncommunicate with this remote). Furthermore, the usage of --track in this\ncase is unnecessary, since the upstreaming config that would be created is\nnever used.\n\nSimply removing --track fixes the issue without changing the expected\nbehavior of the test.\n\nAcked-by: Eric Wong <normalperson@yhbt.net>\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n t/t9114-git-svn-dcommit-merge.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh\nindex 3077851..f524d2f 100755\n--- a/t/t9114-git-svn-dcommit-merge.sh\n+++ b/t/t9114-git-svn-dcommit-merge.sh\n@@ -48,7 +48,7 @@ test_expect_success 'setup svn repository' '\n test_expect_success 'setup git mirror and merge' '\n \tgit svn init \"$svnrepo\" -t tags -T trunk -b branches &&\n \tgit svn fetch &&\n-\tgit checkout --track -b svn remotes/trunk &&\n+\tgit checkout -b svn remotes/trunk &&\n \tgit checkout -b merge &&\n \techo new file > new_file &&\n \tgit add new_file &&\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215040","messageId":"1366581126-3880-8-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 7/8] branch.c: Validate tracking branches with refspecs instead of refs/remotes/*","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:05Z","receivedAt":"2013-04-21T21:52:05Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"The current code for validating tracking branches (e.g. the argument to\nthe -t/--track option) hardcodes refs/heads/* and refs/remotes/* as the\npotential locations for tracking branches. This works with the refspecs\ncreated by \"git clone\" or \"git remote add\", but is suboptimal in other\ncases:\n\n - If \"refs/remotes/foo/bar\" exists without any association to a remote\n   (i.e. there is no remote named \"foo\", or no remote with a refspec\n   that matches \"refs/remotes/foo/bar\"), then it is impossible to set up\n   a valid upstream config that tracks it. Currently, the code defaults\n   to using \"refs/remotes/foo/bar\" from repo \".\" as the upstream, which\n   works, but is probably not what the user had in mind when running\n   \"git branch baz --track foo/bar\".\n\n - If the user has tweaked the fetch refspec for a remote to put its\n   remote-tracking branches outside of refs/remotes/*, e.g. by running\n       git config remote.foo.fetch \"+refs/heads/*:refs/foo_stuff/*\"\n   then the current code will refuse to use its remote-tracking branches\n   as --track arguments, since they do not match refs/remotes/*.\n\nThis patch removes the \"refs/remotes/*\" requirement for upstream branches,\nand replaces it with explicit checking of the refspecs for each remote to\ndetermine whether a given --track argument is a valid remote-tracking\nbranch. This solves both of the above problems, since the matching refspec\nguarantees that there is a both a remote name and a remote branch name\nthat can be used for the upstream config.\n\nHowever, this means that refs located within refs/remotes/* without a\ncorresponding remote/refspec will no longer be usable as upstreams.\nThe few existing tests which depended on this behavioral quirk has\nalready been fixed in the preceding patches.\n\nThis patch fixes the last remaining test failure in t2024-checkout-dwim.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n branch.c                 | 17 ++++++++++++++++-\n t/t2024-checkout-dwim.sh |  2 +-\n t/t3200-branch.sh        |  2 +-\n 3 files changed, 18 insertions(+), 3 deletions(-)\n\ndiff --git a/branch.c b/branch.c\nindex 6ae6a4c..beaf11d 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -197,6 +197,21 @@ int validate_new_branchname(const char *name, struct strbuf *ref,\n \treturn 1;\n }\n \n+static int check_tracking_branch(struct remote *remote, void *cb_data)\n+{\n+\tchar *tracking_branch = cb_data;\n+\tstruct refspec query;\n+\tmemset(&query, 0, sizeof(struct refspec));\n+\tquery.dst = tracking_branch;\n+\treturn !(remote_find_tracking(remote, &query) ||\n+\t\t prefixcmp(query.src, \"refs/heads/\"));\n+}\n+\n+static int validate_remote_tracking_branch(char *ref)\n+{\n+\treturn !for_each_remote(check_tracking_branch, ref);\n+}\n+\n static const char upstream_not_branch[] =\n N_(\"Cannot setup tracking information; starting point '%s' is not a branch.\");\n static const char upstream_missing[] =\n@@ -259,7 +274,7 @@ void create_branch(const char *head,\n \tcase 1:\n \t\t/* Unique completion -- good, only if it is a real branch */\n \t\tif (prefixcmp(real_ref, \"refs/heads/\") &&\n-\t\t    prefixcmp(real_ref, \"refs/remotes/\")) {\n+\t\t    validate_remote_tracking_branch(real_ref)) {\n \t\t\tif (explicit_tracking)\n \t\t\t\tdie(_(upstream_not_branch), start_name);\n \t\t\telse\ndiff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh\nindex 31e3d47..dee55e4 100755\n--- a/t/t2024-checkout-dwim.sh\n+++ b/t/t2024-checkout-dwim.sh\n@@ -154,7 +154,7 @@ test_expect_success 'checkout of branch from a single remote succeeds #3' '\n \ttest_branch_upstream spam repo_c spam\n '\n \n-test_expect_failure 'checkout of branch from a single remote succeeds #4' '\n+test_expect_success 'checkout of branch from a single remote succeeds #4' '\n \tgit checkout -B master &&\n \ttest_might_fail git branch -D eggs &&\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 1bfdadc..44ec6a4 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -317,7 +317,7 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '\n \ttest $(git config branch.my4.merge) = refs/heads/master\n '\n \n-test_expect_failure 'tracking setup fails on non-matching refspec' '\n+test_expect_success 'tracking setup fails on non-matching refspec' '\n \tgit config remote.local.url . &&\n \tgit config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n \t(git show-ref -q refs/remotes/local/master || git fetch local) &&\n-- \n1.8.1.3.704.g33f7d4f\n"},{"id":"215041","messageId":"1366581126-3880-9-git-send-email-johan@herland.net","threadId":"33562","inReplyTo":"1366581126-3880-1-git-send-email-johan@herland.net","subject":"[PATCHv3 8/8] glossary: Update and rephrase the definition of a remote-tracking branch","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-21T21:52:06Z","receivedAt":"2013-04-21T21:52:06Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"The definition of a remote-tracking branch in the glossary have been\nout-of-date for a while (by e.g. referring to \"Pull:\" from old-style\n$GIT_DIR/remotes files).\n\nAlso, the preceding patches have formalized that a remote-tracking branch\nmust match a configured refspec in order to be usable as an upstream.\n\nThis patch rewrites the paragraph on remote-tracking branches accordingly.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n Documentation/glossary-content.txt | 13 +++++++------\n 1 file changed, 7 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt\nindex 2478a39..7a79f26 100644\n--- a/Documentation/glossary-content.txt\n+++ b/Documentation/glossary-content.txt\n@@ -423,12 +423,13 @@ should not be combined with other pathspec.\n \tlinkgit:git-push[1].\n \n [[def_remote_tracking_branch]]remote-tracking branch::\n-\tA regular Git <<def_branch,branch>> that is used to follow changes from\n-\tanother <<def_repository,repository>>. A remote-tracking\n-\tbranch should not contain direct modifications or have local commits\n-\tmade to it. A remote-tracking branch can usually be\n-\tidentified as the right-hand-side <<def_ref,ref>> in a Pull:\n-\t<<def_refspec,refspec>>.\n+\tA <<def_ref,ref>> that is used to follow changes from another\n+\t<<def_repository,repository>>. It typically looks like\n+\t'refs/remotes/foo/bar' (indicating that it tracks a branch named\n+\t'bar' in a remote named 'foo'), and matches the right-hand-side of\n+\ta configured fetch <<def_refspec,refspec>>. A remote-tracking\n+\tbranch should not contain direct modifications or have local\n+\tcommits made to it.\n \n [[def_repository]]repository::\n \tA collection of <<def_ref,refs>> together with an\n-- \n1.8.1.3.704.g33f7d4f\n"}]}