git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v4 0/4] make git worktree add dwim more
       [not found] <mailto:20171118224706.13810-1-t.gummerer@gmail.com>
@ 2017-11-22 22:30 ` Thomas Gummerer
  2017-11-22 22:30   ` [PATCH v4 1/4] checkout: factor out functions to new lib file Thomas Gummerer
                     ` (4 more replies)
  0 siblings, 5 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-22 22:30 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Thomas Gummerer

The previous rounds were at
https://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/,
https://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/ and
https://public-inbox.org/git/20171118224706.13810-1-t.gummerer@gmail.com/.

Thanks Eric for the review of the previous round.

The main change is that the --[no-]track flag now works generally
instead of just disabling the new dwim mode.

Interdiff below:
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index eedead2c4c..abc8f1f50d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -56,22 +56,23 @@ If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are
 used, but there does exist a tracking branch in exactly one remote
 (call it <remote>) with a matching name, treat as equivalent to
 ------------
-$ git worktree add -b <branch> <path> <remote>/<branch>
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,
 then, as a convenience, if there exists a tracking branch in exactly
-one remote (call it <remote>) matching the basename of the path
-(call it <branch>), treat it as equivalent to
+one remote (call it `<remote>`) matching the basename of the path
+(call it `<branch>`), treat it as equivalent to
 ------------
-$ git worktree add -b <branch> <path> <remote>/<branch>
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
-If no tracking branch exists in exactly one remote, <branch> is
+If no tracking branch exists in exactly one remote, `<branch>` is
 created based on HEAD, as if `-b $(basename <path>)` was specified.
 +
 To disable the behaviour of trying to match the basename of <path> to
 a remote, and always create a new branch from HEAD, the `--no-track`
 flag can be passed to `git worktree add`.
+
 list::
 
 List details of each worktree.  The main worktree is listed first, followed by
@@ -123,6 +124,12 @@ OPTIONS
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]track::
+	With `--track` `<branch>` is set as "tracking" branch for
+	`<new-branch>`.  This is the default if `<branch>` is a remote
+	tracking branch, and can be suppressed with `--no-track`.  See
+	also linkgit:git-branch[1].
+
 --lock::
 	Keep the working tree locked after creation. This is the
 	equivalent of `git worktree lock` after `git worktree add`,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index b2a6dd020c..cbcceb0385 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -342,7 +342,7 @@ static int add(int ac, const char **av, const char *prefix)
 	const char *new_branch_force = NULL;
 	char *path;
 	const char *branch;
-	int track_dwim = 1;
+	const char *opt_track = NULL;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -352,7 +352,9 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
 		OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
 		OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
-		OPT_BOOL(0, "track", &track_dwim, N_("checkout upstream branch if there's a unique match")),
+		OPT_PASSTHRU(0, "track", &opt_track, NULL,
+			     N_("set up tracking mode (see git-branch(1))"),
+			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
 		OPT_END()
 	};
 
@@ -387,7 +389,7 @@ static int add(int ac, const char **av, const char *prefix)
 		int n;
 		const char *s = worktree_basename(path, &n);
 		opts.new_branch = xstrndup(s, n);
-		if (track_dwim) {
+		if (!opt_track || strcmp(opt_track, "--no-track")) {
 			struct object_id oid;
 			const char *remote =
 				unique_tracking_name(opts.new_branch, &oid);
@@ -402,11 +404,12 @@ static int add(int ac, const char **av, const char *prefix)
 		const char *remote;
 
 		commit = lookup_commit_reference_by_name(branch);
-		if (!commit)
+		if (!commit) {
 			remote = unique_tracking_name(branch, &oid);
-		if (!commit && remote) {
-			opts.new_branch = branch;
-			branch = remote;
+			if (remote) {
+				opts.new_branch = branch;
+				branch = remote;
+			}
 		}
 	}
 
@@ -418,9 +421,13 @@ static int add(int ac, const char **av, const char *prefix)
 			argv_array_push(&cp.args, "--force");
 		argv_array_push(&cp.args, opts.new_branch);
 		argv_array_push(&cp.args, branch);
+		if (opt_track)
+			argv_array_push(&cp.args, opt_track);
 		if (run_command(&cp))
 			return -1;
 		branch = opts.new_branch;
+	} else if (opt_track) {
+		die(_("--[no-]track can only be used if a new branch is created"));
 	}
 
 	UNLEAK(path);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 87e233f812..6fd3da4036 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -6,16 +6,6 @@ test_description='test git worktree add'
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
-# Is branch "refs/heads/$1" set to pull from "$2/$3"?
-test_branch_upstream () {
-	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
-	{
-		git config "branch.$1.remote" &&
-		git config "branch.$1.merge"
-	} >actual.upstream &&
-	test_cmp expect.upstream actual.upstream
-}
-
 test_expect_success 'setup' '
 	test_commit init
 '
@@ -323,32 +313,72 @@ test_expect_success 'checkout a branch under bisect' '
 test_expect_success 'rename a branch under bisect not allowed' '
 	test_must_fail git branch -M under-bisect bisect-with-new-name
 '
+# Is branch "refs/heads/$1" set to pull from "$2/$3"?
+test_branch_upstream () {
+	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
+	{
+		git config "branch.$1.remote" &&
+		git config "branch.$1.merge"
+	} >actual.upstream &&
+	test_cmp expect.upstream actual.upstream
+}
 
-test_expect_success '"add" <path> <non-existent-branch> fails' '
-	test_must_fail git worktree add foo non-existent
+test_expect_success '--track sets up tracking' '
+	test_when_finished rm -rf track &&
+	git worktree add --track -b track track master &&
+	git config "branch.track.merge" &&
+	(
+		test_branch_upstream track . master
+	)
 '
 
-test_expect_success '"add" <path> <branch> dwims' '
-	test_when_finished rm -rf repo_upstream &&
-	test_when_finished rm -rf repo_dwim &&
-	test_when_finished rm -rf foo &&
-	git init repo_upstream &&
+# setup remote repository $1 and repository $2 with $1 set up as
+# remote.  The remote has two branches, master and foo.
+setup_remote_repo () {
+	git init $1 &&
 	(
-		cd repo_upstream &&
-		test_commit upstream_master &&
+		cd $1 &&
+		test_commit $1_master &&
 		git checkout -b foo &&
-		test_commit a_foo
+		test_commit upstream_foo
 	) &&
+	git init $2 &&
+	(
+		cd $2 &&
+		test_commit $2_master &&
+		git remote add $1 ../$1 &&
+		git config remote.$1.fetch \
+			"refs/heads/*:refs/remotes/$1/*" &&
+		git fetch --all
+	)
+}
+
+test_expect_success '--no-track avoids setting up tracking' '
+	test_when_finished rm -rf repo_upstream repo_local foo &&
+	setup_remote_repo repo_upstream repo_local &&
+	(
+		cd repo_local &&
+		git worktree add --no-track -b foo ../foo repo_upstream/foo
+	) &&
+	(
+		cd foo &&
+		! test_branch_upstream foo repo_upstream foo &&
+		git rev-parse repo_upstream/foo >expect &&
+		git rev-parse foo >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success '"add" <path> <non-existent-branch> fails' '
+	test_must_fail git worktree add foo non-existent
+'
+
+test_expect_success '"add" <path> <branch> dwims' '
+	test_when_finished rm -rf repo_upstream repo_dwim foo &&
+	setup_remote_repo repo_upstream repo_dwim &&
 	git init repo_dwim &&
 	(
 		cd repo_dwim &&
-		test_commit dwim_master &&
-		git remote add repo_upstream ../repo_upstream &&
-		git config remote.repo_upstream.fetch \
-			  "refs/heads/*:refs/remotes/repo_upstream/*" &&
-		git fetch --all &&
-		test_must_fail git worktree add -b foo ../foo foo &&
-		test_must_fail git worktree add --detach ../foo foo &&
 		git worktree add ../foo foo
 	) &&
 	(
@@ -361,60 +391,32 @@ test_expect_success '"add" <path> <branch> dwims' '
 '
 
 test_expect_success 'git worktree add --no-track does not set up tracking' '
-	test_when_finished rm -rf repo_a &&
-	test_when_finished rm -rf repo_b &&
-	test_when_finished rm -rf foo &&
-	git init repo_a &&
-	(
-		cd repo_a &&
-		test_commit a_master &&
-		git checkout -b foo &&
-		test_commit a_foo
-	) &&
-	git init repo_b &&
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
 	(
 		cd repo_b &&
-		test_commit b_master &&
-		git remote add repo_a ../repo_a &&
-		git config remote.repo_a.fetch \
-			"+refs/heads/*:refs/remotes/other_a/*" &&
-		git fetch --all &&
 		git worktree add --no-track ../foo
 	) &&
 	(
 		cd foo &&
 		! test_branch_upstream foo repo_a foo &&
-		git rev-parse other_a/foo >expect &&
+		git rev-parse repo_a/foo >expect &&
 		git rev-parse foo >actual &&
 		! test_cmp expect actual
 	)
 '
 
 test_expect_success 'git worktree add sets up tracking' '
-	test_when_finished rm -rf repo_a &&
-	test_when_finished rm -rf repo_b &&
-	test_when_finished rm -rf foo &&
-	git init repo_a &&
-	(
-		cd repo_a &&
-		test_commit a_master &&
-		git checkout -b foo &&
-		test_commit a_foo
-	) &&
-	git init repo_b &&
+	test_when_finished rm -rf repo_a repo_b &&
+	setup_remote_repo repo_a repo_b &&
 	(
 		cd repo_b &&
-		test_commit b_master &&
-		git remote add repo_a ../repo_a &&
-		git config remote.repo_a.fetch \
-			"+refs/heads/*:refs/remotes/other_a/*" &&
-		git fetch --all &&
 		git worktree add ../foo
 	) &&
 	(
 		cd foo &&
 		test_branch_upstream foo repo_a foo &&
-		git rev-parse other_a/foo >expect &&
+		git rev-parse repo_a/foo >expect &&
 		git rev-parse foo >actual &&
 		test_cmp expect actual
 	)


Thomas Gummerer (4):
  checkout: factor out functions to new lib file
  worktree: add --[no-]track option to the add subcommand
  worktree: make add <path> <branch> dwim
  worktree: make add <path> dwim

 Documentation/git-worktree.txt |  27 ++++++++++-
 Makefile                       |   1 +
 builtin/checkout.c             |  41 +---------------
 builtin/worktree.c             |  31 ++++++++++++
 checkout.c                     |  42 ++++++++++++++++
 checkout.h                     |  13 +++++
 t/t2025-worktree-add.sh        | 108 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 221 insertions(+), 42 deletions(-)
 create mode 100644 checkout.c
 create mode 100644 checkout.h

-- 
2.15.0.345.gf926f18f3


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v4 1/4] checkout: factor out functions to new lib file
  2017-11-22 22:30 ` [PATCH v4 0/4] make git worktree add dwim more Thomas Gummerer
@ 2017-11-22 22:30   ` Thomas Gummerer
  2017-11-24  6:47     ` Junio C Hamano
  2017-11-22 22:30   ` [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-22 22:30 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Thomas Gummerer

Factor the functions out, so they can be re-used from other places.  In
particular these functions will be re-used in builtin/worktree.c to make
git worktree add dwim more.

While there add some docs to the function.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Makefile           |  1 +
 builtin/checkout.c | 41 +----------------------------------------
 checkout.c         | 42 ++++++++++++++++++++++++++++++++++++++++++
 checkout.h         | 13 +++++++++++++
 4 files changed, 57 insertions(+), 40 deletions(-)
 create mode 100644 checkout.c
 create mode 100644 checkout.h

diff --git a/Makefile b/Makefile
index cd75985991..8d603c7443 100644
--- a/Makefile
+++ b/Makefile
@@ -757,6 +757,7 @@ LIB_OBJS += branch.o
 LIB_OBJS += bulk-checkin.o
 LIB_OBJS += bundle.o
 LIB_OBJS += cache-tree.o
+LIB_OBJS += checkout.o
 LIB_OBJS += color.o
 LIB_OBJS += column.o
 LIB_OBJS += combine-diff.o
diff --git a/builtin/checkout.c b/builtin/checkout.c
index fc4f8fd2ea..9e1cfd10b3 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "config.h"
+#include "checkout.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "refs.h"
@@ -874,46 +875,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
 	return git_xmerge_config(var, value, NULL);
 }
 
-struct tracking_name_data {
-	/* const */ char *src_ref;
-	char *dst_ref;
-	struct object_id *dst_oid;
-	int unique;
-};
-
-static int check_tracking_name(struct remote *remote, void *cb_data)
-{
-	struct tracking_name_data *cb = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
-	query.src = cb->src_ref;
-	if (remote_find_tracking(remote, &query) ||
-	    get_oid(query.dst, cb->dst_oid)) {
-		free(query.dst);
-		return 0;
-	}
-	if (cb->dst_ref) {
-		free(query.dst);
-		cb->unique = 0;
-		return 0;
-	}
-	cb->dst_ref = query.dst;
-	return 0;
-}
-
-static const char *unique_tracking_name(const char *name, struct object_id *oid)
-{
-	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
-	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
-	cb_data.dst_oid = oid;
-	for_each_remote(check_tracking_name, &cb_data);
-	free(cb_data.src_ref);
-	if (cb_data.unique)
-		return cb_data.dst_ref;
-	free(cb_data.dst_ref);
-	return NULL;
-}
-
 static int parse_branchname_arg(int argc, const char **argv,
 				int dwim_new_local_branch_ok,
 				struct branch_info *new,
diff --git a/checkout.c b/checkout.c
new file mode 100644
index 0000000000..b0c744d37a
--- /dev/null
+++ b/checkout.c
@@ -0,0 +1,42 @@
+#include "cache.h"
+#include "remote.h"
+
+struct tracking_name_data {
+	/* const */ char *src_ref;
+	char *dst_ref;
+	struct object_id *dst_oid;
+	int unique;
+};
+
+static int check_tracking_name(struct remote *remote, void *cb_data)
+{
+	struct tracking_name_data *cb = cb_data;
+	struct refspec query;
+	memset(&query, 0, sizeof(struct refspec));
+	query.src = cb->src_ref;
+	if (remote_find_tracking(remote, &query) ||
+	    get_oid(query.dst, cb->dst_oid)) {
+		free(query.dst);
+		return 0;
+	}
+	if (cb->dst_ref) {
+		free(query.dst);
+		cb->unique = 0;
+		return 0;
+	}
+	cb->dst_ref = query.dst;
+	return 0;
+}
+
+const char *unique_tracking_name(const char *name, struct object_id *oid)
+{
+	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
+	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
+	cb_data.dst_oid = oid;
+	for_each_remote(check_tracking_name, &cb_data);
+	free(cb_data.src_ref);
+	if (cb_data.unique)
+		return cb_data.dst_ref;
+	free(cb_data.dst_ref);
+	return NULL;
+}
diff --git a/checkout.h b/checkout.h
new file mode 100644
index 0000000000..9980711179
--- /dev/null
+++ b/checkout.h
@@ -0,0 +1,13 @@
+#ifndef CHECKOUT_H
+#define CHECKOUT_H
+
+#include "cache.h"
+
+/*
+ * Check if the branch name uniquely matches a branch name on a remote
+ * tracking branch.  Return the name of the remote if such a branch
+ * exists, NULL otherwise.
+ */
+extern const char *unique_tracking_name(const char *name, struct object_id *oid);
+
+#endif /* CHECKOUT_H */
-- 
2.15.0.345.gf926f18f3


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand
  2017-11-22 22:30 ` [PATCH v4 0/4] make git worktree add dwim more Thomas Gummerer
  2017-11-22 22:30   ` [PATCH v4 1/4] checkout: factor out functions to new lib file Thomas Gummerer
@ 2017-11-22 22:30   ` Thomas Gummerer
  2017-11-24  6:57     ` Junio C Hamano
  2017-11-22 22:30   ` [PATCH v4 3/4] worktree: make add <path> <branch> dwim Thomas Gummerer
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-22 22:30 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Thomas Gummerer

