The previous rounds can be found at
https://public-inbox.org/git/20171112134305.3949-1-t.gumme...@gmail.com/,
https://public-inbox.org/git/20171118181103.28354-1-t.gumme...@gmail.com/,
https://public-inbox.org/git/20171118224706.13810-1-t.gumme...@gmail.com/ and
https://public-inbox.org/git/20171122223020.2780-1-t.gumme...@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

Reply via email to