worktree: make add <path> dwim
Subsystems (2)
A message that is not in the archive (sent off-list or not yet received): mailto:[email protected]
v4 cover make git worktree add dwim more
The previous rounds were at
https://public-inbox.org/git/[email protected]/,
https://public-inbox.org/git/[email protected]/ and
https://public-inbox.org/git/[email protected]/.
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:
Documentation/git-worktree.txt +12 -5
@@ -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`,
builtin/worktree.c +14 -7
@@ -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);
t/t2025-worktree-add.sh +63 -61
171 lines not on this page · raw message
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
Signature · 1 line
2.15.0.345.gf926f18f3
PATCH v4 1/4 checkout: factor out functions to new lib file
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.
--- 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
Makefile +1 -0
@@ -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
builtin/checkout.c +1 -40
52 lines not on this page · raw message
checkout.c new file +42 -0
42 lines not on this page · raw message
checkout.h new file +13 -0
@@ -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 */
Signature · 1 line
2.15.0.345.gf926f18f3
Re: [PATCH v4 1/4] checkout: factor out functions to new lib file
Quoted 33 lines · 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.cto make git worktree add dwim more.While there add some docs to the function.
Signed-off-by Thomas Gummerer <[email protected]>--- 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.hMakefile +1
-0@@ -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.obuiltin/checkout.c +0
-0
builtin/checkout.c line 6
Quoted 6 lines
builtin/checkout.c +1
-0@@ -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 ...
checkout.c line 2
Quoted 8 lines
checkout.c new file +2
-0@@ -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.
PATCH v4 2/4 worktree: add --[no-]track option to the add subcommand
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 6 +++++ builtin/worktree.c | 8 ++++++ t/t2025-worktree-add.sh | 55 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+)
Documentation/git-worktree.txt +6 -0
@@ -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`,
builtin/worktree.c +8 -0
@@ -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);
t/t2025-worktree-add.sh +55 -0
60 lines not on this page · raw message
Signature · 1 line
2.15.0.345.gf926f18f3
Re: [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand
Quoted 7 lines · Thomas Gummerer
t/t2025-worktree-add.sh +0
-0@@ -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
t/t2025-worktree-add.sh test_expect_success 'checkout a branch under bisect' ' · line 324
Quoted 10 lines
t/t2025-worktree-add.sh +9
-0' +# 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.
t/t2025-worktree-add.sh test_expect_success 'checkout a branch under bisect' ' · line 333
Quoted 8 lines
t/t2025-worktree-add.sh +8
-0+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?
Quoted 21 lines
t/t2025-worktree-add.sh +21
-0+# 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 + ) +} +
t/t2025-worktree-add.sh test_expect_success 'checkout a branch under bisect' ' · line 365
Quoted 10 lines
t/t2025-worktree-add.sh +10
-0+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.
Quoted 7 lines
t/t2025-worktree-add.sh +5
-0+ git rev-parse repo_upstream/foo >expect && + git rev-parse foo >actual && + test_cmp expect actual + ) +' test_done
Re: [PATCH v4 2/4] worktree: add --[no-]track option to the add subcommand
Quoted 22 lines · Junio C Hamano
Quoted 7 lines · Thomas Gummerer
t/t2025-worktree-add.sh +0
-0@@ -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-namet/t2025-worktree-add.sh test_expect_success 'checkout a branch under bisect' ' · line 324
Quoted 10 lines
t/t2025-worktree-add.sh +9
-0' +# 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.
Quoted 13 lines
t/t2025-worktree-add.sh test_expect_success 'checkout a branch under bisect' ' · line 333
Quoted 8 lines
t/t2025-worktree-add.sh +8
-0+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.
Quoted 30 lines
Quoted 30 lines
t/t2025-worktree-add.sh +30
-0+# 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 &&
Quoted 8 lines
t/t2025-worktree-add.sh test_expect_success 'checkout a branch under bisect' ' · line 365
Quoted 1 line
t/t2025-worktree-add.sh +1
-0+ ! 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!
Quoted 7 lines
Quoted 7 lines
t/t2025-worktree-add.sh +5
-0+ git rev-parse repo_upstream/foo >expect && + git rev-parse foo >actual && + test_cmp expect actual + ) +' test_done
PATCH v4 3/4 worktree: make add <path> <branch> dwim
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 7 +++++++ builtin/worktree.c | 16 ++++++++++++++++ t/t2025-worktree-add.sh | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+)
Documentation/git-worktree.txt +7 -0
@@ -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.
builtin/worktree.c +16 -0
@@ -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 ;
t/t2025-worktree-add.sh +21 -0
@@ -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
Signature · 1 line
2.15.0.345.gf926f18f3
Re: [PATCH v4 3/4] worktree: make add <path> <branch> dwim
Quoted 9 lines · 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.
Quoted 5 lines
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 <[email protected]>---
This step makes sense and I did not spot anything controversial.
PATCH v4 4/4 worktree: make add <path> dwim
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 14 ++++++++++++-- builtin/worktree.c | 7 +++++++ t/t2025-worktree-add.sh | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-)
Documentation/git-worktree.txt +12 -2
@@ -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::
builtin/worktree.c +7 -0
@@ -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) {
t/t2025-worktree-add.sh +32 -0
@@ -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
Signature · 1 line
2.15.0.345.gf926f18f3
Quoted 9 lines · 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.
Quoted 5 lines
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.
Quoted 4 lines
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.
Quoted 17 lines · Junio C Hamano
Quoted 9 lines · 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.
Quoted 5 lines
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.
Quoted 3 lines
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 blavs. the output without the changed behaviour:
$ git worktree add ../bla
Preparing ../bla (identifier bla)
HEAD is now at 0f215c9 initial importOf 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?
Quoted 5 lines
Quoted 4 lines
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.
Quoted 8 lines
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.
Quoted 8 lines
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.txtand 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.
Quoted 5 lines
That is
refs/remotes/origin/topic is a remote-tracking branch for the branch 'topic' that came from the 'origin' remote.
Quoted 7 lines
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.
Quoted 13 lines · Thomas Gummerer
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 blavs. the output without the changed behaviour:
$ git worktree add ../bla Preparing ../bla (identifier bla) HEAD is now at 0f215c9 initial import
Quoted 7 lines
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.
Quoted 44 lines · Paul Smith
Quoted 13 lines · Thomas Gummerer
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 blavs. the output without the changed behaviour:
$ git worktree add ../bla Preparing ../bla (identifier bla) HEAD is now at 0f215c9 initial importQuoted 7 lines
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.0and 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:
Quoted 6 lines
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.
On November 25, 2017 3:06 PM Thomas Gummerer wrote:
<big snip>
Quoted 1 line
however we currently document one behaviour, which I would like to change
(I usually have branches
Quoted 1 line
without a / in that I want to look at) we currently document one behaviour,
which I'd like to change. So
Quoted 1 line
in that case we are a bit worried about backwards compatibility, and how
this will affect current users
Quoted 1 line
that have a certain expectation of how the command is supposed to work,
hence the discussion of
Quoted 3 lines
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
Quoted 1 line
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.
Quoted 25 lines · Randall S. Becker
On November 25, 2017 3:06 PM Thomas Gummerer wrote:
<big snip>Quoted 10 lines
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.Quoted 4 lines
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>]
Quoted 7 lines
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.
Quoted 5 lines
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.
Quoted 11 lines
Cheers,
Randall-- Brief whoami: NonStop&UNIX developer since approximately UNIX(421664400)/NonStop(211288444200000000)
-- In my real life, I talk too much.
Quoted 3 lines · Thomas Gummerer
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!
Quoted 4 lines · Thomas Gummerer
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.
Quoted 11 lines · Junio C Hamano
Quoted 4 lines · Thomas Gummerer
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!
v5 cover make git worktree add dwim more
In reply to Thomas GummererThe previous rounds can be found at
https://public-inbox.org/git/[email protected]/,
https://public-inbox.org/git/[email protected]/,
https://public-inbox.org/git/[email protected]/ and
https://public-inbox.org/git/[email protected]/.
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:
Documentation/config.txt +10 -0
@@ -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.
Documentation/git-worktree.txt +30 -29
104 lines not on this page · raw message
builtin/worktree.c +16 -1
@@ -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);
checkout.c +1 -0
@@ -1,5 +1,6 @@#include "cache.h" #include "remote.h" +#include "checkout.h" struct tracking_name_data {/* const */ char *src_ref;
t/t2025-worktree-add.sh +44 -22
105 lines not on this page · raw message
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
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v5 1/6 checkout: factor out functions to new lib file
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.
--- 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
Makefile +1 -0
@@ -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
builtin/checkout.c +1 -40
52 lines not on this page · raw message
checkout.c new file +43 -0
43 lines not on this page · raw message
checkout.h new file +13 -0
@@ -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 */
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v5 2/6 worktree: add can be created from any commit-ish
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
Documentation/git-worktree.txt +10 -10
@@ -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].
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v5 3/6 worktree: add --[no-]track option to the add subcommand
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 6 +++++ builtin/worktree.c | 8 +++++++ t/t2025-worktree-add.sh | 51 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+)
Documentation/git-worktree.txt +6 -0
@@ -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`,
builtin/worktree.c +8 -0
@@ -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);
t/t2025-worktree-add.sh +51 -0
56 lines not on this page · raw message
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v5 4/6 worktree: make add <path> <branch> dwim
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 8 ++++++++ builtin/worktree.c | 16 ++++++++++++++++ t/t2025-worktree-add.sh | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+)
Documentation/git-worktree.txt +8 -0
@@ -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.
builtin/worktree.c +16 -0
@@ -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 ;
t/t2025-worktree-add.sh +19 -0
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v5 5/6 worktree: add --guess-remote flag to add subcommand
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 7 +++++++ builtin/worktree.c | 10 ++++++++++ t/t2025-worktree-add.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+)
Documentation/git-worktree.txt +7 -0
@@ -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
builtin/worktree.c +10 -0
@@ -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) {
t/t2025-worktree-add.sh +29 -0
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb
Re: [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand
Quoted 9 lines · 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.
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.
Documentation/git-worktree.txt OPTIONS · line 124
Quoted 7 lines
+--[no-]guess-remote::
Documentation/git-worktree.txt +6
-0+ 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.
builtin/worktree.c static int add(int ac, const char **av, const char *prefix) · line 402
Quoted 12 lines
builtin/worktree.c +7
-0@@ -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)".
Re: [PATCH v5 5/6] worktree: add --guess-remote flag to add subcommand
Quoted 17 lines · Junio C Hamano
Quoted 9 lines · 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.
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:
Quoted 5 lines
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.
Quoted 16 lines
Documentation/git-worktree.txt OPTIONS · line 124
Quoted 7 lines
+--[no-]guess-remote::
Documentation/git-worktree.txt +6
-0+ 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?
Quoted 7 lines
I am reacting to "with
add" part of this desciption. I wouldn't be asking if it said "Withworktree 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!
Quoted 16 lines
builtin/worktree.c static int add(int ac, const char **av, const char *prefix) · line 402
Quoted 12 lines
builtin/worktree.c +7
-0@@ -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)".
PATCH v5 6/6 add worktree.guessRemote config option
In reply to Thomas GummererSome 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.
--- 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(-)
Documentation/config.txt +10 -0
@@ -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.
Documentation/git-worktree.txt +3 -0
@@ -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,
builtin/worktree.c +13 -1
@@ -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 );
t/t2025-worktree-add.sh +31 -0
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb
Re: [PATCH v5 6/6] add worktree.guessRemote config option
Documentation/config.txt web.browser:: · line 3437
Quoted 9 lines · Thomas Gummerer
Documentation/config.txt +9
-0+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.
Quoted 11 lines
builtin/worktree.c +1
-0@@ -33,8 +33,19 @@ struct add_opts {static int show_only;static int verbose; +static int guess_remote;static timestamp_t expire;
builtin/worktree.c struct add_opts { · line 48
Quoted 10 lines
builtin/worktree.c +10
-0+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.
Re: [PATCH v5 6/6] add worktree.guessRemote config option
Quoted 47 lines · Junio C Hamano
Documentation/config.txt web.browser:: · line 3437
Quoted 9 lines · Thomas Gummerer
Documentation/config.txt +9
-0+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.
Quoted 11 lines
builtin/worktree.c +1
-0@@ -33,8 +33,19 @@ struct add_opts {static int show_only;static int verbose; +static int guess_remote;static timestamp_t expire;builtin/worktree.c struct add_opts { · line 48
Quoted 10 lines
builtin/worktree.c +10
-0+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);
Quoted 7 lines
we have in
cmd_worktree()replaced withgit_config(git_worktree_config, NULL);That would avoid having to scan the entire set of config keys once in
cmd_worktree()and then again inadd(), 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!
v6 cover make git worktree add dwim more
In reply to Thomas GummererThe previous rounds were at
https://public-inbox.org/git/[email protected]/,
https://public-inbox.org/git/[email protected]/,
https://public-inbox.org/git/[email protected]/,
https://public-inbox.org/git/[email protected]/ and
https://public-inbox.org/git/[email protected].
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:
Documentation/git-worktree.txt +5 -5
@@ -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.
builtin/worktree.c +2 -4
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v6 1/6 checkout: factor out functions to new lib file
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.
--- 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
Makefile +1 -0
@@ -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
builtin/checkout.c +1 -40
52 lines not on this page · raw message
checkout.c new file +43 -0
43 lines not on this page · raw message
checkout.h new file +13 -0
@@ -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 */
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v6 2/6 worktree: add can be created from any commit-ish
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
Documentation/git-worktree.txt +10 -10
@@ -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].
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v6 3/6 worktree: add --[no-]track option to the add subcommand
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 6 +++++ builtin/worktree.c | 8 +++++++ t/t2025-worktree-add.sh | 51 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+)
Documentation/git-worktree.txt +6 -0
@@ -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`,
builtin/worktree.c +8 -0
@@ -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);
t/t2025-worktree-add.sh +51 -0
56 lines not on this page · raw message
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v6 4/6 worktree: make add <path> <branch> dwim
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 8 ++++++++ builtin/worktree.c | 16 ++++++++++++++++ t/t2025-worktree-add.sh | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+)
Documentation/git-worktree.txt +8 -0
@@ -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.
builtin/worktree.c +16 -0
@@ -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 ;
t/t2025-worktree-add.sh +19 -0
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v6 5/6 worktree: add --guess-remote flag to add subcommand
In reply to Thomas GummererCurrently '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.
--- Documentation/git-worktree.txt | 7 +++++++ builtin/worktree.c | 10 ++++++++++ t/t2025-worktree-add.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+)
Documentation/git-worktree.txt +7 -0
@@ -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
builtin/worktree.c +10 -0
@@ -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) {
t/t2025-worktree-add.sh +29 -0
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb
PATCH v6 6/6 add worktree.guessRemote config option
In reply to Thomas GummererSome 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.
--- 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(-)
Documentation/config.txt +10 -0
@@ -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.
Documentation/git-worktree.txt +3 -0
@@ -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,
builtin/worktree.c +12 -2
@@ -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);
t/t2025-worktree-add.sh +31 -0
@@ -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
Signature · 1 line
2.15.0.426.gb06021eeb