Currently 'git worktree add' sets up tracking branches if '<branch>' is
a remote tracking branch, and doesn't set them up otherwise, as is the
default for 'git branch'.

This may or may not be what the user wants.  Allow overriding this
behaviour with a --[no-]track flag that gets passed through to 'git
branch'.

We already respect branch.autoSetupMerge, as 'git worktree' just calls
'git branch' internally.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  6 +++++
 builtin/worktree.c             |  8 ++++++
 t/t2025-worktree-add.sh        | 55 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index b472acc356..798a642f84 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -107,6 +107,12 @@ OPTIONS
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]track::
+	With `--track` `<branch>` is set as "tracking" branch for
+	`<new-branch>`.  This is the default if `<branch>` is a remote
+	tracking branch, and can be suppressed with `--no-track`.  See
+	also linkgit:git-branch[1].
+
 --lock::
 	Keep the working tree locked after creation. This is the
 	equivalent of `git worktree lock` after `git worktree add`,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7b9307aa58..8f9446d43c 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -341,6 +341,7 @@ static int add(int ac, const char **av, const char *prefix)
 	const char *new_branch_force = NULL;
 	char *path;
 	const char *branch;
+	const char *opt_track = NULL;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -350,6 +351,9 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
 		OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
 		OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+		OPT_PASSTHRU(0, "track", &opt_track, NULL,
+			     N_("set up tracking mode (see git-branch(1))"),
+			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
 		OPT_END()
 	};
 
@@ -394,9 +398,13 @@ static int add(int ac, const char **av, const char *prefix)
 			argv_array_push(&cp.args, "--force");
 		argv_array_push(&cp.args, opts.new_branch);
 		argv_array_push(&cp.args, branch);
+		if (opt_track)
+			argv_array_push(&cp.args, opt_track);
 		if (run_command(&cp))
 			return -1;
 		branch = opts.new_branch;
+	} else if (opt_track) {
+		die(_("--[no-]track can only be used if a new branch is created"));
 	}
 
 	UNLEAK(path);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index b5c47ac602..53042ce565 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -313,5 +313,60 @@ test_expect_success 'checkout a branch under bisect' '
 test_expect_success 'rename a branch under bisect not allowed' '
 	test_must_fail git branch -M under-bisect bisect-with-new-name
 '
+# Is branch "refs/heads/$1" set to pull from "$2/$3"?
+test_branch_upstream () {
+	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
+	{
+		git config "branch.$1.remote" &&
+		git config "branch.$1.merge"
+	} >actual.upstream &&
+	test_cmp expect.upstream actual.upstream
+}
+
+test_expect_success '--track sets up tracking' '
+	test_when_finished rm -rf track &&
+	git worktree add --track -b track track master &&
+	git config "branch.track.merge" &&
+	(
+		test_branch_upstream track . master
+	)
+'
+
+# setup remote repository $1 and repository $2 with $1 set up as
+# remote.  The remote has two branches, master and foo.
+setup_remote_repo () {
+	git init $1 &&
+	(
+		cd $1 &&
+		test_commit $1_master &&
+		git checkout -b foo &&
+		test_commit upstream_foo
+	) &&
+	git init $2 &&
+	(
+		cd $2 &&
+		test_commit $2_master &&
+		git remote add $1 ../$1 &&
+		git config remote.$1.fetch \
+			"refs/heads/*:refs/remotes/$1/*" &&
+		git fetch --all
+	)
+}
+
+test_expect_success '--no-track avoids setting up tracking' '
+	test_when_finished rm -rf repo_upstream repo_local foo &&
+	setup_remote_repo repo_upstream repo_local &&
+	(
+		cd repo_local &&
+		git worktree add --no-track -b foo ../foo repo_upstream/foo
+	) &&
+	(
+		cd foo &&
+		! test_branch_upstream foo repo_upstream foo &&
+		git rev-parse repo_upstream/foo >expect &&
+		git rev-parse foo >actual &&
+		test_cmp expect actual
+	)
+'
 
 test_done
-- 
2.15.0.345.gf926f18f3


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v4 3/4] worktree: make add <path> <branch> dwim
  2017-11-22 22:30 ` [PATCH v4 0/4] make git worktree add dwim more Thomas Gummerer
  2017-11-22 22:30   ` [PATCH v4 1/4] checkout: factor out functions to new lib file Thomas Gummerer
  2017-11-22 22:30   ` [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
@ 2017-11-22 22:30   ` Thomas Gummerer
  2017-11-24  6:59     ` Junio C Hamano
  2017-11-22 22:30   ` [PATCH v4 4/4] worktree: make add <path> dwim Thomas Gummerer
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
  4 siblings, 1 reply; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-22 22:30 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Thomas Gummerer

Currently 'git worktree add <path> <branch>', errors out when 'branch'
is not a local branch.   It has no additional dwim'ing features that one
might expect.

Make it behave more like 'git checkout <branch>' when the branch doesn't
exist locally, but a remote tracking branch uniquely matches the desired
branch name, i.e. create a new branch from the remote tracking branch
and set the upstream to the remote tracking branch.

As 'git worktree add' currently just dies in this situation, there are
no backwards compatibility worries when introducing this feature.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  7 +++++++
 builtin/worktree.c             | 16 ++++++++++++++++
 t/t2025-worktree-add.sh        | 21 +++++++++++++++++++++
 3 files changed, 44 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 798a642f84..45642d3b7f 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -52,6 +52,13 @@ is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc. `-` may also be
 specified as `<branch>`; it is synonymous with `@{-1}`.
 +
+If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are
+used, but there does exist a tracking branch in exactly one remote
+(call it <remote>) with a matching name, treat as equivalent to
+------------
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
+------------
++
 If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,
 then, as a convenience, a new branch based at HEAD is created automatically,
 as if `-b $(basename <path>)` was specified.
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 8f9446d43c..e9cc3f3872 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "checkout.h"
 #include "config.h"
 #include "builtin.h"
 #include "dir.h"
@@ -390,6 +391,21 @@ static int add(int ac, const char **av, const char *prefix)
 		opts.new_branch = xstrndup(s, n);
 	}
 
+	if (ac == 2 && !opts.new_branch && !opts.detach) {
+		struct object_id oid;
+		struct commit *commit;
+		const char *remote;
+
+		commit = lookup_commit_reference_by_name(branch);
+		if (!commit) {
+			remote = unique_tracking_name(branch, &oid);
+			if (remote) {
+				opts.new_branch = branch;
+				branch = remote;
+			}
+		}
+	}
+
 	if (opts.new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 		cp.git_cmd = 1;
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 53042ce565..ea144938a9 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -369,4 +369,25 @@ test_expect_success '--no-track avoids setting up tracking' '
 	)
 '
 
+test_expect_success '"add" <path> <non-existent-branch> fails' '
+	test_must_fail git worktree add foo non-existent
+'
+
+test_expect_success '"add" <path> <branch> dwims' '
+	test_when_finished rm -rf repo_upstream repo_dwim foo &&
+	setup_remote_repo repo_upstream repo_dwim &&
+	git init repo_dwim &&
+	(
+		cd repo_dwim &&
+		git worktree add ../foo foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_upstream foo &&
+		git rev-parse repo_upstream/foo >expect &&
+		git rev-parse foo >actual &&
+		test_cmp expect actual
+	)
+'
+
 test_done
-- 
2.15.0.345.gf926f18f3


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-22 22:30 ` [PATCH v4 0/4] make git worktree add dwim more Thomas Gummerer
                     ` (2 preceding siblings ...)
  2017-11-22 22:30   ` [PATCH v4 3/4] worktree: make add <path> <branch> dwim Thomas Gummerer
@ 2017-11-22 22:30   ` Thomas Gummerer
  2017-11-24  7:11     ` Junio C Hamano
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
  4 siblings, 1 reply; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-22 22:30 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the <path>, that matches the HEAD of whichever worktree we
were on when calling "git worktree add <path>".

Make 'git worktree add <path> behave more like the dwim machinery in
'git checkout <new-branch>', i.e. check if the new branch name uniquely
matches the branch name of a remote tracking branch, and if so check out
that branch and set the upstream to the remote tracking branch.

This is a change of behaviour compared to the current behaviour, where
we create a new branch matching HEAD.  However as 'git worktree' is
still an experimental feature, and it's easy to notice/correct the
behaviour in case it's not what the user desired it's probably okay to
break existing behaviour here.

In order to also satisfy users who want the current behaviour of
creating a new branch from HEAD, add a '--no-track' flag, which disables
the new behaviour, and keeps the old behaviour of creating a new branch
from the head of the current worktree.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt | 14 ++++++++++++--
 builtin/worktree.c             |  7 +++++++
 t/t2025-worktree-add.sh        | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 45642d3b7f..abc8f1f50d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -60,8 +60,18 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, if there exists a tracking branch in exactly
+one remote (call it `<remote>`) matching the basename of the path
+(call it `<branch>`), treat it as equivalent to
+------------
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
+------------
+If no tracking branch exists in exactly one remote, `<branch>` is
+created based on HEAD, as if `-b $(basename <path>)` was specified.
++
+To disable the behaviour of trying to match the basename of <path> to
+a remote, and always create a new branch from HEAD, the `--no-track`
+flag can be passed to `git worktree add`.
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index e9cc3f3872..cbcceb0385 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -389,6 +389,13 @@ static int add(int ac, const char **av, const char *prefix)
 		int n;
 		const char *s = worktree_basename(path, &n);
 		opts.new_branch = xstrndup(s, n);
+		if (!opt_track || strcmp(opt_track, "--no-track")) {
+			struct object_id oid;
+			const char *remote =
+				unique_tracking_name(opts.new_branch, &oid);
+			if (remote)
+				branch = remote;
+		}
 	}
 
 	if (ac == 2 && !opts.new_branch && !opts.detach) {
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index ea144938a9..6fd3da4036 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -390,4 +390,36 @@ test_expect_success '"add" <path> <branch> dwims' '
 	)
 '
 
+test_expect_success 'git worktree add --no-track does not set up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git worktree add --no-track ../foo
+	) &&
+	(
+		cd foo &&
+		! test_branch_upstream foo repo_a foo &&
+		git rev-parse repo_a/foo >expect &&
+		git rev-parse foo >actual &&
+		! test_cmp expect actual
+	)
+'
+
+test_expect_success 'git worktree add sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git worktree add ../foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_a foo &&
+		git rev-parse repo_a/foo >expect &&
+		git rev-parse foo >actual &&
+		test_cmp expect actual
+	)
+'
+
 test_done
-- 
2.15.0.345.gf926f18f3


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 1/4] checkout: factor out functions to new lib file
  2017-11-22 22:30   ` [PATCH v4 1/4] checkout: factor out functions to new lib file Thomas Gummerer
@ 2017-11-24  6:47     ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2017-11-24  6:47 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

Thomas Gummerer <t.gummerer@gmail.com> writes:

> Factor the functions out, so they can be re-used from other places.  In
> particular these functions will be re-used in builtin/worktree.c to make
> git worktree add dwim more.
>
> While there add some docs to the function.
>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---
>  Makefile           |  1 +
>  builtin/checkout.c | 41 +----------------------------------------
>  checkout.c         | 42 ++++++++++++++++++++++++++++++++++++++++++
>  checkout.h         | 13 +++++++++++++
>  4 files changed, 57 insertions(+), 40 deletions(-)
>  create mode 100644 checkout.c
>  create mode 100644 checkout.h
>
> diff --git a/Makefile b/Makefile
> index cd75985991..8d603c7443 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -757,6 +757,7 @@ LIB_OBJS += branch.o
>  LIB_OBJS += bulk-checkin.o
>  LIB_OBJS += bundle.o
>  LIB_OBJS += cache-tree.o
> +LIB_OBJS += checkout.o
>  LIB_OBJS += color.o
>  LIB_OBJS += column.o
>  LIB_OBJS += combine-diff.o
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index fc4f8fd2ea..9e1cfd10b3 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -1,5 +1,6 @@
>  #include "builtin.h"
>  #include "config.h"
> +#include "checkout.h"
>  #include "lockfile.h"
>  #include "parse-options.h"
>  #include "refs.h"

With this, and also ...

> diff --git a/checkout.c b/checkout.c
> new file mode 100644
> index 0000000000..b0c744d37a
> --- /dev/null
> +++ b/checkout.c
> @@ -0,0 +1,42 @@
> +#include "cache.h"
> +#include "remote.h"

... with this, I sort of expected that builtin/checkout.c no longer
has to include "remote.h" but can now rely on the common helpers in
this new file to perform anything remote-related operation.  But it
seems that it is not the case (yet).

Just recording my observation for future reference, as we might also
want to move report_tracking(), etc., to this new file in the future.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand
  2017-11-22 22:30   ` [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
@ 2017-11-24  6:57     ` Junio C Hamano
  2017-11-25 16:58       ` Thomas Gummerer
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2017-11-24  6:57 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

Thomas Gummerer <t.gummerer@gmail.com> writes:

> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> index b5c47ac602..53042ce565 100755
> --- a/t/t2025-worktree-add.sh
> +++ b/t/t2025-worktree-add.sh
> @@ -313,5 +313,60 @@ test_expect_success 'checkout a branch under bisect' '
>  test_expect_success 'rename a branch under bisect not allowed' '
>  	test_must_fail git branch -M under-bisect bisect-with-new-name
>  '
> +# Is branch "refs/heads/$1" set to pull from "$2/$3"?
> +test_branch_upstream () {
> +	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
> +	{
> +		git config "branch.$1.remote" &&
> +		git config "branch.$1.merge"
> +	} >actual.upstream &&
> +	test_cmp expect.upstream actual.upstream
> +}

OK.

> +test_expect_success '--track sets up tracking' '
> +	test_when_finished rm -rf track &&
> +	git worktree add --track -b track track master &&
> +	git config "branch.track.merge" &&
> +	(
> +		test_branch_upstream track . master
> +	)
> +'

Is this "git config" necessary, or is it a remnant of a debugging
session?  It is tested in the helper that branch.track.merge is set
to something, and otherwise the helper would fail the same way as
this standalnoe "git config" would, no?

> +# setup remote repository $1 and repository $2 with $1 set up as
> +# remote.  The remote has two branches, master and foo.
> +setup_remote_repo () {
> +	git init $1 &&
> +	(
> +		cd $1 &&
> +		test_commit $1_master &&
> +		git checkout -b foo &&
> +		test_commit upstream_foo
> +	) &&
> +	git init $2 &&
> +	(
> +		cd $2 &&
> +		test_commit $2_master &&
> +		git remote add $1 ../$1 &&
> +		git config remote.$1.fetch \
> +			"refs/heads/*:refs/remotes/$1/*" &&
> +		git fetch --all
> +	)
> +}
> +
> +test_expect_success '--no-track avoids setting up tracking' '
> +	test_when_finished rm -rf repo_upstream repo_local foo &&
> +	setup_remote_repo repo_upstream repo_local &&
> +	(
> +		cd repo_local &&
> +		git worktree add --no-track -b foo ../foo repo_upstream/foo
> +	) &&
> +	(
> +		cd foo &&
> +		! test_branch_upstream foo repo_upstream foo &&

It is true that this test helper must yield failure.  But what you
expect probably is more than that, no?  For example, the test helper
would fail even if branch.foo.remote is set to the upstream as long
as branch.foo.merge is not set to point at their foo, but what you
really want to make sure is that neither configuration variable is
set.

> +		git rev-parse repo_upstream/foo >expect &&
> +		git rev-parse foo >actual &&
> +		test_cmp expect actual
> +	)
> +'
>  
>  test_done

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 3/4] worktree: make add <path> <branch> dwim
  2017-11-22 22:30   ` [PATCH v4 3/4] worktree: make add <path> <branch> dwim Thomas Gummerer
