{"thread":{"id":"47179","subject":"[PATCH v1 1/2] checkout: factor out functions to new lib file","startedAt":"2017-11-12T13:42:22Z","lastAt":"2017-11-22T19:48:14Z","messageCount":28,"participants":["Thomas Gummerer","Junio C Hamano","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"332327","messageId":"20171112134305.3949-1-t.gummerer@gmail.com","threadId":"47179","inReplyTo":null,"subject":"[PATCH v1 1/2] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-12T13:43:04Z","receivedAt":"2017-11-12T13:42:22Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor the functions out, so they can be re-used from other places.  In\nparticular these functions will be re-used in builtin/worktree.c to make\ngit worktree add dwim more.\n\nWhile there add a description to the function.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nI'm not sure where these functions should go ideally, they don't seem\nto fit in any existing library file, so I created a new one for now.\nAny suggestions for a better home are welcome!\n\n Makefile           |  1 +\n builtin/checkout.c | 41 +----------------------------------------\n checkout.c         | 43 +++++++++++++++++++++++++++++++++++++++++++\n checkout.h         | 14 ++++++++++++++\n 4 files changed, 59 insertions(+), 40 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\ndiff --git a/Makefile b/Makefile\nindex cd75985991..8d603c7443 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,6 +757,7 @@ LIB_OBJS += branch.o\n LIB_OBJS += bulk-checkin.o\n LIB_OBJS += bundle.o\n LIB_OBJS += cache-tree.o\n+LIB_OBJS += checkout.o\n LIB_OBJS += color.o\n LIB_OBJS += column.o\n LIB_OBJS += combine-diff.o\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex fc4f8fd2ea..9e1cfd10b3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"config.h\"\n+#include \"checkout.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n@@ -874,46 +875,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)\n \treturn git_xmerge_config(var, value, NULL);\n }\n \n-struct tracking_name_data {\n-\t/* const */ char *src_ref;\n-\tchar *dst_ref;\n-\tstruct object_id *dst_oid;\n-\tint unique;\n-};\n-\n-static int check_tracking_name(struct remote *remote, void *cb_data)\n-{\n-\tstruct tracking_name_data *cb = cb_data;\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_oid(query.dst, cb->dst_oid)) {\n-\t\tfree(query.dst);\n-\t\treturn 0;\n-\t}\n-\tif (cb->dst_ref) {\n-\t\tfree(query.dst);\n-\t\tcb->unique = 0;\n-\t\treturn 0;\n-\t}\n-\tcb->dst_ref = query.dst;\n-\treturn 0;\n-}\n-\n-static const char *unique_tracking_name(const char *name, struct object_id *oid)\n-{\n-\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n-\tcb_data.src_ref = xstrfmt(\"refs/heads/%s\", name);\n-\tcb_data.dst_oid = oid;\n-\tfor_each_remote(check_tracking_name, &cb_data);\n-\tfree(cb_data.src_ref);\n-\tif (cb_data.unique)\n-\t\treturn cb_data.dst_ref;\n-\tfree(cb_data.dst_ref);\n-\treturn NULL;\n-}\n-\n static int parse_branchname_arg(int argc, const char **argv,\n \t\t\t\tint dwim_new_local_branch_ok,\n \t\t\t\tstruct branch_info *new,\ndiff --git a/checkout.c b/checkout.c\nnew file mode 100644\nindex 0000000000..a9cf378453\n--- /dev/null\n+++ b/checkout.c\n@@ -0,0 +1,43 @@\n+#include \"cache.h\"\n+\n+#include \"remote.h\"\n+\n+struct tracking_name_data {\n+\t/* const */ char *src_ref;\n+\tchar *dst_ref;\n+\tstruct object_id *dst_oid;\n+\tint unique;\n+};\n+\n+static int check_tracking_name(struct remote *remote, void *cb_data)\n+{\n+\tstruct tracking_name_data *cb = cb_data;\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_oid(query.dst, cb->dst_oid)) {\n+\t\tfree(query.dst);\n+\t\treturn 0;\n+\t}\n+\tif (cb->dst_ref) {\n+\t\tfree(query.dst);\n+\t\tcb->unique = 0;\n+\t\treturn 0;\n+\t}\n+\tcb->dst_ref = query.dst;\n+\treturn 0;\n+}\n+\n+const char *unique_tracking_name(const char *name, struct object_id *oid)\n+{\n+\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n+\tcb_data.src_ref = xstrfmt(\"refs/heads/%s\", name);\n+\tcb_data.dst_oid = oid;\n+\tfor_each_remote(check_tracking_name, &cb_data);\n+\tfree(cb_data.src_ref);\n+\tif (cb_data.unique)\n+\t\treturn cb_data.dst_ref;\n+\tfree(cb_data.dst_ref);\n+\treturn NULL;\n+}\ndiff --git a/checkout.h b/checkout.h\nnew file mode 100644\nindex 0000000000..9272fe1449\n--- /dev/null\n+++ b/checkout.h\n@@ -0,0 +1,14 @@\n+#ifndef CHECKOUT_H\n+#define CHECKOUT_H\n+\n+#include \"git-compat-util.h\"\n+#include \"cache.h\"\n+\n+/*\n+ * Check if the branch name uniquely matches a branch name on a remote\n+ * tracking branch.  Return the name of the remote if such a branch\n+ * exists, NULL otherwise.\n+ */\n+extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n+\n+#endif /* CHECKOUT_H */\n-- \n2.15.0.403.gc27cc4dac6\n\n"},{"id":"332328","messageId":"20171112134305.3949-2-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171112134305.3949-1-t.gummerer@gmail.com","subject":"[PATCH v1 2/2] worktree: make add dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-12T13:43:05Z","receivedAt":"2017-11-12T13:42:25Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently git worktree add creates a new branch, that matches the HEAD\nof whichever worktree we were on when calling \"git worktree add\".\n\nAdd a --guess flag to git worktree add, that makes it behave like the\ndwim machinery in 'git checkout <new-branch>', i.e. check if the new\nbranch name uniquely matches the branch name of a remote tracking\nbranch, and if so check out that branch, and set the upstream to the\nremote tracking branch.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nI'm a bit torn about hiding his behind an additional flag in git\nworktree add or not.  I would like to have the feature without the\nadditional flag, but it might break some peoples expectations, so\ndunno.\n\n builtin/worktree.c      | 14 +++++++++-\n t/t2025-worktree-add.sh | 70 +++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 83 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 7b9307aa58..5740d1f8a3 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"checkout.h\"\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"dir.h\"\n@@ -341,6 +342,7 @@ static int add(int ac, const char **av, const char *prefix)\n \tconst char *new_branch_force = NULL;\n \tchar *path;\n \tconst char *branch;\n+\tint dwim_new_branch = 0;\n \tstruct option options[] = {\n \t\tOPT__FORCE(&opts.force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n \t\tOPT_STRING('b', NULL, &opts.new_branch, N_(\"branch\"),\n@@ -350,6 +352,7 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_BOOL(0, \"detach\", &opts.detach, N_(\"detach HEAD at named commit\")),\n \t\tOPT_BOOL(0, \"checkout\", &opts.checkout, N_(\"populate the new working tree\")),\n \t\tOPT_BOOL(0, \"lock\", &opts.keep_locked, N_(\"keep the new working tree locked\")),\n+\t\tOPT_BOOL(0, \"guess\", &dwim_new_branch, N_(\"checkout upstream branch if there's a unique match\")),\n \t\tOPT_END()\n \t};\n \n@@ -363,6 +366,7 @@ static int add(int ac, const char **av, const char *prefix)\n \n \tpath = prefix_filename(prefix, av[0]);\n \tbranch = ac < 2 ? \"HEAD\" : av[1];\n+\tdwim_new_branch = ac < 2 ? dwim_new_branch : 0;\n \n \tif (!strcmp(branch, \"-\"))\n \t\tbranch = \"@{-1}\";\n@@ -387,13 +391,21 @@ static int add(int ac, const char **av, const char *prefix)\n \t}\n \n \tif (opts.new_branch) {\n+\t\tstruct object_id oid;\n+\t\tconst char *remote;\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\t\tremote = unique_tracking_name(opts.new_branch, &oid);\n+\n \t\tcp.git_cmd = 1;\n \t\targv_array_push(&cp.args, \"branch\");\n \t\tif (opts.force_new_branch)\n \t\t\targv_array_push(&cp.args, \"--force\");\n \t\targv_array_push(&cp.args, opts.new_branch);\n-\t\targv_array_push(&cp.args, branch);\n+\t\tif (dwim_new_branch && remote)\n+\t\t\targv_array_push(&cp.args, remote);\n+\t\telse\n+\t\t\targv_array_push(&cp.args, branch);\n \t\tif (run_command(&cp))\n \t\t\treturn -1;\n \t\tbranch = opts.new_branch;\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex b5c47ac602..b37c279787 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -6,6 +6,16 @@ test_description='test git worktree add'\n \n . \"$TEST_DIRECTORY\"/lib-rebase.sh\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 \ttest_commit init\n '\n@@ -314,4 +324,64 @@ test_expect_success 'rename a branch under bisect not allowed' '\n \ttest_must_fail git branch -M under-bisect bisect-with-new-name\n '\n \n+test_expect_success 'git worktree add does not dwim' '\n+\ttest_when_finished rm -rf repo_a &&\n+\ttest_when_finished rm -rf repo_b &&\n+\ttest_when_finished rm -rf foo &&\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) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit remote add repo_a ../repo_a &&\n+\t\tgit config remote.repo_a.fetch \\\n+\t\t\t\"+refs/heads/*:refs/remotes/other_a/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\t! test_branch_upstream foo repo_a foo &&\n+\t\tgit rev-parse other_a/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\t! test_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'git worktree add --guess dwims' '\n+\ttest_when_finished rm -rf repo_a &&\n+\ttest_when_finished rm -rf repo_b &&\n+\ttest_when_finished rm -rf foo &&\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) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit remote add repo_a ../repo_a &&\n+\t\tgit config remote.repo_a.fetch \\\n+\t\t\t\"+refs/heads/*:refs/remotes/other_a/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add --guess ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_a foo &&\n+\t\tgit rev-parse other_a/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.403.gc27cc4dac6\n\n"},{"id":"332382","messageId":"xmqq7euuc32z.fsf@gitster.mtv.corp.google.com","threadId":"47179","inReplyTo":"20171112134305.3949-1-t.gummerer@gmail.com","subject":"Re: [PATCH v1 1/2] checkout: factor out functions to new lib file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-13T02:41:40Z","receivedAt":"2017-11-13T02:41:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> Factor the functions out, so they can be re-used from other places.  In\n> particular these functions will be re-used in builtin/worktree.c to make\n> git worktree add dwim more.\n>\n> While there add a description to the function.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>\n> I'm not sure where these functions should go ideally, they don't seem\n> to fit in any existing library file, so I created a new one for now.\n> Any suggestions for a better home are welcome!\n>\n>  Makefile           |  1 +\n>  builtin/checkout.c | 41 +----------------------------------------\n>  checkout.c         | 43 +++++++++++++++++++++++++++++++++++++++++++\n>  checkout.h         | 14 ++++++++++++++\n>  4 files changed, 59 insertions(+), 40 deletions(-)\n>  create mode 100644 checkout.c\n>  create mode 100644 checkout.h\n\nI am not sure either.  I've always considered that entry.c is the\nlibified thing codepath that want to do a \"checkout\" should call,\nbut the functions that you are moving is at a \"higher layer\" that\ndoes not concern the core-git data structures (i.e. the 'tracking'\nis a mere \"user\" of the ref API, unlike things in entry.c such as\ncheckout_entry() that is a more \"maintainer\" of the index integrity),\nso perhaps it makes sense to have new file for it.\n\n> diff --git a/checkout.c b/checkout.c\n> new file mode 100644\n> index 0000000000..a9cf378453\n> --- /dev/null\n> +++ b/checkout.c\n> @@ -0,0 +1,43 @@\n> +#include \"cache.h\"\n> +\n\nA useless blank line.\n\n> +#include \"remote.h\"\n> +\n\nThis one is useful ;-)\n\n> +struct tracking_name_data {\n> ...\n> diff --git a/checkout.h b/checkout.h\n> new file mode 100644\n> index 0000000000..9272fe1449\n> --- /dev/null\n> +++ b/checkout.h\n> @@ -0,0 +1,14 @@\n> +#ifndef CHECKOUT_H\n> +#define CHECKOUT_H\n> +\n> +#include \"git-compat-util.h\"\n> +#include \"cache.h\"\n\nTry \"git grep -e git-compat-util Documentation/CodingGuidelines\" and\njust keep inclusion of \"cache.h\".\n"},{"id":"332383","messageId":"xmqq1sl2c21g.fsf@gitster.mtv.corp.google.com","threadId":"47179","inReplyTo":"20171112134305.3949-2-t.gummerer@gmail.com","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-13T03:04:11Z","receivedAt":"2017-11-13T03:04:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> I'm a bit torn about hiding his behind an additional flag in git\n> worktree add or not.  I would like to have the feature without the\n> additional flag, but it might break some peoples expectations, so\n> dunno.\n\nYeah, I agree with the sentiment.  But what expectation would we be\nbreaking, I wonder (see below)?\n\nAt the conceptual level, it is even more unfortunate that \"git\nworktree --help\" says this for \"git worktree add <path> [<branch>]\":\n\n    If `<branch>` is omitted and neither `-b` nor `-B` nor\n    `--detach` used, then, as a convenience, a new branch based at\n    HEAD is created automatically, as if `-b $(basename <path>)` was\n    specified.\n\nwhich means that it already does a DWIM, namely \"since you didn't\nsay what branch to create to track what other branch, we'll fork one\nfor you from the HEAD, and give a name to it\".  That may be a useful\nDWIM for some existing users sometimes, and you may even find it\nuseful some of the time but not always.  Different people mean\ndifferent things in different situations, and there is no single\ndefinition for DWIMming that would fit all of them.\n\nWhich in turn means that the new variable name DWIM_NEW_BRANCH and\nthe new option name GUESS are way underspecified.  You'd need to\nname them after the \"kind\" of dwim; otherwise, not only the future\nadditions for new (third) kind of dwim would become cumbersome, but\nreaders of the code would be confused if they are about the existing\ndwim (fork a new branch from HEAD and give it a name guessed by the\npathname) or your new dwim.\n\nThis also needs a documentation update.  Unlike the existing DWIM,\nit is totally unclear when you are dwimming in absence of which\noption.\n\nI am guessing that, when you do not have a branch \"topic\" but your\nupstream does, saying\n\n    $ git worktree add ../a-new-worktree topic\n\nwould create \"refs/heads/topic\" to build on top of\n\"refs/remotes/origin/topic\" just like \"git checkout topic\" would.\n\nIOW, when fully spelled out:\n\n    $ git branch -t -b topic origin/topic\n    $ git worktree add ../a-new-worktree topic\n\nis what your DWIM does?  Am I following you correctly?\n\nIf so, as long as the new DWIM kicks in ONLY when \"topic\" does not\nexist, I suspect that there is no backward compatibility worries.\nThe command line\n\n    $ git worktree add ../a-new-worktree topic\n\nwould just have failed because three was no 'topic' branch yet, no?\n\n"},{"id":"332519","messageId":"20171114084517.GA12097@hank","threadId":"47179","inReplyTo":"xmqq1sl2c21g.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-14T08:45:17Z","receivedAt":"2017-11-14T08:44:01Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/13, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > I'm a bit torn about hiding his behind an additional flag in git\n> > worktree add or not.  I would like to have the feature without the\n> > additional flag, but it might break some peoples expectations, so\n> > dunno.\n> \n> Yeah, I agree with the sentiment.  But what expectation would we be\n> breaking, I wonder (see below)?\n> \n> At the conceptual level, it is even more unfortunate that \"git\n> worktree --help\" says this for \"git worktree add <path> [<branch>]\":\n> \n>     If `<branch>` is omitted and neither `-b` nor `-B` nor\n>     `--detach` used, then, as a convenience, a new branch based at\n>     HEAD is created automatically, as if `-b $(basename <path>)` was\n>     specified.\n> \n> which means that it already does a DWIM, namely \"since you didn't\n> say what branch to create to track what other branch, we'll fork one\n> for you from the HEAD, and give a name to it\".  That may be a useful\n> DWIM for some existing users sometimes, and you may even find it\n> useful some of the time but not always.  Different people mean\n> different things in different situations, and there is no single\n> definition for DWIMming that would fit all of them.\n> \n> Which in turn means that the new variable name DWIM_NEW_BRANCH and\n> the new option name GUESS are way underspecified.  You'd need to\n> name them after the \"kind\" of dwim; otherwise, not only the future\n> additions for new (third) kind of dwim would become cumbersome, but\n> readers of the code would be confused if they are about the existing\n> dwim (fork a new branch from HEAD and give it a name guessed by the\n> pathname) or your new dwim.\n\nYeah I definitely agree with that.  I was mainly thinking about my\npersonal use case with --guess, and didn't fully think through that it\nmight mean different things to other people.\n\n> This also needs a documentation update.  Unlike the existing DWIM,\n> it is totally unclear when you are dwimming in absence of which\n> option.\n\nSorry about that, I totally forgot about the documentation for this.\nWill add in the next round.\n\n> I am guessing that, when you do not have a branch \"topic\" but your\n> upstream does, saying\n> \n>     $ git worktree add ../a-new-worktree topic\n> \n> would create \"refs/heads/topic\" to build on top of\n> \"refs/remotes/origin/topic\" just like \"git checkout topic\" would.\n> \n> IOW, when fully spelled out:\n> \n>     $ git branch -t -b topic origin/topic\n>     $ git worktree add ../a-new-worktree topic\n> \n> is what your DWIM does?  Am I following you correctly?\n\nIt's not quite what my DWIM does/what I originally intended my DWIM to\ndo.  What it does is when\n\n    $ git worktree add ../topic\n\nand omitting the branch argument, it would behave the way you spelled\nout, i.e.\n\n    $ git branch -t -b topic origin/topic\n    $ git worktree add ../topic topic\n\ninstead of just checking it out from HEAD.  I must confess I missed\nthe branch argument, so that still behaves the old way with my code,\nwhile what you have above would make a lot more sense.\n\n> If so, as long as the new DWIM kicks in ONLY when \"topic\" does not\n> exist, I suspect that there is no backward compatibility worries.\n> The command line\n> \n>     $ git worktree add ../a-new-worktree topic\n> \n> would just have failed because three was no 'topic' branch yet, no?\n\nIndeed, with this there would not be any backwards compatility\nworries.\n\nIdeally I'd still like to make\n\n    $ git worktree add ../topic\n\nwork as described above, to avoid having to type 'topic' twice (the\ndirectory name matches the branch name for the vast majority of my\nworktrees) but that should then come behind a flag/config option?\nFollowing your reasoning above it should probably be called something\nother than --guess.\n\nMaybe --guess-remote and worktree.guessRemote would do?  I'm quite bad\nat naming though, so other suggestions are very welcome.\n"},{"id":"332521","messageId":"20171114084607.GB12097@hank","threadId":"47179","inReplyTo":"xmqq7euuc32z.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1 1/2] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-14T08:46:07Z","receivedAt":"2017-11-14T08:44:49Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/13, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > Factor the functions out, so they can be re-used from other places.  In\n> > particular these functions will be re-used in builtin/worktree.c to make\n> > git worktree add dwim more.\n> >\n> > While there add a description to the function.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >\n> > I'm not sure where these functions should go ideally, they don't seem\n> > to fit in any existing library file, so I created a new one for now.\n> > Any suggestions for a better home are welcome!\n> >\n> >  Makefile           |  1 +\n> >  builtin/checkout.c | 41 +----------------------------------------\n> >  checkout.c         | 43 +++++++++++++++++++++++++++++++++++++++++++\n> >  checkout.h         | 14 ++++++++++++++\n> >  4 files changed, 59 insertions(+), 40 deletions(-)\n> >  create mode 100644 checkout.c\n> >  create mode 100644 checkout.h\n> \n> I am not sure either.  I've always considered that entry.c is the\n> libified thing codepath that want to do a \"checkout\" should call,\n> but the functions that you are moving is at a \"higher layer\" that\n> does not concern the core-git data structures (i.e. the 'tracking'\n> is a mere \"user\" of the ref API, unlike things in entry.c such as\n> checkout_entry() that is a more \"maintainer\" of the index integrity),\n> so perhaps it makes sense to have new file for it.\n\nMakes sense, let me keep it as a new file then.\n\n> > diff --git a/checkout.c b/checkout.c\n> > new file mode 100644\n> > index 0000000000..a9cf378453\n> > --- /dev/null\n> > +++ b/checkout.c\n> > @@ -0,0 +1,43 @@\n> > +#include \"cache.h\"\n> > +\n> \n> A useless blank line.\n> \n> > +#include \"remote.h\"\n> > +\n> \n> This one is useful ;-)\n> \n> > +struct tracking_name_data {\n> > ...\n> > diff --git a/checkout.h b/checkout.h\n> > new file mode 100644\n> > index 0000000000..9272fe1449\n> > --- /dev/null\n> > +++ b/checkout.h\n> > @@ -0,0 +1,14 @@\n> > +#ifndef CHECKOUT_H\n> > +#define CHECKOUT_H\n> > +\n> > +#include \"git-compat-util.h\"\n> > +#include \"cache.h\"\n> \n> Try \"git grep -e git-compat-util Documentation/CodingGuidelines\" and\n> just keep inclusion of \"cache.h\".\n\nAh I forgot about that.  Will fix, thanks!\n"},{"id":"332569","messageId":"CAPig+cTYC01Y9-EvyNo9hxQRbT60iqp8MqXEB_zWBi14kPV1Ng@mail.gmail.com","threadId":"47179","inReplyTo":"20171114084517.GA12097@hank","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2017-11-14T20:14:05Z","receivedAt":"2017-11-14T20:14:12Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Nov 14, 2017 at 3:45 AM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> On 11/13, Junio C Hamano wrote:\n>> If so, as long as the new DWIM kicks in ONLY when \"topic\" does not\n>> exist, I suspect that there is no backward compatibility worries.\n>> The command line\n>>\n>>     $ git worktree add ../a-new-worktree topic\n>>\n>> would just have failed because three was no 'topic' branch yet, no?\n>\n> Indeed, with this there would not be any backwards compatility\n> worries.\n>\n> Ideally I'd still like to make\n>\n>     $ git worktree add ../topic\n>\n> work as described above, to avoid having to type 'topic' twice (the\n> directory name matches the branch name for the vast majority of my\n> worktrees) but that should then come behind a flag/config option?\n> Following your reasoning above it should probably be called something\n> other than --guess.\n>\n> Maybe --guess-remote and worktree.guessRemote would do?  I'm quite bad\n> at naming though, so other suggestions are very welcome.\n\nFor my own edification...\n\ngit worktree add ../dir branch\n\n* Checks out branch into ../dir if branch exists.\n\n* Errors out if branch does not exist. However, if we consider the\nhistory of the implementation of worktrees[*1*], then this really\nought to try the \"origin/branch -> branch\" DWIM before erroring-out.\nImplementing this DWIM could be considered a regression fix according\nto [*1*] and, as Junio points out, should not pose backward\ncompatibility worries.\n\ngit worktree add ../topic\n\n* Correctly errors out, refusing to create a new branch named \"topic\",\nif \"topic\" is already a branch.\n\n* Creates a new branch named \"topic\" if no such local branch exists.\n\nThe desired new DWIMing would change the second bullet point to:\n\n* If no local branch named \"topic\" exists, DWIM it from \"origin/topic\"\nif possible, else create a new local branch named \"topic\".\n\nBut that's a behavior change since, with the existing implementation,\na newly created local \"topic\" has no relation to, and does not track,\nany origin/topic branch. The proposed --guess option is to avoid users\nbeing hit by this backward incompatibility, however, one could also\nview the proposed DWIMing as some sort of bug fix since, at least\nsome, users would expect the DWIMing since it already takes place\nelsewhere.\n\nSo, at least two options exist:\n\n* Just make the new DWIMing the default behavior, accepting that it\nmight bite a few people. Fallout can be mitigated somewhat by\nprominently announcing that the DWIMing took place, in which case the\nuser can take corrective action (say, by choosing a different worktree\nname); nothing is lost and no damage done since this is happening only\nat worktree creation time.\n\n* Add a new option to enable DWIMing; perhaps name it -t/--track,\nwhich is familiar terminology and still gives you a relatively short\nand sweet \"git worktree add -t ../topic\".\n\nGiven the mentioned mitigation factor and that some/many users likely\nwould expect it to DWIM \"origin/topic -> topic\" anyhow, I'd lean in\nfavor of the first option (but perhaps I'm too daring with other\npeople's workflows).\n\nFOOTNOTES\n\n[*1*]: When Duy first implemented worktree support, he incorporated it\ndirectly into the git-checkout command (\"git checkout --to worktree\n...\"), which means that he got all the git-checkout features for free,\nincluding the \"origin/branch -> branch\" DWIM. When worktree support\nwas later moved to git-worktree, it lost most of the features\ninherited implicitly from git-checkout, such as -b, -B, --detach, so\nthose were added back to git-worktree explicitly. However, at that\nearly stage, git-worktree was still piggy-backing atop git-checkout,\nthus likely was still getting the \"origin/branch -> branch\" DWIM for\nfree. A final iteration converted git-worktree away from heavyweight\ngit-checkout to lightweight git-reset, at which point he DWIMing was\nlost. If you take this history into account, then loss of\n\"origin/branch -> branch\" DWIMing is a regression, so restoring it\ncould be considered a bug fix.\n"},{"id":"332570","messageId":"CAPig+cTDMvOWW2xLYfvQsOsfBuCOGDJwH_zRDQyxx1vpfkX4tA@mail.gmail.com","threadId":"47179","inReplyTo":"CAPig+cTYC01Y9-EvyNo9hxQRbT60iqp8MqXEB_zWBi14kPV1Ng@mail.gmail.com","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2017-11-14T20:29:27Z","receivedAt":"2017-11-14T20:29:34Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Nov 14, 2017 at 3:14 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> For my own edification...\n> [...]\n> git worktree add ../topic\n>\n> * Correctly errors out, refusing to create a new branch named \"topic\",\n> if \"topic\" is already a branch.\n\nBy the way, there's an additional DWIM that could be done here instead\nof erroring out. Specifically, for \"git worktree add ../topic\":\n\n* If branch \"topic\" exists, check it out (rather than refusing to\ncreate a new branch named \"topic\").\n\n* If origin/topic exists, DWIM local \"topic\" branch into existence.\n\n* Otherwise, create new local branch \"topic\".\n\n> * Creates a new branch named \"topic\" if no such local branch exists.\n>\n> The desired new DWIMing would change the second bullet point to:\n>\n> * If no local branch named \"topic\" exists, DWIM it from \"origin/topic\"\n> if possible, else create a new local branch named \"topic\".\n"},{"id":"332598","messageId":"20171115085039.GA32324@hank","threadId":"47179","inReplyTo":"CAPig+cTYC01Y9-EvyNo9hxQRbT60iqp8MqXEB_zWBi14kPV1Ng@mail.gmail.com","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-15T08:50:39Z","receivedAt":"2017-11-15T08:49:21Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/14, Eric Sunshine wrote:\n> On Tue, Nov 14, 2017 at 3:45 AM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > On 11/13, Junio C Hamano wrote:\n> >> If so, as long as the new DWIM kicks in ONLY when \"topic\" does not\n> >> exist, I suspect that there is no backward compatibility worries.\n> >> The command line\n> >>\n> >>     $ git worktree add ../a-new-worktree topic\n> >>\n> >> would just have failed because three was no 'topic' branch yet, no?\n> >\n> > Indeed, with this there would not be any backwards compatility\n> > worries.\n> >\n> > Ideally I'd still like to make\n> >\n> >     $ git worktree add ../topic\n> >\n> > work as described above, to avoid having to type 'topic' twice (the\n> > directory name matches the branch name for the vast majority of my\n> > worktrees) but that should then come behind a flag/config option?\n> > Following your reasoning above it should probably be called something\n> > other than --guess.\n> >\n> > Maybe --guess-remote and worktree.guessRemote would do?  I'm quite bad\n> > at naming though, so other suggestions are very welcome.\n> \n> For my own edification...\n> \n> git worktree add ../dir branch\n> \n> * Checks out branch into ../dir if branch exists.\n> \n> * Errors out if branch does not exist. However, if we consider the\n> history of the implementation of worktrees[*1*], then this really\n> ought to try the \"origin/branch -> branch\" DWIM before erroring-out.\n> Implementing this DWIM could be considered a regression fix according\n> to [*1*] and, as Junio points out, should not pose backward\n> compatibility worries.\n\nAgreed, I think it is not very controversial that this would be an\nimprovement.\n\n> git worktree add ../topic\n> \n> * Correctly errors out, refusing to create a new branch named \"topic\",\n> if \"topic\" is already a branch.\n> \n> * Creates a new branch named \"topic\" if no such local branch exists.\n> \n> The desired new DWIMing would change the second bullet point to:\n> \n> * If no local branch named \"topic\" exists, DWIM it from \"origin/topic\"\n> if possible, else create a new local branch named \"topic\".\n> \n> But that's a behavior change since, with the existing implementation,\n> a newly created local \"topic\" has no relation to, and does not track,\n> any origin/topic branch. The proposed --guess option is to avoid users\n> being hit by this backward incompatibility, however, one could also\n> view the proposed DWIMing as some sort of bug fix since, at least\n> some, users would expect the DWIMing since it already takes place\n> elsewhere.\n\nI'm not sure we can call it a bug fix anymore, since as Junio pointed\nout the current behaviour of creating a new branch at HEAD is\ndocumented in the man page.\n\nHowever git-worktree is also still marked as experimental in the man\npage, so we could allow ourselves to be a little bit more lax when it\ncomes to backwards compatibility, especially because it is easy to\ntake corrective action after the new DWIMing happened.\n\n> So, at least two options exist:\n> \n> * Just make the new DWIMing the default behavior, accepting that it\n> might bite a few people. Fallout can be mitigated somewhat by\n> prominently announcing that the DWIMing took place, in which case the\n> user can take corrective action (say, by choosing a different worktree\n> name); nothing is lost and no damage done since this is happening only\n> at worktree creation time.\n> \n> * Add a new option to enable DWIMing; perhaps name it -t/--track,\n> which is familiar terminology and still gives you a relatively short\n> and sweet \"git worktree add -t ../topic\".\n> \n> Given the mentioned mitigation factor and that some/many users likely\n> would expect it to DWIM \"origin/topic -> topic\" anyhow, I'd lean in\n> favor of the first option (but perhaps I'm too daring with other\n> people's workflows).\n\nYeah, I'm leaning towards the first option as well, but I'm clearly\nbiased as that's how I'd like it to behave, and others might want the\nother behaviour.  Unfortunately I don't know many worktree users, so I\ncan't tell what the general consensus on this would be.\n\nI guess the second option would be the safer one, and we can still\nswitch that to be the default at some point if we wish to do so\nlater.\n\ntl;dr I have no idea which of the options would be better :)\n\n> FOOTNOTES\n> \n> [*1*]: When Duy first implemented worktree support, he incorporated it\n> directly into the git-checkout command (\"git checkout --to worktree\n> ...\"), which means that he got all the git-checkout features for free,\n> including the \"origin/branch -> branch\" DWIM. When worktree support\n> was later moved to git-worktree, it lost most of the features\n> inherited implicitly from git-checkout, such as -b, -B, --detach, so\n> those were added back to git-worktree explicitly. However, at that\n> early stage, git-worktree was still piggy-backing atop git-checkout,\n> thus likely was still getting the \"origin/branch -> branch\" DWIM for\n> free. A final iteration converted git-worktree away from heavyweight\n> git-checkout to lightweight git-reset, at which point he DWIMing was\n> lost. If you take this history into account, then loss of\n> \"origin/branch -> branch\" DWIMing is a regression, so restoring it\n> could be considered a bug fix.\n"},{"id":"332599","messageId":"20171115085229.GB32324@hank","threadId":"47179","inReplyTo":"CAPig+cTDMvOWW2xLYfvQsOsfBuCOGDJwH_zRDQyxx1vpfkX4tA@mail.gmail.com","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-15T08:52:29Z","receivedAt":"2017-11-15T08:51:11Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/14, Eric Sunshine wrote:\n> On Tue, Nov 14, 2017 at 3:14 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > For my own edification...\n> > [...]\n> > git worktree add ../topic\n> >\n> > * Correctly errors out, refusing to create a new branch named \"topic\",\n> > if \"topic\" is already a branch.\n> \n> By the way, there's an additional DWIM that could be done here instead\n> of erroring out. Specifically, for \"git worktree add ../topic\":\n> \n> * If branch \"topic\" exists, check it out (rather than refusing to\n> create a new branch named \"topic\").\n\nI think this would be a good improvement either way as I suspect this\nis what users would hope for, and as it currently just dies there are\nless backwards compatibility worries.\n\n> * If origin/topic exists, DWIM local \"topic\" branch into existence.\n> \n> * Otherwise, create new local branch \"topic\".\n> \n> > * Creates a new branch named \"topic\" if no such local branch exists.\n> >\n> > The desired new DWIMing would change the second bullet point to:\n> >\n> > * If no local branch named \"topic\" exists, DWIM it from \"origin/topic\"\n> > if possible, else create a new local branch named \"topic\".\n"},{"id":"332600","messageId":"CAPig+cTBkWrmFQeSLhtKXpdNKs2wFDmNArqScv9nHLaBbCZjqg@mail.gmail.com","threadId":"47179","inReplyTo":"20171115085039.GA32324@hank","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2017-11-15T09:12:43Z","receivedAt":"2017-11-15T09:12:53Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Nov 15, 2017 at 3:50 AM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> On 11/14, Eric Sunshine wrote:\n>> git worktree add ../topic\n>> [...]\n>> The desired new DWIMing would change the second bullet point to:\n>>\n>> * If no local branch named \"topic\" exists, DWIM it from \"origin/topic\"\n>> if possible, else create a new local branch named \"topic\".\n>>\n>> But that's a behavior change since, with the existing implementation,\n>> a newly created local \"topic\" has no relation to, and does not track,\n>> any origin/topic branch. The proposed --guess option is to avoid users\n>> being hit by this backward incompatibility, however, one could also\n>> view the proposed DWIMing as some sort of bug fix since, at least\n>> some, users would expect the DWIMing since it already takes place\n>> elsewhere.\n>\n> I'm not sure we can call it a bug fix anymore, since as Junio pointed\n> out the current behaviour of creating a new branch at HEAD is\n> documented in the man page.\n>\n> However git-worktree is also still marked as experimental in the man\n> page, so we could allow ourselves to be a little bit more lax when it\n> comes to backwards compatibility, especially because it is easy to\n> take corrective action after the new DWIMing happened.\n\nYep, my leaning toward making this new DWIMing default (without a\n--guess or --track option) also is based in part on git-worktree still\nbeing marked \"experimental\".\n\n>> So, at least two options exist:\n>>\n>> * Just make the new DWIMing the default behavior, accepting that it\n>> might bite a few people. Fallout can be mitigated somewhat by\n>> prominently announcing that the DWIMing took place, in which case the\n>> user can take corrective action (say, by choosing a different worktree\n>> name); nothing is lost and no damage done since this is happening only\n>> at worktree creation time.\n>>\n>> * Add a new option to enable DWIMing; perhaps name it -t/--track,\n>> which is familiar terminology and still gives you a relatively short\n>> and sweet \"git worktree add -t ../topic\".\n>>\n>> Given the mentioned mitigation factor and that some/many users likely\n>> would expect it to DWIM \"origin/topic -> topic\" anyhow, I'd lean in\n>> favor of the first option (but perhaps I'm too daring with other\n>> people's workflows).\n>\n> Yeah, I'm leaning towards the first option as well, but I'm clearly\n> biased as that's how I'd like it to behave, and others might want the\n> other behaviour.  Unfortunately I don't know many worktree users, so I\n> can't tell what the general consensus on this would be.\n\nAside from the mentioned mitigation factor, which somewhat eases my\nworries about backward incompatibility, one genuine concern is\nbreaking existing scripts. At the very least, if the new DWIM becomes\ndefault, there might need to be some escape hatch for scripts to opt\nout of it.\n\n> I guess the second option would be the safer one, and we can still\n> switch that to be the default at some point if we wish to do so\n> later.\n\nThe longer you wait, the less likely you'll have the chance since\ngit-worktree will (presumably) gain more users and be used in more\nscripts as time passes. So, if the new DWIMing is to become the\ndefault, better to do so earlier rather than later.\n\n> tl;dr I have no idea which of the options would be better :)\n\nI'm probably too cavalier and shortsighted (at least on this topic) to\nmake a well-informed decision about it. Junio probably has a better\nfeeling about whether such a change of behavior makes sense at this\nlate date, and, of course, it's his decision whether to accept such a\nchange into his tree.\n"},{"id":"332814","messageId":"20171118181103.28354-1-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171112134305.3949-1-t.gummerer@gmail.com","subject":"[PATCH v2 1/3] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T18:11:01Z","receivedAt":"2017-11-18T18:09:54Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor the functions out, so they can be re-used from other places.  In\nparticular these functions will be re-used in builtin/worktree.c to make\ngit worktree add dwim more.\n\nWhile there add some docs to the function.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\nThe previous round of this series is at\nhttps://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/.\nThanks Junio and Eric for the comments on the previous round!\n\n Makefile           |  1 +\n builtin/checkout.c | 41 +----------------------------------------\n checkout.c         | 42 ++++++++++++++++++++++++++++++++++++++++++\n checkout.h         | 13 +++++++++++++\n 4 files changed, 57 insertions(+), 40 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\ndiff --git a/Makefile b/Makefile\nindex cd75985991..8d603c7443 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,6 +757,7 @@ LIB_OBJS += branch.o\n LIB_OBJS += bulk-checkin.o\n LIB_OBJS += bundle.o\n LIB_OBJS += cache-tree.o\n+LIB_OBJS += checkout.o\n LIB_OBJS += color.o\n LIB_OBJS += column.o\n LIB_OBJS += combine-diff.o\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex fc4f8fd2ea..9e1cfd10b3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"config.h\"\n+#include \"checkout.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n@@ -874,46 +875,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)\n \treturn git_xmerge_config(var, value, NULL);\n }\n \n-struct tracking_name_data {\n-\t/* const */ char *src_ref;\n-\tchar *dst_ref;\n-\tstruct object_id *dst_oid;\n-\tint unique;\n-};\n-\n-static int check_tracking_name(struct remote *remote, void *cb_data)\n-{\n-\tstruct tracking_name_data *cb = cb_data;\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_oid(query.dst, cb->dst_oid)) {\n-\t\tfree(query.dst);\n-\t\treturn 0;\n-\t}\n-\tif (cb->dst_ref) {\n-\t\tfree(query.dst);\n-\t\tcb->unique = 0;\n-\t\treturn 0;\n-\t}\n-\tcb->dst_ref = query.dst;\n-\treturn 0;\n-}\n-\n-static const char *unique_tracking_name(const char *name, struct object_id *oid)\n-{\n-\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n-\tcb_data.src_ref = xstrfmt(\"refs/heads/%s\", name);\n-\tcb_data.dst_oid = oid;\n-\tfor_each_remote(check_tracking_name, &cb_data);\n-\tfree(cb_data.src_ref);\n-\tif (cb_data.unique)\n-\t\treturn cb_data.dst_ref;\n-\tfree(cb_data.dst_ref);\n-\treturn NULL;\n-}\n-\n static int parse_branchname_arg(int argc, const char **argv,\n \t\t\t\tint dwim_new_local_branch_ok,\n \t\t\t\tstruct branch_info *new,\ndiff --git a/checkout.c b/checkout.c\nnew file mode 100644\nindex 0000000000..b0c744d37a\n--- /dev/null\n+++ b/checkout.c\n@@ -0,0 +1,42 @@\n+#include \"cache.h\"\n+#include \"remote.h\"\n+\n+struct tracking_name_data {\n+\t/* const */ char *src_ref;\n+\tchar *dst_ref;\n+\tstruct object_id *dst_oid;\n+\tint unique;\n+};\n+\n+static int check_tracking_name(struct remote *remote, void *cb_data)\n+{\n+\tstruct tracking_name_data *cb = cb_data;\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_oid(query.dst, cb->dst_oid)) {\n+\t\tfree(query.dst);\n+\t\treturn 0;\n+\t}\n+\tif (cb->dst_ref) {\n+\t\tfree(query.dst);\n+\t\tcb->unique = 0;\n+\t\treturn 0;\n+\t}\n+\tcb->dst_ref = query.dst;\n+\treturn 0;\n+}\n+\n+const char *unique_tracking_name(const char *name, struct object_id *oid)\n+{\n+\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n+\tcb_data.src_ref = xstrfmt(\"refs/heads/%s\", name);\n+\tcb_data.dst_oid = oid;\n+\tfor_each_remote(check_tracking_name, &cb_data);\n+\tfree(cb_data.src_ref);\n+\tif (cb_data.unique)\n+\t\treturn cb_data.dst_ref;\n+\tfree(cb_data.dst_ref);\n+\treturn NULL;\n+}\ndiff --git a/checkout.h b/checkout.h\nnew file mode 100644\nindex 0000000000..9980711179\n--- /dev/null\n+++ b/checkout.h\n@@ -0,0 +1,13 @@\n+#ifndef CHECKOUT_H\n+#define CHECKOUT_H\n+\n+#include \"cache.h\"\n+\n+/*\n+ * Check if the branch name uniquely matches a branch name on a remote\n+ * tracking branch.  Return the name of the remote if such a branch\n+ * exists, NULL otherwise.\n+ */\n+extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n+\n+#endif /* CHECKOUT_H */\n-- \n2.15.0.345.gf926f18f3d\n\n"},{"id":"332815","messageId":"20171118181103.28354-2-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171118181103.28354-1-t.gummerer@gmail.com","subject":"[PATCH v2 2/3] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T18:11:02Z","receivedAt":"2017-11-18T18:09:56Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add <path> <branch>', errors out when 'branch'\nis not a local branch.   It has no additional dwim'ing features that one\nmight expect.\n\nMake it behave more like 'git checkout <branch>' when the branch doesn't\nexist locally, but a remote tracking branch uniquely matches the desired\nbranch name, i.e. create a new branch from the remote tracking branch\nand set the upstream to the remote tracking branch.\n\nAs 'git worktree add' currently just dies in this situation, there are\nno backwards compatibility worries when introducing this feature.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  7 +++++++\n builtin/worktree.c             | 15 ++++++++++++++\n t/t2025-worktree-add.sh        | 44 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 66 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex b472acc356..3c7c8c3cee 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -52,6 +52,13 @@ is linked to the current repository, sharing everything except working\n directory specific files such as HEAD, index, etc. `-` may also be\n specified as `<branch>`; it is synonymous with `@{-1}`.\n +\n+If <branch> is not found but there does exist a tracking branch in\n+exactly one remote (call it <remote>) with a matching name, treat as\n+equivalent to\n+------------\n+$ git worktree add -b <branch> <path> <remote>/<branch>\n+------------\n++\n If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n then, as a convenience, a new branch based at HEAD is created automatically,\n as if `-b $(basename <path>)` was specified.\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 7b9307aa58..92b583ae39 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"checkout.h\"\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"dir.h\"\n@@ -386,6 +387,20 @@ static int add(int ac, const char **av, const char *prefix)\n \t\topts.new_branch = xstrndup(s, n);\n \t}\n \n+\tif (ac == 2) {\n+\t\tstruct object_id oid;\n+\t\tstruct commit *commit;\n+\t\tconst char *remote;\n+\n+\t\tcommit = lookup_commit_reference_by_name(branch);\n+\t\tif (!commit)\n+\t\t\tremote = unique_tracking_name(branch, &oid);\n+\t\tif (!commit && remote) {\n+\t\t\topts.new_branch = branch;\n+\t\t\tbranch = remote;\n+\t\t}\n+\t}\n+\n \tif (opts.new_branch) {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n \t\tcp.git_cmd = 1;\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex b5c47ac602..e5959800c0 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -6,6 +6,16 @@ test_description='test git worktree add'\n \n . \"$TEST_DIRECTORY\"/lib-rebase.sh\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 \ttest_commit init\n '\n@@ -314,4 +324,38 @@ test_expect_success 'rename a branch under bisect not allowed' '\n \ttest_must_fail git branch -M under-bisect bisect-with-new-name\n '\n \n+test_expect_success '\"add\" <path> <non-existent-branch> fails' '\n+\ttest_must_fail git worktree add foo non-existent\n+'\n+\n+test_expect_success '\"add\" <path> <branch> dwims' '\n+\ttest_when_finished rm -rf repo_upstream &&\n+\ttest_when_finished rm -rf repo_dwim &&\n+\ttest_when_finished rm -rf foo &&\n+\tgit init repo_upstream &&\n+\t(\n+\t\tcd repo_upstream &&\n+\t\ttest_commit upstream_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit a_foo\n+\t) &&\n+\tgit init repo_dwim &&\n+\t(\n+\t\tcd repo_dwim &&\n+\t\ttest_commit dwim_master &&\n+\t\tgit remote add repo_upstream ../repo_upstream &&\n+\t\tgit config remote.repo_upstream.fetch \\\n+\t\t\t  \"refs/heads/*:refs/remotes/repo_upstream/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add ../foo foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_upstream foo &&\n+\t\tgit rev-parse repo_upstream/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.345.gf926f18f3d\n\n"},{"id":"332816","messageId":"20171118181103.28354-3-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171118181103.28354-1-t.gummerer@gmail.com","subject":"[PATCH v2 3/3] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T18:11:03Z","receivedAt":"2017-11-18T18:09:58Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add <path>' creates a new branch named after the\nbasename of the <path>, that matches the HEAD of whichever worktree we\nwere on when calling \"git worktree add <path>\".\n\nMake 'git worktree add <path> behave more like the dwim machinery in\n'git checkout <new-branch>', i.e. check if the new branch name uniquely\nmatches the branch name of a remote tracking branch, and if so check out\nthat branch and set the upstream to the remote tracking branch.\n\nThis is a change of behaviour compared to the current behaviour, where\nwe create a new branch matching HEAD.  However as 'git worktree' is\nstill an experimental feature, and it's easy to notice/correct the\nbehaviour in case it's not what the user desired it's probably okay to\nbreak existing behaviour here.\n\nIn order to also satisfy users who want the current behaviour of\ncreating a new branch from HEAD, add a '--no-track' flag, which disables\nthe new behaviour, and keeps the old behaviour of creating a new branch\nfrom the head of the current worktree.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\nI went back and forth between hiding this behing a flag, and making it\ndefault and having a flag for getting the old behaviour back.\n\nIn the end I went for making the new behaviour the default, because\nthe 'worktree' feature is still experimental, and it's easy to correct\nthe behaviour if it's not what was desired.  I also think this is the\nmore intuitve behaviour, but clearly I'm biased because *I* want to it\nto behave this way.\n\nI'm happy to keep the old behaviour the default and hide the new\nbehaviour behind a flag if we feel this is too much of a change in\nbehaviour at this point.\n\n Documentation/git-worktree.txt | 15 ++++++++---\n builtin/worktree.c             |  9 +++++++\n t/t2025-worktree-add.sh        | 60 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 81 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 3c7c8c3cee..11cac104d9 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -60,9 +60,18 @@ $ git worktree add -b <branch> <path> <remote>/<branch>\n ------------\n +\n If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n-then, as a convenience, a new branch based at HEAD is created automatically,\n-as if `-b $(basename <path>)` was specified.\n-\n+then, as a convenience, if there exists a tracking branch in exactly\n+one remote (call it <remote>) matching the basename of the path\n+(call it <branch>), treat it as equivalent to\n+------------\n+$ git worktree add -b <branch> <path> <remote>/<branch>\n+------------\n+If no tracking branch exists in exactly one remote, <branch> is\n+created based on HEAD, as if `-b $(basename <path>)` was specified.\n++\n+To disable the behaviour of trying to match the basename of <path> to\n+a remote, and always create a new branch from HEAD, the `--no-track`\n+flag can be passed to `git worktree add`.\n list::\n \n List details of each worktree.  The main worktree is listed first, followed by\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 92b583ae39..82088415b8 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -342,6 +342,7 @@ static int add(int ac, const char **av, const char *prefix)\n \tconst char *new_branch_force = NULL;\n \tchar *path;\n \tconst char *branch;\n+\tint track_dwim = 1;\n \tstruct option options[] = {\n \t\tOPT__FORCE(&opts.force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n \t\tOPT_STRING('b', NULL, &opts.new_branch, N_(\"branch\"),\n@@ -351,6 +352,7 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_BOOL(0, \"detach\", &opts.detach, N_(\"detach HEAD at named commit\")),\n \t\tOPT_BOOL(0, \"checkout\", &opts.checkout, N_(\"populate the new working tree\")),\n \t\tOPT_BOOL(0, \"lock\", &opts.keep_locked, N_(\"keep the new working tree locked\")),\n+\t\tOPT_BOOL(0, \"track\", &track_dwim, N_(\"checkout upstream branch if there's a unique match\")),\n \t\tOPT_END()\n \t};\n \n@@ -385,6 +387,13 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tint n;\n \t\tconst char *s = worktree_basename(path, &n);\n \t\topts.new_branch = xstrndup(s, n);\n+\t\tif (track_dwim) {\n+\t\t\tstruct object_id oid;\n+\t\t\tconst char *remote =\n+\t\t\t\tunique_tracking_name(opts.new_branch, &oid);\n+\t\t\tif (remote)\n+\t\t\t\tbranch = remote;\n+\t\t}\n \t}\n \n \tif (ac == 2) {\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex e5959800c0..a566d867fe 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -358,4 +358,64 @@ test_expect_success '\"add\" <path> <branch> dwims' '\n \t)\n '\n \n+test_expect_success 'git worktree add --no-track does not set up tracking' '\n+\ttest_when_finished rm -rf repo_a &&\n+\ttest_when_finished rm -rf repo_b &&\n+\ttest_when_finished rm -rf foo &&\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) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit remote add repo_a ../repo_a &&\n+\t\tgit config remote.repo_a.fetch \\\n+\t\t\t\"+refs/heads/*:refs/remotes/other_a/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add --no-track ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\t! test_branch_upstream foo repo_a foo &&\n+\t\tgit rev-parse other_a/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\t! test_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'git worktree add sets up tracking' '\n+\ttest_when_finished rm -rf repo_a &&\n+\ttest_when_finished rm -rf repo_b &&\n+\ttest_when_finished rm -rf foo &&\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) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit remote add repo_a ../repo_a &&\n+\t\tgit config remote.repo_a.fetch \\\n+\t\t\t\"+refs/heads/*:refs/remotes/other_a/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_a foo &&\n+\t\tgit rev-parse other_a/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.345.gf926f18f3d\n\n"},{"id":"332819","messageId":"20171118181345.GC32324@hank","threadId":"47179","inReplyTo":"20171115085229.GB32324@hank","subject":"Re: [PATCH v1 2/2] worktree: make add dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T18:13:45Z","receivedAt":"2017-11-18T18:12:23Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/15, Thomas Gummerer wrote:\n> On 11/14, Eric Sunshine wrote:\n> > On Tue, Nov 14, 2017 at 3:14 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > > For my own edification...\n> > > [...]\n> > > git worktree add ../topic\n> > >\n> > > * Correctly errors out, refusing to create a new branch named \"topic\",\n> > > if \"topic\" is already a branch.\n> > \n> > By the way, there's an additional DWIM that could be done here instead\n> > of erroring out. Specifically, for \"git worktree add ../topic\":\n> > \n> > * If branch \"topic\" exists, check it out (rather than refusing to\n> > create a new branch named \"topic\").\n> \n> I think this would be a good improvement either way as I suspect this\n> is what users would hope for, and as it currently just dies there are\n> less backwards compatibility worries.\n\nWhile I still think this would be an improvement, after thinking about\nit a bit more I think this is somewhat orthogonal to what I'm trying\nto achieve with this patch series.  Therefore I didn't implement this\nyet, but I'm still thinking of implementing this in a separate topic.\n\n> > * If origin/topic exists, DWIM local \"topic\" branch into existence.\n> > \n> > * Otherwise, create new local branch \"topic\".\n> > \n> > > * Creates a new branch named \"topic\" if no such local branch exists.\n> > >\n> > > The desired new DWIMing would change the second bullet point to:\n> > >\n> > > * If no local branch named \"topic\" exists, DWIM it from \"origin/topic\"\n> > > if possible, else create a new local branch named \"topic\".\n"},{"id":"332825","messageId":"20171118221830.GD32324@hank","threadId":"47179","inReplyTo":"20171118181103.28354-2-t.gummerer@gmail.com","subject":"Re: [PATCH v2 2/3] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T22:18:30Z","receivedAt":"2017-11-18T22:17:10Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/18, Thomas Gummerer wrote:\n> Currently 'git worktree add <path> <branch>', errors out when 'branch'\n> is not a local branch.   It has no additional dwim'ing features that one\n> might expect.\n> \n> Make it behave more like 'git checkout <branch>' when the branch doesn't\n> exist locally, but a remote tracking branch uniquely matches the desired\n> branch name, i.e. create a new branch from the remote tracking branch\n> and set the upstream to the remote tracking branch.\n> \n> As 'git worktree add' currently just dies in this situation, there are\n> no backwards compatibility worries when introducing this feature.\n> \n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  Documentation/git-worktree.txt |  7 +++++++\n>  builtin/worktree.c             | 15 ++++++++++++++\n>  t/t2025-worktree-add.sh        | 44 ++++++++++++++++++++++++++++++++++++++++++\n>  3 files changed, 66 insertions(+)\n> \n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> index b472acc356..3c7c8c3cee 100644\n> --- a/Documentation/git-worktree.txt\n> +++ b/Documentation/git-worktree.txt\n> @@ -52,6 +52,13 @@ is linked to the current repository, sharing everything except working\n>  directory specific files such as HEAD, index, etc. `-` may also be\n>  specified as `<branch>`; it is synonymous with `@{-1}`.\n>  +\n> +If <branch> is not found but there does exist a tracking branch in\n> +exactly one remote (call it <remote>) with a matching name, treat as\n> +equivalent to\n> +------------\n> +$ git worktree add -b <branch> <path> <remote>/<branch>\n> +------------\n> ++\n>  If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n>  then, as a convenience, a new branch based at HEAD is created automatically,\n>  as if `-b $(basename <path>)` was specified.\n> diff --git a/builtin/worktree.c b/builtin/worktree.c\n> index 7b9307aa58..92b583ae39 100644\n> --- a/builtin/worktree.c\n> +++ b/builtin/worktree.c\n> @@ -1,4 +1,5 @@\n>  #include \"cache.h\"\n> +#include \"checkout.h\"\n>  #include \"config.h\"\n>  #include \"builtin.h\"\n>  #include \"dir.h\"\n> @@ -386,6 +387,20 @@ static int add(int ac, const char **av, const char *prefix)\n>  \t\topts.new_branch = xstrndup(s, n);\n>  \t}\n>  \n> +\tif (ac == 2) {\n\nErr I just realized this doesn't quite make sense.  Similar to the\ndwim for 'git worktree add <path>', this condition should include\n'!opts.new_branch && !opts.detach'.  In these cases it's still better\nto error out, as the user explicitly asked for a new branch with a\ndifferent name/asked not to be put onto a branch.  I'll send a v3 with\nthis fixed in a bit.\n\n> +\t\tstruct object_id oid;\n> +\t\tstruct commit *commit;\n> +\t\tconst char *remote;\n> +\n> +\t\tcommit = lookup_commit_reference_by_name(branch);\n> +\t\tif (!commit)\n> +\t\t\tremote = unique_tracking_name(branch, &oid);\n> +\t\tif (!commit && remote) {\n> +\t\t\topts.new_branch = branch;\n> +\t\t\tbranch = remote;\n> +\t\t}\n> +\t}\n> +\n>  \tif (opts.new_branch) {\n>  \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \t\tcp.git_cmd = 1;\n> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> index b5c47ac602..e5959800c0 100755\n> --- a/t/t2025-worktree-add.sh\n> +++ b/t/t2025-worktree-add.sh\n> @@ -6,6 +6,16 @@ test_description='test git worktree add'\n>  \n>  . \"$TEST_DIRECTORY\"/lib-rebase.sh\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>  \ttest_commit init\n>  '\n> @@ -314,4 +324,38 @@ test_expect_success 'rename a branch under bisect not allowed' '\n>  \ttest_must_fail git branch -M under-bisect bisect-with-new-name\n>  '\n>  \n> +test_expect_success '\"add\" <path> <non-existent-branch> fails' '\n> +\ttest_must_fail git worktree add foo non-existent\n> +'\n> +\n> +test_expect_success '\"add\" <path> <branch> dwims' '\n> +\ttest_when_finished rm -rf repo_upstream &&\n> +\ttest_when_finished rm -rf repo_dwim &&\n> +\ttest_when_finished rm -rf foo &&\n> +\tgit init repo_upstream &&\n> +\t(\n> +\t\tcd repo_upstream &&\n> +\t\ttest_commit upstream_master &&\n> +\t\tgit checkout -b foo &&\n> +\t\ttest_commit a_foo\n> +\t) &&\n> +\tgit init repo_dwim &&\n> +\t(\n> +\t\tcd repo_dwim &&\n> +\t\ttest_commit dwim_master &&\n> +\t\tgit remote add repo_upstream ../repo_upstream &&\n> +\t\tgit config remote.repo_upstream.fetch \\\n> +\t\t\t  \"refs/heads/*:refs/remotes/repo_upstream/*\" &&\n> +\t\tgit fetch --all &&\n> +\t\tgit worktree add ../foo foo\n> +\t) &&\n> +\t(\n> +\t\tcd foo &&\n> +\t\ttest_branch_upstream foo repo_upstream foo &&\n> +\t\tgit rev-parse repo_upstream/foo >expect &&\n> +\t\tgit rev-parse foo >actual &&\n> +\t\ttest_cmp expect actual\n> +\t)\n> +'\n> +\n>  test_done\n> -- \n> 2.15.0.345.gf926f18f3d\n> \n"},{"id":"332828","messageId":"20171118224706.13810-1-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171118181103.28354-1-t.gummerer@gmail.com","subject":"[PATCH v3 0/3] make git worktree add dwim more","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T22:47:03Z","receivedAt":"2017-11-18T22:45:53Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Sorry about the noise with v2 and v3 so quickly one after another.  I\nonly too late realized that the new dwim for 'add <path> <branch>'\ndoesn't make much sense if -b or --detach are given, and it's better\nto keep on erroring out in these cases.\n\nThe previous rounds were at https://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/\nand https://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/.\n\nIn case anybody already started reading v2, an interdiff between the\ntwo versions is below:\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 11cac104d9..eedead2c4c 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -52,9 +52,9 @@ is linked to the current repository, sharing everything except working\n directory specific files such as HEAD, index, etc. `-` may also be\n specified as `<branch>`; it is synonymous with `@{-1}`.\n +\n-If <branch> is not found but there does exist a tracking branch in\n-exactly one remote (call it <remote>) with a matching name, treat as\n-equivalent to\n+If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are\n+used, but there does exist a tracking branch in exactly one remote\n+(call it <remote>) with a matching name, treat as equivalent to\n ------------\n $ git worktree add -b <branch> <path> <remote>/<branch>\n ------------\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 82088415b8..b2a6dd020c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -396,7 +396,7 @@ static int add(int ac, const char **av, const char *prefix)\n \t\t}\n \t}\n \n-\tif (ac == 2) {\n+\tif (ac == 2 && !opts.new_branch && !opts.detach) {\n \t\tstruct object_id oid;\n \t\tstruct commit *commit;\n \t\tconst char *remote;\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex a566d867fe..87e233f812 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -347,6 +347,8 @@ test_expect_success '\"add\" <path> <branch> dwims' '\n \t\tgit config remote.repo_upstream.fetch \\\n \t\t\t  \"refs/heads/*:refs/remotes/repo_upstream/*\" &&\n \t\tgit fetch --all &&\n+\t\ttest_must_fail git worktree add -b foo ../foo foo &&\n+\t\ttest_must_fail git worktree add --detach ../foo foo &&\n \t\tgit worktree add ../foo foo\n \t) &&\n \t(\n\nThomas Gummerer (3):\n  checkout: factor out functions to new lib file\n  worktree: make add <path> <branch> dwim\n  worktree: make add <path> dwim\n\n Documentation/git-worktree.txt |  22 +++++++--\n Makefile                       |   1 +\n builtin/checkout.c             |  41 +---------------\n builtin/worktree.c             |  24 ++++++++++\n checkout.c                     |  42 ++++++++++++++++\n checkout.h                     |  13 +++++\n t/t2025-worktree-add.sh        | 106 +++++++++++++++++++++++++++++++++++++++++\n 7 files changed, 206 insertions(+), 43 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\n-- \n2.15.0.345.gf926f18f3\n"},{"id":"332829","messageId":"20171118224706.13810-3-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171118224706.13810-1-t.gummerer@gmail.com","subject":"[PATCH v3 2/3] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T22:47:05Z","receivedAt":"2017-11-18T22:45:55Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add <path> <branch>', errors out when 'branch'\nis not a local branch.   It has no additional dwim'ing features that one\nmight expect.\n\nMake it behave more like 'git checkout <branch>' when the branch doesn't\nexist locally, but a remote tracking branch uniquely matches the desired\nbranch name, i.e. create a new branch from the remote tracking branch\nand set the upstream to the remote tracking branch.\n\nAs 'git worktree add' currently just dies in this situation, there are\nno backwards compatibility worries when introducing this feature.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  7 +++++++\n builtin/worktree.c             | 15 ++++++++++++++\n t/t2025-worktree-add.sh        | 46 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 68 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex b472acc356..abf48fecb8 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -52,6 +52,13 @@ is linked to the current repository, sharing everything except working\n directory specific files such as HEAD, index, etc. `-` may also be\n specified as `<branch>`; it is synonymous with `@{-1}`.\n +\n+If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are\n+used, but there does exist a tracking branch in exactly one remote\n+(call it <remote>) with a matching name, treat as equivalent to\n+------------\n+$ git worktree add -b <branch> <path> <remote>/<branch>\n+------------\n++\n If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n then, as a convenience, a new branch based at HEAD is created automatically,\n as if `-b $(basename <path>)` was specified.\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 7b9307aa58..05fc902bcc 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"checkout.h\"\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"dir.h\"\n@@ -386,6 +387,20 @@ static int add(int ac, const char **av, const char *prefix)\n \t\topts.new_branch = xstrndup(s, n);\n \t}\n \n+\tif (ac == 2 && !opts.new_branch && !opts.detach) {\n+\t\tstruct object_id oid;\n+\t\tstruct commit *commit;\n+\t\tconst char *remote;\n+\n+\t\tcommit = lookup_commit_reference_by_name(branch);\n+\t\tif (!commit)\n+\t\t\tremote = unique_tracking_name(branch, &oid);\n+\t\tif (!commit && remote) {\n+\t\t\topts.new_branch = branch;\n+\t\t\tbranch = remote;\n+\t\t}\n+\t}\n+\n \tif (opts.new_branch) {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n \t\tcp.git_cmd = 1;\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex b5c47ac602..e3fc60dd1c 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -6,6 +6,16 @@ test_description='test git worktree add'\n \n . \"$TEST_DIRECTORY\"/lib-rebase.sh\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 \ttest_commit init\n '\n@@ -314,4 +324,40 @@ test_expect_success 'rename a branch under bisect not allowed' '\n \ttest_must_fail git branch -M under-bisect bisect-with-new-name\n '\n \n+test_expect_success '\"add\" <path> <non-existent-branch> fails' '\n+\ttest_must_fail git worktree add foo non-existent\n+'\n+\n+test_expect_success '\"add\" <path> <branch> dwims' '\n+\ttest_when_finished rm -rf repo_upstream &&\n+\ttest_when_finished rm -rf repo_dwim &&\n+\ttest_when_finished rm -rf foo &&\n+\tgit init repo_upstream &&\n+\t(\n+\t\tcd repo_upstream &&\n+\t\ttest_commit upstream_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit a_foo\n+\t) &&\n+\tgit init repo_dwim &&\n+\t(\n+\t\tcd repo_dwim &&\n+\t\ttest_commit dwim_master &&\n+\t\tgit remote add repo_upstream ../repo_upstream &&\n+\t\tgit config remote.repo_upstream.fetch \\\n+\t\t\t  \"refs/heads/*:refs/remotes/repo_upstream/*\" &&\n+\t\tgit fetch --all &&\n+\t\ttest_must_fail git worktree add -b foo ../foo foo &&\n+\t\ttest_must_fail git worktree add --detach ../foo foo &&\n+\t\tgit worktree add ../foo foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_upstream foo &&\n+\t\tgit rev-parse repo_upstream/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.345.gf926f18f3\n\n"},{"id":"332830","messageId":"20171118224706.13810-2-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171118224706.13810-1-t.gummerer@gmail.com","subject":"[PATCH v3 1/3] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T22:47:04Z","receivedAt":"2017-11-18T22:45:56Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor the functions out, so they can be re-used from other places.  In\nparticular these functions will be re-used in builtin/worktree.c to make\ngit worktree add dwim more.\n\nWhile there add some docs to the function.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Makefile           |  1 +\n builtin/checkout.c | 41 +----------------------------------------\n checkout.c         | 42 ++++++++++++++++++++++++++++++++++++++++++\n checkout.h         | 13 +++++++++++++\n 4 files changed, 57 insertions(+), 40 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\ndiff --git a/Makefile b/Makefile\nindex cd75985991..8d603c7443 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,6 +757,7 @@ LIB_OBJS += branch.o\n LIB_OBJS += bulk-checkin.o\n LIB_OBJS += bundle.o\n LIB_OBJS += cache-tree.o\n+LIB_OBJS += checkout.o\n LIB_OBJS += color.o\n LIB_OBJS += column.o\n LIB_OBJS += combine-diff.o\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex fc4f8fd2ea..9e1cfd10b3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1,5 +1,6 @@\n #include \"builtin.h\"\n #include \"config.h\"\n+#include \"checkout.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n@@ -874,46 +875,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)\n \treturn git_xmerge_config(var, value, NULL);\n }\n \n-struct tracking_name_data {\n-\t/* const */ char *src_ref;\n-\tchar *dst_ref;\n-\tstruct object_id *dst_oid;\n-\tint unique;\n-};\n-\n-static int check_tracking_name(struct remote *remote, void *cb_data)\n-{\n-\tstruct tracking_name_data *cb = cb_data;\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_oid(query.dst, cb->dst_oid)) {\n-\t\tfree(query.dst);\n-\t\treturn 0;\n-\t}\n-\tif (cb->dst_ref) {\n-\t\tfree(query.dst);\n-\t\tcb->unique = 0;\n-\t\treturn 0;\n-\t}\n-\tcb->dst_ref = query.dst;\n-\treturn 0;\n-}\n-\n-static const char *unique_tracking_name(const char *name, struct object_id *oid)\n-{\n-\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n-\tcb_data.src_ref = xstrfmt(\"refs/heads/%s\", name);\n-\tcb_data.dst_oid = oid;\n-\tfor_each_remote(check_tracking_name, &cb_data);\n-\tfree(cb_data.src_ref);\n-\tif (cb_data.unique)\n-\t\treturn cb_data.dst_ref;\n-\tfree(cb_data.dst_ref);\n-\treturn NULL;\n-}\n-\n static int parse_branchname_arg(int argc, const char **argv,\n \t\t\t\tint dwim_new_local_branch_ok,\n \t\t\t\tstruct branch_info *new,\ndiff --git a/checkout.c b/checkout.c\nnew file mode 100644\nindex 0000000000..b0c744d37a\n--- /dev/null\n+++ b/checkout.c\n@@ -0,0 +1,42 @@\n+#include \"cache.h\"\n+#include \"remote.h\"\n+\n+struct tracking_name_data {\n+\t/* const */ char *src_ref;\n+\tchar *dst_ref;\n+\tstruct object_id *dst_oid;\n+\tint unique;\n+};\n+\n+static int check_tracking_name(struct remote *remote, void *cb_data)\n+{\n+\tstruct tracking_name_data *cb = cb_data;\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_oid(query.dst, cb->dst_oid)) {\n+\t\tfree(query.dst);\n+\t\treturn 0;\n+\t}\n+\tif (cb->dst_ref) {\n+\t\tfree(query.dst);\n+\t\tcb->unique = 0;\n+\t\treturn 0;\n+\t}\n+\tcb->dst_ref = query.dst;\n+\treturn 0;\n+}\n+\n+const char *unique_tracking_name(const char *name, struct object_id *oid)\n+{\n+\tstruct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };\n+\tcb_data.src_ref = xstrfmt(\"refs/heads/%s\", name);\n+\tcb_data.dst_oid = oid;\n+\tfor_each_remote(check_tracking_name, &cb_data);\n+\tfree(cb_data.src_ref);\n+\tif (cb_data.unique)\n+\t\treturn cb_data.dst_ref;\n+\tfree(cb_data.dst_ref);\n+\treturn NULL;\n+}\ndiff --git a/checkout.h b/checkout.h\nnew file mode 100644\nindex 0000000000..9980711179\n--- /dev/null\n+++ b/checkout.h\n@@ -0,0 +1,13 @@\n+#ifndef CHECKOUT_H\n+#define CHECKOUT_H\n+\n+#include \"cache.h\"\n+\n+/*\n+ * Check if the branch name uniquely matches a branch name on a remote\n+ * tracking branch.  Return the name of the remote if such a branch\n+ * exists, NULL otherwise.\n+ */\n+extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n+\n+#endif /* CHECKOUT_H */\n-- \n2.15.0.345.gf926f18f3\n\n"},{"id":"332831","messageId":"20171118224706.13810-4-t.gummerer@gmail.com","threadId":"47179","inReplyTo":"20171118224706.13810-1-t.gummerer@gmail.com","subject":"[PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-18T22:47:06Z","receivedAt":"2017-11-18T22:45:58Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add <path>' creates a new branch named after the\nbasename of the <path>, that matches the HEAD of whichever worktree we\nwere on when calling \"git worktree add <path>\".\n\nMake 'git worktree add <path> behave more like the dwim machinery in\n'git checkout <new-branch>', i.e. check if the new branch name uniquely\nmatches the branch name of a remote tracking branch, and if so check out\nthat branch and set the upstream to the remote tracking branch.\n\nThis is a change of behaviour compared to the current behaviour, where\nwe create a new branch matching HEAD.  However as 'git worktree' is\nstill an experimental feature, and it's easy to notice/correct the\nbehaviour in case it's not what the user desired it's probably okay to\nbreak existing behaviour here.\n\nIn order to also satisfy users who want the current behaviour of\ncreating a new branch from HEAD, add a '--no-track' flag, which disables\nthe new behaviour, and keeps the old behaviour of creating a new branch\nfrom the head of the current worktree.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt | 15 ++++++++---\n builtin/worktree.c             |  9 +++++++\n t/t2025-worktree-add.sh        | 60 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 81 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex abf48fecb8..eedead2c4c 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -60,9 +60,18 @@ $ git worktree add -b <branch> <path> <remote>/<branch>\n ------------\n +\n If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n-then, as a convenience, a new branch based at HEAD is created automatically,\n-as if `-b $(basename <path>)` was specified.\n-\n+then, as a convenience, if there exists a tracking branch in exactly\n+one remote (call it <remote>) matching the basename of the path\n+(call it <branch>), treat it as equivalent to\n+------------\n+$ git worktree add -b <branch> <path> <remote>/<branch>\n+------------\n+If no tracking branch exists in exactly one remote, <branch> is\n+created based on HEAD, as if `-b $(basename <path>)` was specified.\n++\n+To disable the behaviour of trying to match the basename of <path> to\n+a remote, and always create a new branch from HEAD, the `--no-track`\n+flag can be passed to `git worktree add`.\n list::\n \n List details of each worktree.  The main worktree is listed first, followed by\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 05fc902bcc..b2a6dd020c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -342,6 +342,7 @@ static int add(int ac, const char **av, const char *prefix)\n \tconst char *new_branch_force = NULL;\n \tchar *path;\n \tconst char *branch;\n+\tint track_dwim = 1;\n \tstruct option options[] = {\n \t\tOPT__FORCE(&opts.force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n \t\tOPT_STRING('b', NULL, &opts.new_branch, N_(\"branch\"),\n@@ -351,6 +352,7 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_BOOL(0, \"detach\", &opts.detach, N_(\"detach HEAD at named commit\")),\n \t\tOPT_BOOL(0, \"checkout\", &opts.checkout, N_(\"populate the new working tree\")),\n \t\tOPT_BOOL(0, \"lock\", &opts.keep_locked, N_(\"keep the new working tree locked\")),\n+\t\tOPT_BOOL(0, \"track\", &track_dwim, N_(\"checkout upstream branch if there's a unique match\")),\n \t\tOPT_END()\n \t};\n \n@@ -385,6 +387,13 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tint n;\n \t\tconst char *s = worktree_basename(path, &n);\n \t\topts.new_branch = xstrndup(s, n);\n+\t\tif (track_dwim) {\n+\t\t\tstruct object_id oid;\n+\t\t\tconst char *remote =\n+\t\t\t\tunique_tracking_name(opts.new_branch, &oid);\n+\t\t\tif (remote)\n+\t\t\t\tbranch = remote;\n+\t\t}\n \t}\n \n \tif (ac == 2 && !opts.new_branch && !opts.detach) {\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex e3fc60dd1c..87e233f812 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -360,4 +360,64 @@ test_expect_success '\"add\" <path> <branch> dwims' '\n \t)\n '\n \n+test_expect_success 'git worktree add --no-track does not set up tracking' '\n+\ttest_when_finished rm -rf repo_a &&\n+\ttest_when_finished rm -rf repo_b &&\n+\ttest_when_finished rm -rf foo &&\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) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit remote add repo_a ../repo_a &&\n+\t\tgit config remote.repo_a.fetch \\\n+\t\t\t\"+refs/heads/*:refs/remotes/other_a/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add --no-track ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\t! test_branch_upstream foo repo_a foo &&\n+\t\tgit rev-parse other_a/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\t! test_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'git worktree add sets up tracking' '\n+\ttest_when_finished rm -rf repo_a &&\n+\ttest_when_finished rm -rf repo_b &&\n+\ttest_when_finished rm -rf foo &&\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) &&\n+\tgit init repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\ttest_commit b_master &&\n+\t\tgit remote add repo_a ../repo_a &&\n+\t\tgit config remote.repo_a.fetch \\\n+\t\t\t\"+refs/heads/*:refs/remotes/other_a/*\" &&\n+\t\tgit fetch --all &&\n+\t\tgit worktree add ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_a foo &&\n+\t\tgit rev-parse other_a/foo >expect &&\n+\t\tgit rev-parse foo >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.345.gf926f18f3\n\n"},{"id":"332843","messageId":"CAPig+cS-eQGXU8YKsOAP_RE55GreqLJXPooddpzewUYUZeP6LQ@mail.gmail.com","threadId":"47179","inReplyTo":"20171118224706.13810-3-t.gummerer@gmail.com","subject":"Re: [PATCH v3 2/3] worktree: make add <path> <branch> dwim","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2017-11-19T08:31:57Z","receivedAt":"2017-11-19T08:32:05Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Nov 18, 2017 at 5:47 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> Currently 'git worktree add <path> <branch>', errors out when 'branch'\n> is not a local branch.   It has no additional dwim'ing features that one\n> might expect.\n>\n> Make it behave more like 'git checkout <branch>' when the branch doesn't\n> exist locally, but a remote tracking branch uniquely matches the desired\n> branch name, i.e. create a new branch from the remote tracking branch\n> and set the upstream to the remote tracking branch.\n>\n> As 'git worktree add' currently just dies in this situation, there are\n> no backwards compatibility worries when introducing this feature.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> @@ -52,6 +52,13 @@ is linked to the current repository, sharing everything except working\n> +If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are\n> +used, but there does exist a tracking branch in exactly one remote\n> +(call it <remote>) with a matching name, treat as equivalent to\n> +------------\n> +$ git worktree add -b <branch> <path> <remote>/<branch>\n> +------------\n\nThe example from which this was copied in git-checkout.txt shows the\n--track option being used, which makes it clear that the new local\nbranch will track the remote-tracking branch. git-worktree, of course,\ndoes not have a --track option, but would it make sense to mention\nexplicitly in the prose that the newly-created local branch tracks the\nremote one? (Or are readers sufficiently savvy to intuit it?)\n\n> diff --git a/builtin/worktree.c b/builtin/worktree.c\n> index 7b9307aa58..05fc902bcc 100644\n> --- a/builtin/worktree.c\n> +++ b/builtin/worktree.c\n> @@ -1,4 +1,5 @@\n>  #include \"cache.h\"\n> +#include \"checkout.h\"\n>  #include \"config.h\"\n>  #include \"builtin.h\"\n>  #include \"dir.h\"\n> @@ -386,6 +387,20 @@ static int add(int ac, const char **av, const char *prefix)\n>                 opts.new_branch = xstrndup(s, n);\n>         }\n>\n> +       if (ac == 2 && !opts.new_branch && !opts.detach) {\n> +               struct object_id oid;\n> +               struct commit *commit;\n> +               const char *remote;\n> +\n> +               commit = lookup_commit_reference_by_name(branch);\n> +               if (!commit)\n> +                       remote = unique_tracking_name(branch, &oid);\n> +               if (!commit && remote) {\n> +                       opts.new_branch = branch;\n> +                       branch = remote;\n> +               }\n> +       }\n\nYou can simplify the above conditionals to:\n\n    commit = ...\n    if (!commit) {\n        remote = ...\n        if (remote) {\n            ...\n        }\n    }\n\nSo, although you're not passing --track explicitly to the \"git branch\"\ninvocation just below, you get --track for free since it's the default\nbehavior when creating a new local branch from a remote one, correct?\n(Just checking my understanding.)\n\n>         if (opts.new_branch) {\n>                 struct child_process cp = CHILD_PROCESS_INIT;\n>                 cp.git_cmd = 1;\n> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> @@ -6,6 +6,16 @@ test_description='test git worktree add'\n> +# Is branch \"refs/heads/$1\" set to pull from \"$2/$3\"?\n> +test_branch_upstream () {\n> +       printf \"%s\\n\" \"$2\" \"refs/heads/$3\" >expect.upstream &&\n> +       {\n> +               git config \"branch.$1.remote\" &&\n> +               git config \"branch.$1.merge\"\n> +       } >actual.upstream &&\n> +       test_cmp expect.upstream actual.upstream\n> +}\n\nNot a big deal, but it wouldn't hurt to move this function down to the\npoint where it is first needed...\n\n>  test_expect_success 'setup' '\n>         test_commit init\n>  '\n> @@ -314,4 +324,40 @@ test_expect_success 'rename a branch under bisect not allowed' '\n> +test_expect_success '\"add\" <path> <non-existent-branch> fails' '\n> +       test_must_fail git worktree add foo non-existent\n> +'\n> +\n> +test_expect_success '\"add\" <path> <branch> dwims' '\n> +       test_when_finished rm -rf repo_upstream &&\n> +       test_when_finished rm -rf repo_dwim &&\n> +       test_when_finished rm -rf foo &&\n\nAlso not a big deal, but could all be combined into a single invocation:\n\n    test_when_finished rm -rf repo_upstream repo_dwim foo &&\n\n> +       git init repo_upstream &&\n> +       (\n> +               cd repo_upstream &&\n> +               test_commit upstream_master &&\n> +               git checkout -b foo &&\n> +               test_commit a_foo\n> +       ) &&\n> +       git init repo_dwim &&\n> +       (\n> +               cd repo_dwim &&\n> +               test_commit dwim_master &&\n> +               git remote add repo_upstream ../repo_upstream &&\n> +               git config remote.repo_upstream.fetch \\\n> +                         \"refs/heads/*:refs/remotes/repo_upstream/*\" &&\n> +               git fetch --all &&\n> +               test_must_fail git worktree add -b foo ../foo foo &&\n> +               test_must_fail git worktree add --detach ../foo foo &&\n> +               git worktree add ../foo foo\n> +       ) &&\n> +       (\n> +               cd foo &&\n> +               test_branch_upstream foo repo_upstream foo &&\n> +               git rev-parse repo_upstream/foo >expect &&\n> +               git rev-parse foo >actual &&\n> +               test_cmp expect actual\n> +       )\n> +'\n"},{"id":"332860","messageId":"20171119174345.GA24891@hank","threadId":"47179","inReplyTo":"CAPig+cS-eQGXU8YKsOAP_RE55GreqLJXPooddpzewUYUZeP6LQ@mail.gmail.com","subject":"Re: [PATCH v3 2/3] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-19T17:43:45Z","receivedAt":"2017-11-19T17:42:23Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/19, Eric Sunshine wrote:\n> On Sat, Nov 18, 2017 at 5:47 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > Currently 'git worktree add <path> <branch>', errors out when 'branch'\n> > is not a local branch.   It has no additional dwim'ing features that one\n> > might expect.\n> >\n> > Make it behave more like 'git checkout <branch>' when the branch doesn't\n> > exist locally, but a remote tracking branch uniquely matches the desired\n> > branch name, i.e. create a new branch from the remote tracking branch\n> > and set the upstream to the remote tracking branch.\n> >\n> > As 'git worktree add' currently just dies in this situation, there are\n> > no backwards compatibility worries when introducing this feature.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> > diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> > @@ -52,6 +52,13 @@ is linked to the current repository, sharing everything except working\n> > +If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are\n> > +used, but there does exist a tracking branch in exactly one remote\n> > +(call it <remote>) with a matching name, treat as equivalent to\n> > +------------\n> > +$ git worktree add -b <branch> <path> <remote>/<branch>\n> > +------------\n> \n> The example from which this was copied in git-checkout.txt shows the\n> --track option being used, which makes it clear that the new local\n> branch will track the remote-tracking branch. git-worktree, of course,\n> does not have a --track option, but would it make sense to mention\n> explicitly in the prose that the newly-created local branch tracks the\n> remote one? (Or are readers sufficiently savvy to intuit it?)\n\nIt is how 'git worktree add -b <branch> <path> <remote>/<branch>'\ncurrently works, which is also not documented anywhere.  However I'm\nnot sure it's super intuitive, from just reading the command, so I'll\nadd an explicit mention about it.\n\n> > diff --git a/builtin/worktree.c b/builtin/worktree.c\n> > index 7b9307aa58..05fc902bcc 100644\n> > --- a/builtin/worktree.c\n> > +++ b/builtin/worktree.c\n> > @@ -1,4 +1,5 @@\n> >  #include \"cache.h\"\n> > +#include \"checkout.h\"\n> >  #include \"config.h\"\n> >  #include \"builtin.h\"\n> >  #include \"dir.h\"\n> > @@ -386,6 +387,20 @@ static int add(int ac, const char **av, const char *prefix)\n> >                 opts.new_branch = xstrndup(s, n);\n> >         }\n> >\n> > +       if (ac == 2 && !opts.new_branch && !opts.detach) {\n> > +               struct object_id oid;\n> > +               struct commit *commit;\n> > +               const char *remote;\n> > +\n> > +               commit = lookup_commit_reference_by_name(branch);\n> > +               if (!commit)\n> > +                       remote = unique_tracking_name(branch, &oid);\n> > +               if (!commit && remote) {\n> > +                       opts.new_branch = branch;\n> > +                       branch = remote;\n> > +               }\n> > +       }\n> \n> You can simplify the above conditionals to:\n> \n>     commit = ...\n>     if (!commit) {\n>         remote = ...\n>         if (remote) {\n>             ...\n>         }\n>     }\n\nWill change, thanks!\n\n> So, although you're not passing --track explicitly to the \"git branch\"\n> invocation just below, you get --track for free since it's the default\n> behavior when creating a new local branch from a remote one, correct?\n> (Just checking my understanding.)\n\nYes that's correct.  The default behaviour of git branch does exactly\nwhat we want here, so we're relying on it, instead of gouing through\nthe trouble of explicitly specifying --track.\n\nWe have a test checking the expected behaviour of setting up the\nupstream, so in the unlikely event that the behaviour in 'git branch'\nchanges, we'd still guard against it there.  Therefore I don't think\nthere's a need to be extra defensive here.\n\n> >         if (opts.new_branch) {\n> >                 struct child_process cp = CHILD_PROCESS_INIT;\n> >                 cp.git_cmd = 1;\n> > diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> > @@ -6,6 +6,16 @@ test_description='test git worktree add'\n> > +# Is branch \"refs/heads/$1\" set to pull from \"$2/$3\"?\n> > +test_branch_upstream () {\n> > +       printf \"%s\\n\" \"$2\" \"refs/heads/$3\" >expect.upstream &&\n> > +       {\n> > +               git config \"branch.$1.remote\" &&\n> > +               git config \"branch.$1.merge\"\n> > +       } >actual.upstream &&\n> > +       test_cmp expect.upstream actual.upstream\n> > +}\n> \n> Not a big deal, but it wouldn't hurt to move this function down to the\n> point where it is first needed...\n\nWill do.\n\n> >  test_expect_success 'setup' '\n> >         test_commit init\n> >  '\n> > @@ -314,4 +324,40 @@ test_expect_success 'rename a branch under bisect not allowed' '\n> > +test_expect_success '\"add\" <path> <non-existent-branch> fails' '\n> > +       test_must_fail git worktree add foo non-existent\n> > +'\n> > +\n> > +test_expect_success '\"add\" <path> <branch> dwims' '\n> > +       test_when_finished rm -rf repo_upstream &&\n> > +       test_when_finished rm -rf repo_dwim &&\n> > +       test_when_finished rm -rf foo &&\n> \n> Also not a big deal, but could all be combined into a single invocation:\n> \n>     test_when_finished rm -rf repo_upstream repo_dwim foo &&\n\nThanks, will change!\n\nThanks a lot for the review!\n\n> > +       git init repo_upstream &&\n> > +       (\n> > +               cd repo_upstream &&\n> > +               test_commit upstream_master &&\n> > +               git checkout -b foo &&\n> > +               test_commit a_foo\n> > +       ) &&\n> > +       git init repo_dwim &&\n> > +       (\n> > +               cd repo_dwim &&\n> > +               test_commit dwim_master &&\n> > +               git remote add repo_upstream ../repo_upstream &&\n> > +               git config remote.repo_upstream.fetch \\\n> > +                         \"refs/heads/*:refs/remotes/repo_upstream/*\" &&\n> > +               git fetch --all &&\n> > +               test_must_fail git worktree add -b foo ../foo foo &&\n> > +               test_must_fail git worktree add --detach ../foo foo &&\n> > +               git worktree add ../foo foo\n> > +       ) &&\n> > +       (\n> > +               cd foo &&\n> > +               test_branch_upstream foo repo_upstream foo &&\n> > +               git rev-parse repo_upstream/foo >expect &&\n> > +               git rev-parse foo >actual &&\n> > +               test_cmp expect actual\n> > +       )\n> > +'\n"},{"id":"332874","messageId":"CAPig+cQqbvuZg0Y8ZMObZc7mYXzohooVBFj0-o+CGGXrgGLp5w@mail.gmail.com","threadId":"47179","inReplyTo":"20171118224706.13810-4-t.gummerer@gmail.com","subject":"Re: [PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2017-11-19T19:04:13Z","receivedAt":"2017-11-19T19:04:19Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Nov 18, 2017 at 5:47 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> Currently 'git worktree add <path>' creates a new branch named after the\n> basename of the <path>, that matches the HEAD of whichever worktree we\n> were on when calling \"git worktree add <path>\".\n>\n> Make 'git worktree add <path> behave more like the dwim machinery in\n> 'git checkout <new-branch>', i.e. check if the new branch name uniquely\n> matches the branch name of a remote tracking branch, and if so check out\n> that branch and set the upstream to the remote tracking branch.\n>\n> This is a change of behaviour compared to the current behaviour, where\n> we create a new branch matching HEAD.  However as 'git worktree' is\n> still an experimental feature, and it's easy to notice/correct the\n> behaviour in case it's not what the user desired it's probably okay to\n> break existing behaviour here.\n>\n> In order to also satisfy users who want the current behaviour of\n> creating a new branch from HEAD, add a '--no-track' flag, which disables\n> the new behaviour, and keeps the old behaviour of creating a new branch\n> from the head of the current worktree.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> @@ -60,9 +60,18 @@ $ git worktree add -b <branch> <path> <remote>/<branch>\n>  ------------\n>  If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n> -then, as a convenience, a new branch based at HEAD is created automatically,\n> -as if `-b $(basename <path>)` was specified.\n> -\n> +then, as a convenience, if there exists a tracking branch in exactly\n> +one remote (call it <remote>) matching the basename of the path\n> +(call it <branch>), treat it as equivalent to\n\nInconsistent typesetting. In the context, typesetting is `<foo>`,\nwhereas in the new content, you've used <foo> for these two.\n\n> +------------\n> +$ git worktree add -b <branch> <path> <remote>/<branch>\n> +------------\n> +If no tracking branch exists in exactly one remote, <branch> is\n\nTypesetting: `<foo>`\n\n> +created based on HEAD, as if `-b $(basename <path>)` was specified.\n> ++\n> +To disable the behaviour of trying to match the basename of <path> to\n> +a remote, and always create a new branch from HEAD, the `--no-track`\n\nDoes --[no-]track deserve to be documented in the OPTIONS section like\nthe other options are?\n\n> +flag can be passed to `git worktree add`.\n>  list::\n\nYou lost a blank line before \"list::\".\n\n>  List details of each worktree.  The main worktree is listed first, followed by\n> diff --git a/builtin/worktree.c b/builtin/worktree.c\n> @@ -351,6 +352,7 @@ static int add(int ac, const char **av, const char *prefix)\n> +               OPT_BOOL(0, \"track\", &track_dwim, N_(\"checkout upstream branch if there's a unique match\")),\n\ngit-checkout and git-branch help describe this as \"setting upstream\"\nand \"setting up tracking\", respectively. Using \"checkout\" in this help\nmessage could be confusing, especially since git-worktree has a\n--no-checkout option; this seems to imply that --track would override\nit.\n\n>                 OPT_END()\n>         };\n>\n> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> @@ -360,4 +360,64 @@ test_expect_success '\"add\" <path> <branch> dwims' '\n> +test_expect_success 'git worktree add --no-track does not set up tracking' '\n> +       test_when_finished rm -rf repo_a &&\n> +       test_when_finished rm -rf repo_b &&\n> +       test_when_finished rm -rf foo &&\n> +       git init repo_a &&\n> +       (\n> +               cd repo_a &&\n> +               test_commit a_master &&\n> +               git checkout -b foo &&\n> +               test_commit a_foo\n> +       ) &&\n> +       git init repo_b &&\n> +       (\n> +               cd repo_b &&\n> +               test_commit b_master &&\n> +               git remote add repo_a ../repo_a &&\n> +               git config remote.repo_a.fetch \\\n> +                       \"+refs/heads/*:refs/remotes/other_a/*\" &&\n> +               git fetch --all &&\n> +               git worktree add --no-track ../foo\n> +       ) &&\n> +       (\n> +               cd foo &&\n> +               ! test_branch_upstream foo repo_a foo &&\n> +               git rev-parse other_a/foo >expect &&\n> +               git rev-parse foo >actual &&\n> +               ! test_cmp expect actual\n> +       )\n> +'\n\nMost of the boilerplate in the three new tests (added in this and the\nprevious patch) is identical (and very verbose). Perhaps the bulk of\nit can be factored out into a function?\n\n> +\n> +test_expect_success 'git worktree add sets up tracking' '\n> +       test_when_finished rm -rf repo_a &&\n> +       test_when_finished rm -rf repo_b &&\n> +       test_when_finished rm -rf foo &&\n> +       git init repo_a &&\n> +       (\n> +               cd repo_a &&\n> +               test_commit a_master &&\n> +               git checkout -b foo &&\n> +               test_commit a_foo\n> +       ) &&\n> +       git init repo_b &&\n> +       (\n> +               cd repo_b &&\n> +               test_commit b_master &&\n> +               git remote add repo_a ../repo_a &&\n> +               git config remote.repo_a.fetch \\\n> +                       \"+refs/heads/*:refs/remotes/other_a/*\" &&\n> +               git fetch --all &&\n> +               git worktree add ../foo\n> +       ) &&\n> +       (\n> +               cd foo &&\n> +               test_branch_upstream foo repo_a foo &&\n> +               git rev-parse other_a/foo >expect &&\n> +               git rev-parse foo >actual &&\n> +               test_cmp expect actual\n> +       )\n> +'\n> +\n>  test_done\n"},{"id":"332877","messageId":"CAPig+cTmqHt5s+C1vTFA7S4ZBwjqnzkn-2wA6i3jVeLw7i1_Lg@mail.gmail.com","threadId":"47179","inReplyTo":"CAPig+cQqbvuZg0Y8ZMObZc7mYXzohooVBFj0-o+CGGXrgGLp5w@mail.gmail.com","subject":"Re: [PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2017-11-19T20:20:00Z","receivedAt":"2017-11-19T20:20:07Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Nov 19, 2017 at 2:04 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sat, Nov 18, 2017 at 5:47 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>> +To disable the behaviour of trying to match the basename of <path> to\n>> +a remote, and always create a new branch from HEAD, the `--no-track`\n>\n> Does --[no-]track deserve to be documented in the OPTIONS section like\n> the other options are?\n\nOne other question: Since this is re-using the well-known option name\n--no-track, should it also get applied to the \"git worktree add -b foo\ndir origin/foo\" case, as well, which you pointed out (in the patch 2/3\nthread) already DWIMs tracking automatically? (I can easily see\nsomeone reporting it as a bug if \"git worktree add --no-track -b foo\ndir origin/foo\" does not suppress tracking.)\n"},{"id":"332884","messageId":"xmqqefotokbe.fsf@gitster.mtv.corp.google.com","threadId":"47179","inReplyTo":"CAPig+cTmqHt5s+C1vTFA7S4ZBwjqnzkn-2wA6i3jVeLw7i1_Lg@mail.gmail.com","subject":"Re: [PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-20T00:39:01Z","receivedAt":"2017-11-20T00:39:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Sun, Nov 19, 2017 at 2:04 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> On Sat, Nov 18, 2017 at 5:47 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>>> +To disable the behaviour of trying to match the basename of <path> to\n>>> +a remote, and always create a new branch from HEAD, the `--no-track`\n>>\n>> Does --[no-]track deserve to be documented in the OPTIONS section like\n>> the other options are?\n>\n> One other question: Since this is re-using the well-known option name\n> --no-track, should it also get applied to the \"git worktree add -b foo\n> dir origin/foo\" case, as well, which you pointed out (in the patch 2/3\n> thread) already DWIMs tracking automatically? (I can easily see\n> someone reporting it as a bug if \"git worktree add --no-track -b foo\n> dir origin/foo\" does not suppress tracking.)\n\nSensible suggestion.  Thanks.\n"},{"id":"333175","messageId":"20171121221339.GA4047@hank","threadId":"47179","inReplyTo":"CAPig+cTmqHt5s+C1vTFA7S4ZBwjqnzkn-2wA6i3jVeLw7i1_Lg@mail.gmail.com","subject":"Re: [PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-21T22:13:39Z","receivedAt":"2017-11-21T22:12:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/19, Eric Sunshine wrote:\n> On Sun, Nov 19, 2017 at 2:04 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > On Sat, Nov 18, 2017 at 5:47 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >> +To disable the behaviour of trying to match the basename of <path> to\n> >> +a remote, and always create a new branch from HEAD, the `--no-track`\n> >\n> > Does --[no-]track deserve to be documented in the OPTIONS section like\n> > the other options are?\n> \n> One other question: Since this is re-using the well-known option name\n> --no-track, should it also get applied to the \"git worktree add -b foo\n> dir origin/foo\" case, as well, which you pointed out (in the patch 2/3\n> thread) already DWIMs tracking automatically? (I can easily see\n> someone reporting it as a bug if \"git worktree add --no-track -b foo\n> dir origin/foo\" does not suppress tracking.)\n\nI didn't consider that, I think you are right, and the flag should\napply in that case as well.  I think at that point we may as well pass\nthis flag through to the 'git branch' call, and let users set up\ntracking if they want to, the same way it works in 'git branch'.  Thanks!\n"},{"id":"333210","messageId":"xmqqh8tnyuq3.fsf@gitster.mtv.corp.google.com","threadId":"47179","inReplyTo":"20171121221339.GA4047@hank","subject":"Re: [PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-22T01:20:52Z","receivedAt":"2017-11-22T01:20:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> I didn't consider that, I think you are right, and the flag should\n> apply in that case as well.  I think at that point we may as well pass\n> this flag through to the 'git branch' call, and let users set up\n> tracking if they want to, the same way it works in 'git branch'.\n\nOK, so tracking is set up by default in the current implementation\nof \"git worktree\" (even without your proposed update), but we will\nstop doing so, and instead take an explicit \"--track\" option (or\n\"--no-track\" to countermand an earlier \"--track\" on the command line\nand/or a default configured with branch.autosetupmerge) just like\n\"git branch\" does?\n\nI think that it is very sensible thing to make sure that \"branch\",\n\"checkout -b\" and \"worktree\", i.e. the three ways to create a branch\nto work on (the latter two being short-hands), behave consistently.\n\nThanks.\n"},{"id":"333317","messageId":"20171122194937.GA11773@hank","threadId":"47179","inReplyTo":"xmqqh8tnyuq3.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 3/3] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-22T19:49:37Z","receivedAt":"2017-11-22T19:48:14Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/22, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > I didn't consider that, I think you are right, and the flag should\n> > apply in that case as well.  I think at that point we may as well pass\n> > this flag through to the 'git branch' call, and let users set up\n> > tracking if they want to, the same way it works in 'git branch'.\n> \n> OK, so tracking is set up by default in the current implementation\n> of \"git worktree\" (even without your proposed update), but we will\n> stop doing so, and instead take an explicit \"--track\" option (or\n> \"--no-track\" to countermand an earlier \"--track\" on the command line\n> and/or a default configured with branch.autosetupmerge) just like\n> \"git branch\" does?\n\nI was a bit brief in the above.  The full story is that tracking is\nset up by default if the '<branch>' given is a remote tracking branch,\nand isn't set up otherwise, the same way as 'git branch' behaves.\n\nWhat I'm planning to do is introduce a --[no-]track flag to override\nthis behaviour.  As 'git worktree' really just calls 'git branch'\ninternally, the branch.autoSetupMerge configuration is also\nrespected.\n\n> I think that it is very sensible thing to make sure that \"branch\",\n> \"checkout -b\" and \"worktree\", i.e. the three ways to create a branch\n> to work on (the latter two being short-hands), behave consistently.\n\nSo in summary \"branch\" and \"worktree\" already behave consistently, the\nplan is just to introduce the same \"--[no-]track\" flag as branch to\nallow users to override the behaviour the same way as they are allowed\nin \"branch\".\n\n> Thanks.\n"}]}