{"thread":{"id":"47303","subject":"[PATCH v4 4/4] worktree: make add <path> dwim","startedAt":"2017-11-22T22:30:14Z","lastAt":"2017-11-29T20:03:40Z","messageCount":36,"participants":["Thomas Gummerer","Junio C Hamano","Paul Smith","Randall S. Becker"],"isPatch":true,"patchVersion":4,"patchTotal":4},"messages":[{"id":"333332","messageId":"20171122223020.2780-5-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171122223020.2780-1-t.gummerer@gmail.com","subject":"[PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-22T22:30:20Z","receivedAt":"2017-11-22T22:30:14Z","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 | 14 ++++++++++++--\n builtin/worktree.c             |  7 +++++++\n t/t2025-worktree-add.sh        | 32 ++++++++++++++++++++++++++++++++\n 3 files changed, 51 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 45642d3b7f..abc8f1f50d 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -60,8 +60,18 @@ $ git worktree add --track -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+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 --track -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 \n list::\n \ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex e9cc3f3872..cbcceb0385 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -389,6 +389,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 (!opt_track || strcmp(opt_track, \"--no-track\")) {\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 ea144938a9..6fd3da4036 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -390,4 +390,36 @@ 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 repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\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 repo_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 repo_b &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\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 repo_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":"333333","messageId":"20171122223020.2780-4-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171122223020.2780-1-t.gummerer@gmail.com","subject":"[PATCH v4 3/4] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-22T22:30:19Z","receivedAt":"2017-11-22T22:30:19Z","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             | 16 ++++++++++++++++\n t/t2025-worktree-add.sh        | 21 +++++++++++++++++++++\n 3 files changed, 44 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 798a642f84..45642d3b7f 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 --track -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 8f9446d43c..e9cc3f3872 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@@ -390,6 +391,21 @@ 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\t\tif (remote) {\n+\t\t\t\topts.new_branch = branch;\n+\t\t\t\tbranch = remote;\n+\t\t\t}\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 53042ce565..ea144938a9 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -369,4 +369,25 @@ test_expect_success '--no-track avoids setting up tracking' '\n \t)\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 repo_dwim foo &&\n+\tsetup_remote_repo repo_upstream repo_dwim &&\n+\tgit init repo_dwim &&\n+\t(\n+\t\tcd repo_dwim &&\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":"333334","messageId":"20171122223020.2780-2-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171122223020.2780-1-t.gummerer@gmail.com","subject":"[PATCH v4 1/4] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-22T22:30:17Z","receivedAt":"2017-11-22T22:30:28Z","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":"333335","messageId":"20171122223020.2780-3-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171122223020.2780-1-t.gummerer@gmail.com","subject":"[PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-22T22:30:18Z","receivedAt":"2017-11-22T22:30:38Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add' sets up tracking branches if '<branch>' is\na remote tracking branch, and doesn't set them up otherwise, as is the\ndefault for 'git branch'.\n\nThis may or may not be what the user wants.  Allow overriding this\nbehaviour with a --[no-]track flag that gets passed through to 'git\nbranch'.\n\nWe already respect branch.autoSetupMerge, as 'git worktree' just calls\n'git branch' internally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  6 +++++\n builtin/worktree.c             |  8 ++++++\n t/t2025-worktree-add.sh        | 55 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 69 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex b472acc356..798a642f84 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -107,6 +107,12 @@ OPTIONS\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]track::\n+\tWith `--track` `<branch>` is set as \"tracking\" branch for\n+\t`<new-branch>`.  This is the default if `<branch>` is a remote\n+\ttracking branch, and can be suppressed with `--no-track`.  See\n+\talso linkgit:git-branch[1].\n+\n --lock::\n \tKeep the working tree locked after creation. This is the\n \tequivalent of `git worktree lock` after `git worktree add`,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 7b9307aa58..8f9446d43c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -341,6 +341,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+\tconst char *opt_track = NULL;\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 +351,9 @@ 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_PASSTHRU(0, \"track\", &opt_track, NULL,\n+\t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n+\t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n \t\tOPT_END()\n \t};\n \n@@ -394,9 +398,13 @@ static int add(int ac, const char **av, const char *prefix)\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 (opt_track)\n+\t\t\targv_array_push(&cp.args, opt_track);\n \t\tif (run_command(&cp))\n \t\t\treturn -1;\n \t\tbranch = opts.new_branch;\n+\t} else if (opt_track) {\n+\t\tdie(_(\"--[no-]track can only be used if a new branch is created\"));\n \t}\n \n \tUNLEAK(path);\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex b5c47ac602..53042ce565 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -313,5 +313,60 @@ test_expect_success 'checkout a branch under bisect' '\n 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+# 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 '--track sets up tracking' '\n+\ttest_when_finished rm -rf track &&\n+\tgit worktree add --track -b track track master &&\n+\tgit config \"branch.track.merge\" &&\n+\t(\n+\t\ttest_branch_upstream track . master\n+\t)\n+'\n+\n+# setup remote repository $1 and repository $2 with $1 set up as\n+# remote.  The remote has two branches, master and foo.\n+setup_remote_repo () {\n+\tgit init $1 &&\n+\t(\n+\t\tcd $1 &&\n+\t\ttest_commit $1_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit upstream_foo\n+\t) &&\n+\tgit init $2 &&\n+\t(\n+\t\tcd $2 &&\n+\t\ttest_commit $2_master &&\n+\t\tgit remote add $1 ../$1 &&\n+\t\tgit config remote.$1.fetch \\\n+\t\t\t\"refs/heads/*:refs/remotes/$1/*\" &&\n+\t\tgit fetch --all\n+\t)\n+}\n+\n+test_expect_success '--no-track avoids setting up tracking' '\n+\ttest_when_finished rm -rf repo_upstream repo_local foo &&\n+\tsetup_remote_repo repo_upstream repo_local &&\n+\t(\n+\t\tcd repo_local &&\n+\t\tgit worktree add --no-track -b foo ../foo repo_upstream/foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\t! test_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":"333336","messageId":"20171122223020.2780-1-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"mailto:20171118224706.13810-1-t.gummerer@gmail.com","subject":"[PATCH v4 0/4] make git worktree add dwim more","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-22T22:30:16Z","receivedAt":"2017-11-22T22:30:42Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The previous rounds were at\nhttps://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/,\nhttps://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/ and\nhttps://public-inbox.org/git/20171118224706.13810-1-t.gummerer@gmail.com/.\n\nThanks Eric for the review of the previous round.\n\nThe main change is that the --[no-]track flag now works generally\ninstead of just disabling the new dwim mode.\n\nInterdiff below:\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex eedead2c4c..abc8f1f50d 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -56,22 +56,23 @@ 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+$ git worktree add --track -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, 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+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+$ git worktree add --track -b <branch> <path> <remote>/<branch>\n ------------\n-If no tracking branch exists in exactly one remote, <branch> is\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+\n list::\n \n List details of each worktree.  The main worktree is listed first, followed by\n@@ -123,6 +124,12 @@ OPTIONS\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]track::\n+\tWith `--track` `<branch>` is set as \"tracking\" branch for\n+\t`<new-branch>`.  This is the default if `<branch>` is a remote\n+\ttracking branch, and can be suppressed with `--no-track`.  See\n+\talso linkgit:git-branch[1].\n+\n --lock::\n \tKeep the working tree locked after creation. This is the\n \tequivalent of `git worktree lock` after `git worktree add`,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex b2a6dd020c..cbcceb0385 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -342,7 +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+\tconst char *opt_track = NULL;\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@@ -352,7 +352,9 @@ 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_PASSTHRU(0, \"track\", &opt_track, NULL,\n+\t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n+\t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n \t\tOPT_END()\n \t};\n \n@@ -387,7 +389,7 @@ 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\tif (!opt_track || strcmp(opt_track, \"--no-track\")) {\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@@ -402,11 +404,12 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tconst char *remote;\n \n \t\tcommit = lookup_commit_reference_by_name(branch);\n-\t\tif (!commit)\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\tif (remote) {\n+\t\t\t\topts.new_branch = branch;\n+\t\t\t\tbranch = remote;\n+\t\t\t}\n \t\t}\n \t}\n \n@@ -418,9 +421,13 @@ static int add(int ac, const char **av, const char *prefix)\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 (opt_track)\n+\t\t\targv_array_push(&cp.args, opt_track);\n \t\tif (run_command(&cp))\n \t\t\treturn -1;\n \t\tbranch = opts.new_branch;\n+\t} else if (opt_track) {\n+\t\tdie(_(\"--[no-]track can only be used if a new branch is created\"));\n \t}\n \n \tUNLEAK(path);\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex 87e233f812..6fd3da4036 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -6,16 +6,6 @@ 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@@ -323,32 +313,72 @@ test_expect_success 'checkout a branch under bisect' '\n 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+# 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 '\"add\" <path> <non-existent-branch> fails' '\n-\ttest_must_fail git worktree add foo non-existent\n+test_expect_success '--track sets up tracking' '\n+\ttest_when_finished rm -rf track &&\n+\tgit worktree add --track -b track track master &&\n+\tgit config \"branch.track.merge\" &&\n+\t(\n+\t\ttest_branch_upstream track . master\n+\t)\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+# setup remote repository $1 and repository $2 with $1 set up as\n+# remote.  The remote has two branches, master and foo.\n+setup_remote_repo () {\n+\tgit init $1 &&\n \t(\n-\t\tcd repo_upstream &&\n-\t\ttest_commit upstream_master &&\n+\t\tcd $1 &&\n+\t\ttest_commit $1_master &&\n \t\tgit checkout -b foo &&\n-\t\ttest_commit a_foo\n+\t\ttest_commit upstream_foo\n \t) &&\n+\tgit init $2 &&\n+\t(\n+\t\tcd $2 &&\n+\t\ttest_commit $2_master &&\n+\t\tgit remote add $1 ../$1 &&\n+\t\tgit config remote.$1.fetch \\\n+\t\t\t\"refs/heads/*:refs/remotes/$1/*\" &&\n+\t\tgit fetch --all\n+\t)\n+}\n+\n+test_expect_success '--no-track avoids setting up tracking' '\n+\ttest_when_finished rm -rf repo_upstream repo_local foo &&\n+\tsetup_remote_repo repo_upstream repo_local &&\n+\t(\n+\t\tcd repo_local &&\n+\t\tgit worktree add --no-track -b foo ../foo repo_upstream/foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\t! test_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_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 repo_dwim foo &&\n+\tsetup_remote_repo repo_upstream repo_dwim &&\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@@ -361,60 +391,32 @@ test_expect_success '\"add\" <path> <branch> dwims' '\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+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a 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 repo_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+\ttest_when_finished rm -rf repo_a repo_b &&\n+\tsetup_remote_repo repo_a 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 repo_a/foo >expect &&\n \t\tgit rev-parse foo >actual &&\n \t\ttest_cmp expect actual\n \t)\n\n\nThomas Gummerer (4):\n  checkout: factor out functions to new lib file\n  worktree: add --[no-]track option to the add subcommand\n  worktree: make add <path> <branch> dwim\n  worktree: make add <path> dwim\n\n Documentation/git-worktree.txt |  27 ++++++++++-\n Makefile                       |   1 +\n builtin/checkout.c             |  41 +---------------\n builtin/worktree.c             |  31 ++++++++++++\n checkout.c                     |  42 ++++++++++++++++\n checkout.h                     |  13 +++++\n t/t2025-worktree-add.sh        | 108 +++++++++++++++++++++++++++++++++++++++++\n 7 files changed, 221 insertions(+), 42 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\n-- \n2.15.0.345.gf926f18f3\n\n"},{"id":"333416","messageId":"xmqqfu94npga.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171122223020.2780-2-t.gummerer@gmail.com","subject":"Re: [PATCH v4 1/4] checkout: factor out functions to new lib file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-24T06:47:01Z","receivedAt":"2017-11-24T06:47:07Z","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 some docs to the function.\n>\n> Signed-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>\n> diff --git a/Makefile b/Makefile\n> index 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\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 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\nWith this, and also ...\n\n> diff --git a/checkout.c b/checkout.c\n> new file mode 100644\n> index 0000000000..b0c744d37a\n> --- /dev/null\n> +++ b/checkout.c\n> @@ -0,0 +1,42 @@\n> +#include \"cache.h\"\n> +#include \"remote.h\"\n\n... with this, I sort of expected that builtin/checkout.c no longer\nhas to include \"remote.h\" but can now rely on the common helpers in\nthis new file to perform anything remote-related operation.  But it\nseems that it is not the case (yet).\n\nJust recording my observation for future reference, as we might also\nwant to move report_tracking(), etc., to this new file in the future.\n"},{"id":"333417","messageId":"xmqqa7zcnozj.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171122223020.2780-3-t.gummerer@gmail.com","subject":"Re: [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-24T06:57:04Z","receivedAt":"2017-11-24T06:57:14Z","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> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> index b5c47ac602..53042ce565 100755\n> --- a/t/t2025-worktree-add.sh\n> +++ b/t/t2025-worktree-add.sh\n> @@ -313,5 +313,60 @@ test_expect_success 'checkout a branch under bisect' '\n>  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> +# 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\nOK.\n\n> +test_expect_success '--track sets up tracking' '\n> +\ttest_when_finished rm -rf track &&\n> +\tgit worktree add --track -b track track master &&\n> +\tgit config \"branch.track.merge\" &&\n> +\t(\n> +\t\ttest_branch_upstream track . master\n> +\t)\n> +'\n\nIs this \"git config\" necessary, or is it a remnant of a debugging\nsession?  It is tested in the helper that branch.track.merge is set\nto something, and otherwise the helper would fail the same way as\nthis standalnoe \"git config\" would, no?\n\n> +# setup remote repository $1 and repository $2 with $1 set up as\n> +# remote.  The remote has two branches, master and foo.\n> +setup_remote_repo () {\n> +\tgit init $1 &&\n> +\t(\n> +\t\tcd $1 &&\n> +\t\ttest_commit $1_master &&\n> +\t\tgit checkout -b foo &&\n> +\t\ttest_commit upstream_foo\n> +\t) &&\n> +\tgit init $2 &&\n> +\t(\n> +\t\tcd $2 &&\n> +\t\ttest_commit $2_master &&\n> +\t\tgit remote add $1 ../$1 &&\n> +\t\tgit config remote.$1.fetch \\\n> +\t\t\t\"refs/heads/*:refs/remotes/$1/*\" &&\n> +\t\tgit fetch --all\n> +\t)\n> +}\n> +\n> +test_expect_success '--no-track avoids setting up tracking' '\n> +\ttest_when_finished rm -rf repo_upstream repo_local foo &&\n> +\tsetup_remote_repo repo_upstream repo_local &&\n> +\t(\n> +\t\tcd repo_local &&\n> +\t\tgit worktree add --no-track -b foo ../foo repo_upstream/foo\n> +\t) &&\n> +\t(\n> +\t\tcd foo &&\n> +\t\t! test_branch_upstream foo repo_upstream foo &&\n\nIt is true that this test helper must yield failure.  But what you\nexpect probably is more than that, no?  For example, the test helper\nwould fail even if branch.foo.remote is set to the upstream as long\nas branch.foo.merge is not set to point at their foo, but what you\nreally want to make sure is that neither configuration variable is\nset.\n\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"},{"id":"333418","messageId":"xmqq60a0noup.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171122223020.2780-4-t.gummerer@gmail.com","subject":"Re: [PATCH v4 3/4] worktree: make add <path> <branch> dwim","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-24T06:59:58Z","receivedAt":"2017-11-24T07:00:07Z","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> 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\nThis step makes sense and I did not spot anything controversial.\n"},{"id":"333419","messageId":"xmqq1skonoaw.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171122223020.2780-5-t.gummerer@gmail.com","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-24T07:11:51Z","receivedAt":"2017-11-24T07:11: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> 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\nIs it \"easy to notice\"?  I doubt it.  Even if you assume that\neverybody uses bash prompt that shows the name of the branch, the\nuser sees the same name of the branch in either mode.\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\nI am not sure if this is a good match for \"--track/--no-track\";\nwhich branch is to be checked out (either \"automatically from the\nunique remote-tracking branch\" or \"the current one\") is one choice,\nand whether the resulting branch is marked explicitly as integrating\nwith the remote or not is another choice within one branch of the\nfirst choice.  IOW, this makes it impossible to say \"create the branch\nbased on the unique remote-tracking branch, but do not add the two\nbranch.*.{merge,remote} variables\".\n\nAlso, you have several mention of \"remote tracking branch\" in these\npatches.  Please consistently spell them as \"remote-tracking branch\"\nto be consistent with Documentation/glossary-content.txt and avoid a\ncasual/careful reference to \"tracking branch\" if possible, unless it\nis quite clear to the readers that you are being loose for the sake\nof brevity.  Some people used \"tracking branch\" to mean the local\nbranch that is marked as the branch to integrate with the work on\na branch at a remote that caused user confusion in the past.\n\nThat is\n\n    refs/remotes/origin/topic is a remote-tracking branch for the\n    branch 'topic' that came from the 'origin' remote.\n\n    when you have branch.foo.remote=origin and\n    branch.foo.merge=refs/heads/topic, then your local branch foo is\n    marked to integrate with the 'topic' branch at the 'origin'\n    remote.\n\nand these two are quite different things that people in the past and\nover time loosely used a phrase \"tracking branch\" to cause confusion.\n"},{"id":"333476","messageId":"20171125165833.GA14993@hank","threadId":"47303","inReplyTo":"xmqqa7zcnozj.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-25T16:58:40Z","receivedAt":"2017-11-25T16:57:15Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/24, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> > index b5c47ac602..53042ce565 100755\n> > --- a/t/t2025-worktree-add.sh\n> > +++ b/t/t2025-worktree-add.sh\n> > @@ -313,5 +313,60 @@ test_expect_success 'checkout a branch under bisect' '\n> >  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> > +# 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> OK.\n> \n> > +test_expect_success '--track sets up tracking' '\n> > +\ttest_when_finished rm -rf track &&\n> > +\tgit worktree add --track -b track track master &&\n> > +\tgit config \"branch.track.merge\" &&\n> > +\t(\n> > +\t\ttest_branch_upstream track . master\n> > +\t)\n> > +'\n> \n> Is this \"git config\" necessary, or is it a remnant of a debugging\n> session?  It is tested in the helper that branch.track.merge is set\n> to something, and otherwise the helper would fail the same way as\n> this standalnoe \"git config\" would, no?\n\nIt's a remnant of a debugging session, sorry.  It would indeed fail in\nthe same way, so just leaving the 'test_branch_upstream' is enough.\nAlso looking at that, there's no need for it to be in a subshell, will\nfix that as well.\n\n\n> > +# setup remote repository $1 and repository $2 with $1 set up as\n> > +# remote.  The remote has two branches, master and foo.\n> > +setup_remote_repo () {\n> > +\tgit init $1 &&\n> > +\t(\n> > +\t\tcd $1 &&\n> > +\t\ttest_commit $1_master &&\n> > +\t\tgit checkout -b foo &&\n> > +\t\ttest_commit upstream_foo\n> > +\t) &&\n> > +\tgit init $2 &&\n> > +\t(\n> > +\t\tcd $2 &&\n> > +\t\ttest_commit $2_master &&\n> > +\t\tgit remote add $1 ../$1 &&\n> > +\t\tgit config remote.$1.fetch \\\n> > +\t\t\t\"refs/heads/*:refs/remotes/$1/*\" &&\n> > +\t\tgit fetch --all\n> > +\t)\n> > +}\n> > +\n> > +test_expect_success '--no-track avoids setting up tracking' '\n> > +\ttest_when_finished rm -rf repo_upstream repo_local foo &&\n> > +\tsetup_remote_repo repo_upstream repo_local &&\n> > +\t(\n> > +\t\tcd repo_local &&\n> > +\t\tgit worktree add --no-track -b foo ../foo repo_upstream/foo\n> > +\t) &&\n> > +\t(\n> > +\t\tcd foo &&\n> > +\t\t! test_branch_upstream foo repo_upstream foo &&\n> \n> It is true that this test helper must yield failure.  But what you\n> expect probably is more than that, no?  For example, the test helper\n> would fail even if branch.foo.remote is set to the upstream as long\n> as branch.foo.merge is not set to point at their foo, but what you\n> really want to make sure is that neither configuration variable is\n> set.\n\nYeah you're right, this test is a bit too loose.  Will fix that in the\nre-roll.  Thanks!\n\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"},{"id":"333479","messageId":"20171125175010.GB14993@hank","threadId":"47303","inReplyTo":"xmqq1skonoaw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-25T17:50:11Z","receivedAt":"2017-11-25T17:48:45Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/24, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \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> Is it \"easy to notice\"?  I doubt it.  Even if you assume that\n> everybody uses bash prompt that shows the name of the branch, the\n> user sees the same name of the branch in either mode.\n\nWith \"easy\" I meant at creation time, looking at the output of 'git\nworktree add', which with the new version shows that the the new\nbranch has been set up to track the remote branch, and also shows the\ncommit HEAD now points to.\n\nThis would be the output in the new version:\n\n     $ git worktree add ../bla\n     Branch 'bla' set up to track remote branch 'bla' from 'origin'.\n     Preparing ../bla (identifier bla)\n     HEAD is now at 4aade43 bla\n\nvs. the output without the changed behaviour:\n\n     $ git worktree add ../bla\n     Preparing ../bla (identifier bla)\n     HEAD is now at 0f215c9 initial import\n\nOf course that assumes that it's used directly, not in scripts, and\nthat users will actually read the output of the command when they\ninvoke it.  Maybe these are not safe assumptions to make though, and\nwe'd rather not have this on by default then.  As I mentioned\npreviously I would prefer having this as default, but I'm happy to\nhide this behaviour behind a flag if we want to be more careful about\nintroducing this.  Dunno?\n\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> I am not sure if this is a good match for \"--track/--no-track\";\n> which branch is to be checked out (either \"automatically from the\n> unique remote-tracking branch\" or \"the current one\") is one choice,\n> and whether the resulting branch is marked explicitly as integrating\n> with the remote or not is another choice within one branch of the\n> first choice.  IOW, this makes it impossible to say \"create the branch\n> based on the unique remote-tracking branch, but do not add the two\n> branch.*.{merge,remote} variables\".\n\nHmm good point.  Maybe we'll need another flag for this.  Maybe\n--[no-]guess-remote would work, and a corresponding\nworktree.guessRemote config would work?  That's the best I could come\nup with, better suggestions are definitely welcome.\n\n> Also, you have several mention of \"remote tracking branch\" in these\n> patches.  Please consistently spell them as \"remote-tracking branch\"\n> to be consistent with Documentation/glossary-content.txt and avoid a\n> casual/careful reference to \"tracking branch\" if possible, unless it\n> is quite clear to the readers that you are being loose for the sake\n> of brevity.  Some people used \"tracking branch\" to mean the local\n> branch that is marked as the branch to integrate with the work on\n> a branch at a remote that caused user confusion in the past.\n\nI must admit I wasn't aware of Documentation/glossary-content.txt and\nhave seen \"tracking branch\" in other places, so I was just repeating\nthe pattern.\n\n> That is\n> \n>     refs/remotes/origin/topic is a remote-tracking branch for the\n>     branch 'topic' that came from the 'origin' remote.\n> \n>     when you have branch.foo.remote=origin and\n>     branch.foo.merge=refs/heads/topic, then your local branch foo is\n>     marked to integrate with the 'topic' branch at the 'origin'\n>     remote.\n> \n> and these two are quite different things that people in the past and\n> over time loosely used a phrase \"tracking branch\" to cause confusion.\n\n\nThanks for the clarification, will fix in the re-roll.\n"},{"id":"333481","messageId":"1511634365.2847.211.camel@mad-scientist.net","threadId":"47303","inReplyTo":"20171125175010.GB14993@hank","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Paul Smith","fromEmail":"paul@mad-scientist.net","sentAt":"2017-11-25T18:26:05Z","receivedAt":"2017-11-25T18:51:07Z","isPatch":true,"sender":{"key":"paul@mad-scientist.net","avatar":"https://avatars.githubusercontent.com/u/109636?v=4"},"body":"On Sat, 2017-11-25 at 17:50 +0000, Thomas Gummerer wrote:\n> This would be the output in the new version:\n> \n>      $ git worktree add ../bla\n>      Branch 'bla' set up to track remote branch 'bla' from 'origin'.\n>      Preparing ../bla (identifier bla)\n>      HEAD is now at 4aade43 bla\n> \n> vs. the output without the changed behaviour:\n> \n>      $ git worktree add ../bla\n>      Preparing ../bla (identifier bla)\n>      HEAD is now at 0f215c9 initial import\n> \n> Of course that assumes that it's used directly, not in scripts, and\n> that users will actually read the output of the command when they\n> invoke it.  Maybe these are not safe assumptions to make though, and\n> we'd rather not have this on by default then.  As I mentioned\n> previously I would prefer having this as default, but I'm happy to\n> hide this behaviour behind a flag if we want to be more careful about\n> introducing this.  Dunno?\n\nSpeaking as a simple user, I find the current behavior of Git worktree\nadd very frustrating; I am constantly wanting to create worktrees for\nother peoples' branches so I can look at the code there without messing\nup my workspace, and it's really inconvenient to do that now.\n\nAlso, the current special handling of the directory name as a putative\nbranch name is not helpful for me because many of the branches I need\nto examine use \"/\" as their separator.  I don't begrudge making that\nfeature more \"DWIM\" for those that can use it, but hopefully some help\nis forthcoming for those who can't.\n\nFor example, I need to create a local worktree for the remote rel/1.0\nbranch... what do I do?\n\nWhat I want to work is this:\n\n    git worktree add ../1.0 rel/1.0\n\nand have it create a worktree at ../1.0, then do the equivalent of \"git\ncheckout rel/1.0\" which includes setting up to track the remote branch.\n But of course this doesn't work at all; I get:\n\n    fatal: invalid reference: rel/1.0\n\nPersonally I would think it odd to have to add an extra flag to get\nwhat I would expect would be \"normal\" behavior (checkout).\n\nBut maybe that's just me.\n"},{"id":"333484","messageId":"20171125200615.GA4344@hank","threadId":"47303","inReplyTo":"1511634365.2847.211.camel@mad-scientist.net","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-25T20:06:15Z","receivedAt":"2017-11-25T20:04:48Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/25, Paul Smith wrote:\n> On Sat, 2017-11-25 at 17:50 +0000, Thomas Gummerer wrote:\n> > This would be the output in the new version:\n> > \n> >      $ git worktree add ../bla\n> >      Branch 'bla' set up to track remote branch 'bla' from 'origin'.\n> >      Preparing ../bla (identifier bla)\n> >      HEAD is now at 4aade43 bla\n> > \n> > vs. the output without the changed behaviour:\n> > \n> >      $ git worktree add ../bla\n> >      Preparing ../bla (identifier bla)\n> >      HEAD is now at 0f215c9 initial import\n> > \n> > Of course that assumes that it's used directly, not in scripts, and\n> > that users will actually read the output of the command when they\n> > invoke it.  Maybe these are not safe assumptions to make though, and\n> > we'd rather not have this on by default then.  As I mentioned\n> > previously I would prefer having this as default, but I'm happy to\n> > hide this behaviour behind a flag if we want to be more careful about\n> > introducing this.  Dunno?\n> \n> Speaking as a simple user, I find the current behavior of Git worktree\n> add very frustrating; I am constantly wanting to create worktrees for\n> other peoples' branches so I can look at the code there without messing\n> up my workspace, and it's really inconvenient to do that now.\n> \n> Also, the current special handling of the directory name as a putative\n> branch name is not helpful for me because many of the branches I need\n> to examine use \"/\" as their separator.  I don't begrudge making that\n> feature more \"DWIM\" for those that can use it, but hopefully some help\n> is forthcoming for those who can't.\n> \n> For example, I need to create a local worktree for the remote rel/1.0\n> branch... what do I do?\n> \n> What I want to work is this:\n> \n>     git worktree add ../1.0 rel/1.0\n> \n> and have it create a worktree at ../1.0, then do the equivalent of \"git\n> checkout rel/1.0\" which includes setting up to track the remote branch.\n>  But of course this doesn't work at all; I get:\n> \n>     fatal: invalid reference: rel/1.0\n> \n> Personally I would think it odd to have to add an extra flag to get\n> what I would expect would be \"normal\" behavior (checkout).\n> \n> But maybe that's just me.\n\nThis part is getting done in 3/4, and is definitely going to work\nwithout an additional flag, so this is (hopefully) soon going to work\njust as you want :)\n\nThis is less controversial because as you mentioned this currently\ndoesn't work at all, so there are no backwards compatibility worries.\n\nFor the other case of\n\n    git worktree add ../foo\n\nhowever we currently document one behaviour, which I would like to\nchange (I usually have branches without a / in that I want to look at)\nwe currently document one behaviour, which I'd like to change.  So in\nthat case we are a bit worried about backwards compatibility, and how\nthis will affect current users that have a certain expectation of how\nthe command is supposed to work, hence the discussion of whether to\nhide the new behaviour behind a flag or not.\n\nEither way, if we do put the behaviour behind a flag, I'll also add a\nconfiguration variable, which can be set to enable the new behaviour\nso one doesn't have to type out the flag all the time.\n"},{"id":"333486","messageId":"004401d3662d$8f099e10$ad1cda30$@nexbridge.com","threadId":"47303","inReplyTo":"20171125200615.GA4344@hank","subject":"RE: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Randall S. Becker","fromEmail":"rsbecker@nexbridge.com","sentAt":"2017-11-25T20:39:52Z","receivedAt":"2017-11-25T20:40:17Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 25, 2017 3:06 PM Thomas Gummerer wrote:\n<big snip>\n>however we currently document one behaviour, which I would like to change\n(I usually have branches\n>without a / in that I want to look at) we currently document one behaviour,\nwhich I'd like to change.  So \n>in that case we are a bit worried about backwards compatibility, and how\nthis will affect current users\n>that have a certain expectation of how the command is supposed to work,\nhence the discussion of\n>whether to hide the new behaviour behind a flag or not.\n\n>Either way, if we do put the behaviour behind a flag, I'll also add a\nconfiguration variable, which can\n>be set to enable the new behaviour so one doesn't have to type out the flag\nall the time.\n\nTo be consistent with other commands, you could put path after -- and the\nambiguity with refs containing '/' goes away, as refs before the -- would\nalways be considered refs while after you have paths.\n\nWhat I don't like is the current add syntax of:\ngit worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]\n<path> [<branch>]\n\nwhere the path-spec precedes branch making things a bit icky. It might be\nbetter to have an alternate syntax of:\n\ngit worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]\n<path> [<branch>]\ngit worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]\n[<branch>] -- <path>\n\nBut since we only have one path, that may be redundant. Just a thought, as\n-- avoids a lot of interpretation evils. While we're here, I wonder whether\n<branch> should be changed to <ref-spec> for more general use. Consider\nrelease identifiers using tags, and using the tag instead of branch to\ndefine commit on which the worktree is based.\n\nCheers,\nRandall\n\n-- Brief whoami: NonStop&UNIX developer since approximately\nUNIX(421664400)/NonStop(211288444200000000) \n-- In my real life, I talk too much.\n\n\n\n\n\n"},{"id":"333488","messageId":"20171125214856.GB4344@hank","threadId":"47303","inReplyTo":"004401d3662d$8f099e10$ad1cda30$@nexbridge.com","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-25T21:48:56Z","receivedAt":"2017-11-25T21:47:31Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/25, Randall S. Becker wrote:\n> On November 25, 2017 3:06 PM Thomas Gummerer wrote:\n> <big snip>\n> >however we currently document one behaviour, which I would like to change\n> >(I usually have branches\n> >without a / in that I want to look at) we currently document one behaviour,\n> >which I'd like to change.  So \n> >in that case we are a bit worried about backwards compatibility, and how\n> >this will affect current users\n> >that have a certain expectation of how the command is supposed to work,\n> >hence the discussion of\n> >whether to hide the new behaviour behind a flag or not.\n> \n> >Either way, if we do put the behaviour behind a flag, I'll also add a\n> >configuration variable, which can\n> >be set to enable the new behaviour so one doesn't have to type out the flag\n> >all the time.\n> \n> To be consistent with other commands, you could put path after -- and the\n> ambiguity with refs containing '/' goes away, as refs before the -- would\n> always be considered refs while after you have paths.\n>\n> What I don't like is the current add syntax of:\n> git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]\n> <path> [<branch>]\n> \n> where the path-spec precedes branch making things a bit icky. It might be\n> better to have an alternate syntax of:\n> \n> git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]\n> <path> [<branch>]\n> git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]\n> [<branch>] -- <path>\n\nHmm I don't think there is any ambiguity there, the first argument\nalways needs to be a path, and the second one is always a commit-ish.\nSo this way there is no disambiguation needed.\n\nI'm not convinced the alternative syntax would buy us much, at least\nnot in the context of what this series is trying to do.\n\n> But since we only have one path, that may be redundant. Just a thought, as\n> -- avoids a lot of interpretation evils. While we're here, I wonder whether\n> <branch> should be changed to <ref-spec> for more general use. Consider\n> release identifiers using tags, and using the tag instead of branch to\n> define commit on which the worktree is based.\n\n'git worktree add' can already take a commit-ish, it's just not\ndocumented that way.  I'll add a patch updating the documentation to\nthe series.\n\n> Cheers,\n> Randall\n> \n> -- Brief whoami: NonStop&UNIX developer since approximately\n> UNIX(421664400)/NonStop(211288444200000000) \n> -- In my real life, I talk too much.\n> \n> \n> \n> \n> \n"},{"id":"333495","messageId":"1511651467.2847.212.camel@mad-scientist.net","threadId":"47303","inReplyTo":"20171125200615.GA4344@hank","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Paul Smith","fromEmail":"paul@mad-scientist.net","sentAt":"2017-11-25T23:11:07Z","receivedAt":"2017-11-25T23:11:18Z","isPatch":true,"sender":{"key":"paul@mad-scientist.net","avatar":"https://avatars.githubusercontent.com/u/109636?v=4"},"body":"On Sat, 2017-11-25 at 20:06 +0000, Thomas Gummerer wrote:\n> This part is getting done in 3/4, and is definitely going to work\n> without an additional flag, so this is (hopefully) soon going to work\n> just as you want :)\n\nYay!  Thanks!\n"},{"id":"333515","messageId":"xmqqshd1iueo.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171125175010.GB14993@hank","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-26T03:35:43Z","receivedAt":"2017-11-26T03:35:49Z","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> Of course that assumes that it's used directly, not in scripts, and\n> that users will actually read the output of the command when they\n> invoke it.  Maybe these are not safe assumptions to make though, and\n> we'd rather not have this on by default then.\n\nNone of these is a safe assumption to make.  With a transition plan,\nwe could change the default eventually, but if this feature is already\nused by real users, the proposed change without any transition plan\nwill hurt them and make them hate us, I am afraid.\n\n"},{"id":"333526","messageId":"20171126113706.GA6055@hank","threadId":"47303","inReplyTo":"xmqqshd1iueo.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 4/4] worktree: make add <path> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T11:37:06Z","receivedAt":"2017-11-26T11:35:41Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/26, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > Of course that assumes that it's used directly, not in scripts, and\n> > that users will actually read the output of the command when they\n> > invoke it.  Maybe these are not safe assumptions to make though, and\n> > we'd rather not have this on by default then.\n> \n> None of these is a safe assumption to make.  With a transition plan,\n> we could change the default eventually, but if this feature is already\n> used by real users, the proposed change without any transition plan\n> will hurt them and make them hate us, I am afraid.\n\nFair enough, I definitely wouldn't want users to hate us.  I guess\nI'll add this to the list of things that I'd like to change when git\n3.0 comes along.\n\nHow about once we make the decision when git 3.0 happens, adding a\nwarning:\n\n    warning: The current behaviour of creating a branch from HEAD when\n    no <branch> is given will change in git 3.0, to try and match the\n    new branch name to a remote-tracking branch.  To get rid of this\n    warning in the meantime, set git.guessRemote to true or false,\n    depending on whether you'd like to enable the new behaviour now,\n    or would like to keep the existing behaviour. (see also\n    --guess-remote in man git-worktree)\n\nor something along the lines, and once we decide to release git 3.0 we\nflip the default?  The warning would be displayed whenever the new\nbehaviour would be invoked, but no config option or flag is set.\n\nEither way I'm going to add a flag and a config option to hide this\nbehaviour behind for now.\n\nThanks!\n"},{"id":"333539","messageId":"20171126194356.16187-1-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171122223020.2780-1-t.gummerer@gmail.com","subject":"[PATCH v5 0/6] make git worktree add dwim more","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:50Z","receivedAt":"2017-11-26T19:42:33Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The previous rounds can be found at\nhttps://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/,\nhttps://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/,\nhttps://public-inbox.org/git/20171118224706.13810-1-t.gummerer@gmail.com/ and\nhttps://public-inbox.org/git/20171122223020.2780-1-t.gummerer@gmail.com/.\n\nThanks Junio for the review of the previous round and Randall for the\nsuggestion of documenting that git worktree add can take a commit-ish,\nnot just a branch.\n\nThe main changes in this round are hiding the new behaviour for 'git\nworktree <path>' behind a flag, and adding a config option to turn the\nnew behaviour on by default.  It's also no longer relying on the\n--[no]-track flag, but using a new --[no-]guess-remote flag instead.\n\nInterdiff between this and the previous round below:\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5f65fa9234..4966d90ebb 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -3425,3 +3425,13 @@ web.browser::\n \tSpecify a web browser that may be used by some commands.\n \tCurrently only linkgit:git-instaweb[1] and linkgit:git-help[1]\n \tmay use it.\n+\n+worktree.guessRemote::\n+\tWith `add`, if no branch argument, and neither of `-b` nor\n+\t`-B` nor `--detach` are given, the command defaults to\n+\tcreating a new branch from HEAD.  If `worktree.guessRemote` is\n+\tset to true, `worktree add` tries to find a remote-tracking\n+\tbranch whose name uniquely matches the new branch name.  If\n+\tsuch a branch exists, it is checked out and set as \"upstream\"\n+\tfor the new branch.  If no such match can be found, it falls\n+\tback to creating a new branch from the current HEAD.\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex abc8f1f50d..fd841886ef 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees\n SYNOPSIS\n --------\n [verse]\n-'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<branch>]\n+'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]\n 'git worktree list' [--porcelain]\n 'git worktree lock' [--reason <string>] <worktree>\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n@@ -45,33 +45,24 @@ specifying `--reason` to explain why the working tree is locked.\n \n COMMANDS\n --------\n-add <path> [<branch>]::\n+add <path> [<commit-ish>]::\n \n-Create `<path>` and checkout `<branch>` into it. The new working directory\n+Create `<path>` and checkout `<commit-ish>` into it. The new working directory\n 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+specified as `<commit-ish>`; 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+If <commit-ish> is a branch name (call it `<branch>` and is not found,\n+and neither `-b` nor `-B` nor `--detach` are used, but there does\n+exist a tracking branch in exactly one remote (call it `<remote>`)\n+with a matching name, treat as equivalent to\n ------------\n $ git worktree add --track -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, 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 --track -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+If `<commit-ish>` 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 list::\n \n@@ -101,34 +92,44 @@ OPTIONS\n \n -f::\n --force::\n-\tBy default, `add` refuses to create a new working tree when `<branch>`\n+\tBy default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and\n \tis already checked out by another working tree. This option overrides\n \tthat safeguard.\n \n -b <new-branch>::\n -B <new-branch>::\n \tWith `add`, create a new branch named `<new-branch>` starting at\n-\t`<branch>`, and check out `<new-branch>` into the new working tree.\n-\tIf `<branch>` is omitted, it defaults to HEAD.\n+\t`<commit-ish>`, and check out `<new-branch>` into the new working tree.\n+\tIf `<commit-ish>` is omitted, it defaults to HEAD.\n \tBy default, `-b` refuses to create a new branch if it already\n \texists. `-B` overrides this safeguard, resetting `<new-branch>` to\n-\t`<branch>`.\n+\t`<commit-ish>`.\n \n --detach::\n \tWith `add`, detach HEAD in the new working tree. See \"DETACHED HEAD\"\n \tin linkgit:git-checkout[1].\n \n --[no-]checkout::\n-\tBy default, `add` checks out `<branch>`, however, `--no-checkout` can\n+\tBy default, `add` checks out `<commit-ish>`, however, `--no-checkout` can\n \tbe used to suppress checkout in order to make customizations,\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]guess-remote::\n+\tWith `add`, instead of creating a new branch from HEAD when\n+\t`<commit-ish>` is not given, if there exists a tracking branch\n+\tin exactly one remote matching the basename of the path, base\n+\tthe new branch on the remote-tracking branch, and mark the\n+\tremote-tracking branch as \"upstream\" from the new branch.\n++\n+This can also be set up as the default behaviour by using the\n+`worktree.guessRemote` config option.\n+\n --[no-]track::\n-\tWith `--track` `<branch>` is set as \"tracking\" branch for\n-\t`<new-branch>`.  This is the default if `<branch>` is a remote\n-\ttracking branch, and can be suppressed with `--no-track`.  See\n-\talso linkgit:git-branch[1].\n+\tWhen creating a new branch, if `<commit-ish>` is a branch,\n+\tmark it as \"upstream\" from the new branch.  This is the\n+\tdefault if `<commit-ish>` is a remote-tracking branch.  See\n+\t\"--track\" in linkgit:git-branch[1] for details.\n \n --lock::\n \tKeep the working tree locked after creation. This is the\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 83c73ecb0d..426aea8761 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -33,8 +33,19 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n+static int guess_remote;\n static timestamp_t expire;\n \n+static int git_worktree_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"worktree.guessremote\")) {\n+\t\tguess_remote = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n \tstruct stat st;\n@@ -355,9 +366,13 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_PASSTHRU(0, \"track\", &opt_track, NULL,\n \t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n \t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n+\t\tOPT_BOOL(0, \"guess-remote\", &guess_remote,\n+\t\t\t N_(\"try to match the new branch name with a remote-tracking branch\")),\n \t\tOPT_END()\n \t};\n \n+\tgit_config(git_worktree_config, NULL);\n+\n \tmemset(&opts, 0, sizeof(opts));\n \topts.checkout = 1;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n@@ -389,7 +404,7 @@ 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 (!opt_track || strcmp(opt_track, \"--no-track\")) {\n+\t\tif (guess_remote) {\n \t\t\tstruct object_id oid;\n \t\t\tconst char *remote =\n \t\t\t\tunique_tracking_name(opts.new_branch, &oid);\ndiff --git a/checkout.c b/checkout.c\nindex b0c744d37a..ac42630f74 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"remote.h\"\n+#include \"checkout.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex 6fd3da4036..6ce9b9c070 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -326,10 +326,7 @@ test_branch_upstream () {\n test_expect_success '--track sets up tracking' '\n \ttest_when_finished rm -rf track &&\n \tgit worktree add --track -b track track master &&\n-\tgit config \"branch.track.merge\" &&\n-\t(\n-\t\ttest_branch_upstream track . master\n-\t)\n+\ttest_branch_upstream track . master\n '\n \n # setup remote repository $1 and repository $2 with $1 set up as\n@@ -362,10 +359,9 @@ test_expect_success '--no-track avoids setting up tracking' '\n \t) &&\n \t(\n \t\tcd foo &&\n-\t\t! test_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\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\ttest_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo\n \t)\n '\n \n@@ -384,41 +380,67 @@ test_expect_success '\"add\" <path> <branch> dwims' '\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\ttest_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo\n \t)\n '\n \n-test_expect_success 'git worktree add --no-track does not set up tracking' '\n+test_expect_success 'git worktree add does not match remote' '\n \ttest_when_finished rm -rf repo_a repo_b foo &&\n \tsetup_remote_repo repo_a repo_b &&\n \t(\n \t\tcd repo_b &&\n-\t\tgit worktree add --no-track ../foo\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 repo_a/foo >expect &&\n-\t\tgit rev-parse foo >actual &&\n-\t\t! test_cmp expect actual\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\t! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n \t)\n '\n \n-test_expect_success 'git worktree add sets up tracking' '\n-\ttest_when_finished rm -rf repo_a repo_b &&\n+test_expect_success 'git worktree add --guess-remote sets up tracking' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n \tsetup_remote_repo repo_a repo_b &&\n \t(\n \t\tcd repo_b &&\n+\t\tgit worktree add --guess-remote ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_a foo &&\n+\t\ttest_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n+test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit config worktree.guessRemote true &&\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 repo_a/foo >expect &&\n-\t\tgit rev-parse foo >actual &&\n-\t\ttest_cmp expect actual\n+\t\ttest_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n+test_expect_success 'git worktree --no-guess-remote option overrides config' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit config worktree.guessRemote true &&\n+\t\tgit worktree add --no-guess-remote ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\t! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n \t)\n '\n \nThomas Gummerer (6):\n  checkout: factor out functions to new lib file\n  worktree: add can be created from any commit-ish\n  worktree: add --[no-]track option to the add subcommand\n  worktree: make add <path> <branch> dwim\n  worktree: add --guess-remote flag to add subcommand\n  add worktree.guessRemote config option\n\n Documentation/config.txt       |  10 ++++\n Documentation/git-worktree.txt |  44 ++++++++++----\n Makefile                       |   1 +\n builtin/checkout.c             |  41 +------------\n builtin/worktree.c             |  46 +++++++++++++++\n checkout.c                     |  43 ++++++++++++++\n checkout.h                     |  13 +++++\n t/t2025-worktree-add.sh        | 130 +++++++++++++++++++++++++++++++++++++++++\n 8 files changed, 278 insertions(+), 50 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333540","messageId":"20171126194356.16187-2-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v5 1/6] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:51Z","receivedAt":"2017-11-26T19:42:35Z","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         | 43 +++++++++++++++++++++++++++++++++++++++++++\n checkout.h         | 13 +++++++++++++\n 4 files changed, 58 insertions(+), 40 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\ndiff --git a/Makefile b/Makefile\nindex e53750ca01..a80a8fcca9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -759,6 +759,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 7d8bcc3833..ad8f94044c 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@@ -872,46 +873,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..ac42630f74\n--- /dev/null\n+++ b/checkout.c\n@@ -0,0 +1,43 @@\n+#include \"cache.h\"\n+#include \"remote.h\"\n+#include \"checkout.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.426.gb06021eeb\n\n"},{"id":"333541","messageId":"20171126194356.16187-3-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v5 2/6] worktree: add can be created from any commit-ish","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:52Z","receivedAt":"2017-11-26T19:42:40Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add' is documented to take an optional <branch>\nargument, which is checked out in the new worktree.  However it is more\ngenerally possible to use a commit-ish as the optional argument, and\ncheck that out into the new worktree.\n\nDocument that this is a possibility, as new users of git worktree add\nmight find it helpful.\n\nReported-by: Randall S. Becker <rsbecker@nexbridge.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex b472acc356..121895209d 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees\n SYNOPSIS\n --------\n [verse]\n-'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<branch>]\n+'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]\n 'git worktree list' [--porcelain]\n 'git worktree lock' [--reason <string>] <worktree>\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n@@ -45,14 +45,14 @@ specifying `--reason` to explain why the working tree is locked.\n \n COMMANDS\n --------\n-add <path> [<branch>]::\n+add <path> [<commit-ish>]::\n \n-Create `<path>` and checkout `<branch>` into it. The new working directory\n+Create `<path>` and checkout `<commit-ish>` into it. The new working directory\n 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+specified as `<commit-ish>`; it is synonymous with `@{-1}`.\n +\n-If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n+If `<commit-ish>` 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@@ -84,25 +84,25 @@ OPTIONS\n \n -f::\n --force::\n-\tBy default, `add` refuses to create a new working tree when `<branch>`\n+\tBy default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and\n \tis already checked out by another working tree. This option overrides\n \tthat safeguard.\n \n -b <new-branch>::\n -B <new-branch>::\n \tWith `add`, create a new branch named `<new-branch>` starting at\n-\t`<branch>`, and check out `<new-branch>` into the new working tree.\n-\tIf `<branch>` is omitted, it defaults to HEAD.\n+\t`<commit-ish>`, and check out `<new-branch>` into the new working tree.\n+\tIf `<commit-ish>` is omitted, it defaults to HEAD.\n \tBy default, `-b` refuses to create a new branch if it already\n \texists. `-B` overrides this safeguard, resetting `<new-branch>` to\n-\t`<branch>`.\n+\t`<commit-ish>`.\n \n --detach::\n \tWith `add`, detach HEAD in the new working tree. See \"DETACHED HEAD\"\n \tin linkgit:git-checkout[1].\n \n --[no-]checkout::\n-\tBy default, `add` checks out `<branch>`, however, `--no-checkout` can\n+\tBy default, `add` checks out `<commit-ish>`, however, `--no-checkout` can\n \tbe used to suppress checkout in order to make customizations,\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333542","messageId":"20171126194356.16187-4-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v5 3/6] worktree: add --[no-]track option to the add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:53Z","receivedAt":"2017-11-26T19:42:41Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add' sets up tracking branches if '<branch>' is\na remote tracking branch, and doesn't set them up otherwise, as is the\ndefault for 'git branch'.\n\nThis may or may not be what the user wants.  Allow overriding this\nbehaviour with a --[no-]track flag that gets passed through to 'git\nbranch'.\n\nWe already respect branch.autoSetupMerge, as 'git worktree' just calls\n'git branch' internally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  6 +++++\n builtin/worktree.c             |  8 +++++++\n t/t2025-worktree-add.sh        | 51 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 65 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 121895209d..15e58b18f7 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -107,6 +107,12 @@ OPTIONS\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]track::\n+\tWhen creating a new branch, if `<commit-ish>` is a branch,\n+\tmark it as \"upstream\" from the new branch.  This is the\n+\tdefault if `<commit-ish>` is a remote-tracking branch.  See\n+\t\"--track\" in linkgit:git-branch[1] for details.\n+\n --lock::\n \tKeep the working tree locked after creation. This is the\n \tequivalent of `git worktree lock` after `git worktree add`,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex ed043d5f1c..ea9678cac8 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -341,6 +341,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+\tconst char *opt_track = NULL;\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 +351,9 @@ 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_PASSTHRU(0, \"track\", &opt_track, NULL,\n+\t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n+\t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n \t\tOPT_END()\n \t};\n \n@@ -394,9 +398,13 @@ static int add(int ac, const char **av, const char *prefix)\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 (opt_track)\n+\t\t\targv_array_push(&cp.args, opt_track);\n \t\tif (run_command(&cp))\n \t\t\treturn -1;\n \t\tbranch = opts.new_branch;\n+\t} else if (opt_track) {\n+\t\tdie(_(\"--[no-]track can only be used if a new branch is created\"));\n \t}\n \n \tUNLEAK(path);\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex b5c47ac602..72e8b62927 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -313,5 +313,56 @@ test_expect_success 'checkout a branch under bisect' '\n 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+# 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 '--track sets up tracking' '\n+\ttest_when_finished rm -rf track &&\n+\tgit worktree add --track -b track track master &&\n+\ttest_branch_upstream track . master\n+'\n+\n+# setup remote repository $1 and repository $2 with $1 set up as\n+# remote.  The remote has two branches, master and foo.\n+setup_remote_repo () {\n+\tgit init $1 &&\n+\t(\n+\t\tcd $1 &&\n+\t\ttest_commit $1_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit upstream_foo\n+\t) &&\n+\tgit init $2 &&\n+\t(\n+\t\tcd $2 &&\n+\t\ttest_commit $2_master &&\n+\t\tgit remote add $1 ../$1 &&\n+\t\tgit config remote.$1.fetch \\\n+\t\t\t\"refs/heads/*:refs/remotes/$1/*\" &&\n+\t\tgit fetch --all\n+\t)\n+}\n+\n+test_expect_success '--no-track avoids setting up tracking' '\n+\ttest_when_finished rm -rf repo_upstream repo_local foo &&\n+\tsetup_remote_repo repo_upstream repo_local &&\n+\t(\n+\t\tcd repo_local &&\n+\t\tgit worktree add --no-track -b foo ../foo repo_upstream/foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\ttest_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo\n+\t)\n+'\n \n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333543","messageId":"20171126194356.16187-5-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v5 4/6] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:54Z","receivedAt":"2017-11-26T19:42:43Z","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 |  8 ++++++++\n builtin/worktree.c             | 16 ++++++++++++++++\n t/t2025-worktree-add.sh        | 19 +++++++++++++++++++\n 3 files changed, 43 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 15e58b18f7..3044d305a6 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -52,6 +52,14 @@ 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 `<commit-ish>`; it is synonymous with `@{-1}`.\n +\n+If <commit-ish> is a branch name (call it `<branch>` and is not found,\n+and neither `-b` nor `-B` nor `--detach` are used, but there does\n+exist a tracking branch in exactly one remote (call it `<remote>`)\n+with a matching name, treat as equivalent to\n+------------\n+$ git worktree add --track -b <branch> <path> <remote>/<branch>\n+------------\n++\n If `<commit-ish>` 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 ea9678cac8..7021d02585 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@@ -390,6 +391,21 @@ 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\t\tif (remote) {\n+\t\t\t\topts.new_branch = branch;\n+\t\t\t\tbranch = remote;\n+\t\t\t}\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 72e8b62927..96ebc63d04 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -365,4 +365,23 @@ test_expect_success '--no-track avoids setting up tracking' '\n \t)\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 repo_dwim foo &&\n+\tsetup_remote_repo repo_upstream repo_dwim &&\n+\tgit init repo_dwim &&\n+\t(\n+\t\tcd repo_dwim &&\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\ttest_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333544","messageId":"20171126194356.16187-7-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v5 6/6] add worktree.guessRemote config option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:56Z","receivedAt":"2017-11-26T19:42:46Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Some users might want to have the --guess-remote option introduced in\nthe previous commit on by default, so they don't have to type it out\nevery time they create a new worktree.\n\nAdd a config option worktree.guessRemote that allows users to configure\nthe default behaviour for themselves.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/config.txt       | 10 ++++++++++\n Documentation/git-worktree.txt |  3 +++\n builtin/worktree.c             | 14 +++++++++++++-\n t/t2025-worktree-add.sh        | 31 +++++++++++++++++++++++++++++++\n 4 files changed, 57 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5f65fa9234..4966d90ebb 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -3425,3 +3425,13 @@ web.browser::\n \tSpecify a web browser that may be used by some commands.\n \tCurrently only linkgit:git-instaweb[1] and linkgit:git-help[1]\n \tmay use it.\n+\n+worktree.guessRemote::\n+\tWith `add`, if no branch argument, and neither of `-b` nor\n+\t`-B` nor `--detach` are given, the command defaults to\n+\tcreating a new branch from HEAD.  If `worktree.guessRemote` is\n+\tset to true, `worktree add` tries to find a remote-tracking\n+\tbranch whose name uniquely matches the new branch name.  If\n+\tsuch a branch exists, it is checked out and set as \"upstream\"\n+\tfor the new branch.  If no such match can be found, it falls\n+\tback to creating a new branch from the current HEAD.\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex a81cfb2229..fd841886ef 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -121,6 +121,9 @@ OPTIONS\n \tin exactly one remote matching the basename of the path, base\n \tthe new branch on the remote-tracking branch, and mark the\n \tremote-tracking branch as \"upstream\" from the new branch.\n++\n+This can also be set up as the default behaviour by using the\n+`worktree.guessRemote` config option.\n \n --[no-]track::\n \tWhen creating a new branch, if `<commit-ish>` is a branch,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 15cb1600ee..426aea8761 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -33,8 +33,19 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n+static int guess_remote;\n static timestamp_t expire;\n \n+static int git_worktree_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"worktree.guessremote\")) {\n+\t\tguess_remote = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n \tstruct stat st;\n@@ -343,7 +354,6 @@ static int add(int ac, const char **av, const char *prefix)\n \tchar *path;\n \tconst char *branch;\n \tconst char *opt_track = NULL;\n-\tint guess_remote = 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@@ -361,6 +371,8 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tgit_config(git_worktree_config, NULL);\n+\n \tmemset(&opts, 0, sizeof(opts));\n \topts.checkout = 1;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex d25c774cb7..6ce9b9c070 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -413,4 +413,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '\n \t)\n '\n \n+test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit config worktree.guessRemote true &&\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\ttest_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n+test_expect_success 'git worktree --no-guess-remote option overrides config' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit config worktree.guessRemote true &&\n+\t\tgit worktree add --no-guess-remote ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\t! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333545","messageId":"20171126194356.16187-6-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-26T19:43:55Z","receivedAt":"2017-11-26T19:42:49Z","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\nIt's sometimes useful to have 'git worktree add <path> behave more like\nthe dwim 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\nAdd a new --guess-remote option that enables exactly that behaviour.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  7 +++++++\n builtin/worktree.c             | 10 ++++++++++\n t/t2025-worktree-add.sh        | 29 +++++++++++++++++++++++++++++\n 3 files changed, 46 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 3044d305a6..a81cfb2229 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -115,6 +115,13 @@ OPTIONS\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]guess-remote::\n+\tWith `add`, instead of creating a new branch from HEAD when\n+\t`<commit-ish>` is not given, if there exists a tracking branch\n+\tin exactly one remote matching the basename of the path, base\n+\tthe new branch on the remote-tracking branch, and mark the\n+\tremote-tracking branch as \"upstream\" from the new branch.\n+\n --[no-]track::\n \tWhen creating a new branch, if `<commit-ish>` is a branch,\n \tmark it as \"upstream\" from the new branch.  This is the\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 7021d02585..15cb1600ee 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -343,6 +343,7 @@ static int add(int ac, const char **av, const char *prefix)\n \tchar *path;\n \tconst char *branch;\n \tconst char *opt_track = NULL;\n+\tint guess_remote = 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@@ -355,6 +356,8 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_PASSTHRU(0, \"track\", &opt_track, NULL,\n \t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n \t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n+\t\tOPT_BOOL(0, \"guess-remote\", &guess_remote,\n+\t\t\t N_(\"try to match the new branch name with a remote-tracking branch\")),\n \t\tOPT_END()\n \t};\n \n@@ -389,6 +392,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 (guess_remote) {\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 96ebc63d04..d25c774cb7 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -384,4 +384,33 @@ test_expect_success '\"add\" <path> <branch> dwims' '\n \t)\n '\n \n+test_expect_success 'git worktree add does not match remote' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit worktree add ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\t! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n+test_expect_success 'git worktree add --guess-remote sets up tracking' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit worktree add --guess-remote ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_a foo &&\n+\t\ttest_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333599","messageId":"xmqqd144cjnw.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171126194356.16187-6-t.gummerer@gmail.com","subject":"Re: [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-27T06:36:35Z","receivedAt":"2017-11-27T06:36:43Z","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> 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> It's sometimes useful to have 'git worktree add <path> behave more like\n> the dwim machinery in 'git checkout <new-branch>', i.e. check if the new\n> branch name uniquely matches the branch name of a remote-tracking\n> branch, and if so check out that branch and set the upstream to the\n> remote-tracking branch.\n\nThis paragraph was a bit hard to sympathize because it was not\nobvious that the new feature still assumes how <path> is used to\ncompute the name of the new branch.  Perhaps if it were written like\nso:\n\n\tcheck if the new branch name, derived from the basename of\n\tthe <path>, uniquely matches the branch name of ...\n\nI would not have had to read it twice to understand what was going\non.\n\n> +--[no-]guess-remote::\n> +\tWith `add`, instead of creating a new branch from HEAD when\n> +\t`<commit-ish>` is not given, if there exists a tracking branch\n> +\tin exactly one remote matching the basename of the path, base\n> +\tthe new branch on the remote-tracking branch, and mark the\n> +\tremote-tracking branch as \"upstream\" from the new branch.\n> +\n\nWould\n\n\tgit worktree add --guess-remote <path> <branch>\n\nbe an error?  It is allowed as long as <branch> and the basename of\nthe <path> matches?  The option is silently ignored?  Something\nelse?\n\nI am reacting to \"with `add`\" part of this desciption.  I wouldn't\nbe asking if it said \"With `worktree add <path>` without <branch>\",\nas that would make the scenario I am wondering about automatically\n\"undefined\".  Yes, we should strive for leaving things undefined as\nlittle as practically possible, but at least saying something like\n\"without <branch>\" explicitly there would make sure that readers\nknow in what scenario this option is meant to be used a bit better.\n\n> @@ -389,6 +392,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 (guess_remote) {\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\nI think the answer is \"silently ignored\", as the above hunk is\ninside \"if (ac < 2 && !opts.new_branch && !opts.detach)\".\n\n"},{"id":"333600","messageId":"xmqq8tescj9p.fsf@gitster.mtv.corp.google.com","threadId":"47303","inReplyTo":"20171126194356.16187-7-t.gummerer@gmail.com","subject":"Re: [PATCH v5 6/6] add worktree.guessRemote config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-27T06:45:06Z","receivedAt":"2017-11-27T06:45:13Z","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> +worktree.guessRemote::\n> +\tWith `add`, if no branch argument, and neither of `-b` nor\n> +\t`-B` nor `--detach` are given, the command defaults to\n> +\tcreating a new branch from HEAD.  If `worktree.guessRemote` is\n> +\tset to true, `worktree add` tries to find a remote-tracking\n> +\tbranch whose name uniquely matches the new branch name.  If\n> +\tsuch a branch exists, it is checked out and set as \"upstream\"\n> +\tfor the new branch.  If no such match can be found, it falls\n> +\tback to creating a new branch from the current HEAD.\n\nUnlike the part I commented on in the previous step, this one is\nclear that the feature only kicks in for 'add <path>' without\nanything else, which is good.\n\n> diff --git a/builtin/worktree.c b/builtin/worktree.c\n> index 15cb1600ee..426aea8761 100644\n> --- a/builtin/worktree.c\n> +++ b/builtin/worktree.c\n> @@ -33,8 +33,19 @@ struct add_opts {\n>  \n>  static int show_only;\n>  static int verbose;\n> +static int guess_remote;\n>  static timestamp_t expire;\n>  \n> +static int git_worktree_config(const char *var, const char *value, void *cb)\n> +{\n> +\tif (!strcmp(var, \"worktree.guessremote\")) {\n> +\t\tguess_remote = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n\nIt is a lot more consistent with the established practice if this\nfunction had\n\n\treturn git_default_config(var, value, cb);\n\ninstead of \"return 0\" at the end, and then have the call to\n\n\tgit_config(git_default_config, NULL);\n\nwe have in cmd_worktree() replaced with\n\n\tgit_config(git_worktree_config, NULL);\n\nThat would avoid having to scan the entire set of config keys once\nin cmd_worktree() and then again in add(), the latter one only\nlooking for a single variable.\n"},{"id":"333635","messageId":"20171127205653.GA32057@hank","threadId":"47303","inReplyTo":"xmqqd144cjnw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-27T20:56:53Z","receivedAt":"2017-11-27T20:55:27Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/27, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \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> > It's sometimes useful to have 'git worktree add <path> behave more like\n> > the dwim machinery in 'git checkout <new-branch>', i.e. check if the new\n> > branch name uniquely matches the branch name of a remote-tracking\n> > branch, and if so check out that branch and set the upstream to the\n> > remote-tracking branch.\n> \n> This paragraph was a bit hard to sympathize because it was not\n> obvious that the new feature still assumes how <path> is used to\n> compute the name of the new branch.  Perhaps if it were written like\n> so:\n> \n> \tcheck if the new branch name, derived from the basename of\n> \tthe <path>, uniquely matches the branch name of ...\n> \n> I would not have had to read it twice to understand what was going\n> on.\n\nSorry about that, will re-phrase.\n\n> > +--[no-]guess-remote::\n> > +\tWith `add`, instead of creating a new branch from HEAD when\n> > +\t`<commit-ish>` is not given, if there exists a tracking branch\n> > +\tin exactly one remote matching the basename of the path, base\n> > +\tthe new branch on the remote-tracking branch, and mark the\n> > +\tremote-tracking branch as \"upstream\" from the new branch.\n> > +\n> \n> Would\n> \n> \tgit worktree add --guess-remote <path> <branch>\n> \n> be an error?  It is allowed as long as <branch> and the basename of\n> the <path> matches?  The option is silently ignored?  Something\n> else?\n> \n> I am reacting to \"with `add`\" part of this desciption.  I wouldn't\n> be asking if it said \"With `worktree add <path>` without <branch>\",\n> as that would make the scenario I am wondering about automatically\n> \"undefined\".  Yes, we should strive for leaving things undefined as\n> little as practically possible, but at least saying something like\n> \"without <branch>\" explicitly there would make sure that readers\n> know in what scenario this option is meant to be used a bit better.\n\nAs you mentioned below it's silently ignored.  The main reason for not\nerroring out is that it would get a little bit (although not too much)\nmore annoying once the config variable is introduced.  If it's\nstrongly preferred to error out when <branch> is given I can change it\nto that.\n\nEither way I'll update the documentation.\n\nThanks!\n\n> > @@ -389,6 +392,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 (guess_remote) {\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> I think the answer is \"silently ignored\", as the above hunk is\n> inside \"if (ac < 2 && !opts.new_branch && !opts.detach)\".\n> \n"},{"id":"333637","messageId":"20171127205918.GB32057@hank","threadId":"47303","inReplyTo":"xmqq8tescj9p.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 6/6] add worktree.guessRemote config option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-27T20:59:18Z","receivedAt":"2017-11-27T20:57:52Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 11/27, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > +worktree.guessRemote::\n> > +\tWith `add`, if no branch argument, and neither of `-b` nor\n> > +\t`-B` nor `--detach` are given, the command defaults to\n> > +\tcreating a new branch from HEAD.  If `worktree.guessRemote` is\n> > +\tset to true, `worktree add` tries to find a remote-tracking\n> > +\tbranch whose name uniquely matches the new branch name.  If\n> > +\tsuch a branch exists, it is checked out and set as \"upstream\"\n> > +\tfor the new branch.  If no such match can be found, it falls\n> > +\tback to creating a new branch from the current HEAD.\n> \n> Unlike the part I commented on in the previous step, this one is\n> clear that the feature only kicks in for 'add <path>' without\n> anything else, which is good.\n> \n> > diff --git a/builtin/worktree.c b/builtin/worktree.c\n> > index 15cb1600ee..426aea8761 100644\n> > --- a/builtin/worktree.c\n> > +++ b/builtin/worktree.c\n> > @@ -33,8 +33,19 @@ struct add_opts {\n> >  \n> >  static int show_only;\n> >  static int verbose;\n> > +static int guess_remote;\n> >  static timestamp_t expire;\n> >  \n> > +static int git_worktree_config(const char *var, const char *value, void *cb)\n> > +{\n> > +\tif (!strcmp(var, \"worktree.guessremote\")) {\n> > +\t\tguess_remote = git_config_bool(var, value);\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> \n> It is a lot more consistent with the established practice if this\n> function had\n> \n> \treturn git_default_config(var, value, cb);\n> \n> instead of \"return 0\" at the end, and then have the call to\n> \n> \tgit_config(git_default_config, NULL);\n> \n> we have in cmd_worktree() replaced with\n> \n> \tgit_config(git_worktree_config, NULL);\n> \n> That would avoid having to scan the entire set of config keys once\n> in cmd_worktree() and then again in add(), the latter one only\n> looking for a single variable.\n\nMakes sense, I missed that.  I'll fix it in the re-roll.  I'll wait a\nfew days to see if there are any more comments on the series and then\nre-roll it with the suggested changes.\n\nThanks for the review!\n"},{"id":"333799","messageId":"20171129200451.16856-1-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171126194356.16187-1-t.gummerer@gmail.com","subject":"[PATCH v6 0/6] make git worktree add dwim more","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:45Z","receivedAt":"2017-11-29T20:03:26Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The previous rounds were at\nhttps://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/,\nhttps://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/,\nhttps://public-inbox.org/git/20171118224706.13810-1-t.gummerer@gmail.com/,\nhttps://public-inbox.org/git/20171122223020.2780-1-t.gummerer@gmail.com/ and\nhttps://public-inbox.org/git/20171126194356.16187-1-t.gummerer@gmail.com.\n\nThanks Junio for the review of the last round!\n\nChanges since the last round:\n\n- rephrased documentation and commit messaegs a bit use the\n- established pattern and call git_config only once, instead of\n  calling it multiple times.\n\nInterdiff below:\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex fd841886ef..89ad0faecf 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -116,11 +116,11 @@ OPTIONS\n \tin linkgit:git-read-tree[1].\n \n --[no-]guess-remote::\n-\tWith `add`, instead of creating a new branch from HEAD when\n-\t`<commit-ish>` is not given, if there exists a tracking branch\n-\tin exactly one remote matching the basename of the path, base\n-\tthe new branch on the remote-tracking branch, and mark the\n-\tremote-tracking branch as \"upstream\" from the new branch.\n+\tWith `worktree add <path>`, withouth `<commit-ish>`, instead\n+\tof creating a new branch from HEAD, if there exists a tracking\n+\tbranch in exactly one remote matching the basename of `<path>,\n+\tbase the new branch on the remote-tracking branch, and mark\n+\tthe remote-tracking branch as \"upstream\" from the new branch.\n +\n This can also be set up as the default behaviour by using the\n `worktree.guessRemote` config option.\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 426aea8761..002a569a11 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -43,7 +43,7 @@ static int git_worktree_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\treturn 0;\n+\treturn git_default_config(var, value, cb);\n }\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n@@ -371,8 +371,6 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_worktree_config, NULL);\n-\n \tmemset(&opts, 0, sizeof(opts));\n \topts.checkout = 1;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n@@ -603,7 +601,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(git_worktree_config, NULL);\n \n \tif (ac < 2)\n \t\tusage_with_options(worktree_usage, options);\n\nThomas Gummerer (6):\n  checkout: factor out functions to new lib file\n  worktree: add can be created from any commit-ish\n  worktree: add --[no-]track option to the add subcommand\n  worktree: make add <path> <branch> dwim\n  worktree: add --guess-remote flag to add subcommand\n  add worktree.guessRemote config option\n\n Documentation/config.txt       |  10 ++++\n Documentation/git-worktree.txt |  44 ++++++++++----\n Makefile                       |   1 +\n builtin/checkout.c             |  41 +------------\n builtin/worktree.c             |  46 ++++++++++++++-\n checkout.c                     |  43 ++++++++++++++\n checkout.h                     |  13 +++++\n t/t2025-worktree-add.sh        | 130 +++++++++++++++++++++++++++++++++++++++++\n 8 files changed, 277 insertions(+), 51 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333800","messageId":"20171129200451.16856-2-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171129200451.16856-1-t.gummerer@gmail.com","subject":"[PATCH v6 1/6] checkout: factor out functions to new lib file","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:46Z","receivedAt":"2017-11-29T20:03:28Z","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         | 43 +++++++++++++++++++++++++++++++++++++++++++\n checkout.h         | 13 +++++++++++++\n 4 files changed, 58 insertions(+), 40 deletions(-)\n create mode 100644 checkout.c\n create mode 100644 checkout.h\n\ndiff --git a/Makefile b/Makefile\nindex e53750ca01..a80a8fcca9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -759,6 +759,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 7d8bcc3833..ad8f94044c 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@@ -872,46 +873,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..ac42630f74\n--- /dev/null\n+++ b/checkout.c\n@@ -0,0 +1,43 @@\n+#include \"cache.h\"\n+#include \"remote.h\"\n+#include \"checkout.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.426.gb06021eeb\n\n"},{"id":"333801","messageId":"20171129200451.16856-3-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171129200451.16856-1-t.gummerer@gmail.com","subject":"[PATCH v6 2/6] worktree: add can be created from any commit-ish","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:47Z","receivedAt":"2017-11-29T20:03:29Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add' is documented to take an optional <branch>\nargument, which is checked out in the new worktree.  However it is more\ngenerally possible to use a commit-ish as the optional argument, and\ncheck that out into the new worktree.\n\nDocument that this is a possibility, as new users of git worktree add\nmight find it helpful.\n\nReported-by: Randall S. Becker <rsbecker@nexbridge.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex b472acc356..121895209d 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees\n SYNOPSIS\n --------\n [verse]\n-'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<branch>]\n+'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]\n 'git worktree list' [--porcelain]\n 'git worktree lock' [--reason <string>] <worktree>\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n@@ -45,14 +45,14 @@ specifying `--reason` to explain why the working tree is locked.\n \n COMMANDS\n --------\n-add <path> [<branch>]::\n+add <path> [<commit-ish>]::\n \n-Create `<path>` and checkout `<branch>` into it. The new working directory\n+Create `<path>` and checkout `<commit-ish>` into it. The new working directory\n 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+specified as `<commit-ish>`; it is synonymous with `@{-1}`.\n +\n-If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,\n+If `<commit-ish>` 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@@ -84,25 +84,25 @@ OPTIONS\n \n -f::\n --force::\n-\tBy default, `add` refuses to create a new working tree when `<branch>`\n+\tBy default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and\n \tis already checked out by another working tree. This option overrides\n \tthat safeguard.\n \n -b <new-branch>::\n -B <new-branch>::\n \tWith `add`, create a new branch named `<new-branch>` starting at\n-\t`<branch>`, and check out `<new-branch>` into the new working tree.\n-\tIf `<branch>` is omitted, it defaults to HEAD.\n+\t`<commit-ish>`, and check out `<new-branch>` into the new working tree.\n+\tIf `<commit-ish>` is omitted, it defaults to HEAD.\n \tBy default, `-b` refuses to create a new branch if it already\n \texists. `-B` overrides this safeguard, resetting `<new-branch>` to\n-\t`<branch>`.\n+\t`<commit-ish>`.\n \n --detach::\n \tWith `add`, detach HEAD in the new working tree. See \"DETACHED HEAD\"\n \tin linkgit:git-checkout[1].\n \n --[no-]checkout::\n-\tBy default, `add` checks out `<branch>`, however, `--no-checkout` can\n+\tBy default, `add` checks out `<commit-ish>`, however, `--no-checkout` can\n \tbe used to suppress checkout in order to make customizations,\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333802","messageId":"20171129200451.16856-4-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171129200451.16856-1-t.gummerer@gmail.com","subject":"[PATCH v6 3/6] worktree: add --[no-]track option to the add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:48Z","receivedAt":"2017-11-29T20:03:31Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git worktree add' sets up tracking branches if '<branch>' is\na remote tracking branch, and doesn't set them up otherwise, as is the\ndefault for 'git branch'.\n\nThis may or may not be what the user wants.  Allow overriding this\nbehaviour with a --[no-]track flag that gets passed through to 'git\nbranch'.\n\nWe already respect branch.autoSetupMerge, as 'git worktree' just calls\n'git branch' internally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  6 +++++\n builtin/worktree.c             |  8 +++++++\n t/t2025-worktree-add.sh        | 51 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 65 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 121895209d..15e58b18f7 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -107,6 +107,12 @@ OPTIONS\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]track::\n+\tWhen creating a new branch, if `<commit-ish>` is a branch,\n+\tmark it as \"upstream\" from the new branch.  This is the\n+\tdefault if `<commit-ish>` is a remote-tracking branch.  See\n+\t\"--track\" in linkgit:git-branch[1] for details.\n+\n --lock::\n \tKeep the working tree locked after creation. This is the\n \tequivalent of `git worktree lock` after `git worktree add`,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex ed043d5f1c..ea9678cac8 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -341,6 +341,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+\tconst char *opt_track = NULL;\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 +351,9 @@ 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_PASSTHRU(0, \"track\", &opt_track, NULL,\n+\t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n+\t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n \t\tOPT_END()\n \t};\n \n@@ -394,9 +398,13 @@ static int add(int ac, const char **av, const char *prefix)\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 (opt_track)\n+\t\t\targv_array_push(&cp.args, opt_track);\n \t\tif (run_command(&cp))\n \t\t\treturn -1;\n \t\tbranch = opts.new_branch;\n+\t} else if (opt_track) {\n+\t\tdie(_(\"--[no-]track can only be used if a new branch is created\"));\n \t}\n \n \tUNLEAK(path);\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex b5c47ac602..72e8b62927 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -313,5 +313,56 @@ test_expect_success 'checkout a branch under bisect' '\n 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+# 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 '--track sets up tracking' '\n+\ttest_when_finished rm -rf track &&\n+\tgit worktree add --track -b track track master &&\n+\ttest_branch_upstream track . master\n+'\n+\n+# setup remote repository $1 and repository $2 with $1 set up as\n+# remote.  The remote has two branches, master and foo.\n+setup_remote_repo () {\n+\tgit init $1 &&\n+\t(\n+\t\tcd $1 &&\n+\t\ttest_commit $1_master &&\n+\t\tgit checkout -b foo &&\n+\t\ttest_commit upstream_foo\n+\t) &&\n+\tgit init $2 &&\n+\t(\n+\t\tcd $2 &&\n+\t\ttest_commit $2_master &&\n+\t\tgit remote add $1 ../$1 &&\n+\t\tgit config remote.$1.fetch \\\n+\t\t\t\"refs/heads/*:refs/remotes/$1/*\" &&\n+\t\tgit fetch --all\n+\t)\n+}\n+\n+test_expect_success '--no-track avoids setting up tracking' '\n+\ttest_when_finished rm -rf repo_upstream repo_local foo &&\n+\tsetup_remote_repo repo_upstream repo_local &&\n+\t(\n+\t\tcd repo_local &&\n+\t\tgit worktree add --no-track -b foo ../foo repo_upstream/foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\ttest_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo\n+\t)\n+'\n \n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333803","messageId":"20171129200451.16856-6-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171129200451.16856-1-t.gummerer@gmail.com","subject":"[PATCH v6 5/6] worktree: add --guess-remote flag to add subcommand","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:50Z","receivedAt":"2017-11-29T20:03:34Z","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\nIt's sometimes useful to have 'git worktree add <path> behave more like\nthe dwim machinery in 'git checkout <new-branch>', i.e. check if the new\nbranch name, derived from the basename of the <path>, uniquely matches\nthe branch name of a remote-tracking branch, and if so check out that\nbranch and set the upstream to the remote-tracking branch.\n\nAdd a new --guess-remote option that enables exactly that behaviour.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-worktree.txt |  7 +++++++\n builtin/worktree.c             | 10 ++++++++++\n t/t2025-worktree-add.sh        | 29 +++++++++++++++++++++++++++++\n 3 files changed, 46 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 3044d305a6..a4ffee5e08 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -115,6 +115,13 @@ OPTIONS\n \tsuch as configuring sparse-checkout. See \"Sparse checkout\"\n \tin linkgit:git-read-tree[1].\n \n+--[no-]guess-remote::\n+\tWith `worktree add <path>`, withouth `<commit-ish>`, instead\n+\tof creating a new branch from HEAD, if there exists a tracking\n+\tbranch in exactly one remote matching the basename of `<path>,\n+\tbase the new branch on the remote-tracking branch, and mark\n+\tthe remote-tracking branch as \"upstream\" from the new branch.\n+\n --[no-]track::\n \tWhen creating a new branch, if `<commit-ish>` is a branch,\n \tmark it as \"upstream\" from the new branch.  This is the\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 7021d02585..15cb1600ee 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -343,6 +343,7 @@ static int add(int ac, const char **av, const char *prefix)\n \tchar *path;\n \tconst char *branch;\n \tconst char *opt_track = NULL;\n+\tint guess_remote = 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@@ -355,6 +356,8 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_PASSTHRU(0, \"track\", &opt_track, NULL,\n \t\t\t     N_(\"set up tracking mode (see git-branch(1))\"),\n \t\t\t     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),\n+\t\tOPT_BOOL(0, \"guess-remote\", &guess_remote,\n+\t\t\t N_(\"try to match the new branch name with a remote-tracking branch\")),\n \t\tOPT_END()\n \t};\n \n@@ -389,6 +392,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 (guess_remote) {\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 96ebc63d04..d25c774cb7 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -384,4 +384,33 @@ test_expect_success '\"add\" <path> <branch> dwims' '\n \t)\n '\n \n+test_expect_success 'git worktree add does not match remote' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit worktree add ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\t! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n+test_expect_success 'git worktree add --guess-remote sets up tracking' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit worktree add --guess-remote ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_branch_upstream foo repo_a foo &&\n+\t\ttest_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333804","messageId":"20171129200451.16856-7-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171129200451.16856-1-t.gummerer@gmail.com","subject":"[PATCH v6 6/6] add worktree.guessRemote config option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:51Z","receivedAt":"2017-11-29T20:03:38Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Some users might want to have the --guess-remote option introduced in\nthe previous commit on by default, so they don't have to type it out\nevery time they create a new worktree.\n\nAdd a config option worktree.guessRemote that allows users to configure\nthe default behaviour for themselves.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/config.txt       | 10 ++++++++++\n Documentation/git-worktree.txt |  3 +++\n builtin/worktree.c             | 14 ++++++++++++--\n t/t2025-worktree-add.sh        | 31 +++++++++++++++++++++++++++++++\n 4 files changed, 56 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5f65fa9234..4966d90ebb 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -3425,3 +3425,13 @@ web.browser::\n \tSpecify a web browser that may be used by some commands.\n \tCurrently only linkgit:git-instaweb[1] and linkgit:git-help[1]\n \tmay use it.\n+\n+worktree.guessRemote::\n+\tWith `add`, if no branch argument, and neither of `-b` nor\n+\t`-B` nor `--detach` are given, the command defaults to\n+\tcreating a new branch from HEAD.  If `worktree.guessRemote` is\n+\tset to true, `worktree add` tries to find a remote-tracking\n+\tbranch whose name uniquely matches the new branch name.  If\n+\tsuch a branch exists, it is checked out and set as \"upstream\"\n+\tfor the new branch.  If no such match can be found, it falls\n+\tback to creating a new branch from the current HEAD.\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex a4ffee5e08..89ad0faecf 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -121,6 +121,9 @@ OPTIONS\n \tbranch in exactly one remote matching the basename of `<path>,\n \tbase the new branch on the remote-tracking branch, and mark\n \tthe remote-tracking branch as \"upstream\" from the new branch.\n++\n+This can also be set up as the default behaviour by using the\n+`worktree.guessRemote` config option.\n \n --[no-]track::\n \tWhen creating a new branch, if `<commit-ish>` is a branch,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 15cb1600ee..002a569a11 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -33,8 +33,19 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n+static int guess_remote;\n static timestamp_t expire;\n \n+static int git_worktree_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"worktree.guessremote\")) {\n+\t\tguess_remote = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n \tstruct stat st;\n@@ -343,7 +354,6 @@ static int add(int ac, const char **av, const char *prefix)\n \tchar *path;\n \tconst char *branch;\n \tconst char *opt_track = NULL;\n-\tint guess_remote = 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@@ -591,7 +601,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(git_worktree_config, NULL);\n \n \tif (ac < 2)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex d25c774cb7..6ce9b9c070 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -413,4 +413,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '\n \t)\n '\n \n+test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit config worktree.guessRemote true &&\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\ttest_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n+test_expect_success 'git worktree --no-guess-remote option overrides config' '\n+\ttest_when_finished rm -rf repo_a repo_b foo &&\n+\tsetup_remote_repo repo_a repo_b &&\n+\t(\n+\t\tcd repo_b &&\n+\t\tgit config worktree.guessRemote true &&\n+\t\tgit worktree add --no-guess-remote ../foo\n+\t) &&\n+\t(\n+\t\tcd foo &&\n+\t\ttest_must_fail git config \"branch.foo.remote\" &&\n+\t\ttest_must_fail git config \"branch.foo.merge\" &&\n+\t\t! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"},{"id":"333805","messageId":"20171129200451.16856-5-t.gummerer@gmail.com","threadId":"47303","inReplyTo":"20171129200451.16856-1-t.gummerer@gmail.com","subject":"[PATCH v6 4/6] worktree: make add <path> <branch> dwim","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-11-29T20:04:49Z","receivedAt":"2017-11-29T20:03:40Z","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 |  8 ++++++++\n builtin/worktree.c             | 16 ++++++++++++++++\n t/t2025-worktree-add.sh        | 19 +++++++++++++++++++\n 3 files changed, 43 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 15e58b18f7..3044d305a6 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -52,6 +52,14 @@ 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 `<commit-ish>`; it is synonymous with `@{-1}`.\n +\n+If <commit-ish> is a branch name (call it `<branch>` and is not found,\n+and neither `-b` nor `-B` nor `--detach` are used, but there does\n+exist a tracking branch in exactly one remote (call it `<remote>`)\n+with a matching name, treat as equivalent to\n+------------\n+$ git worktree add --track -b <branch> <path> <remote>/<branch>\n+------------\n++\n If `<commit-ish>` 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 ea9678cac8..7021d02585 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@@ -390,6 +391,21 @@ 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\t\tif (remote) {\n+\t\t\t\topts.new_branch = branch;\n+\t\t\t\tbranch = remote;\n+\t\t\t}\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 72e8b62927..96ebc63d04 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -365,4 +365,23 @@ test_expect_success '--no-track avoids setting up tracking' '\n \t)\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 repo_dwim foo &&\n+\tsetup_remote_repo repo_upstream repo_dwim &&\n+\tgit init repo_dwim &&\n+\t(\n+\t\tcd repo_dwim &&\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\ttest_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.426.gb06021eeb\n\n"}]}