@ 2017-11-24  6:59     ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2017-11-24  6:59 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

Thomas Gummerer <t.gummerer@gmail.com> writes:

> Currently 'git worktree add <path> <branch>', errors out when 'branch'
> is not a local branch.   It has no additional dwim'ing features that one
> might expect.
>
> Make it behave more like 'git checkout <branch>' when the branch doesn't
> exist locally, but a remote tracking branch uniquely matches the desired
> branch name, i.e. create a new branch from the remote tracking branch
> and set the upstream to the remote tracking branch.
>
> As 'git worktree add' currently just dies in this situation, there are
> no backwards compatibility worries when introducing this feature.
>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---

This step makes sense and I did not spot anything controversial.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-22 22:30   ` [PATCH v4 4/4] worktree: make add <path> dwim Thomas Gummerer
@ 2017-11-24  7:11     ` Junio C Hamano
  2017-11-25 17:50       ` Thomas Gummerer
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2017-11-24  7:11 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

Thomas Gummerer <t.gummerer@gmail.com> writes:

> Currently 'git worktree add <path>' creates a new branch named after the
> basename of the <path>, that matches the HEAD of whichever worktree we
> were on when calling "git worktree add <path>".
>
> Make 'git worktree add <path> behave more like the dwim machinery in
> 'git checkout <new-branch>', i.e. check if the new branch name uniquely
> matches the branch name of a remote tracking branch, and if so check out
> that branch and set the upstream to the remote tracking branch.
>
> This is a change of behaviour compared to the current behaviour, where
> we create a new branch matching HEAD.  However as 'git worktree' is
> still an experimental feature, and it's easy to notice/correct the
> behaviour in case it's not what the user desired it's probably okay to
> break existing behaviour here.

Is it "easy to notice"?  I doubt it.  Even if you assume that
everybody uses bash prompt that shows the name of the branch, the
user sees the same name of the branch in either mode.

> In order to also satisfy users who want the current behaviour of
> creating a new branch from HEAD, add a '--no-track' flag, which disables
> the new behaviour, and keeps the old behaviour of creating a new branch
> from the head of the current worktree.

I am not sure if this is a good match for "--track/--no-track";
which branch is to be checked out (either "automatically from the
unique remote-tracking branch" or "the current one") is one choice,
and whether the resulting branch is marked explicitly as integrating
with the remote or not is another choice within one branch of the
first choice.  IOW, this makes it impossible to say "create the branch
based on the unique remote-tracking branch, but do not add the two
branch.*.{merge,remote} variables".

Also, you have several mention of "remote tracking branch" in these
patches.  Please consistently spell them as "remote-tracking branch"
to be consistent with Documentation/glossary-content.txt and avoid a
casual/careful reference to "tracking branch" if possible, unless it
is quite clear to the readers that you are being loose for the sake
of brevity.  Some people used "tracking branch" to mean the local
branch that is marked as the branch to integrate with the work on
a branch at a remote that caused user confusion in the past.

That is

    refs/remotes/origin/topic is a remote-tracking branch for the
    branch 'topic' that came from the 'origin' remote.

    when you have branch.foo.remote=origin and
    branch.foo.merge=refs/heads/topic, then your local branch foo is
    marked to integrate with the 'topic' branch at the 'origin'
    remote.

and these two are quite different things that people in the past and
over time loosely used a phrase "tracking branch" to cause confusion.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand
  2017-11-24  6:57     ` Junio C Hamano
@ 2017-11-25 16:58       ` Thomas Gummerer
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-25 16:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

On 11/24, Junio C Hamano wrote:
> Thomas Gummerer <t.gummerer@gmail.com> writes:
> 
> > diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> > index b5c47ac602..53042ce565 100755
> > --- a/t/t2025-worktree-add.sh
> > +++ b/t/t2025-worktree-add.sh
> > @@ -313,5 +313,60 @@ test_expect_success 'checkout a branch under bisect' '
> >  test_expect_success 'rename a branch under bisect not allowed' '
> >  	test_must_fail git branch -M under-bisect bisect-with-new-name
> >  '
> > +# Is branch "refs/heads/$1" set to pull from "$2/$3"?
> > +test_branch_upstream () {
> > +	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
> > +	{
> > +		git config "branch.$1.remote" &&
> > +		git config "branch.$1.merge"
> > +	} >actual.upstream &&
> > +	test_cmp expect.upstream actual.upstream
> > +}
> 
> OK.
> 
> > +test_expect_success '--track sets up tracking' '
> > +	test_when_finished rm -rf track &&
> > +	git worktree add --track -b track track master &&
> > +	git config "branch.track.merge" &&
> > +	(
> > +		test_branch_upstream track . master
> > +	)
> > +'
> 
> Is this "git config" necessary, or is it a remnant of a debugging
> session?  It is tested in the helper that branch.track.merge is set
> to something, and otherwise the helper would fail the same way as
> this standalnoe "git config" would, no?

It's a remnant of a debugging session, sorry.  It would indeed fail in
the same way, so just leaving the 'test_branch_upstream' is enough.
Also looking at that, there's no need for it to be in a subshell, will
fix that as well.


> > +# setup remote repository $1 and repository $2 with $1 set up as
> > +# remote.  The remote has two branches, master and foo.
> > +setup_remote_repo () {
> > +	git init $1 &&
> > +	(
> > +		cd $1 &&
> > +		test_commit $1_master &&
> > +		git checkout -b foo &&
> > +		test_commit upstream_foo
> > +	) &&
> > +	git init $2 &&
> > +	(
> > +		cd $2 &&
> > +		test_commit $2_master &&
> > +		git remote add $1 ../$1 &&
> > +		git config remote.$1.fetch \
> > +			"refs/heads/*:refs/remotes/$1/*" &&
> > +		git fetch --all
> > +	)
> > +}
> > +
> > +test_expect_success '--no-track avoids setting up tracking' '
> > +	test_when_finished rm -rf repo_upstream repo_local foo &&
> > +	setup_remote_repo repo_upstream repo_local &&
> > +	(
> > +		cd repo_local &&
> > +		git worktree add --no-track -b foo ../foo repo_upstream/foo
> > +	) &&
> > +	(
> > +		cd foo &&
> > +		! test_branch_upstream foo repo_upstream foo &&
> 
> It is true that this test helper must yield failure.  But what you
> expect probably is more than that, no?  For example, the test helper
> would fail even if branch.foo.remote is set to the upstream as long
> as branch.foo.merge is not set to point at their foo, but what you
> really want to make sure is that neither configuration variable is
> set.

Yeah you're right, this test is a bit too loose.  Will fix that in the
re-roll.  Thanks!

> > +		git rev-parse repo_upstream/foo >expect &&
> > +		git rev-parse foo >actual &&
> > +		test_cmp expect actual
> > +	)
> > +'
> >  
> >  test_done

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-24  7:11     ` Junio C Hamano
@ 2017-11-25 17:50       ` Thomas Gummerer
  2017-11-25 18:26         ` Paul Smith
  2017-11-26  3:35         ` Junio C Hamano
  0 siblings, 2 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-25 17:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

On 11/24, Junio C Hamano wrote:
> Thomas Gummerer <t.gummerer@gmail.com> writes:
> 
> > Currently 'git worktree add <path>' creates a new branch named after the
> > basename of the <path>, that matches the HEAD of whichever worktree we
> > were on when calling "git worktree add <path>".
> >
> > Make 'git worktree add <path> behave more like the dwim machinery in
> > 'git checkout <new-branch>', i.e. check if the new branch name uniquely
> > matches the branch name of a remote tracking branch, and if so check out
> > that branch and set the upstream to the remote tracking branch.
> >
> > This is a change of behaviour compared to the current behaviour, where
> > we create a new branch matching HEAD.  However as 'git worktree' is
> > still an experimental feature, and it's easy to notice/correct the
> > behaviour in case it's not what the user desired it's probably okay to
> > break existing behaviour here.
> 
> Is it "easy to notice"?  I doubt it.  Even if you assume that
> everybody uses bash prompt that shows the name of the branch, the
> user sees the same name of the branch in either mode.

With "easy" I meant at creation time, looking at the output of 'git
worktree add', which with the new version shows that the the new
branch has been set up to track the remote branch, and also shows the
commit HEAD now points to.

This would be the output in the new version:

     $ git worktree add ../bla
     Branch 'bla' set up to track remote branch 'bla' from 'origin'.
     Preparing ../bla (identifier bla)
     HEAD is now at 4aade43 bla

vs. the output without the changed behaviour:

     $ git worktree add ../bla
     Preparing ../bla (identifier bla)
     HEAD is now at 0f215c9 initial import

Of course that assumes that it's used directly, not in scripts, and
that users will actually read the output of the command when they
invoke it.  Maybe these are not safe assumptions to make though, and
we'd rather not have this on by default then.  As I mentioned
previously I would prefer having this as default, but I'm happy to
hide this behaviour behind a flag if we want to be more careful about
introducing this.  Dunno?


> > In order to also satisfy users who want the current behaviour of
> > creating a new branch from HEAD, add a '--no-track' flag, which disables
> > the new behaviour, and keeps the old behaviour of creating a new branch
> > from the head of the current worktree.
> 
> I am not sure if this is a good match for "--track/--no-track";
> which branch is to be checked out (either "automatically from the
> unique remote-tracking branch" or "the current one") is one choice,
> and whether the resulting branch is marked explicitly as integrating
> with the remote or not is another choice within one branch of the
> first choice.  IOW, this makes it impossible to say "create the branch
> based on the unique remote-tracking branch, but do not add the two
> branch.*.{merge,remote} variables".

Hmm good point.  Maybe we'll need another flag for this.  Maybe
--[no-]guess-remote would work, and a corresponding
worktree.guessRemote config would work?  That's the best I could come
up with, better suggestions are definitely welcome.

> Also, you have several mention of "remote tracking branch" in these
> patches.  Please consistently spell them as "remote-tracking branch"
> to be consistent with Documentation/glossary-content.txt and avoid a
> casual/careful reference to "tracking branch" if possible, unless it
> is quite clear to the readers that you are being loose for the sake
> of brevity.  Some people used "tracking branch" to mean the local
> branch that is marked as the branch to integrate with the work on
> a branch at a remote that caused user confusion in the past.

I must admit I wasn't aware of Documentation/glossary-content.txt and
have seen "tracking branch" in other places, so I was just repeating
the pattern.

> That is
> 
>     refs/remotes/origin/topic is a remote-tracking branch for the
>     branch 'topic' that came from the 'origin' remote.
> 
>     when you have branch.foo.remote=origin and
>     branch.foo.merge=refs/heads/topic, then your local branch foo is
>     marked to integrate with the 'topic' branch at the 'origin'
>     remote.
> 
> and these two are quite different things that people in the past and
> over time loosely used a phrase "tracking branch" to cause confusion.


Thanks for the clarification, will fix in the re-roll.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-25 17:50       ` Thomas Gummerer
@ 2017-11-25 18:26         ` Paul Smith
  2017-11-25 20:06           ` Thomas Gummerer
  2017-11-26  3:35         ` Junio C Hamano
  1 sibling, 1 reply; 36+ messages in thread
From: Paul Smith @ 2017-11-25 18:26 UTC (permalink / raw)
  To: git

On Sat, 2017-11-25 at 17:50 +0000, Thomas Gummerer wrote:
> This would be the output in the new version:
> 
>      $ git worktree add ../bla
>      Branch 'bla' set up to track remote branch 'bla' from 'origin'.
>      Preparing ../bla (identifier bla)
>      HEAD is now at 4aade43 bla
> 
> vs. the output without the changed behaviour:
> 
>      $ git worktree add ../bla
>      Preparing ../bla (identifier bla)
>      HEAD is now at 0f215c9 initial import
> 
> Of course that assumes that it's used directly, not in scripts, and
> that users will actually read the output of the command when they
> invoke it.  Maybe these are not safe assumptions to make though, and
> we'd rather not have this on by default then.  As I mentioned
> previously I would prefer having this as default, but I'm happy to
> hide this behaviour behind a flag if we want to be more careful about
> introducing this.  Dunno?

Speaking as a simple user, I find the current behavior of Git worktree
add very frustrating; I am constantly wanting to create worktrees for
other peoples' branches so I can look at the code there without messing
up my workspace, and it's really inconvenient to do that now.

Also, the current special handling of the directory name as a putative
branch name is not helpful for me because many of the branches I need
to examine use "/" as their separator.  I don't begrudge making that
feature more "DWIM" for those that can use it, but hopefully some help
is forthcoming for those who can't.

For example, I need to create a local worktree for the remote rel/1.0
branch... what do I do?

What I want to work is this:

    git worktree add ../1.0 rel/1.0

and have it create a worktree at ../1.0, then do the equivalent of "git
checkout rel/1.0" which includes setting up to track the remote branch.
 But of course this doesn't work at all; I get:

    fatal: invalid reference: rel/1.0

Personally I would think it odd to have to add an extra flag to get
what I would expect would be "normal" behavior (checkout).

But maybe that's just me.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-25 18:26         ` Paul Smith
@ 2017-11-25 20:06           ` Thomas Gummerer
  2017-11-25 20:39             ` Randall S. Becker
  2017-11-25 23:11             ` Paul Smith
  0 siblings, 2 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-25 20:06 UTC (permalink / raw)
  To: Paul Smith; +Cc: git

On 11/25, Paul Smith wrote:
> On Sat, 2017-11-25 at 17:50 +0000, Thomas Gummerer wrote:
> > This would be the output in the new version:
> > 
> >      $ git worktree add ../bla
> >      Branch 'bla' set up to track remote branch 'bla' from 'origin'.
> >      Preparing ../bla (identifier bla)
> >      HEAD is now at 4aade43 bla
> > 
> > vs. the output without the changed behaviour:
> > 
> >      $ git worktree add ../bla
> >      Preparing ../bla (identifier bla)
> >      HEAD is now at 0f215c9 initial import
> > 
> > Of course that assumes that it's used directly, not in scripts, and
> > that users will actually read the output of the command when they
> > invoke it.  Maybe these are not safe assumptions to make though, and
> > we'd rather not have this on by default then.  As I mentioned
> > previously I would prefer having this as default, but I'm happy to
> > hide this behaviour behind a flag if we want to be more careful about
> > introducing this.  Dunno?
> 
> Speaking as a simple user, I find the current behavior of Git worktree
> add very frustrating; I am constantly wanting to create worktrees for
> other peoples' branches so I can look at the code there without messing
> up my workspace, and it's really inconvenient to do that now.
> 
> Also, the current special handling of the directory name as a putative
> branch name is not helpful for me because many of the branches I need
> to examine use "/" as their separator.  I don't begrudge making that
> feature more "DWIM" for those that can use it, but hopefully some help
> is forthcoming for those who can't.
> 
> For example, I need to create a local worktree for the remote rel/1.0
> branch... what do I do?
> 
> What I want to work is this:
> 
>     git worktree add ../1.0 rel/1.0
> 
> and have it create a worktree at ../1.0, then do the equivalent of "git
> checkout rel/1.0" which includes setting up to track the remote branch.
>  But of course this doesn't work at all; I get:
> 
>     fatal: invalid reference: rel/1.0
> 
> Personally I would think it odd to have to add an extra flag to get
> what I would expect would be "normal" behavior (checkout).
> 
> But maybe that's just me.

This part is getting done in 3/4, and is definitely going to work
without an additional flag, so this is (hopefully) soon going to work
just as you want :)

This is less controversial because as you mentioned this currently
doesn't work at all, so there are no backwards compatibility worries.

For the other case of

    git worktree add ../foo

however we currently document one behaviour, which I would like to
change (I usually have branches without a / in that I want to look at)
we currently document one behaviour, which I'd like to change.  So in
that case we are a bit worried about backwards compatibility, and how
this will affect current users that have a certain expectation of how
the command is supposed to work, hence the discussion of whether to
hide the new behaviour behind a flag or not.

Either way, if we do put the behaviour behind a flag, I'll also add a
configuration variable, which can be set to enable the new behaviour
so one doesn't have to type out the flag all the time.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-25 20:06           ` Thomas Gummerer
@ 2017-11-25 20:39             ` Randall S. Becker
  2017-11-25 21:48               ` Thomas Gummerer
  2017-11-25 23:11             ` Paul Smith
  1 sibling, 1 reply; 36+ messages in thread
From: Randall S. Becker @ 2017-11-25 20:39 UTC (permalink / raw)
  To: 'Thomas Gummerer', 'Paul Smith'; +Cc: git

On November 25, 2017 3:06 PM Thomas Gummerer wrote:
<big snip>
>however we currently document one behaviour, which I would like to change
(I usually have branches
>without a / in that I want to look at) we currently document one behaviour,
which I'd like to change.  So 
>in that case we are a bit worried about backwards compatibility, and how
this will affect current users
>that have a certain expectation of how the command is supposed to work,
hence the discussion of
>whether to hide the new behaviour behind a flag or not.

>Either way, if we do put the behaviour behind a flag, I'll also add a
configuration variable, which can
>be set to enable the new behaviour so one doesn't have to type out the flag
all the time.

To be consistent with other commands, you could put path after -- and the
ambiguity with refs containing '/' goes away, as refs before the -- would
always be considered refs while after you have paths.

What I don't like is the current add syntax of:
git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]
<path> [<branch>]

where the path-spec precedes branch making things a bit icky. It might be
better to have an alternate syntax of:

git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]
<path> [<branch>]
git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]
[<branch>] -- <path>

But since we only have one path, that may be redundant. Just a thought, as
-- avoids a lot of interpretation evils. While we're here, I wonder whether
<branch> should be changed to <ref-spec> for more general use. Consider
release identifiers using tags, and using the tag instead of branch to
define commit on which the worktree is based.

Cheers,
Randall

-- Brief whoami: NonStop&UNIX developer since approximately
UNIX(421664400)/NonStop(211288444200000000) 
-- In my real life, I talk too much.






^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-25 20:39             ` Randall S. Becker
@ 2017-11-25 21:48               ` Thomas Gummerer
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-25 21:48 UTC (permalink / raw)
  To: Randall S. Becker; +Cc: 'Paul Smith', git

On 11/25, Randall S. Becker wrote:
> On November 25, 2017 3:06 PM Thomas Gummerer wrote:
> <big snip>
> >however we currently document one behaviour, which I would like to change
> >(I usually have branches
> >without a / in that I want to look at) we currently document one behaviour,
> >which I'd like to change.  So 
> >in that case we are a bit worried about backwards compatibility, and how
> >this will affect current users
> >that have a certain expectation of how the command is supposed to work,
> >hence the discussion of
> >whether to hide the new behaviour behind a flag or not.
> 
> >Either way, if we do put the behaviour behind a flag, I'll also add a
> >configuration variable, which can
> >be set to enable the new behaviour so one doesn't have to type out the flag
> >all the time.
> 
> To be consistent with other commands, you could put path after -- and the
> ambiguity with refs containing '/' goes away, as refs before the -- would
> always be considered refs while after you have paths.
>
> What I don't like is the current add syntax of:
> git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]
> <path> [<branch>]
> 
> where the path-spec precedes branch making things a bit icky. It might be
> better to have an alternate syntax of:
> 
> git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]
> <path> [<branch>]
> git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>]
> [<branch>] -- <path>

Hmm I don't think there is any ambiguity there, the first argument
always needs to be a path, and the second one is always a commit-ish.
So this way there is no disambiguation needed.

I'm not convinced the alternative syntax would buy us much, at least
not in the context of what this series is trying to do.

> But since we only have one path, that may be redundant. Just a thought, as
> -- avoids a lot of interpretation evils. While we're here, I wonder whether
> <branch> should be changed to <ref-spec> for more general use. Consider
> release identifiers using tags, and using the tag instead of branch to
> define commit on which the worktree is based.

'git worktree add' can already take a commit-ish, it's just not
documented that way.  I'll add a patch updating the documentation to
the series.

> Cheers,
> Randall
> 
> -- Brief whoami: NonStop&UNIX developer since approximately
> UNIX(421664400)/NonStop(211288444200000000) 
> -- In my real life, I talk too much.
> 
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-25 20:06           ` Thomas Gummerer
  2017-11-25 20:39             ` Randall S. Becker
@ 2017-11-25 23:11             ` Paul Smith
  1 sibling, 0 replies; 36+ messages in thread
