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@xxxxxxxxx> --- 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