From: Paul Smith @ 2017-11-25 23:11 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git

On Sat, 2017-11-25 at 20:06 +0000, Thomas Gummerer wrote:
> This part is getting done in 3/4, and is definitely going to work
> without an additional flag, so this is (hopefully) soon going to work
> just as you want :)

Yay!  Thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-25 17:50       ` Thomas Gummerer
  2017-11-25 18:26         ` Paul Smith
@ 2017-11-26  3:35         ` Junio C Hamano
  2017-11-26 11:37           ` Thomas Gummerer
  1 sibling, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2017-11-26  3:35 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

Thomas Gummerer <t.gummerer@gmail.com> writes:

> Of course that assumes that it's used directly, not in scripts, and
> that users will actually read the output of the command when they
> invoke it.  Maybe these are not safe assumptions to make though, and
> we'd rather not have this on by default then.

None of these is a safe assumption to make.  With a transition plan,
we could change the default eventually, but if this feature is already
used by real users, the proposed change without any transition plan
will hurt them and make them hate us, I am afraid.


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v4 4/4] worktree: make add <path> dwim
  2017-11-26  3:35         ` Junio C Hamano
@ 2017-11-26 11:37           ` Thomas Gummerer
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 11:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine

On 11/26, Junio C Hamano wrote:
> Thomas Gummerer <t.gummerer@gmail.com> writes:
> 
> > Of course that assumes that it's used directly, not in scripts, and
> > that users will actually read the output of the command when they
> > invoke it.  Maybe these are not safe assumptions to make though, and
> > we'd rather not have this on by default then.
> 
> None of these is a safe assumption to make.  With a transition plan,
> we could change the default eventually, but if this feature is already
> used by real users, the proposed change without any transition plan
> will hurt them and make them hate us, I am afraid.

Fair enough, I definitely wouldn't want users to hate us.  I guess
I'll add this to the list of things that I'd like to change when git
3.0 comes along.

How about once we make the decision when git 3.0 happens, adding a
warning:

    warning: The current behaviour of creating a branch from HEAD when
    no <branch> is given will change in git 3.0, to try and match the
    new branch name to a remote-tracking branch.  To get rid of this
    warning in the meantime, set git.guessRemote to true or false,
    depending on whether you'd like to enable the new behaviour now,
    or would like to keep the existing behaviour. (see also
    --guess-remote in man git-worktree)

or something along the lines, and once we decide to release git 3.0 we
flip the default?  The warning would be displayed whenever the new
behaviour would be invoked, but no config option or flag is set.

Either way I'm going to add a flag and a config option to hide this
behaviour behind for now.

Thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v5 0/6] make git worktree add dwim more
  2017-11-22 22:30 ` [PATCH v4 0/4] make git worktree add dwim more Thomas Gummerer
                     ` (3 preceding siblings ...)
  2017-11-22 22:30   ` [PATCH v4 4/4] worktree: make add <path> dwim Thomas Gummerer
@ 2017-11-26 19:43   ` Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 1/6] checkout: factor out functions to new lib file Thomas Gummerer
                       ` (6 more replies)
  4 siblings, 7 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

The previous rounds can be found at
https://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/,
https://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/,
https://public-inbox.org/git/20171118224706.13810-1-t.gummerer@gmail.com/ and
https://public-inbox.org/git/20171122223020.2780-1-t.gummerer@gmail.com/.

Thanks Junio for the review of the previous round and Randall for the
suggestion of documenting that git worktree add can take a commit-ish,
not just a branch.

The main changes in this round are hiding the new behaviour for 'git
worktree <path>' behind a flag, and adding a config option to turn the
new behaviour on by default.  It's also no longer relying on the
--[no]-track flag, but using a new --[no-]guess-remote flag instead.

Interdiff between this and the previous round below:

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5f65fa9234..4966d90ebb 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -3425,3 +3425,13 @@ web.browser::
 	Specify a web browser that may be used by some commands.
 	Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
 	may use it.
+
+worktree.guessRemote::
+	With `add`, if no branch argument, and neither of `-b` nor
+	`-B` nor `--detach` are given, the command defaults to
+	creating a new branch from HEAD.  If `worktree.guessRemote` is
+	set to true, `worktree add` tries to find a remote-tracking
+	branch whose name uniquely matches the new branch name.  If
+	such a branch exists, it is checked out and set as "upstream"
+	for the new branch.  If no such match can be found, it falls
+	back to creating a new branch from the current HEAD.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index abc8f1f50d..fd841886ef 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<branch>]
+'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]
 'git worktree list' [--porcelain]
 'git worktree lock' [--reason <string>] <worktree>
 'git worktree prune' [-n] [-v] [--expire <expire>]
@@ -45,33 +45,24 @@ specifying `--reason` to explain why the working tree is locked.
 
 COMMANDS
 --------
-add <path> [<branch>]::
+add <path> [<commit-ish>]::
 
-Create `<path>` and checkout `<branch>` into it. The new working directory
+Create `<path>` and checkout `<commit-ish>` into it. The new working directory
 is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc. `-` may also be
-specified as `<branch>`; it is synonymous with `@{-1}`.
+specified as `<commit-ish>`; it is synonymous with `@{-1}`.
 +
-If <branch> is not found, and neither `-b` nor `-B` nor `--detach` are
-used, but there does exist a tracking branch in exactly one remote
-(call it <remote>) with a matching name, treat as equivalent to
+If <commit-ish> is a branch name (call it `<branch>` and is not found,
+and neither `-b` nor `-B` nor `--detach` are used, but there does
+exist a tracking branch in exactly one remote (call it `<remote>`)
+with a matching name, treat as equivalent to
 ------------
 $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
-If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, if there exists a tracking branch in exactly
-one remote (call it `<remote>`) matching the basename of the path
-(call it `<branch>`), treat it as equivalent to
-------------
-$ git worktree add --track -b <branch> <path> <remote>/<branch>
-------------
-If no tracking branch exists in exactly one remote, `<branch>` is
-created based on HEAD, as if `-b $(basename <path>)` was specified.
-+
-To disable the behaviour of trying to match the basename of <path> to
-a remote, and always create a new branch from HEAD, the `--no-track`
-flag can be passed to `git worktree add`.
+If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
+then, as a convenience, a new branch based at HEAD is created automatically,
+as if `-b $(basename <path>)` was specified.
 
 list::
 
@@ -101,34 +92,44 @@ OPTIONS
 
 -f::
 --force::
-	By default, `add` refuses to create a new working tree when `<branch>`
+	By default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and
 	is already checked out by another working tree. This option overrides
 	that safeguard.
 
 -b <new-branch>::
 -B <new-branch>::
 	With `add`, create a new branch named `<new-branch>` starting at
-	`<branch>`, and check out `<new-branch>` into the new working tree.
-	If `<branch>` is omitted, it defaults to HEAD.
+	`<commit-ish>`, and check out `<new-branch>` into the new working tree.
+	If `<commit-ish>` is omitted, it defaults to HEAD.
 	By default, `-b` refuses to create a new branch if it already
 	exists. `-B` overrides this safeguard, resetting `<new-branch>` to
-	`<branch>`.
+	`<commit-ish>`.
 
 --detach::
 	With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
 	in linkgit:git-checkout[1].
 
 --[no-]checkout::
-	By default, `add` checks out `<branch>`, however, `--no-checkout` can
+	By default, `add` checks out `<commit-ish>`, however, `--no-checkout` can
 	be used to suppress checkout in order to make customizations,
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]guess-remote::
+	With `add`, instead of creating a new branch from HEAD when
+	`<commit-ish>` is not given, if there exists a tracking branch
+	in exactly one remote matching the basename of the path, base
+	the new branch on the remote-tracking branch, and mark the
+	remote-tracking branch as "upstream" from the new branch.
++
+This can also be set up as the default behaviour by using the
+`worktree.guessRemote` config option.
+
 --[no-]track::
-	With `--track` `<branch>` is set as "tracking" branch for
-	`<new-branch>`.  This is the default if `<branch>` is a remote
-	tracking branch, and can be suppressed with `--no-track`.  See
-	also linkgit:git-branch[1].
+	When creating a new branch, if `<commit-ish>` is a branch,
+	mark it as "upstream" from the new branch.  This is the
+	default if `<commit-ish>` is a remote-tracking branch.  See
+	"--track" in linkgit:git-branch[1] for details.
 
 --lock::
 	Keep the working tree locked after creation. This is the
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 83c73ecb0d..426aea8761 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -33,8 +33,19 @@ struct add_opts {
 
 static int show_only;
 static int verbose;
+static int guess_remote;
 static timestamp_t expire;
 
+static int git_worktree_config(const char *var, const char *value, void *cb)
+{
+	if (!strcmp(var, "worktree.guessremote")) {
+		guess_remote = git_config_bool(var, value);
+		return 0;
+	}
+
+	return 0;
+}
+
 static int prune_worktree(const char *id, struct strbuf *reason)
 {
 	struct stat st;
@@ -355,9 +366,13 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_PASSTHRU(0, "track", &opt_track, NULL,
 			     N_("set up tracking mode (see git-branch(1))"),
 			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
+		OPT_BOOL(0, "guess-remote", &guess_remote,
+			 N_("try to match the new branch name with a remote-tracking branch")),
 		OPT_END()
 	};
 
+	git_config(git_worktree_config, NULL);
+
 	memset(&opts, 0, sizeof(opts));
 	opts.checkout = 1;
 	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
@@ -389,7 +404,7 @@ static int add(int ac, const char **av, const char *prefix)
 		int n;
 		const char *s = worktree_basename(path, &n);
 		opts.new_branch = xstrndup(s, n);
-		if (!opt_track || strcmp(opt_track, "--no-track")) {
+		if (guess_remote) {
 			struct object_id oid;
 			const char *remote =
 				unique_tracking_name(opts.new_branch, &oid);
diff --git a/checkout.c b/checkout.c
index b0c744d37a..ac42630f74 100644
--- a/checkout.c
+++ b/checkout.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "remote.h"
+#include "checkout.h"
 
 struct tracking_name_data {
 	/* const */ char *src_ref;
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 6fd3da4036..6ce9b9c070 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -326,10 +326,7 @@ test_branch_upstream () {
 test_expect_success '--track sets up tracking' '
 	test_when_finished rm -rf track &&
 	git worktree add --track -b track track master &&
-	git config "branch.track.merge" &&
-	(
-		test_branch_upstream track . master
-	)
+	test_branch_upstream track . master
 '
 
 # setup remote repository $1 and repository $2 with $1 set up as
@@ -362,10 +359,9 @@ test_expect_success '--no-track avoids setting up tracking' '
 	) &&
 	(
 		cd foo &&
-		! test_branch_upstream foo repo_upstream foo &&
-		git rev-parse repo_upstream/foo >expect &&
-		git rev-parse foo >actual &&
-		test_cmp expect actual
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
 	)
 '
 
@@ -384,41 +380,67 @@ test_expect_success '"add" <path> <branch> dwims' '
 	(
 		cd foo &&
 		test_branch_upstream foo repo_upstream foo &&
-		git rev-parse repo_upstream/foo >expect &&
-		git rev-parse foo >actual &&
-		test_cmp expect actual
+		test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
 	)
 '
 
-test_expect_success 'git worktree add --no-track does not set up tracking' '
+test_expect_success 'git worktree add does not match remote' '
 	test_when_finished rm -rf repo_a repo_b foo &&
 	setup_remote_repo repo_a repo_b &&
 	(
 		cd repo_b &&
-		git worktree add --no-track ../foo
+		git worktree add ../foo
 	) &&
 	(
 		cd foo &&
-		! test_branch_upstream foo repo_a foo &&
-		git rev-parse repo_a/foo >expect &&
-		git rev-parse foo >actual &&
-		! test_cmp expect actual
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
 	)
 '
 
-test_expect_success 'git worktree add sets up tracking' '
-	test_when_finished rm -rf repo_a repo_b &&
+test_expect_success 'git worktree add --guess-remote sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
 	setup_remote_repo repo_a repo_b &&
 	(
 		cd repo_b &&
+		git worktree add --guess-remote ../foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_a foo &&
+		test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
+test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git config worktree.guessRemote true &&
 		git worktree add ../foo
 	) &&
 	(
 		cd foo &&
 		test_branch_upstream foo repo_a foo &&
-		git rev-parse repo_a/foo >expect &&
-		git rev-parse foo >actual &&
-		test_cmp expect actual
+		test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
+test_expect_success 'git worktree --no-guess-remote option overrides config' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git config worktree.guessRemote true &&
+		git worktree add --no-guess-remote ../foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
 	)
 '
 
Thomas Gummerer (6):
  checkout: factor out functions to new lib file
  worktree: add can be created from any commit-ish
  worktree: add --[no-]track option to the add subcommand
  worktree: make add <path> <branch> dwim
  worktree: add --guess-remote flag to add subcommand
  add worktree.guessRemote config option

 Documentation/config.txt       |  10 ++++
 Documentation/git-worktree.txt |  44 ++++++++++----
 Makefile                       |   1 +
 builtin/checkout.c             |  41 +------------
 builtin/worktree.c             |  46 +++++++++++++++
 checkout.c                     |  43 ++++++++++++++
 checkout.h                     |  13 +++++
 t/t2025-worktree-add.sh        | 130 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 278 insertions(+), 50 deletions(-)
 create mode 100644 checkout.c
 create mode 100644 checkout.h

-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 1/6] checkout: factor out functions to new lib file
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
@ 2017-11-26 19:43     ` Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 2/6] worktree: add can be created from any commit-ish Thomas Gummerer
                       ` (5 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Factor the functions out, so they can be re-used from other places.  In
particular these functions will be re-used in builtin/worktree.c to make
git worktree add dwim more.

While there add some docs to the function.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Makefile           |  1 +
 builtin/checkout.c | 41 +----------------------------------------
 checkout.c         | 43 +++++++++++++++++++++++++++++++++++++++++++
 checkout.h         | 13 +++++++++++++
 4 files changed, 58 insertions(+), 40 deletions(-)
 create mode 100644 checkout.c
 create mode 100644 checkout.h

diff --git a/Makefile b/Makefile
index e53750ca01..a80a8fcca9 100644
--- a/Makefile
+++ b/Makefile
@@ -759,6 +759,7 @@ LIB_OBJS += branch.o
 LIB_OBJS += bulk-checkin.o
 LIB_OBJS += bundle.o
 LIB_OBJS += cache-tree.o
+LIB_OBJS += checkout.o
 LIB_OBJS += color.o
 LIB_OBJS += column.o
 LIB_OBJS += combine-diff.o
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 7d8bcc3833..ad8f94044c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "config.h"
+#include "checkout.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "refs.h"
@@ -872,46 +873,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
 	return git_xmerge_config(var, value, NULL);
 }
 
-struct tracking_name_data {
-	/* const */ char *src_ref;
-	char *dst_ref;
-	struct object_id *dst_oid;
-	int unique;
-};
-
-static int check_tracking_name(struct remote *remote, void *cb_data)
-{
-	struct tracking_name_data *cb = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
-	query.src = cb->src_ref;
-	if (remote_find_tracking(remote, &query) ||
-	    get_oid(query.dst, cb->dst_oid)) {
-		free(query.dst);
-		return 0;
-	}
-	if (cb->dst_ref) {
-		free(query.dst);
-		cb->unique = 0;
-		return 0;
-	}
-	cb->dst_ref = query.dst;
-	return 0;
-}
-
-static const char *unique_tracking_name(const char *name, struct object_id *oid)
-{
-	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
-	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
-	cb_data.dst_oid = oid;
-	for_each_remote(check_tracking_name, &cb_data);
-	free(cb_data.src_ref);
-	if (cb_data.unique)
-		return cb_data.dst_ref;
-	free(cb_data.dst_ref);
-	return NULL;
-}
-
 static int parse_branchname_arg(int argc, const char **argv,
 				int dwim_new_local_branch_ok,
 				struct branch_info *new,
diff --git a/checkout.c b/checkout.c
new file mode 100644
index 0000000000..ac42630f74
--- /dev/null
+++ b/checkout.c
@@ -0,0 +1,43 @@
+#include "cache.h"
+#include "remote.h"
+#include "checkout.h"
+
+struct tracking_name_data {
+	/* const */ char *src_ref;
+	char *dst_ref;
+	struct object_id *dst_oid;
+	int unique;
+};
+
+static int check_tracking_name(struct remote *remote, void *cb_data)
+{
+	struct tracking_name_data *cb = cb_data;
+	struct refspec query;
+	memset(&query, 0, sizeof(struct refspec));
+	query.src = cb->src_ref;
+	if (remote_find_tracking(remote, &query) ||
+	    get_oid(query.dst, cb->dst_oid)) {
+		free(query.dst);
+		return 0;
+	}
+	if (cb->dst_ref) {
+		free(query.dst);
+		cb->unique = 0;
+		return 0;
+	}
+	cb->dst_ref = query.dst;
+	return 0;
+}
+
+const char *unique_tracking_name(const char *name, struct object_id *oid)
+{
+	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
+	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
+	cb_data.dst_oid = oid;
+	for_each_remote(check_tracking_name, &cb_data);
+	free(cb_data.src_ref);
+	if (cb_data.unique)
+		return cb_data.dst_ref;
+	free(cb_data.dst_ref);
+	return NULL;
+}
diff --git a/checkout.h b/checkout.h
new file mode 100644
index 0000000000..9980711179
--- /dev/null
+++ b/checkout.h
@@ -0,0 +1,13 @@
+#ifndef CHECKOUT_H
+#define CHECKOUT_H
+
+#include "cache.h"
+
+/*
+ * Check if the branch name uniquely matches a branch name on a remote
+ * tracking branch.  Return the name of the remote if such a branch
+ * exists, NULL otherwise.
+ */
+extern const char *unique_tracking_name(const char *name, struct object_id *oid);
+
+#endif /* CHECKOUT_H */
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 2/6] worktree: add can be created from any commit-ish
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 1/6] checkout: factor out functions to new lib file Thomas Gummerer
@ 2017-11-26 19:43     ` Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 3/6] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
                       ` (4 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add' is documented to take an optional <branch>
argument, which is checked out in the new worktree.  However it is more
generally possible to use a commit-ish as the optional argument, and
check that out into the new worktree.

Document that this is a possibility, as new users of git worktree add
might find it helpful.

Reported-by: Randall S. Becker <rsbecker@nexbridge.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index b472acc356..121895209d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<branch>]
+'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]
 'git worktree list' [--porcelain]
 'git worktree lock' [--reason <string>] <worktree>
 'git worktree prune' [-n] [-v] [--expire <expire>]
@@ -45,14 +45,14 @@ specifying `--reason` to explain why the working tree is locked.
 
 COMMANDS
 --------
-add <path> [<branch>]::
+add <path> [<commit-ish>]::
 
-Create `<path>` and checkout `<branch>` into it. The new working directory
+Create `<path>` and checkout `<commit-ish>` into it. The new working directory
 is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc. `-` may also be
-specified as `<branch>`; it is synonymous with `@{-1}`.
+specified as `<commit-ish>`; it is synonymous with `@{-1}`.
 +
-If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,
+If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
 then, as a convenience, a new branch based at HEAD is created automatically,
 as if `-b $(basename <path>)` was specified.
 
@@ -84,25 +84,25 @@ OPTIONS
 
 -f::
 --force::
-	By default, `add` refuses to create a new working tree when `<branch>`
+	By default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and
 	is already checked out by another working tree. This option overrides
 	that safeguard.
 
 -b <new-branch>::
 -B <new-branch>::
 	With `add`, create a new branch named `<new-branch>` starting at
-	`<branch>`, and check out `<new-branch>` into the new working tree.
-	If `<branch>` is omitted, it defaults to HEAD.
+	`<commit-ish>`, and check out `<new-branch>` into the new working tree.
+	If `<commit-ish>` is omitted, it defaults to HEAD.
 	By default, `-b` refuses to create a new branch if it already
 	exists. `-B` overrides this safeguard, resetting `<new-branch>` to
-	`<branch>`.
+	`<commit-ish>`.
 
 --detach::
 	With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
 	in linkgit:git-checkout[1].
 
 --[no-]checkout::
-	By default, `add` checks out `<branch>`, however, `--no-checkout` can
+	By default, `add` checks out `<commit-ish>`, however, `--no-checkout` can
 	be used to suppress checkout in order to make customizations,
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 3/6] worktree: add --[no-]track option to the add subcommand
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 1/6] checkout: factor out functions to new lib file Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 2/6] worktree: add can be created from any commit-ish Thomas Gummerer
@ 2017-11-26 19:43     ` Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 4/6] worktree: make add <path> <branch> dwim Thomas Gummerer
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add' sets up tracking branches if '<branch>' is
a remote tracking branch, and doesn't set them up otherwise, as is the
default for 'git branch'.

This may or may not be what the user wants.  Allow overriding this
behaviour with a --[no-]track flag that gets passed through to 'git
branch'.

We already respect branch.autoSetupMerge, as 'git worktree' just calls
'git branch' internally.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  6 +++++
 builtin/worktree.c             |  8 +++++++
 t/t2025-worktree-add.sh        | 51 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 121895209d..15e58b18f7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -107,6 +107,12 @@ OPTIONS
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]track::
+	When creating a new branch, if `<commit-ish>` is a branch,
+	mark it as "upstream" from the new branch.  This is the
+	default if `<commit-ish>` is a remote-tracking branch.  See
+	"--track" in linkgit:git-branch[1] for details.
+
 --lock::
 	Keep the working tree locked after creation. This is the
 	equivalent of `git worktree lock` after `git worktree add`,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index ed043d5f1c..ea9678cac8 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -341,6 +341,7 @@ static int add(int ac, const char **av, const char *prefix)
 	const char *new_branch_force = NULL;
 	char *path;
 	const char *branch;
+	const char *opt_track = NULL;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -350,6 +351,9 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
 		OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
 		OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+		OPT_PASSTHRU(0, "track", &opt_track, NULL,
+			     N_("set up tracking mode (see git-branch(1))"),
+			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
 		OPT_END()
 	};
 
@@ -394,9 +398,13 @@ static int add(int ac, const char **av, const char *prefix)
 			argv_array_push(&cp.args, "--force");
 		argv_array_push(&cp.args, opts.new_branch);
 		argv_array_push(&cp.args, branch);
+		if (opt_track)
+			argv_array_push(&cp.args, opt_track);
 		if (run_command(&cp))
 			return -1;
 		branch = opts.new_branch;
+	} else if (opt_track) {
+		die(_("--[no-]track can only be used if a new branch is created"));
 	}
 
 	UNLEAK(path);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index b5c47ac602..72e8b62927 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -313,5 +313,56 @@ test_expect_success 'checkout a branch under bisect' '
 test_expect_success 'rename a branch under bisect not allowed' '
 	test_must_fail git branch -M under-bisect bisect-with-new-name
 '
+# Is branch "refs/heads/$1" set to pull from "$2/$3"?
+test_branch_upstream () {
+	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
+	{
+		git config "branch.$1.remote" &&
+		git config "branch.$1.merge"
+	} >actual.upstream &&
+	test_cmp expect.upstream actual.upstream
+}
+
+test_expect_success '--track sets up tracking' '
+	test_when_finished rm -rf track &&
+	git worktree add --track -b track track master &&
+	test_branch_upstream track . master
+'
+
+# setup remote repository $1 and repository $2 with $1 set up as
+# remote.  The remote has two branches, master and foo.
+setup_remote_repo () {
+	git init $1 &&
+	(
+		cd $1 &&
+		test_commit $1_master &&
+		git checkout -b foo &&
+		test_commit upstream_foo
+	) &&
+	git init $2 &&
+	(
+		cd $2 &&
+		test_commit $2_master &&
+		git remote add $1 ../$1 &&
+		git config remote.$1.fetch \
+			"refs/heads/*:refs/remotes/$1/*" &&
+		git fetch --all
+	)
+}
+
+test_expect_success '--no-track avoids setting up tracking' '
+	test_when_finished rm -rf repo_upstream repo_local foo &&
+	setup_remote_repo repo_upstream repo_local &&
+	(
+		cd repo_local &&
+		git worktree add --no-track -b foo ../foo repo_upstream/foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
+	)
+'
 
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 4/6] worktree: make add <path> <branch> dwim
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
                       ` (2 preceding siblings ...)
  2017-11-26 19:43     ` [PATCH v5 3/6] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
@ 2017-11-26 19:43     ` Thomas Gummerer
  2017-11-26 19:43     ` [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
                       ` (2 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add <path> <branch>', errors out when 'branch'
is not a local branch.  It has no additional dwim'ing features that one
might expect.

Make it behave more like 'git checkout <branch>' when the branch doesn't
exist locally, but a remote tracking branch uniquely matches the desired
branch name, i.e. create a new branch from the remote tracking branch
and set the upstream to the remote tracking branch.

As 'git worktree add' currently just dies in this situation, there are
no backwards compatibility worries when introducing this feature.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  8 ++++++++
 builtin/worktree.c             | 16 ++++++++++++++++
 t/t2025-worktree-add.sh        | 19 +++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 15e58b18f7..3044d305a6 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -52,6 +52,14 @@ is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc. `-` may also be
 specified as `<commit-ish>`; it is synonymous with `@{-1}`.
 +
+If <commit-ish> is a branch name (call it `<branch>` and is not found,
+and neither `-b` nor `-B` nor `--detach` are used, but there does
+exist a tracking branch in exactly one remote (call it `<remote>`)
+with a matching name, treat as equivalent to
+------------
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
+------------
++
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
 then, as a convenience, a new branch based at HEAD is created automatically,
 as if `-b $(basename <path>)` was specified.
diff --git a/builtin/worktree.c b/builtin/worktree.c
index ea9678cac8..7021d02585 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "checkout.h"
 #include "config.h"
 #include "builtin.h"
 #include "dir.h"
@@ -390,6 +391,21 @@ static int add(int ac, const char **av, const char *prefix)
 		opts.new_branch = xstrndup(s, n);
 	}
 
+	if (ac == 2 && !opts.new_branch && !opts.detach) {
+		struct object_id oid;
+		struct commit *commit;
+		const char *remote;
+
+		commit = lookup_commit_reference_by_name(branch);
+		if (!commit) {
+			remote = unique_tracking_name(branch, &oid);
+			if (remote) {
+				opts.new_branch = branch;
+				branch = remote;
+			}
+		}
+	}
+
 	if (opts.new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 		cp.git_cmd = 1;
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 72e8b62927..96ebc63d04 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -365,4 +365,23 @@ test_expect_success '--no-track avoids setting up tracking' '
 	)
 '
 
+test_expect_success '"add" <path> <non-existent-branch> fails' '
+	test_must_fail git worktree add foo non-existent
+'
+
+test_expect_success '"add" <path> <branch> dwims' '
+	test_when_finished rm -rf repo_upstream repo_dwim foo &&
+	setup_remote_repo repo_upstream repo_dwim &&
+	git init repo_dwim &&
+	(
+		cd repo_dwim &&
+		git worktree add ../foo foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_upstream foo &&
+		test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
+	)
+'
+
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
                       ` (3 preceding siblings ...)
  2017-11-26 19:43     ` [PATCH v5 4/6] worktree: make add <path> <branch> dwim Thomas Gummerer
@ 2017-11-26 19:43     ` Thomas Gummerer
  2017-11-27  6:36       ` Junio C Hamano
  2017-11-26 19:43     ` [PATCH v5 6/6] add worktree.guessRemote config option Thomas Gummerer
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
  6 siblings, 1 reply; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the <path>, that matches the HEAD of whichever worktree we
were on when calling "git worktree add <path>".

It's sometimes useful to have 'git worktree add <path> behave more like
the dwim machinery in 'git checkout <new-branch>', i.e. check if the new
branch name uniquely matches the branch name of a remote-tracking
branch, and if so check out that branch and set the upstream to the
remote-tracking branch.

Add a new --guess-remote option that enables exactly that behaviour.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  7 +++++++
 builtin/worktree.c             | 10 ++++++++++
 t/t2025-worktree-add.sh        | 29 +++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 3044d305a6..a81cfb2229 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -115,6 +115,13 @@ OPTIONS
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]guess-remote::
+	With `add`, instead of creating a new branch from HEAD when
+	`<commit-ish>` is not given, if there exists a tracking branch
+	in exactly one remote matching the basename of the path, base
+	the new branch on the remote-tracking branch, and mark the
+	remote-tracking branch as "upstream" from the new branch.
+
 --[no-]track::
 	When creating a new branch, if `<commit-ish>` is a branch,
 	mark it as "upstream" from the new branch.  This is the
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7021d02585..15cb1600ee 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -343,6 +343,7 @@ static int add(int ac, const char **av, const char *prefix)
 	char *path;
 	const char *branch;
 	const char *opt_track = NULL;
+	int guess_remote = 0;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -355,6 +356,8 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_PASSTHRU(0, "track", &opt_track, NULL,
 			     N_("set up tracking mode (see git-branch(1))"),
 			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
+		OPT_BOOL(0, "guess-remote", &guess_remote,
+			 N_("try to match the new branch name with a remote-tracking branch")),
 		OPT_END()
 	};
 
@@ -389,6 +392,13 @@ static int add(int ac, const char **av, const char *prefix)
 		int n;
 		const char *s = worktree_basename(path, &n);
 		opts.new_branch = xstrndup(s, n);
+		if (guess_remote) {
+			struct object_id oid;
+			const char *remote =
+				unique_tracking_name(opts.new_branch, &oid);
+			if (remote)
+				branch = remote;
+		}
 	}
 
 	if (ac == 2 && !opts.new_branch && !opts.detach) {
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 96ebc63d04..d25c774cb7 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -384,4 +384,33 @@ test_expect_success '"add" <path> <branch> dwims' '
 	)
 '
 
+test_expect_success 'git worktree add does not match remote' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git worktree add ../foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
+test_expect_success 'git worktree add --guess-remote sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git worktree add --guess-remote ../foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_a foo &&
+		test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 6/6] add worktree.guessRemote config option
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
                       ` (4 preceding siblings ...)
  2017-11-26 19:43     ` [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
@ 2017-11-26 19:43     ` Thomas Gummerer
  2017-11-27  6:45       ` Junio C Hamano
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
  6 siblings, 1 reply; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-26 19:43 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Some users might want to have the --guess-remote option introduced in
the previous commit on by default, so they don't have to type it out
every time they create a new worktree.

Add a config option worktree.guessRemote that allows users to configure
the default behaviour for themselves.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/config.txt       | 10 ++++++++++
 Documentation/git-worktree.txt |  3 +++
 builtin/worktree.c             | 14 +++++++++++++-
 t/t2025-worktree-add.sh        | 31 +++++++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5f65fa9234..4966d90ebb 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -3425,3 +3425,13 @@ web.browser::
 	Specify a web browser that may be used by some commands.
 	Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
 	may use it.
+
+worktree.guessRemote::
+	With `add`, if no branch argument, and neither of `-b` nor
+	`-B` nor `--detach` are given, the command defaults to
+	creating a new branch from HEAD.  If `worktree.guessRemote` is
+	set to true, `worktree add` tries to find a remote-tracking
+	branch whose name uniquely matches the new branch name.  If
+	such a branch exists, it is checked out and set as "upstream"
+	for the new branch.  If no such match can be found, it falls
+	back to creating a new branch from the current HEAD.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index a81cfb2229..fd841886ef 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -121,6 +121,9 @@ OPTIONS
 	in exactly one remote matching the basename of the path, base
 	the new branch on the remote-tracking branch, and mark the
 	remote-tracking branch as "upstream" from the new branch.
++
+This can also be set up as the default behaviour by using the
+`worktree.guessRemote` config option.
 
 --[no-]track::
 	When creating a new branch, if `<commit-ish>` is a branch,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 15cb1600ee..426aea8761 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -33,8 +33,19 @@ struct add_opts {
 
 static int show_only;
 static int verbose;
+static int guess_remote;
 static timestamp_t expire;
 
+static int git_worktree_config(const char *var, const char *value, void *cb)
+{
+	if (!strcmp(var, "worktree.guessremote")) {
+		guess_remote = git_config_bool(var, value);
+		return 0;
+	}
+
+	return 0;
+}
+
 static int prune_worktree(const char *id, struct strbuf *reason)
 {
 	struct stat st;
@@ -343,7 +354,6 @@ static int add(int ac, const char **av, const char *prefix)
 	char *path;
 	const char *branch;
 	const char *opt_track = NULL;
-	int guess_remote = 0;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -361,6 +371,8 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_END()
 	};
 
+	git_config(git_worktree_config, NULL);
+
 	memset(&opts, 0, sizeof(opts));
 	opts.checkout = 1;
 	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index d25c774cb7..6ce9b9c070 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -413,4 +413,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '
 	)
 '
 
+test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git config worktree.guessRemote true &&
+		git worktree add ../foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_a foo &&
+		test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
+test_expect_success 'git worktree --no-guess-remote option overrides config' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git config worktree.guessRemote true &&
+		git worktree add --no-guess-remote ../foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand
  2017-11-26 19:43     ` [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
@ 2017-11-27  6:36       ` Junio C Hamano
  2017-11-27 20:56         ` Thomas Gummerer
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2017-11-27  6:36 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine,
	Randall S. Becker, Paul Smith

Thomas Gummerer <t.gummerer@gmail.com> writes:

> Currently 'git worktree add <path>' creates a new branch named after the
> basename of the <path>, that matches the HEAD of whichever worktree we
> were on when calling "git worktree add <path>".
>
> It's sometimes useful to have 'git worktree add <path> behave more like
> the dwim machinery in 'git checkout <new-branch>', i.e. check if the new
> branch name uniquely matches the branch name of a remote-tracking
> branch, and if so check out that branch and set the upstream to the
> remote-tracking branch.

This paragraph was a bit hard to sympathize because it was not
obvious that the new feature still assumes how <path> is used to
compute the name of the new branch.  Perhaps if it were written like
so:

	check if the new branch name, derived from the basename of
	the <path>, uniquely matches the branch name of ...

I would not have had to read it twice to understand what was going
on.

> +--[no-]guess-remote::
> +	With `add`, instead of creating a new branch from HEAD when
> +	`<commit-ish>` is not given, if there exists a tracking branch
> +	in exactly one remote matching the basename of the path, base
> +	the new branch on the remote-tracking branch, and mark the
> +	remote-tracking branch as "upstream" from the new branch.
> +

Would

	git worktree add --guess-remote <path> <branch>

be an error?  It is allowed as long as <branch> and the basename of
the <path> matches?  The option is silently ignored?  Something
else?

I am reacting to "with `add`" part of this desciption.  I wouldn't
be asking if it said "With `worktree add <path>` without <branch>",
as that would make the scenario I am wondering about automatically
"undefined".  Yes, we should strive for leaving things undefined as
little as practically possible, but at least saying something like
"without <branch>" explicitly there would make sure that readers
know in what scenario this option is meant to be used a bit better.

> @@ -389,6 +392,13 @@ static int add(int ac, const char **av, const char *prefix)
>  		int n;
>  		const char *s = worktree_basename(path, &n);
>  		opts.new_branch = xstrndup(s, n);
> +		if (guess_remote) {
> +			struct object_id oid;
> +			const char *remote =
> +				unique_tracking_name(opts.new_branch, &oid);
> +			if (remote)
> +				branch = remote;
> +		}
>  	}

I think the answer is "silently ignored", as the above hunk is
inside "if (ac < 2 && !opts.new_branch && !opts.detach)".


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 6/6] add worktree.guessRemote config option
  2017-11-26 19:43     ` [PATCH v5 6/6] add worktree.guessRemote config option Thomas Gummerer
@ 2017-11-27  6:45       ` Junio C Hamano
  2017-11-27 20:59         ` Thomas Gummerer
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2017-11-27  6:45 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine,
	Randall S. Becker, Paul Smith

Thomas Gummerer <t.gummerer@gmail.com> writes:

> +worktree.guessRemote::
> +	With `add`, if no branch argument, and neither of `-b` nor
> +	`-B` nor `--detach` are given, the command defaults to
> +	creating a new branch from HEAD.  If `worktree.guessRemote` is
> +	set to true, `worktree add` tries to find a remote-tracking
> +	branch whose name uniquely matches the new branch name.  If
> +	such a branch exists, it is checked out and set as "upstream"
> +	for the new branch.  If no such match can be found, it falls
> +	back to creating a new branch from the current HEAD.

Unlike the part I commented on in the previous step, this one is
clear that the feature only kicks in for 'add <path>' without
anything else, which is good.

> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 15cb1600ee..426aea8761 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -33,8 +33,19 @@ struct add_opts {
>  
>  static int show_only;
>  static int verbose;
> +static int guess_remote;
>  static timestamp_t expire;
>  
> +static int git_worktree_config(const char *var, const char *value, void *cb)
> +{
> +	if (!strcmp(var, "worktree.guessremote")) {
> +		guess_remote = git_config_bool(var, value);
> +		return 0;
> +	}
> +
> +	return 0;
> +}
> +

It is a lot more consistent with the established practice if this
function had

	return git_default_config(var, value, cb);

instead of "return 0" at the end, and then have the call to

	git_config(git_default_config, NULL);

we have in cmd_worktree() replaced with

	git_config(git_worktree_config, NULL);

That would avoid having to scan the entire set of config keys once
in cmd_worktree() and then again in add(), the latter one only
looking for a single variable.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand
  2017-11-27  6:36       ` Junio C Hamano
@ 2017-11-27 20:56         ` Thomas Gummerer
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-27 20:56 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine,
	Randall S. Becker, Paul Smith

On 11/27, Junio C Hamano wrote:
> Thomas Gummerer <t.gummerer@gmail.com> writes:
> 
> > Currently 'git worktree add <path>' creates a new branch named after the
> > basename of the <path>, that matches the HEAD of whichever worktree we
> > were on when calling "git worktree add <path>".
> >
> > It's sometimes useful to have 'git worktree add <path> behave more like
> > the dwim machinery in 'git checkout <new-branch>', i.e. check if the new
> > branch name uniquely matches the branch name of a remote-tracking
> > branch, and if so check out that branch and set the upstream to the
> > remote-tracking branch.
> 
> This paragraph was a bit hard to sympathize because it was not
> obvious that the new feature still assumes how <path> is used to
> compute the name of the new branch.  Perhaps if it were written like
> so:
> 
> 	check if the new branch name, derived from the basename of
> 	the <path>, uniquely matches the branch name of ...
> 
> I would not have had to read it twice to understand what was going
> on.

Sorry about that, will re-phrase.

> > +--[no-]guess-remote::
> > +	With `add`, instead of creating a new branch from HEAD when
> > +	`<commit-ish>` is not given, if there exists a tracking branch
> > +	in exactly one remote matching the basename of the path, base
> > +	the new branch on the remote-tracking branch, and mark the
> > +	remote-tracking branch as "upstream" from the new branch.
> > +
> 
> Would
> 
> 	git worktree add --guess-remote <path> <branch>
> 
> be an error?  It is allowed as long as <branch> and the basename of
> the <path> matches?  The option is silently ignored?  Something
> else?
> 
> I am reacting to "with `add`" part of this desciption.  I wouldn't
> be asking if it said "With `worktree add <path>` without <branch>",
> as that would make the scenario I am wondering about automatically
> "undefined".  Yes, we should strive for leaving things undefined as
> little as practically possible, but at least saying something like
> "without <branch>" explicitly there would make sure that readers
> know in what scenario this option is meant to be used a bit better.

As you mentioned below it's silently ignored.  The main reason for not
erroring out is that it would get a little bit (although not too much)
more annoying once the config variable is introduced.  If it's
strongly preferred to error out when <branch> is given I can change it
to that.

Either way I'll update the documentation.

Thanks!

> > @@ -389,6 +392,13 @@ static int add(int ac, const char **av, const char *prefix)
> >  		int n;
> >  		const char *s = worktree_basename(path, &n);
> >  		opts.new_branch = xstrndup(s, n);
> > +		if (guess_remote) {
> > +			struct object_id oid;
> > +			const char *remote =
> > +				unique_tracking_name(opts.new_branch, &oid);
> > +			if (remote)
> > +				branch = remote;
> > +		}
> >  	}
> 
> I think the answer is "silently ignored", as the above hunk is
> inside "if (ac < 2 && !opts.new_branch && !opts.detach)".
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 6/6] add worktree.guessRemote config option
  2017-11-27  6:45       ` Junio C Hamano
@ 2017-11-27 20:59         ` Thomas Gummerer
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-27 20:59 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Nguyễn Thái Ngọc Duy, Eric Sunshine,
	Randall S. Becker, Paul Smith

On 11/27, Junio C Hamano wrote:
> Thomas Gummerer <t.gummerer@gmail.com> writes:
> 
> > +worktree.guessRemote::
> > +	With `add`, if no branch argument, and neither of `-b` nor
> > +	`-B` nor `--detach` are given, the command defaults to
> > +	creating a new branch from HEAD.  If `worktree.guessRemote` is
> > +	set to true, `worktree add` tries to find a remote-tracking
> > +	branch whose name uniquely matches the new branch name.  If
> > +	such a branch exists, it is checked out and set as "upstream"
> > +	for the new branch.  If no such match can be found, it falls
> > +	back to creating a new branch from the current HEAD.
> 
> Unlike the part I commented on in the previous step, this one is
> clear that the feature only kicks in for 'add <path>' without
> anything else, which is good.
> 
> > diff --git a/builtin/worktree.c b/builtin/worktree.c
> > index 15cb1600ee..426aea8761 100644
> > --- a/builtin/worktree.c
> > +++ b/builtin/worktree.c
> > @@ -33,8 +33,19 @@ struct add_opts {
> >  
> >  static int show_only;
> >  static int verbose;
> > +static int guess_remote;
> >  static timestamp_t expire;
> >  
> > +static int git_worktree_config(const char *var, const char *value, void *cb)
> > +{
> > +	if (!strcmp(var, "worktree.guessremote")) {
> > +		guess_remote = git_config_bool(var, value);
> > +		return 0;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> 
> It is a lot more consistent with the established practice if this
> function had
> 
> 	return git_default_config(var, value, cb);
> 
> instead of "return 0" at the end, and then have the call to
> 
> 	git_config(git_default_config, NULL);
> 
> we have in cmd_worktree() replaced with
> 
> 	git_config(git_worktree_config, NULL);
> 
> That would avoid having to scan the entire set of config keys once
> in cmd_worktree() and then again in add(), the latter one only
> looking for a single variable.

Makes sense, I missed that.  I'll fix it in the re-roll.  I'll wait a
few days to see if there are any more comments on the series and then
re-roll it with the suggested changes.

Thanks for the review!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v6 0/6] make git worktree add dwim more
  2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
                       ` (5 preceding siblings ...)
  2017-11-26 19:43     ` [PATCH v5 6/6] add worktree.guessRemote config option Thomas Gummerer
@ 2017-11-29 20:04     ` Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 1/6] checkout: factor out functions to new lib file Thomas Gummerer
                         ` (5 more replies)
  6 siblings, 6 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

The previous rounds were at
https://public-inbox.org/git/20171112134305.3949-1-t.gummerer@gmail.com/,
https://public-inbox.org/git/20171118181103.28354-1-t.gummerer@gmail.com/,
https://public-inbox.org/git/20171118224706.13810-1-t.gummerer@gmail.com/,
https://public-inbox.org/git/20171122223020.2780-1-t.gummerer@gmail.com/ and
https://public-inbox.org/git/20171126194356.16187-1-t.gummerer@gmail.com.

Thanks Junio for the review of the last round!

Changes since the last round:

- rephrased documentation and commit messaegs a bit use the
- established pattern and call git_config only once, instead of
  calling it multiple times.

Interdiff below:
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index fd841886ef..89ad0faecf 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -116,11 +116,11 @@ OPTIONS
 	in linkgit:git-read-tree[1].
 
 --[no-]guess-remote::
-	With `add`, instead of creating a new branch from HEAD when
-	`<commit-ish>` is not given, if there exists a tracking branch
-	in exactly one remote matching the basename of the path, base
-	the new branch on the remote-tracking branch, and mark the
-	remote-tracking branch as "upstream" from the new branch.
+	With `worktree add <path>`, withouth `<commit-ish>`, instead
+	of creating a new branch from HEAD, if there exists a tracking
+	branch in exactly one remote matching the basename of `<path>,
+	base the new branch on the remote-tracking branch, and mark
+	the remote-tracking branch as "upstream" from the new branch.
 +
 This can also be set up as the default behaviour by using the
 `worktree.guessRemote` config option.
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 426aea8761..002a569a11 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -43,7 +43,7 @@ static int git_worktree_config(const char *var, const char *value, void *cb)
 		return 0;
 	}
 
-	return 0;
+	return git_default_config(var, value, cb);
 }
 
 static int prune_worktree(const char *id, struct strbuf *reason)
@@ -371,8 +371,6 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_END()
 	};
 
-	git_config(git_worktree_config, NULL);
-
 	memset(&opts, 0, sizeof(opts));
 	opts.checkout = 1;
 	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
@@ -603,7 +601,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 		OPT_END()
 	};
 
-	git_config(git_default_config, NULL);
+	git_config(git_worktree_config, NULL);
 
 	if (ac < 2)
 		usage_with_options(worktree_usage, options);

Thomas Gummerer (6):
  checkout: factor out functions to new lib file
  worktree: add can be created from any commit-ish
  worktree: add --[no-]track option to the add subcommand
  worktree: make add <path> <branch> dwim
  worktree: add --guess-remote flag to add subcommand
  add worktree.guessRemote config option

 Documentation/config.txt       |  10 ++++
 Documentation/git-worktree.txt |  44 ++++++++++----
 Makefile                       |   1 +
 builtin/checkout.c             |  41 +------------
 builtin/worktree.c             |  46 ++++++++++++++-
 checkout.c                     |  43 ++++++++++++++
 checkout.h                     |  13 +++++
 t/t2025-worktree-add.sh        | 130 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 277 insertions(+), 51 deletions(-)
 create mode 100644 checkout.c
 create mode 100644 checkout.h

-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 1/6] checkout: factor out functions to new lib file
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
@ 2017-11-29 20:04       ` Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 2/6] worktree: add can be created from any commit-ish Thomas Gummerer
                         ` (4 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Factor the functions out, so they can be re-used from other places.  In
particular these functions will be re-used in builtin/worktree.c to make
git worktree add dwim more.

While there add some docs to the function.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Makefile           |  1 +
 builtin/checkout.c | 41 +----------------------------------------
 checkout.c         | 43 +++++++++++++++++++++++++++++++++++++++++++
 checkout.h         | 13 +++++++++++++
 4 files changed, 58 insertions(+), 40 deletions(-)
 create mode 100644 checkout.c
 create mode 100644 checkout.h

diff --git a/Makefile b/Makefile
index e53750ca01..a80a8fcca9 100644
--- a/Makefile
+++ b/Makefile
@@ -759,6 +759,7 @@ LIB_OBJS += branch.o
 LIB_OBJS += bulk-checkin.o
 LIB_OBJS += bundle.o
 LIB_OBJS += cache-tree.o
+LIB_OBJS += checkout.o
 LIB_OBJS += color.o
 LIB_OBJS += column.o
 LIB_OBJS += combine-diff.o
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 7d8bcc3833..ad8f94044c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "config.h"
+#include "checkout.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "refs.h"
@@ -872,46 +873,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
 	return git_xmerge_config(var, value, NULL);
 }
 
-struct tracking_name_data {
-	/* const */ char *src_ref;
-	char *dst_ref;
-	struct object_id *dst_oid;
-	int unique;
-};
-
-static int check_tracking_name(struct remote *remote, void *cb_data)
-{
-	struct tracking_name_data *cb = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
-	query.src = cb->src_ref;
-	if (remote_find_tracking(remote, &query) ||
-	    get_oid(query.dst, cb->dst_oid)) {
-		free(query.dst);
-		return 0;
-	}
-	if (cb->dst_ref) {
-		free(query.dst);
-		cb->unique = 0;
-		return 0;
-	}
-	cb->dst_ref = query.dst;
-	return 0;
-}
-
-static const char *unique_tracking_name(const char *name, struct object_id *oid)
-{
-	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
-	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
-	cb_data.dst_oid = oid;
-	for_each_remote(check_tracking_name, &cb_data);
-	free(cb_data.src_ref);
-	if (cb_data.unique)
-		return cb_data.dst_ref;
-	free(cb_data.dst_ref);
-	return NULL;
-}
-
 static int parse_branchname_arg(int argc, const char **argv,
 				int dwim_new_local_branch_ok,
 				struct branch_info *new,
diff --git a/checkout.c b/checkout.c
new file mode 100644
index 0000000000..ac42630f74
--- /dev/null
+++ b/checkout.c
@@ -0,0 +1,43 @@
+#include "cache.h"
+#include "remote.h"
+#include "checkout.h"
+
+struct tracking_name_data {
+	/* const */ char *src_ref;
+	char *dst_ref;
+	struct object_id *dst_oid;
+	int unique;
+};
+
+static int check_tracking_name(struct remote *remote, void *cb_data)
+{
+	struct tracking_name_data *cb = cb_data;
+	struct refspec query;
+	memset(&query, 0, sizeof(struct refspec));
+	query.src = cb->src_ref;
+	if (remote_find_tracking(remote, &query) ||
+	    get_oid(query.dst, cb->dst_oid)) {
+		free(query.dst);
+		return 0;
+	}
+	if (cb->dst_ref) {
+		free(query.dst);
+		cb->unique = 0;
+		return 0;
+	}
+	cb->dst_ref = query.dst;
+	return 0;
+}
+
+const char *unique_tracking_name(const char *name, struct object_id *oid)
+{
+	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
+	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
+	cb_data.dst_oid = oid;
+	for_each_remote(check_tracking_name, &cb_data);
+	free(cb_data.src_ref);
+	if (cb_data.unique)
+		return cb_data.dst_ref;
+	free(cb_data.dst_ref);
+	return NULL;
+}
diff --git a/checkout.h b/checkout.h
new file mode 100644
index 0000000000..9980711179
--- /dev/null
+++ b/checkout.h
@@ -0,0 +1,13 @@
+#ifndef CHECKOUT_H
+#define CHECKOUT_H
+
+#include "cache.h"
+
+/*
+ * Check if the branch name uniquely matches a branch name on a remote
+ * tracking branch.  Return the name of the remote if such a branch
+ * exists, NULL otherwise.
+ */
+extern const char *unique_tracking_name(const char *name, struct object_id *oid);
+
+#endif /* CHECKOUT_H */
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 2/6] worktree: add can be created from any commit-ish
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 1/6] checkout: factor out functions to new lib file Thomas Gummerer
@ 2017-11-29 20:04       ` Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 3/6] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
                         ` (3 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add' is documented to take an optional <branch>
argument, which is checked out in the new worktree.  However it is more
generally possible to use a commit-ish as the optional argument, and
check that out into the new worktree.

Document that this is a possibility, as new users of git worktree add
might find it helpful.

Reported-by: Randall S. Becker <rsbecker@nexbridge.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index b472acc356..121895209d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<branch>]
+'git worktree add' [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]
 'git worktree list' [--porcelain]
 'git worktree lock' [--reason <string>] <worktree>
 'git worktree prune' [-n] [-v] [--expire <expire>]
@@ -45,14 +45,14 @@ specifying `--reason` to explain why the working tree is locked.
 
 COMMANDS
 --------
-add <path> [<branch>]::
+add <path> [<commit-ish>]::
 
-Create `<path>` and checkout `<branch>` into it. The new working directory
+Create `<path>` and checkout `<commit-ish>` into it. The new working directory
 is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc. `-` may also be
-specified as `<branch>`; it is synonymous with `@{-1}`.
+specified as `<commit-ish>`; it is synonymous with `@{-1}`.
 +
-If `<branch>` is omitted and neither `-b` nor `-B` nor `--detach` used,
+If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
 then, as a convenience, a new branch based at HEAD is created automatically,
 as if `-b $(basename <path>)` was specified.
 
@@ -84,25 +84,25 @@ OPTIONS
 
 -f::
 --force::
-	By default, `add` refuses to create a new working tree when `<branch>`
+	By default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and
 	is already checked out by another working tree. This option overrides
 	that safeguard.
 
 -b <new-branch>::
 -B <new-branch>::
 	With `add`, create a new branch named `<new-branch>` starting at
-	`<branch>`, and check out `<new-branch>` into the new working tree.
-	If `<branch>` is omitted, it defaults to HEAD.
+	`<commit-ish>`, and check out `<new-branch>` into the new working tree.
+	If `<commit-ish>` is omitted, it defaults to HEAD.
 	By default, `-b` refuses to create a new branch if it already
 	exists. `-B` overrides this safeguard, resetting `<new-branch>` to
-	`<branch>`.
+	`<commit-ish>`.
 
 --detach::
 	With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
 	in linkgit:git-checkout[1].
 
 --[no-]checkout::
-	By default, `add` checks out `<branch>`, however, `--no-checkout` can
+	By default, `add` checks out `<commit-ish>`, however, `--no-checkout` can
 	be used to suppress checkout in order to make customizations,
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 3/6] worktree: add --[no-]track option to the add subcommand
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 1/6] checkout: factor out functions to new lib file Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 2/6] worktree: add can be created from any commit-ish Thomas Gummerer
@ 2017-11-29 20:04       ` Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 4/6] worktree: make add <path> <branch> dwim Thomas Gummerer
                         ` (2 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add' sets up tracking branches if '<branch>' is
a remote tracking branch, and doesn't set them up otherwise, as is the
default for 'git branch'.

This may or may not be what the user wants.  Allow overriding this
behaviour with a --[no-]track flag that gets passed through to 'git
branch'.

We already respect branch.autoSetupMerge, as 'git worktree' just calls
'git branch' internally.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  6 +++++
 builtin/worktree.c             |  8 +++++++
 t/t2025-worktree-add.sh        | 51 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 121895209d..15e58b18f7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -107,6 +107,12 @@ OPTIONS
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]track::
+	When creating a new branch, if `<commit-ish>` is a branch,
+	mark it as "upstream" from the new branch.  This is the
+	default if `<commit-ish>` is a remote-tracking branch.  See
+	"--track" in linkgit:git-branch[1] for details.
+
 --lock::
 	Keep the working tree locked after creation. This is the
 	equivalent of `git worktree lock` after `git worktree add`,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index ed043d5f1c..ea9678cac8 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -341,6 +341,7 @@ static int add(int ac, const char **av, const char *prefix)
 	const char *new_branch_force = NULL;
 	char *path;
 	const char *branch;
+	const char *opt_track = NULL;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -350,6 +351,9 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
 		OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
 		OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+		OPT_PASSTHRU(0, "track", &opt_track, NULL,
+			     N_("set up tracking mode (see git-branch(1))"),
+			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
 		OPT_END()
 	};
 
@@ -394,9 +398,13 @@ static int add(int ac, const char **av, const char *prefix)
 			argv_array_push(&cp.args, "--force");
 		argv_array_push(&cp.args, opts.new_branch);
 		argv_array_push(&cp.args, branch);
+		if (opt_track)
+			argv_array_push(&cp.args, opt_track);
 		if (run_command(&cp))
 			return -1;
 		branch = opts.new_branch;
+	} else if (opt_track) {
+		die(_("--[no-]track can only be used if a new branch is created"));
 	}
 
 	UNLEAK(path);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index b5c47ac602..72e8b62927 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -313,5 +313,56 @@ test_expect_success 'checkout a branch under bisect' '
 test_expect_success 'rename a branch under bisect not allowed' '
 	test_must_fail git branch -M under-bisect bisect-with-new-name
 '
+# Is branch "refs/heads/$1" set to pull from "$2/$3"?
+test_branch_upstream () {
+	printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
+	{
+		git config "branch.$1.remote" &&
+		git config "branch.$1.merge"
+	} >actual.upstream &&
+	test_cmp expect.upstream actual.upstream
+}
+
+test_expect_success '--track sets up tracking' '
+	test_when_finished rm -rf track &&
+	git worktree add --track -b track track master &&
+	test_branch_upstream track . master
+'
+
+# setup remote repository $1 and repository $2 with $1 set up as
+# remote.  The remote has two branches, master and foo.
+setup_remote_repo () {
+	git init $1 &&
+	(
+		cd $1 &&
+		test_commit $1_master &&
+		git checkout -b foo &&
+		test_commit upstream_foo
+	) &&
+	git init $2 &&
+	(
+		cd $2 &&
+		test_commit $2_master &&
+		git remote add $1 ../$1 &&
+		git config remote.$1.fetch \
+			"refs/heads/*:refs/remotes/$1/*" &&
+		git fetch --all
+	)
+}
+
+test_expect_success '--no-track avoids setting up tracking' '
+	test_when_finished rm -rf repo_upstream repo_local foo &&
+	setup_remote_repo repo_upstream repo_local &&
+	(
+		cd repo_local &&
+		git worktree add --no-track -b foo ../foo repo_upstream/foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
+	)
+'
 
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 4/6] worktree: make add <path> <branch> dwim
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
                         ` (2 preceding siblings ...)
  2017-11-29 20:04       ` [PATCH v6 3/6] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
@ 2017-11-29 20:04       ` Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 6/6] add worktree.guessRemote config option Thomas Gummerer
  5 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add <path> <branch>', errors out when 'branch'
is not a local branch.  It has no additional dwim'ing features that one
might expect.

Make it behave more like 'git checkout <branch>' when the branch doesn't
exist locally, but a remote tracking branch uniquely matches the desired
branch name, i.e. create a new branch from the remote tracking branch
and set the upstream to the remote tracking branch.

As 'git worktree add' currently just dies in this situation, there are
no backwards compatibility worries when introducing this feature.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  8 ++++++++
 builtin/worktree.c             | 16 ++++++++++++++++
 t/t2025-worktree-add.sh        | 19 +++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 15e58b18f7..3044d305a6 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -52,6 +52,14 @@ is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc. `-` may also be
 specified as `<commit-ish>`; it is synonymous with `@{-1}`.
 +
+If <commit-ish> is a branch name (call it `<branch>` and is not found,
+and neither `-b` nor `-B` nor `--detach` are used, but there does
+exist a tracking branch in exactly one remote (call it `<remote>`)
+with a matching name, treat as equivalent to
+------------
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
+------------
++
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
 then, as a convenience, a new branch based at HEAD is created automatically,
 as if `-b $(basename <path>)` was specified.
diff --git a/builtin/worktree.c b/builtin/worktree.c
index ea9678cac8..7021d02585 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "checkout.h"
 #include "config.h"
 #include "builtin.h"
 #include "dir.h"
@@ -390,6 +391,21 @@ static int add(int ac, const char **av, const char *prefix)
 		opts.new_branch = xstrndup(s, n);
 	}
 
+	if (ac == 2 && !opts.new_branch && !opts.detach) {
+		struct object_id oid;
+		struct commit *commit;
+		const char *remote;
+
+		commit = lookup_commit_reference_by_name(branch);
+		if (!commit) {
+			remote = unique_tracking_name(branch, &oid);
+			if (remote) {
+				opts.new_branch = branch;
+				branch = remote;
+			}
+		}
+	}
+
 	if (opts.new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 		cp.git_cmd = 1;
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 72e8b62927..96ebc63d04 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -365,4 +365,23 @@ test_expect_success '--no-track avoids setting up tracking' '
 	)
 '
 
+test_expect_success '"add" <path> <non-existent-branch> fails' '
+	test_must_fail git worktree add foo non-existent
+'
+
+test_expect_success '"add" <path> <branch> dwims' '
+	test_when_finished rm -rf repo_upstream repo_dwim foo &&
+	setup_remote_repo repo_upstream repo_dwim &&
+	git init repo_dwim &&
+	(
+		cd repo_dwim &&
+		git worktree add ../foo foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_upstream foo &&
+		test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
+	)
+'
+
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 5/6] worktree: add --guess-remote flag to add subcommand
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
                         ` (3 preceding siblings ...)
  2017-11-29 20:04       ` [PATCH v6 4/6] worktree: make add <path> <branch> dwim Thomas Gummerer
@ 2017-11-29 20:04       ` Thomas Gummerer
  2017-11-29 20:04       ` [PATCH v6 6/6] add worktree.guessRemote config option Thomas Gummerer
  5 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the <path>, that matches the HEAD of whichever worktree we
were on when calling "git worktree add <path>".

It's sometimes useful to have 'git worktree add <path> behave more like
the dwim machinery in 'git checkout <new-branch>', i.e. check if the new
branch name, derived from the basename of the <path>, uniquely matches
the branch name of a remote-tracking branch, and if so check out that
branch and set the upstream to the remote-tracking branch.

Add a new --guess-remote option that enables exactly that behaviour.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  7 +++++++
 builtin/worktree.c             | 10 ++++++++++
 t/t2025-worktree-add.sh        | 29 +++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 3044d305a6..a4ffee5e08 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -115,6 +115,13 @@ OPTIONS
 	such as configuring sparse-checkout. See "Sparse checkout"
 	in linkgit:git-read-tree[1].
 
+--[no-]guess-remote::
+	With `worktree add <path>`, withouth `<commit-ish>`, instead
+	of creating a new branch from HEAD, if there exists a tracking
+	branch in exactly one remote matching the basename of `<path>,
+	base the new branch on the remote-tracking branch, and mark
+	the remote-tracking branch as "upstream" from the new branch.
+
 --[no-]track::
 	When creating a new branch, if `<commit-ish>` is a branch,
 	mark it as "upstream" from the new branch.  This is the
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7021d02585..15cb1600ee 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -343,6 +343,7 @@ static int add(int ac, const char **av, const char *prefix)
 	char *path;
 	const char *branch;
 	const char *opt_track = NULL;
+	int guess_remote = 0;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -355,6 +356,8 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_PASSTHRU(0, "track", &opt_track, NULL,
 			     N_("set up tracking mode (see git-branch(1))"),
 			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
+		OPT_BOOL(0, "guess-remote", &guess_remote,
+			 N_("try to match the new branch name with a remote-tracking branch")),
 		OPT_END()
 	};
 
@@ -389,6 +392,13 @@ static int add(int ac, const char **av, const char *prefix)
 		int n;
 		const char *s = worktree_basename(path, &n);
 		opts.new_branch = xstrndup(s, n);
+		if (guess_remote) {
+			struct object_id oid;
+			const char *remote =
+				unique_tracking_name(opts.new_branch, &oid);
+			if (remote)
+				branch = remote;
+		}
 	}
 
 	if (ac == 2 && !opts.new_branch && !opts.detach) {
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 96ebc63d04..d25c774cb7 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -384,4 +384,33 @@ test_expect_success '"add" <path> <branch> dwims' '
 	)
 '
 
+test_expect_success 'git worktree add does not match remote' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git worktree add ../foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
+test_expect_success 'git worktree add --guess-remote sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git worktree add --guess-remote ../foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_a foo &&
+		test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 6/6] add worktree.guessRemote config option
  2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
                         ` (4 preceding siblings ...)
  2017-11-29 20:04       ` [PATCH v6 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
@ 2017-11-29 20:04       ` Thomas Gummerer
  5 siblings, 0 replies; 36+ messages in thread
From: Thomas Gummerer @ 2017-11-29 20:04 UTC (permalink / raw)
  To: git
  Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano,
	Eric Sunshine, Randall S. Becker, Paul Smith, Thomas Gummerer

Some users might want to have the --guess-remote option introduced in
the previous commit on by default, so they don't have to type it out
every time they create a new worktree.

Add a config option worktree.guessRemote that allows users to configure
the default behaviour for themselves.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/config.txt       | 10 ++++++++++
 Documentation/git-worktree.txt |  3 +++
 builtin/worktree.c             | 14 ++++++++++++--
 t/t2025-worktree-add.sh        | 31 +++++++++++++++++++++++++++++++
 4 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5f65fa9234..4966d90ebb 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -3425,3 +3425,13 @@ web.browser::
 	Specify a web browser that may be used by some commands.
 	Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
 	may use it.
+
+worktree.guessRemote::
+	With `add`, if no branch argument, and neither of `-b` nor
+	`-B` nor `--detach` are given, the command defaults to
+	creating a new branch from HEAD.  If `worktree.guessRemote` is
+	set to true, `worktree add` tries to find a remote-tracking
+	branch whose name uniquely matches the new branch name.  If
+	such a branch exists, it is checked out and set as "upstream"
+	for the new branch.  If no such match can be found, it falls
+	back to creating a new branch from the current HEAD.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index a4ffee5e08..89ad0faecf 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -121,6 +121,9 @@ OPTIONS
 	branch in exactly one remote matching the basename of `<path>,
 	base the new branch on the remote-tracking branch, and mark
 	the remote-tracking branch as "upstream" from the new branch.
++
+This can also be set up as the default behaviour by using the
+`worktree.guessRemote` config option.
 
 --[no-]track::
 	When creating a new branch, if `<commit-ish>` is a branch,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 15cb1600ee..002a569a11 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -33,8 +33,19 @@ struct add_opts {
 
 static int show_only;
 static int verbose;
+static int guess_remote;
 static timestamp_t expire;
 
+static int git_worktree_config(const char *var, const char *value, void *cb)
+{
+	if (!strcmp(var, "worktree.guessremote")) {
+		guess_remote = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value, cb);
+}
+
 static int prune_worktree(const char *id, struct strbuf *reason)
 {
 	struct stat st;
@@ -343,7 +354,6 @@ static int add(int ac, const char **av, const char *prefix)
 	char *path;
 	const char *branch;
 	const char *opt_track = NULL;
-	int guess_remote = 0;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -591,7 +601,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 		OPT_END()
 	};
 
-	git_config(git_default_config, NULL);
+	git_config(git_worktree_config, NULL);
 
 	if (ac < 2)
 		usage_with_options(worktree_usage, options);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index d25c774cb7..6ce9b9c070 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -413,4 +413,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '
 	)
 '
 
+test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git config worktree.guessRemote true &&
+		git worktree add ../foo
+	) &&
+	(
+		cd foo &&
+		test_branch_upstream foo repo_a foo &&
+		test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
+test_expect_success 'git worktree --no-guess-remote option overrides config' '
+	test_when_finished rm -rf repo_a repo_b foo &&
+	setup_remote_repo repo_a repo_b &&
+	(
+		cd repo_b &&
+		git config worktree.guessRemote true &&
+		git worktree add --no-guess-remote ../foo
+	) &&
+	(
+		cd foo &&
+		test_must_fail git config "branch.foo.remote" &&
+		test_must_fail git config "branch.foo.merge" &&
+		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+	)
+'
+
 test_done
-- 
2.15.0.426.gb06021eeb


^ permalink raw reply related	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2017-11-29 20:03 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <mailto:20171118224706.13810-1-t.gummerer@gmail.com>
2017-11-22 22:30 ` [PATCH v4 0/4] make git worktree add dwim more Thomas Gummerer
2017-11-22 22:30   ` [PATCH v4 1/4] checkout: factor out functions to new lib file Thomas Gummerer
2017-11-24  6:47     ` Junio C Hamano
2017-11-22 22:30   ` [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
2017-11-24  6:57     ` Junio C Hamano
2017-11-25 16:58       ` Thomas Gummerer
2017-11-22 22:30   ` [PATCH v4 3/4] worktree: make add <path> <branch> dwim Thomas Gummerer
2017-11-24  6:59     ` Junio C Hamano
2017-11-22 22:30   ` [PATCH v4 4/4] worktree: make add <path> dwim Thomas Gummerer
2017-11-24  7:11     ` Junio C Hamano
2017-11-25 17:50       ` Thomas Gummerer
2017-11-25 18:26         ` Paul Smith
2017-11-25 20:06           ` Thomas Gummerer
2017-11-25 20:39             ` Randall S. Becker
2017-11-25 21:48               ` Thomas Gummerer
2017-11-25 23:11             ` Paul Smith
2017-11-26  3:35         ` Junio C Hamano
2017-11-26 11:37           ` Thomas Gummerer
2017-11-26 19:43   ` [PATCH v5 0/6] make git worktree add dwim more Thomas Gummerer
2017-11-26 19:43     ` [PATCH v5 1/6] checkout: factor out functions to new lib file Thomas Gummerer
2017-11-26 19:43     ` [PATCH v5 2/6] worktree: add can be created from any commit-ish Thomas Gummerer
2017-11-26 19:43     ` [PATCH v5 3/6] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
2017-11-26 19:43     ` [PATCH v5 4/6] worktree: make add <path> <branch> dwim Thomas Gummerer
2017-11-26 19:43     ` [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
2017-11-27  6:36       ` Junio C Hamano
2017-11-27 20:56         ` Thomas Gummerer
2017-11-26 19:43     ` [PATCH v5 6/6] add worktree.guessRemote config option Thomas Gummerer
2017-11-27  6:45       ` Junio C Hamano
2017-11-27 20:59         ` Thomas Gummerer
2017-11-29 20:04     ` [PATCH v6 0/6] make git worktree add dwim more Thomas Gummerer
2017-11-29 20:04       ` [PATCH v6 1/6] checkout: factor out functions to new lib file Thomas Gummerer
2017-11-29 20:04       ` [PATCH v6 2/6] worktree: add can be created from any commit-ish Thomas Gummerer
2017-11-29 20:04       ` [PATCH v6 3/6] worktree: add --[no-]track option to the add subcommand Thomas Gummerer
2017-11-29 20:04       ` [PATCH v6 4/6] worktree: make add <path> <branch> dwim Thomas Gummerer
2017-11-29 20:04       ` [PATCH v6 5/6] worktree: add --guess-remote flag to add subcommand Thomas Gummerer
2017-11-29 20:04       ` [PATCH v6 6/6] add worktree.guessRemote config option Thomas Gummerer

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).