All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/23] replace "checkout --to" with "worktree add"
@ 2015-07-06 17:30 Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 01/23] Documentation/git-checkout: fix incorrect worktree prune command Eric Sunshine
                   ` (22 more replies)
  0 siblings, 23 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

This is v3 of the series to replace "git checkout --to" with "git
worktree add". It's built atop Duy's df0b6cf (worktree: new place for
"git prune --worktrees", 2015-06-29). Thanks to Duy for his review
of v2[*1*].

A v2 to v3 interdiff is included below for ease of review.

Changes since v2:

* retire --to from git-checkout documentation (v1 did this, but v2
  forgot)

* add "git worktree list" to the enumeration of not-yet-implemented
  commands in the BUGS section of the documentation

* state only that "git worktree add" will create <path> rather than
  mentioning that a pre-existing <path> is valid as long as it is an
  empty directory[*2*]

* fix comment stating that "any valid value" is acceptable as temporary
  HEAD in the newly created worktree, as patch 8/23 proves this to be
  false

* use test_cmp_rev to simplify a couple new tests

* minor grammatical fixes to documentation and a few commit messages

[*1*]: http://thread.gmane.org/gmane.comp.version-control.git/273316
[*2*]: http://article.gmane.org/gmane.comp.version-control.git/273358

Eric Sunshine (23):
  Documentation/git-checkout: fix incorrect worktree prune command
  Documentation/git-worktree: associate options with commands
  Documentation: move linked worktree description from checkout to
    worktree
  Documentation/git-worktree: add BUGS section
  Documentation/git-worktree: split technical info from general
    description
  Documentation/git-worktree: add high-level 'lock' overview
  Documentation/git-worktree: add EXAMPLES section
  checkout: fix bug with --to and relative HEAD
  checkout: relocate --to's "no branch specified" check
  checkout: prepare_linked_checkout: drop now-unused 'new' argument
  checkout: make --to unconditionally verbose
  checkout: drop 'checkout_opts' dependency from prepare_linked_checkout
  worktree: introduce "add" command
  worktree: add --force option
  worktree: add --detach option
  worktree: add -b/-B options
  tests: worktree: retrofit "checkout --to" tests for "worktree add"
  checkout: retire --to option
  checkout: require worktree unconditionally
  worktree: extract basename computation to new function
  worktree: add: make -b/-B default to HEAD when <branch> is omitted
  worktree: add: auto-vivify new branch when <branch> is omitted
  checkout: retire --ignore-other-worktrees in favor of --force

 Documentation/git-checkout.txt                    |  81 +--------
 Documentation/git-worktree.txt                    | 141 ++++++++++++++-
 builtin/checkout.c                                | 161 +-----------------
 builtin/worktree.c                                | 198 ++++++++++++++++++++++
 git.c                                             |   2 +-
 t/{t2025-checkout-to.sh => t2025-worktree-add.sh} |  64 ++++---
 t/t2026-prune-linked-checkouts.sh                 |   2 +-
 t/t7410-submodule-checkout-to.sh                  |   4 +-
 8 files changed, 382 insertions(+), 271 deletions(-)
 rename t/{t2025-checkout-to.sh => t2025-worktree-add.sh} (54%)

-- 
2.5.0.rc1.197.g417e668


--- 8< ---
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 41148ce..6c3085d 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -228,13 +228,6 @@ This means that you can use `git checkout -p` to selectively discard
 edits from your current working tree. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
---to=<path>::
-	Check out a branch in a separate working directory at
-	`<path>`. A new working directory is linked to the current
-	repository, sharing everything except working directory
-	specific files such as HEAD, index, etc. See
-	linkgit:git-worktree[1] for a description of linked worktrees.
-
 <branch>::
 	Branch to checkout; if it refers to a branch (i.e., a name that,
 	when prepended with "refs/heads/", is a valid ref), then that
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 938bdab..da71f50 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -47,13 +47,12 @@ COMMANDS
 --------
 add <path> [<branch>]::
 
-Check out `<branch>` into a separate working directory, `<path>`, creating
-`<path>` if necessary. The new working directory is linked to the current
-repository, sharing everything except working directory specific files
-such as HEAD, index, etc. If `<path>` already exists, it must be empty.
+Create `<path>` and checkout `<branch>` into it. The new working directory
+is linked to the current repository, sharing everything except working
+directory specific files such as HEAD, index, etc.
 +
-If `<branch>` is omitted and neither `-b` nor `-B` used, then, as a
-convenience, a new branch rooted at HEAD is created automatically, as if
+If `<branch>` is omitted and neither `-b` nor `-B` is used, then, as a
+convenience, a new branch based at HEAD is created automatically, as if
 `-b $(basename <path>)` was specified.
 
 prune::
@@ -137,10 +136,10 @@ linkgit:gitrepository-layout[5] for details.
 
 EXAMPLES
 --------
-You are middle of a refactoring session and your boss comes in and demands
-that you fix something immediately. You might typically use
+You are in the middle of a refactoring session and your boss comes in and
+demands that you fix something immediately. You might typically use
 linkgit:git-stash[1] to store your changes away temporarily, however, your
-worktree is in such a state of disarray (with new, removed, moved files,
+worktree is in such a state of disarray (with new, moved, and removed files,
 and other bits and pieces strewn around) that you don't want to risk
 disturbing any of it. Instead, you create a temporary linked worktree to
 make the emergency fix, remove it when done, and then resume your earlier
@@ -167,6 +166,7 @@ performed manually, such as:
 - `remove` to remove a linked worktree and its administrative files (and
   warn if the worktree is dirty)
 - `mv` to move or rename a worktree and update its administrative files
+- `list` to list linked worktrees
 - `lock` to prevent automatic pruning of administrative files (for instance,
   for a worktree on a portable device)
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 8a6c7fa..050b443 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -227,9 +227,14 @@ static int add_worktree(const char *path, const char **child_argv)
 		   real_path(get_git_common_dir()), name);
 	/*
 	 * This is to keep resolve_ref() happy. We need a valid HEAD
-	 * or is_git_directory() will reject the directory. Any valid
-	 * value would do because this value will be ignored and
-	 * replaced at the next (real) checkout.
+	 * or is_git_directory() will reject the directory. Moreover, HEAD
+	 * in the new worktree must resolve to the same value as HEAD in
+	 * the current tree since the command invoked to populate the new
+	 * worktree will be handed the branch/ref specified by the user.
+	 * For instance, if the user asks for the new worktree to be based
+	 * at HEAD~5, then the resolved HEAD~5 in the new worktree must
+	 * match the resolved HEAD~5 in the current tree in order to match
+	 * the user's expectation.
 	 */
 	if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
 		die(_("unable to resolve HEAD"));
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 59d73ff..8fe242f 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -141,17 +141,13 @@ test_expect_success '"add" from relative HEAD' '
 '
 
 test_expect_success '"add -b" with <branch> omitted' '
-	git rev-parse HEAD >expected &&
 	git worktree add -b burble flornk &&
-	git rev-parse burble >actual &&
-	test_cmp expected actual
+	test_cmp_rev HEAD burble
 '
 
 test_expect_success '"add" with <branch> omitted' '
-	git rev-parse HEAD >expected &&
 	git worktree add wiffle/bat &&
-	git rev-parse bat >actual &&
-	test_cmp expected actual
+	test_cmp_rev HEAD bat
 '
 
 test_done
--- 8< ---

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

* [PATCH v3 01/23] Documentation/git-checkout: fix incorrect worktree prune command
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 02/23] Documentation/git-worktree: associate options with commands Eric Sunshine
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

This was missed when "git prune --worktrees" became "git worktree prune".

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-checkout.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 72def5b..ce223e6 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -444,7 +444,7 @@ When you are done with a linked working tree you can simply delete it.
 The working tree's entry in the repository's $GIT_DIR/worktrees
 directory will eventually be removed automatically (see
 `gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
-`git prune --worktrees` in the main or any linked working tree to
+`git worktree prune` in the main or any linked working tree to
 clean up any stale entries in $GIT_DIR/worktrees.
 
 If you move a linked working directory to another file system, or
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 02/23] Documentation/git-worktree: associate options with commands
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 01/23] Documentation/git-checkout: fix incorrect worktree prune command Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 03/23] Documentation: move linked worktree description from checkout to worktree Eric Sunshine
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

git-worktree options affect some worktree commands but not others, but
this is not necessarily obvious from the option descriptions. Make this
clear by indicating explicitly which commands are affected by which
options.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41103e5..1ac1217 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -28,15 +28,15 @@ OPTIONS
 
 -n::
 --dry-run::
-	Do not remove anything; just report what it would
+	With `prune`, do not remove anything; just report what it would
 	remove.
 
 -v::
 --verbose::
-	Report all removals.
+	With `prune`, report all removals.
 
 --expire <time>::
-	Only expire unused worktrees older than <time>.
+	With `prune`, only expire unused worktrees older than <time>.
 
 SEE ALSO
 --------
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 03/23] Documentation: move linked worktree description from checkout to worktree
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 01/23] Documentation/git-checkout: fix incorrect worktree prune command Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 02/23] Documentation/git-worktree: associate options with commands Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 04/23] Documentation/git-worktree: add BUGS section Eric Sunshine
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

Now that the git-worktree command exists, its documentation page is the
natural place for the linked worktree description to reside. Relocate
the "MULTIPLE WORKING TREES" description verbatim from git-checkout.txt
to git-worktree.txt.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-checkout.txt | 69 ++----------------------------------------
 Documentation/git-worktree.txt | 62 +++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 67 deletions(-)

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index ce223e6..77b7141 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -229,8 +229,8 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 	Check out a branch in a separate working directory at
 	`<path>`. A new working directory is linked to the current
 	repository, sharing everything except working directory
-	specific files such as HEAD, index... See "MULTIPLE WORKING
-	TREES" section for more information.
+	specific files such as HEAD, index, etc. See
+	linkgit:git-worktree[1] for a description of linked worktrees.
 
 --ignore-other-worktrees::
 	`git checkout` refuses when the wanted ref is already checked
@@ -401,71 +401,6 @@ $ git reflog -2 HEAD # or
 $ git log -g -2 HEAD
 ------------
 
-MULTIPLE WORKING TREES
-----------------------
-
-A git repository can support multiple working trees, allowing you to check
-out more than one branch at a time.  With `git checkout --to` a new working
-tree is associated with the repository.  This new working tree is called a
-"linked working tree" as opposed to the "main working tree" prepared by "git
-init" or "git clone".  A repository has one main working tree (if it's not a
-bare repository) and zero or more linked working trees.
-
-Each linked working tree has a private sub-directory in the repository's
-$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
-the base name of the linked working tree's path, possibly appended with a
-number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
-command `git checkout --to /path/other/test-next next` creates the linked
-working tree in `/path/other/test-next` and also creates a
-`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
-if `test-next` is already taken).
-
-Within a linked working tree, $GIT_DIR is set to point to this private
-directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
-$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
-(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
-the top directory of the linked working tree.
-
-Path resolution via `git rev-parse --git-path` uses either
-$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
-linked working tree `git rev-parse --git-path HEAD` returns
-`/path/main/.git/worktrees/test-next/HEAD` (not
-`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
-rev-parse --git-path refs/heads/master` uses
-$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
-since refs are shared across all working trees.
-
-See linkgit:gitrepository-layout[5] for more information. The rule of
-thumb is do not make any assumption about whether a path belongs to
-$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
-inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
-
-When you are done with a linked working tree you can simply delete it.
-The working tree's entry in the repository's $GIT_DIR/worktrees
-directory will eventually be removed automatically (see
-`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
-`git worktree prune` in the main or any linked working tree to
-clean up any stale entries in $GIT_DIR/worktrees.
-
-If you move a linked working directory to another file system, or
-within a file system that does not support hard links, you need to run
-at least one git command inside the linked working directory
-(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
-so that it does not get automatically removed.
-
-To prevent a $GIT_DIR/worktrees entry from from being pruned (which
-can be useful in some situations, such as when the
-entry's working tree is stored on a portable device), add a file named
-'locked' to the entry's directory. The file contains the reason in
-plain text. For example, if a linked working tree's `.git` file points
-to `/path/main/.git/worktrees/test-next` then a file named
-`/path/main/.git/worktrees/test-next/locked` will prevent the
-`test-next` entry from being pruned.  See
-linkgit:gitrepository-layout[5] for details.
-
-Multiple checkout support for submodules is incomplete. It is NOT
-recommended to make multiple checkouts of a superproject.
-
 EXAMPLES
 --------
 
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 1ac1217..3d28896 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -17,6 +17,68 @@ DESCRIPTION
 Manage multiple worktrees attached to the same repository. These are
 created by the command `git checkout --to`.
 
+A git repository can support multiple working trees, allowing you to check
+out more than one branch at a time.  With `git checkout --to` a new working
+tree is associated with the repository.  This new working tree is called a
+"linked working tree" as opposed to the "main working tree" prepared by "git
+init" or "git clone".  A repository has one main working tree (if it's not a
+bare repository) and zero or more linked working trees.
+
+Each linked working tree has a private sub-directory in the repository's
+$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
+the base name of the linked working tree's path, possibly appended with a
+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
+command `git checkout --to /path/other/test-next next` creates the linked
+working tree in `/path/other/test-next` and also creates a
+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+if `test-next` is already taken).
+
+Within a linked working tree, $GIT_DIR is set to point to this private
+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+the top directory of the linked working tree.
+
+Path resolution via `git rev-parse --git-path` uses either
+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+linked working tree `git rev-parse --git-path HEAD` returns
+`/path/main/.git/worktrees/test-next/HEAD` (not
+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+rev-parse --git-path refs/heads/master` uses
+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all working trees.
+
+See linkgit:gitrepository-layout[5] for more information. The rule of
+thumb is do not make any assumption about whether a path belongs to
+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+
+When you are done with a linked working tree you can simply delete it.
+The working tree's entry in the repository's $GIT_DIR/worktrees
+directory will eventually be removed automatically (see
+`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
+`git worktree prune` in the main or any linked working tree to
+clean up any stale entries in $GIT_DIR/worktrees.
+
+If you move a linked working directory to another file system, or
+within a file system that does not support hard links, you need to run
+at least one git command inside the linked working directory
+(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
+so that it does not get automatically removed.
+
+To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+can be useful in some situations, such as when the
+entry's working tree is stored on a portable device), add a file named
+'locked' to the entry's directory. The file contains the reason in
+plain text. For example, if a linked working tree's `.git` file points
+to `/path/main/.git/worktrees/test-next` then a file named
+`/path/main/.git/worktrees/test-next/locked` will prevent the
+`test-next` entry from being pruned.  See
+linkgit:gitrepository-layout[5] for details.
+
+Multiple checkout support for submodules is incomplete. It is NOT
+recommended to make multiple checkouts of a superproject.
+
 COMMANDS
 --------
 prune::
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 04/23] Documentation/git-worktree: add BUGS section
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (2 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 03/23] Documentation: move linked worktree description from checkout to worktree Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 05/23] Documentation/git-worktree: split technical info from general description Eric Sunshine
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

Relocate submodule warning to BUGS and enumerate missing commands.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 3d28896..bf6a1e2 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -76,9 +76,6 @@ to `/path/main/.git/worktrees/test-next` then a file named
 `test-next` entry from being pruned.  See
 linkgit:gitrepository-layout[5] for details.
 
-Multiple checkout support for submodules is incomplete. It is NOT
-recommended to make multiple checkouts of a superproject.
-
 COMMANDS
 --------
 prune::
@@ -100,6 +97,22 @@ OPTIONS
 --expire <time>::
 	With `prune`, only expire unused worktrees older than <time>.
 
+BUGS
+----
+Multiple checkout support for submodules is incomplete. It is NOT
+recommended to make multiple checkouts of a superproject.
+
+git-worktree could provide more automation for tasks currently
+performed manually or via other commands, such as:
+
+- `add` to create a new linked worktree
+- `remove` to remove a linked worktree and its administrative files (and
+  warn if the worktree is dirty)
+- `mv` to move or rename a worktree and update its administrative files
+- `list` to list linked worktrees
+- `lock` to prevent automatic pruning of administrative files (for instance,
+  for a worktree on a portable device)
+
 SEE ALSO
 --------
 
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 05/23] Documentation/git-worktree: split technical info from general description
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (3 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 04/23] Documentation/git-worktree: add BUGS section Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 06/23] Documentation/git-worktree: add high-level 'lock' overview Eric Sunshine
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

The DESCRIPTION section should provide a high-level overview of linked
worktree functionality to bring users up to speed quickly, without
overloading them with low-level details, so relocate the technical
information to a new DETAILS section.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 70 ++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 34 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index bf6a1e2..2954dc6 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -24,47 +24,18 @@ tree is associated with the repository.  This new working tree is called a
 init" or "git clone".  A repository has one main working tree (if it's not a
 bare repository) and zero or more linked working trees.
 
-Each linked working tree has a private sub-directory in the repository's
-$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
-the base name of the linked working tree's path, possibly appended with a
-number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
-command `git checkout --to /path/other/test-next next` creates the linked
-working tree in `/path/other/test-next` and also creates a
-`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
-if `test-next` is already taken).
-
-Within a linked working tree, $GIT_DIR is set to point to this private
-directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
-$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
-(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
-the top directory of the linked working tree.
-
-Path resolution via `git rev-parse --git-path` uses either
-$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
-linked working tree `git rev-parse --git-path HEAD` returns
-`/path/main/.git/worktrees/test-next/HEAD` (not
-`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
-rev-parse --git-path refs/heads/master` uses
-$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
-since refs are shared across all working trees.
-
-See linkgit:gitrepository-layout[5] for more information. The rule of
-thumb is do not make any assumption about whether a path belongs to
-$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
-inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
-
 When you are done with a linked working tree you can simply delete it.
-The working tree's entry in the repository's $GIT_DIR/worktrees
-directory will eventually be removed automatically (see
+The working tree's administrative files in the repository (see
+"DETAILS" below) will eventually be removed automatically (see
 `gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
 `git worktree prune` in the main or any linked working tree to
-clean up any stale entries in $GIT_DIR/worktrees.
+clean up any stale administrative files.
 
 If you move a linked working directory to another file system, or
 within a file system that does not support hard links, you need to run
 at least one git command inside the linked working directory
-(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
-so that it does not get automatically removed.
+(e.g. `git status`) in order to update its administrative files in the
+repository so that they do not get automatically pruned.
 
 To prevent a $GIT_DIR/worktrees entry from from being pruned (which
 can be useful in some situations, such as when the
@@ -97,6 +68,37 @@ OPTIONS
 --expire <time>::
 	With `prune`, only expire unused worktrees older than <time>.
 
+DETAILS
+-------
+Each linked working tree has a private sub-directory in the repository's
+$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
+the base name of the linked working tree's path, possibly appended with a
+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
+command `git checkout --to /path/other/test-next next` creates the linked
+working tree in `/path/other/test-next` and also creates a
+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+if `test-next` is already taken).
+
+Within a linked working tree, $GIT_DIR is set to point to this private
+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+the top directory of the linked working tree.
+
+Path resolution via `git rev-parse --git-path` uses either
+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+linked working tree `git rev-parse --git-path HEAD` returns
+`/path/main/.git/worktrees/test-next/HEAD` (not
+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+rev-parse --git-path refs/heads/master` uses
+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all working trees.
+
+See linkgit:gitrepository-layout[5] for more information. The rule of
+thumb is do not make any assumption about whether a path belongs to
+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+
 BUGS
 ----
 Multiple checkout support for submodules is incomplete. It is NOT
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 06/23] Documentation/git-worktree: add high-level 'lock' overview
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (4 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 05/23] Documentation/git-worktree: split technical info from general description Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 07/23] Documentation/git-worktree: add EXAMPLES section Eric Sunshine
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

Due to the (current) absence of a "git worktree lock" command, locking
a worktree's administrative files to prevent automatic pruning is a
manual task, necessarily requiring low-level understanding of linked
worktree functionality. However, this level of detail does not belong
in the high-level DESCRIPTION section, so add a generalized discussion
of locking to DESCRIPTION and move the technical information to DETAILS.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 2954dc6..0385e9a 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -37,15 +37,11 @@ at least one git command inside the linked working directory
 (e.g. `git status`) in order to update its administrative files in the
 repository so that they do not get automatically pruned.
 
-To prevent a $GIT_DIR/worktrees entry from from being pruned (which
-can be useful in some situations, such as when the
-entry's working tree is stored on a portable device), add a file named
-'locked' to the entry's directory. The file contains the reason in
-plain text. For example, if a linked working tree's `.git` file points
-to `/path/main/.git/worktrees/test-next` then a file named
-`/path/main/.git/worktrees/test-next/locked` will prevent the
-`test-next` entry from being pruned.  See
-linkgit:gitrepository-layout[5] for details.
+If a linked working tree is stored on a portable device or network share
+which is not always mounted, you can prevent its administrative files from
+being pruned by creating a file named 'lock' alongside the other
+administrative files, optionally containing a plain text reason that
+pruning should be suppressed. See section "DETAILS" for more information.
 
 COMMANDS
 --------
@@ -99,6 +95,16 @@ thumb is do not make any assumption about whether a path belongs to
 $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
+To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+can be useful in some situations, such as when the
+entry's working tree is stored on a portable device), add a file named
+'locked' to the entry's directory. The file contains the reason in
+plain text. For example, if a linked working tree's `.git` file points
+to `/path/main/.git/worktrees/test-next` then a file named
+`/path/main/.git/worktrees/test-next/locked` will prevent the
+`test-next` entry from being pruned.  See
+linkgit:gitrepository-layout[5] for details.
+
 BUGS
 ----
 Multiple checkout support for submodules is incomplete. It is NOT
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 07/23] Documentation/git-worktree: add EXAMPLES section
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (5 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 06/23] Documentation/git-worktree: add high-level 'lock' overview Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 08/23] checkout: fix bug with --to and relative HEAD Eric Sunshine
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 0385e9a..6afff1e 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -105,6 +105,28 @@ to `/path/main/.git/worktrees/test-next` then a file named
 `test-next` entry from being pruned.  See
 linkgit:gitrepository-layout[5] for details.
 
+EXAMPLES
+--------
+You are in the middle of a refactoring session and your boss comes in and
+demands that you fix something immediately. You might typically use
+linkgit:git-stash[1] to store your changes away temporarily, however, your
+worktree is in such a state of disarray (with new, moved, and removed files,
+and other bits and pieces strewn around) that you don't want to risk
+disturbing any of it. Instead, you create a temporary linked worktree to
+make the emergency fix, remove it when done, and then resume your earlier
+refactoring session.
+
+------------
+$ git branch emergency-fix master
+$ git checkout --to ../temp emergency-fix
+$ pushd ../temp
+# ... hack hack hack ...
+$ git commit -a -m 'emergency fix for boss'
+$ popd
+$ rm -rf ../temp
+$ git worktree prune
+------------
+
 BUGS
 ----
 Multiple checkout support for submodules is incomplete. It is NOT
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 08/23] checkout: fix bug with --to and relative HEAD
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (6 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 07/23] Documentation/git-worktree: add EXAMPLES section Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 09/23] checkout: relocate --to's "no branch specified" check Eric Sunshine
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

Given "git checkout --to <path> HEAD~1", the new worktree's HEAD should
begin life at the current branch's HEAD~1, however, it actually ends up
at HEAD~2. This happens because:

    1. git-checkout resolves HEAD~1

    2. to satisfy is_git_directory(), prepare_linked_worktree() creates
       a HEAD for the new worktree with the value of the resolved HEAD~1

    3. git-checkout re-invokes itself with the same arguments within the
       new worktree to populate the worktree

    4. the sub git-checkout resolves HEAD~1 relative to its own HEAD,
       which is the resolved HEAD~1 from the original invocation,
       resulting unexpectedly and incorrectly in HEAD~2 (relative to the
       original)

Fix this by unconditionally assigning the current worktree's HEAD as the
value of the new worktree's HEAD.

As a side-effect, this change also eliminates a dependence within
prepare_linked_checkout() upon 'struct branch_info'. The plan is to
eventually relocate "git checkout --to" functionality to "git worktree
add", and worktree.c won't have knowledge of 'struct branch_info', so
removal of this dependency is a step toward that goal.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/checkout.c     | 16 ++++++++++++----
 t/t2025-checkout-to.sh | 10 ++++++++++
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2079aa4..5ada22a 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -863,6 +863,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
 	struct stat st;
 	struct child_process cp;
 	int counter = 0, len, ret;
+	unsigned char rev[20];
 
 	if (!new->commit)
 		die(_("no branch specified"));
@@ -920,13 +921,20 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
 		   real_path(get_git_common_dir()), name);
 	/*
 	 * This is to keep resolve_ref() happy. We need a valid HEAD
-	 * or is_git_directory() will reject the directory. Any valid
-	 * value would do because this value will be ignored and
-	 * replaced at the next (real) checkout.
+	 * or is_git_directory() will reject the directory. Moreover, HEAD
+	 * in the new worktree must resolve to the same value as HEAD in
+	 * the current tree since the command invoked to populate the new
+	 * worktree will be handed the branch/ref specified by the user.
+	 * For instance, if the user asks for the new worktree to be based
+	 * at HEAD~5, then the resolved HEAD~5 in the new worktree must
+	 * match the resolved HEAD~5 in the current tree in order to match
+	 * the user's expectation.
 	 */
+	if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
+		die(_("unable to resolve HEAD"));
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
-	write_file(sb.buf, 1, "%s\n", sha1_to_hex(new->commit->object.sha1));
+	write_file(sb.buf, 1, "%s\n", sha1_to_hex(rev));
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
 	write_file(sb.buf, 1, "../..\n");
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index a8d9336..0fd731b 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -134,4 +134,14 @@ test_expect_success 'checkout with grafts' '
 	test_cmp expected actual
 '
 
+test_expect_success 'checkout --to from relative HEAD' '
+	test_commit a &&
+	test_commit b &&
+	test_commit c &&
+	git rev-parse HEAD~1 >expected &&
+	git checkout --to relhead HEAD~1 &&
+	git -C relhead rev-parse HEAD >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 09/23] checkout: relocate --to's "no branch specified" check
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (7 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 08/23] checkout: fix bug with --to and relative HEAD Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 10/23] checkout: prepare_linked_checkout: drop now-unused 'new' argument Eric Sunshine
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

The plan is to relocate "git checkout --to" functionality to "git
worktree add", however, this check expects a 'struct branch_info' which
git-worktree won't have at hand. It will, however, have access to its
own command-line from which it can pick up the branch name. Therefore,
as a preparatory step, rather than having prepare_linked_checkout()
perform this check, make it the caller's responsibility.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/checkout.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5ada22a..162c822 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -865,8 +865,6 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
 	int counter = 0, len, ret;
 	unsigned char rev[20];
 
-	if (!new->commit)
-		die(_("no branch specified"));
 	if (file_exists(path) && !is_empty_dir(path))
 		die(_("'%s' already exists"), path);
 
@@ -1303,8 +1301,11 @@ static int checkout_branch(struct checkout_opts *opts,
 		free(head_ref);
 	}
 
-	if (opts->new_worktree)
+	if (opts->new_worktree) {
+		if (!new->commit)
+			die(_("no branch specified"));
 		return prepare_linked_checkout(opts, new);
+	}
 
 	if (!new->commit && opts->new_branch) {
 		unsigned char rev[20];
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 10/23] checkout: prepare_linked_checkout: drop now-unused 'new' argument
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (8 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 09/23] checkout: relocate --to's "no branch specified" check Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 11/23] checkout: make --to unconditionally verbose Eric Sunshine
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

The only references to 'new' were folded out by the last two patches.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/checkout.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 162c822..134b6d6 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -854,8 +854,7 @@ static void remove_junk_on_signal(int signo)
 	raise(signo);
 }
 
-static int prepare_linked_checkout(const struct checkout_opts *opts,
-				   struct branch_info *new)
+static int prepare_linked_checkout(const struct checkout_opts *opts)
 {
 	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
 	struct strbuf sb = STRBUF_INIT;
@@ -1304,7 +1303,7 @@ static int checkout_branch(struct checkout_opts *opts,
 	if (opts->new_worktree) {
 		if (!new->commit)
 			die(_("no branch specified"));
-		return prepare_linked_checkout(opts, new);
+		return prepare_linked_checkout(opts);
 	}
 
 	if (!new->commit && opts->new_branch) {
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 11/23] checkout: make --to unconditionally verbose
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (9 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 10/23] checkout: prepare_linked_checkout: drop now-unused 'new' argument Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 12/23] checkout: drop 'checkout_opts' dependency from prepare_linked_checkout Eric Sunshine
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

prepare_linked_checkout() respects git-checkout's --quiet flag, however,
the plan is to relocate "git checkout --to" functionality to "git
worktree add", and git-worktree does not (yet) have a --quiet flag.
Consequently, make prepare_linked_checkout() unconditionally verbose to
ease eventual code movement to worktree.c.

(A --quiet flag can be added to git-worktree later if there is demand
for it.)

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/checkout.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 134b6d6..90bb3cd 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -936,8 +936,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts)
 	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
 	write_file(sb.buf, 1, "../..\n");
 
-	if (!opts->quiet)
-		fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+	fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
 
 	setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
 	setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 12/23] checkout: drop 'checkout_opts' dependency from prepare_linked_checkout
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (10 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 11/23] checkout: make --to unconditionally verbose Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 13/23] worktree: introduce "add" command Eric Sunshine
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

The plan is to relocate "git checkout --to" functionality to "git
worktree add", however, worktree.c won't have access to the 'struct
checkout_opts' passed to prepare_linked_worktree(), which it consults
for the pathname of the new worktree and the argv[] of the command it
should run to populate the new worktree. Facilitate relocation of
prepare_linked_worktree() by instead having it accept the pathname and
argv[] directly, thus eliminating the final references to 'struct
checkout_opts'.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/checkout.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 90bb3cd..e4064a8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -854,11 +854,11 @@ static void remove_junk_on_signal(int signo)
 	raise(signo);
 }
 
-static int prepare_linked_checkout(const struct checkout_opts *opts)
+static int prepare_linked_checkout(const char *path, const char **child_argv)
 {
 	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
 	struct strbuf sb = STRBUF_INIT;
-	const char *path = opts->new_worktree, *name;
+	const char *name;
 	struct stat st;
 	struct child_process cp;
 	int counter = 0, len, ret;
@@ -943,7 +943,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts)
 	setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
 	memset(&cp, 0, sizeof(cp));
 	cp.git_cmd = 1;
-	cp.argv = opts->saved_argv;
+	cp.argv = child_argv;
 	ret = run_command(&cp);
 	if (!ret) {
 		is_junk = 0;
@@ -1302,7 +1302,8 @@ static int checkout_branch(struct checkout_opts *opts,
 	if (opts->new_worktree) {
 		if (!new->commit)
 			die(_("no branch specified"));
-		return prepare_linked_checkout(opts);
+		return prepare_linked_checkout(opts->new_worktree,
+					       opts->saved_argv);
 	}
 
 	if (!new->commit && opts->new_branch) {
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 13/23] worktree: introduce "add" command
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (11 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 12/23] checkout: drop 'checkout_opts' dependency from prepare_linked_checkout Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 14/23] worktree: add --force option Eric Sunshine
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

The plan is to relocate "git checkout --to" functionality to "git
worktree add". As a first step, introduce a bare-bones git-worktree
"add" command along with documentation. At this stage, "git worktree
add" merely invokes "git checkout --to" behind the scenes, but an
upcoming patch will move the actual functionality
(checkout.c:prepare_linked_checkout() and its helpers) to worktree.c.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 20 ++++++++++----------
 builtin/worktree.c             | 31 +++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 6afff1e..def3027 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,13 +9,13 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
+'git worktree add' <path> <branch>
 'git worktree prune' [-n] [-v] [--expire <expire>]
 
 DESCRIPTION
 -----------
 
-Manage multiple worktrees attached to the same repository. These are
-created by the command `git checkout --to`.
+Manage multiple worktrees attached to the same repository.
 
 A git repository can support multiple working trees, allowing you to check
 out more than one branch at a time.  With `git checkout --to` a new working
@@ -45,6 +45,12 @@ pruning should be suppressed. See section "DETAILS" for more information.
 
 COMMANDS
 --------
+add <path> <branch>::
+
+Create `<path>` and checkout `<branch>` into it. The new working directory
+is linked to the current repository, sharing everything except working
+directory specific files such as HEAD, index, etc.
+
 prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
@@ -118,7 +124,7 @@ refactoring session.
 
 ------------
 $ git branch emergency-fix master
-$ git checkout --to ../temp emergency-fix
+$ git worktree add ../temp emergency-fix
 $ pushd ../temp
 # ... hack hack hack ...
 $ git commit -a -m 'emergency fix for boss'
@@ -133,9 +139,8 @@ Multiple checkout support for submodules is incomplete. It is NOT
 recommended to make multiple checkouts of a superproject.
 
 git-worktree could provide more automation for tasks currently
-performed manually or via other commands, such as:
+performed manually, such as:
 
-- `add` to create a new linked worktree
 - `remove` to remove a linked worktree and its administrative files (and
   warn if the worktree is dirty)
 - `mv` to move or rename a worktree and update its administrative files
@@ -143,11 +148,6 @@ performed manually or via other commands, such as:
 - `lock` to prevent automatic pruning of administrative files (for instance,
   for a worktree on a portable device)
 
-SEE ALSO
---------
-
-linkgit:git-checkout[1]
-
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 2a729c6..e0749c0 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -2,8 +2,11 @@
 #include "builtin.h"
 #include "dir.h"
 #include "parse-options.h"
+#include "argv-array.h"
+#include "run-command.h"
 
 static const char * const worktree_usage[] = {
+	N_("git worktree add <path> <branch>"),
 	N_("git worktree prune [<options>]"),
 	NULL
 };
@@ -119,6 +122,32 @@ static int prune(int ac, const char **av, const char *prefix)
 	return 0;
 }
 
+static int add(int ac, const char **av, const char *prefix)
+{
+	struct child_process c;
+	const char *path, *branch;
+	struct argv_array cmd = ARGV_ARRAY_INIT;
+	struct option options[] = {
+		OPT_END()
+	};
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (ac != 2)
+		usage_with_options(worktree_usage, options);
+
+	path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
+	branch = av[1];
+
+	argv_array_push(&cmd, "checkout");
+	argv_array_pushl(&cmd, "--to", path, NULL);
+	argv_array_push(&cmd, branch);
+
+	memset(&c, 0, sizeof(c));
+	c.git_cmd = 1;
+	c.argv = cmd.argv;
+	return run_command(&c);
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -127,6 +156,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 
 	if (ac < 2)
 		usage_with_options(worktree_usage, options);
+	if (!strcmp(av[1], "add"))
+		return add(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "prune"))
 		return prune(ac - 1, av + 1, prefix);
 	usage_with_options(worktree_usage, options);
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 14/23] worktree: add --force option
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (12 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 13/23] worktree: introduce "add" command Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 15/23] worktree: add --detach option Eric Sunshine
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

By default, "git worktree add" refuses to create a new worktree when
the requested branch is already checked out elsewhere. Add a --force
option to override this safeguard.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 8 +++++++-
 builtin/worktree.c             | 6 +++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index def3027..8891de0 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' <path> <branch>
+'git worktree add' [-f] <path> <branch>
 'git worktree prune' [-n] [-v] [--expire <expire>]
 
 DESCRIPTION
@@ -58,6 +58,12 @@ Prune working tree information in $GIT_DIR/worktrees.
 OPTIONS
 -------
 
+-f::
+--force::
+	By default, `add` refuses to create a new worktree when	`<branch>`
+	is already checked out by another worktree. This option overrides
+	that safeguard.
+
 -n::
 --dry-run::
 	With `prune`, do not remove anything; just report what it would
diff --git a/builtin/worktree.c b/builtin/worktree.c
index e0749c0..8c35023 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -6,7 +6,7 @@
 #include "run-command.h"
 
 static const char * const worktree_usage[] = {
-	N_("git worktree add <path> <branch>"),
+	N_("git worktree add [<options>] <path> <branch>"),
 	N_("git worktree prune [<options>]"),
 	NULL
 };
@@ -125,9 +125,11 @@ static int prune(int ac, const char **av, const char *prefix)
 static int add(int ac, const char **av, const char *prefix)
 {
 	struct child_process c;
+	int force = 0;
 	const char *path, *branch;
 	struct argv_array cmd = ARGV_ARRAY_INIT;
 	struct option options[] = {
+		OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_END()
 	};
 
@@ -140,6 +142,8 @@ static int add(int ac, const char **av, const char *prefix)
 
 	argv_array_push(&cmd, "checkout");
 	argv_array_pushl(&cmd, "--to", path, NULL);
+	if (force)
+		argv_array_push(&cmd, "--ignore-other-worktrees");
 	argv_array_push(&cmd, branch);
 
 	memset(&c, 0, sizeof(c));
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 15/23] worktree: add --detach option
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (13 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 14/23] worktree: add --force option Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 16/23] worktree: add -b/-B options Eric Sunshine
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

One of git-worktree's roles is to populate the new worktree, much like
git-checkout, and thus, for convenience, ought to support several of the
same shortcuts. Toward this goal, add a --detach option to detach HEAD
in the new worktree.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 6 +++++-
 builtin/worktree.c             | 5 ++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 8891de0..231271b 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] <path> <branch>
+'git worktree add' [-f] [--detach] <path> <branch>
 'git worktree prune' [-n] [-v] [--expire <expire>]
 
 DESCRIPTION
@@ -64,6 +64,10 @@ OPTIONS
 	is already checked out by another worktree. This option overrides
 	that safeguard.
 
+--detach::
+	With `add`, detach HEAD in the new worktree. See "DETACHED HEAD" in
+	linkgit:git-checkout[1].
+
 -n::
 --dry-run::
 	With `prune`, do not remove anything; just report what it would
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 8c35023..9dc92b0 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -125,11 +125,12 @@ static int prune(int ac, const char **av, const char *prefix)
 static int add(int ac, const char **av, const char *prefix)
 {
 	struct child_process c;
-	int force = 0;
+	int force = 0, detach = 0;
 	const char *path, *branch;
 	struct argv_array cmd = ARGV_ARRAY_INIT;
 	struct option options[] = {
 		OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
+		OPT_BOOL(0, "detach", &detach, N_("detach HEAD at named commit")),
 		OPT_END()
 	};
 
@@ -144,6 +145,8 @@ static int add(int ac, const char **av, const char *prefix)
 	argv_array_pushl(&cmd, "--to", path, NULL);
 	if (force)
 		argv_array_push(&cmd, "--ignore-other-worktrees");
+	if (detach)
+		argv_array_push(&cmd, "--detach");
 	argv_array_push(&cmd, branch);
 
 	memset(&c, 0, sizeof(c));
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 16/23] worktree: add -b/-B options
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (14 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 15/23] worktree: add --detach option Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 17/23] tests: worktree: retrofit "checkout --to" tests for "worktree add" Eric Sunshine
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

One of git-worktree's roles is to populate the new worktree, much like
git-checkout, and thus, for convenience, ought to support several of the
same shortcuts. Toward this goal, add -b/-B options to create a new
branch and check it out in the new worktree.

(For brevity, only -b is mentioned in the synopsis; -B is omitted.)

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 13 ++++++++++---
 builtin/worktree.c             | 11 +++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 231271b..f44cd78 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] [--detach] <path> <branch>
+'git worktree add' [-f] [--detach] [-b <new-branch>] <path> <branch>
 'git worktree prune' [-n] [-v] [--expire <expire>]
 
 DESCRIPTION
@@ -64,6 +64,14 @@ OPTIONS
 	is already checked out by another worktree. 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 worktree.
+	By default, `-b` refuses to create a new branch if it already
+	exists. `-B` overrides this safeguard, resetting `<new-branch>` to
+	`<branch>`.
+
 --detach::
 	With `add`, detach HEAD in the new worktree. See "DETACHED HEAD" in
 	linkgit:git-checkout[1].
@@ -133,8 +141,7 @@ make the emergency fix, remove it when done, and then resume your earlier
 refactoring session.
 
 ------------
-$ git branch emergency-fix master
-$ git worktree add ../temp emergency-fix
+$ git worktree add -b emergency-fix ../temp master
 $ pushd ../temp
 # ... hack hack hack ...
 $ git commit -a -m 'emergency fix for boss'
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 9dc92b0..d6d0eee 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -126,15 +126,22 @@ static int add(int ac, const char **av, const char *prefix)
 {
 	struct child_process c;
 	int force = 0, detach = 0;
+	const char *new_branch = NULL, *new_branch_force = NULL;
 	const char *path, *branch;
 	struct argv_array cmd = ARGV_ARRAY_INIT;
 	struct option options[] = {
 		OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
+		OPT_STRING('b', NULL, &new_branch, N_("branch"),
+			   N_("create a new branch")),
+		OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
+			   N_("create or reset a branch")),
 		OPT_BOOL(0, "detach", &detach, N_("detach HEAD at named commit")),
 		OPT_END()
 	};
 
 	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (new_branch && new_branch_force)
+		die(_("-b and -B are mutually exclusive"));
 	if (ac != 2)
 		usage_with_options(worktree_usage, options);
 
@@ -145,6 +152,10 @@ static int add(int ac, const char **av, const char *prefix)
 	argv_array_pushl(&cmd, "--to", path, NULL);
 	if (force)
 		argv_array_push(&cmd, "--ignore-other-worktrees");
+	if (new_branch)
+		argv_array_pushl(&cmd, "-b", new_branch, NULL);
+	if (new_branch_force)
+		argv_array_pushl(&cmd, "-B", new_branch_force, NULL);
 	if (detach)
 		argv_array_push(&cmd, "--detach");
 	argv_array_push(&cmd, branch);
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 17/23] tests: worktree: retrofit "checkout --to" tests for "worktree add"
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (15 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 16/23] worktree: add -b/-B options Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 18/23] checkout: retire --to option Eric Sunshine
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

With the introduction of "git worktree add", "git checkout --to" is
slated for removal. Therefore, retrofit linked worktree creation tests
to use "git worktree add" instead.

(The test to check exclusivity of "checkout --to" and "checkout <paths>"
is dropped altogether since it becomes meaningless with retirement of
"checkout --to".)

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/{t2025-checkout-to.sh => t2025-worktree-add.sh} | 48 +++++++++++------------
 t/t2026-prune-linked-checkouts.sh                 |  2 +-
 t/t7410-submodule-checkout-to.sh                  |  4 +-
 3 files changed, 25 insertions(+), 29 deletions(-)
 rename t/{t2025-checkout-to.sh => t2025-worktree-add.sh} (59%)

diff --git a/t/t2025-checkout-to.sh b/t/t2025-worktree-add.sh
similarity index 59%
rename from t/t2025-checkout-to.sh
rename to t/t2025-worktree-add.sh
index 0fd731b..192c936 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-worktree-add.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='test git checkout --to'
+test_description='test git worktree add'
 
 . ./test-lib.sh
 
@@ -8,22 +8,18 @@ test_expect_success 'setup' '
 	test_commit init
 '
 
-test_expect_success 'checkout --to not updating paths' '
-	test_must_fail git checkout --to -- init.t
-'
-
-test_expect_success 'checkout --to an existing worktree' '
+test_expect_success '"add" an existing worktree' '
 	mkdir -p existing/subtree &&
-	test_must_fail git checkout --detach --to existing master
+	test_must_fail git worktree add --detach existing master
 '
 
-test_expect_success 'checkout --to an existing empty worktree' '
+test_expect_success '"add" an existing empty worktree' '
 	mkdir existing_empty &&
-	git checkout --detach --to existing_empty master
+	git worktree add --detach existing_empty master
 '
 
-test_expect_success 'checkout --to refuses to checkout locked branch' '
-	test_must_fail git checkout --to zere master &&
+test_expect_success '"add" refuses to checkout locked branch' '
+	test_must_fail git worktree add zere master &&
 	! test -d zere &&
 	! test -d .git/worktrees/zere
 '
@@ -36,9 +32,9 @@ test_expect_success 'checking out paths not complaining about linked checkouts'
 	)
 '
 
-test_expect_success 'checkout --to a new worktree' '
+test_expect_success '"add" worktree' '
 	git rev-parse HEAD >expect &&
-	git checkout --detach --to here master &&
+	git worktree add --detach here master &&
 	(
 		cd here &&
 		test_cmp ../init.t init.t &&
@@ -49,27 +45,27 @@ test_expect_success 'checkout --to a new worktree' '
 	)
 '
 
-test_expect_success 'checkout --to a new worktree from a subdir' '
+test_expect_success '"add" worktree from a subdir' '
 	(
 		mkdir sub &&
 		cd sub &&
-		git checkout --detach --to here master &&
+		git worktree add --detach here master &&
 		cd here &&
 		test_cmp ../../init.t init.t
 	)
 '
 
-test_expect_success 'checkout --to from a linked checkout' '
+test_expect_success '"add" from a linked checkout' '
 	(
 		cd here &&
-		git checkout --detach --to nested-here master &&
+		git worktree add --detach nested-here master &&
 		cd nested-here &&
 		git fsck
 	)
 '
 
-test_expect_success 'checkout --to a new worktree creating new branch' '
-	git checkout --to there -b newmaster master &&
+test_expect_success '"add" worktree creating new branch' '
+	git worktree add -b newmaster there master &&
 	(
 		cd there &&
 		test_cmp ../init.t init.t &&
@@ -90,7 +86,7 @@ test_expect_success 'die the same branch is already checked out' '
 test_expect_success 'not die the same branch is already checked out' '
 	(
 		cd here &&
-		git checkout --ignore-other-worktrees --to anothernewmaster newmaster
+		git worktree add --force anothernewmaster newmaster
 	)
 '
 
@@ -101,15 +97,15 @@ test_expect_success 'not die on re-checking out current branch' '
 	)
 '
 
-test_expect_success 'checkout --to from a bare repo' '
+test_expect_success '"add" from a bare repo' '
 	(
 		git clone --bare . bare &&
 		cd bare &&
-		git checkout --to ../there2 -b bare-master master
+		git worktree add -b bare-master ../there2 master
 	)
 '
 
-test_expect_success 'checkout from a bare repo without --to' '
+test_expect_success 'checkout from a bare repo without "add"' '
 	(
 		cd bare &&
 		test_must_fail git checkout master
@@ -129,17 +125,17 @@ test_expect_success 'checkout with grafts' '
 	EOF
 	git log --format=%s -2 >actual &&
 	test_cmp expected actual &&
-	git checkout --detach --to grafted master &&
+	git worktree add --detach grafted master &&
 	git --git-dir=grafted/.git log --format=%s -2 >actual &&
 	test_cmp expected actual
 '
 
-test_expect_success 'checkout --to from relative HEAD' '
+test_expect_success '"add" from relative HEAD' '
 	test_commit a &&
 	test_commit b &&
 	test_commit c &&
 	git rev-parse HEAD~1 >expected &&
-	git checkout --to relhead HEAD~1 &&
+	git worktree add relhead HEAD~1 &&
 	git -C relhead rev-parse HEAD >actual &&
 	test_cmp expected actual
 '
diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh
index e872f02..a0f1e3b 100755
--- a/t/t2026-prune-linked-checkouts.sh
+++ b/t/t2026-prune-linked-checkouts.sh
@@ -88,7 +88,7 @@ test_expect_success 'not prune recent checkouts' '
 
 test_expect_success 'not prune proper checkouts' '
 	test_when_finished rm -r .git/worktrees &&
-	git checkout "--to=$PWD/nop" --detach master &&
+	git worktree add --detach "$PWD/nop" master &&
 	git worktree prune &&
 	test -d .git/worktrees/nop
 '
diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
index 8f30aed..3f609e8 100755
--- a/t/t7410-submodule-checkout-to.sh
+++ b/t/t7410-submodule-checkout-to.sh
@@ -33,7 +33,7 @@ rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1
 test_expect_success 'checkout main' \
     'mkdir default_checkout &&
     (cd clone/main &&
-	git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")'
+	git worktree add "$base_path/default_checkout/main" "$rev1_hash_main")'
 
 test_expect_failure 'can see submodule diffs just after checkout' \
     '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")'
@@ -41,7 +41,7 @@ test_expect_failure 'can see submodule diffs just after checkout' \
 test_expect_success 'checkout main and initialize independed clones' \
     'mkdir fully_cloned_submodule &&
     (cd clone/main &&
-	git checkout --to "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") &&
+	git worktree add "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") &&
     (cd fully_cloned_submodule/main && git submodule update)'
 
 test_expect_success 'can see submodule diffs after independed cloning' \
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 18/23] checkout: retire --to option
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (16 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 17/23] tests: worktree: retrofit "checkout --to" tests for "worktree add" Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 19:41   ` Junio C Hamano
  2015-07-06 17:30 ` [PATCH v3 19/23] checkout: require worktree unconditionally Eric Sunshine
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

Now that "git worktree add" has achieved user-facing feature-parity with
"git checkout --to", retire the latter.

Move the actual linked worktree creation functionality,
prepare_linked_checkout() and its helpers, verbatim from checkout.c to
worktree.c.

This effectively reverts changes to checkout.c by 529fef2 (checkout:
support checking out into a new working directory, 2014-11-30) with the
exception of merge_working_tree() and switch_branches() which still
require specialized knowledge that a the checkout is occurring in a
newly-created linked worktree (signaled to them by the private
GIT_CHECKOUT_NEW_WORKTREE environment variable).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-checkout.txt |   7 --
 builtin/checkout.c             | 161 +----------------------------------------
 builtin/worktree.c             | 144 ++++++++++++++++++++++++++++++++++--
 3 files changed, 139 insertions(+), 173 deletions(-)

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 77b7141..efe6a02 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -225,13 +225,6 @@ This means that you can use `git checkout -p` to selectively discard
 edits from your current working tree. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
---to=<path>::
-	Check out a branch in a separate working directory at
-	`<path>`. A new working directory is linked to the current
-	repository, sharing everything except working directory
-	specific files such as HEAD, index, etc. See
-	linkgit:git-worktree[1] for a description of linked worktrees.
-
 --ignore-other-worktrees::
 	`git checkout` refuses when the wanted ref is already checked
 	out by another worktree. This option makes it check the ref
diff --git a/builtin/checkout.c b/builtin/checkout.c
index e4064a8..b1e68b3 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -19,8 +19,6 @@
 #include "ll-merge.h"
 #include "resolve-undo.h"
 #include "submodule.h"
-#include "argv-array.h"
-#include "sigchain.h"
 
 static const char * const checkout_usage[] = {
 	N_("git checkout [options] <branch>"),
@@ -51,8 +49,6 @@ struct checkout_opts {
 	struct pathspec pathspec;
 	struct tree *source_tree;
 
-	const char *new_worktree;
-	const char **saved_argv;
 	int new_worktree_mode;
 };
 
@@ -255,9 +251,6 @@ static int checkout_paths(const struct checkout_opts *opts,
 		die(_("Cannot update paths and switch to branch '%s' at the same time."),
 		    opts->new_branch);
 
-	if (opts->new_worktree)
-		die(_("'%s' cannot be used with updating paths"), "--to");
-
 	if (opts->patch_mode)
 		return run_add_interactive(revision, "--patch=checkout",
 					   &opts->pathspec);
@@ -825,142 +818,6 @@ static int switch_branches(const struct checkout_opts *opts,
 	return ret || writeout_error;
 }
 
-static char *junk_work_tree;
-static char *junk_git_dir;
-static int is_junk;
-static pid_t junk_pid;
-
-static void remove_junk(void)
-{
-	struct strbuf sb = STRBUF_INIT;
-	if (!is_junk || getpid() != junk_pid)
-		return;
-	if (junk_git_dir) {
-		strbuf_addstr(&sb, junk_git_dir);
-		remove_dir_recursively(&sb, 0);
-		strbuf_reset(&sb);
-	}
-	if (junk_work_tree) {
-		strbuf_addstr(&sb, junk_work_tree);
-		remove_dir_recursively(&sb, 0);
-	}
-	strbuf_release(&sb);
-}
-
-static void remove_junk_on_signal(int signo)
-{
-	remove_junk();
-	sigchain_pop(signo);
-	raise(signo);
-}
-
-static int prepare_linked_checkout(const char *path, const char **child_argv)
-{
-	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
-	struct strbuf sb = STRBUF_INIT;
-	const char *name;
-	struct stat st;
-	struct child_process cp;
-	int counter = 0, len, ret;
-	unsigned char rev[20];
-
-	if (file_exists(path) && !is_empty_dir(path))
-		die(_("'%s' already exists"), path);
-
-	len = strlen(path);
-	while (len && is_dir_sep(path[len - 1]))
-		len--;
-
-	for (name = path + len - 1; name > path; name--)
-		if (is_dir_sep(*name)) {
-			name++;
-			break;
-		}
-	strbuf_addstr(&sb_repo,
-		      git_path("worktrees/%.*s", (int)(path + len - name), name));
-	len = sb_repo.len;
-	if (safe_create_leading_directories_const(sb_repo.buf))
-		die_errno(_("could not create leading directories of '%s'"),
-			  sb_repo.buf);
-	while (!stat(sb_repo.buf, &st)) {
-		counter++;
-		strbuf_setlen(&sb_repo, len);
-		strbuf_addf(&sb_repo, "%d", counter);
-	}
-	name = strrchr(sb_repo.buf, '/') + 1;
-
-	junk_pid = getpid();
-	atexit(remove_junk);
-	sigchain_push_common(remove_junk_on_signal);
-
-	if (mkdir(sb_repo.buf, 0777))
-		die_errno(_("could not create directory of '%s'"), sb_repo.buf);
-	junk_git_dir = xstrdup(sb_repo.buf);
-	is_junk = 1;
-
-	/*
-	 * lock the incomplete repo so prune won't delete it, unlock
-	 * after the preparation is over.
-	 */
-	strbuf_addf(&sb, "%s/locked", sb_repo.buf);
-	write_file(sb.buf, 1, "initializing\n");
-
-	strbuf_addf(&sb_git, "%s/.git", path);
-	if (safe_create_leading_directories_const(sb_git.buf))
-		die_errno(_("could not create leading directories of '%s'"),
-			  sb_git.buf);
-	junk_work_tree = xstrdup(path);
-
-	strbuf_reset(&sb);
-	strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
-	write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
-	write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
-		   real_path(get_git_common_dir()), name);
-	/*
-	 * This is to keep resolve_ref() happy. We need a valid HEAD
-	 * or is_git_directory() will reject the directory. Moreover, HEAD
-	 * in the new worktree must resolve to the same value as HEAD in
-	 * the current tree since the command invoked to populate the new
-	 * worktree will be handed the branch/ref specified by the user.
-	 * For instance, if the user asks for the new worktree to be based
-	 * at HEAD~5, then the resolved HEAD~5 in the new worktree must
-	 * match the resolved HEAD~5 in the current tree in order to match
-	 * the user's expectation.
-	 */
-	if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
-		die(_("unable to resolve HEAD"));
-	strbuf_reset(&sb);
-	strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
-	write_file(sb.buf, 1, "%s\n", sha1_to_hex(rev));
-	strbuf_reset(&sb);
-	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
-	write_file(sb.buf, 1, "../..\n");
-
-	fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
-
-	setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
-	setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
-	setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
-	memset(&cp, 0, sizeof(cp));
-	cp.git_cmd = 1;
-	cp.argv = child_argv;
-	ret = run_command(&cp);
-	if (!ret) {
-		is_junk = 0;
-		free(junk_work_tree);
-		free(junk_git_dir);
-		junk_work_tree = NULL;
-		junk_git_dir = NULL;
-	}
-	strbuf_reset(&sb);
-	strbuf_addf(&sb, "%s/locked", sb_repo.buf);
-	unlink_or_warn(sb.buf);
-	strbuf_release(&sb);
-	strbuf_release(&sb_repo);
-	strbuf_release(&sb_git);
-	return ret;
-}
-
 static int git_checkout_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "diff.ignoresubmodules")) {
@@ -1299,13 +1156,6 @@ static int checkout_branch(struct checkout_opts *opts,
 		free(head_ref);
 	}
 
-	if (opts->new_worktree) {
-		if (!new->commit)
-			die(_("no branch specified"));
-		return prepare_linked_checkout(opts->new_worktree,
-					       opts->saved_argv);
-	}
-
 	if (!new->commit && opts->new_branch) {
 		unsigned char rev[20];
 		int flag;
@@ -1348,8 +1198,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 			 N_("do not limit pathspecs to sparse entries only")),
 		OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
 				N_("second guess 'git checkout no-such-branch'")),
-		OPT_FILENAME(0, "to", &opts.new_worktree,
-			   N_("check a branch out in a separate working directory")),
 		OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
 			 N_("do not check if another worktree is holding the given ref")),
 		OPT_END(),
@@ -1360,9 +1208,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	opts.overwrite_ignore = 1;
 	opts.prefix = prefix;
 
-	opts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));
-	memcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));
-
 	gitmodules_config();
 	git_config(git_checkout_config, &opts);
 
@@ -1371,13 +1216,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, options, checkout_usage,
 			     PARSE_OPT_KEEP_DASHDASH);
 
-	/* recursive execution from checkout_new_worktree() */
 	opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
-	if (opts.new_worktree_mode)
-		opts.new_worktree = NULL;
 
-	if (!opts.new_worktree)
-		setup_work_tree();
+	setup_work_tree();
 
 	if (conflict_style) {
 		opts.merge = 1; /* implied */
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d6d0eee..04e6d0f 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -4,6 +4,7 @@
 #include "parse-options.h"
 #include "argv-array.h"
 #include "run-command.h"
+#include "sigchain.h"
 
 static const char * const worktree_usage[] = {
 	N_("git worktree add [<options>] <path> <branch>"),
@@ -122,9 +123,144 @@ static int prune(int ac, const char **av, const char *prefix)
 	return 0;
 }
 
+static char *junk_work_tree;
+static char *junk_git_dir;
+static int is_junk;
+static pid_t junk_pid;
+
+static void remove_junk(void)
+{
+	struct strbuf sb = STRBUF_INIT;
+	if (!is_junk || getpid() != junk_pid)
+		return;
+	if (junk_git_dir) {
+		strbuf_addstr(&sb, junk_git_dir);
+		remove_dir_recursively(&sb, 0);
+		strbuf_reset(&sb);
+	}
+	if (junk_work_tree) {
+		strbuf_addstr(&sb, junk_work_tree);
+		remove_dir_recursively(&sb, 0);
+	}
+	strbuf_release(&sb);
+}
+
+static void remove_junk_on_signal(int signo)
+{
+	remove_junk();
+	sigchain_pop(signo);
+	raise(signo);
+}
+
+static int add_worktree(const char *path, const char **child_argv)
+{
+	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	const char *name;
+	struct stat st;
+	struct child_process cp;
+	int counter = 0, len, ret;
+	unsigned char rev[20];
+
+	if (file_exists(path) && !is_empty_dir(path))
+		die(_("'%s' already exists"), path);
+
+	len = strlen(path);
+	while (len && is_dir_sep(path[len - 1]))
+		len--;
+
+	for (name = path + len - 1; name > path; name--)
+		if (is_dir_sep(*name)) {
+			name++;
+			break;
+		}
+	strbuf_addstr(&sb_repo,
+		      git_path("worktrees/%.*s", (int)(path + len - name), name));
+	len = sb_repo.len;
+	if (safe_create_leading_directories_const(sb_repo.buf))
+		die_errno(_("could not create leading directories of '%s'"),
+			  sb_repo.buf);
+	while (!stat(sb_repo.buf, &st)) {
+		counter++;
+		strbuf_setlen(&sb_repo, len);
+		strbuf_addf(&sb_repo, "%d", counter);
+	}
+	name = strrchr(sb_repo.buf, '/') + 1;
+
+	junk_pid = getpid();
+	atexit(remove_junk);
+	sigchain_push_common(remove_junk_on_signal);
+
+	if (mkdir(sb_repo.buf, 0777))
+		die_errno(_("could not create directory of '%s'"), sb_repo.buf);
+	junk_git_dir = xstrdup(sb_repo.buf);
+	is_junk = 1;
+
+	/*
+	 * lock the incomplete repo so prune won't delete it, unlock
+	 * after the preparation is over.
+	 */
+	strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+	write_file(sb.buf, 1, "initializing\n");
+
+	strbuf_addf(&sb_git, "%s/.git", path);
+	if (safe_create_leading_directories_const(sb_git.buf))
+		die_errno(_("could not create leading directories of '%s'"),
+			  sb_git.buf);
+	junk_work_tree = xstrdup(path);
+
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
+	write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
+	write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
+		   real_path(get_git_common_dir()), name);
+	/*
+	 * This is to keep resolve_ref() happy. We need a valid HEAD
+	 * or is_git_directory() will reject the directory. Moreover, HEAD
+	 * in the new worktree must resolve to the same value as HEAD in
+	 * the current tree since the command invoked to populate the new
+	 * worktree will be handed the branch/ref specified by the user.
+	 * For instance, if the user asks for the new worktree to be based
+	 * at HEAD~5, then the resolved HEAD~5 in the new worktree must
+	 * match the resolved HEAD~5 in the current tree in order to match
+	 * the user's expectation.
+	 */
+	if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
+		die(_("unable to resolve HEAD"));
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
+	write_file(sb.buf, 1, "%s\n", sha1_to_hex(rev));
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
+	write_file(sb.buf, 1, "../..\n");
+
+	fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+
+	setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
+	setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
+	setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
+	memset(&cp, 0, sizeof(cp));
+	cp.git_cmd = 1;
+	cp.argv = child_argv;
+	ret = run_command(&cp);
+	if (!ret) {
+		is_junk = 0;
+		free(junk_work_tree);
+		free(junk_git_dir);
+		junk_work_tree = NULL;
+		junk_git_dir = NULL;
+	}
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+	unlink_or_warn(sb.buf);
+	strbuf_release(&sb);
+	strbuf_release(&sb_repo);
+	strbuf_release(&sb_git);
+	return ret;
+}
+
 static int add(int ac, const char **av, const char *prefix)
 {
-	struct child_process c;
 	int force = 0, detach = 0;
 	const char *new_branch = NULL, *new_branch_force = NULL;
 	const char *path, *branch;
@@ -149,7 +285,6 @@ static int add(int ac, const char **av, const char *prefix)
 	branch = av[1];
 
 	argv_array_push(&cmd, "checkout");
-	argv_array_pushl(&cmd, "--to", path, NULL);
 	if (force)
 		argv_array_push(&cmd, "--ignore-other-worktrees");
 	if (new_branch)
@@ -160,10 +295,7 @@ static int add(int ac, const char **av, const char *prefix)
 		argv_array_push(&cmd, "--detach");
 	argv_array_push(&cmd, branch);
 
-	memset(&c, 0, sizeof(c));
-	c.git_cmd = 1;
-	c.argv = cmd.argv;
-	return run_command(&c);
+	return add_worktree(path, cmd.argv);
 }
 
 int cmd_worktree(int ac, const char **av, const char *prefix)
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 19/23] checkout: require worktree unconditionally
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (17 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 18/23] checkout: retire --to option Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 20/23] worktree: extract basename computation to new function Eric Sunshine
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

In order to allow linked worktree creation via "git checkout --to" from
a bare repository, 3473ad0 (checkout: don't require a work tree when
checking out into a new one, 2014-11-30) dropped git-checkout's
unconditional NEED_WORK_TREE requirement and instead performed worktree
setup conditionally based upon presence or absence of the --to option.
Now that --to has been retired and git-checkout is no longer responsible
for linked worktree creation, the NEED_WORK_TREE requirement can be
re-instated.

This effectively reverts 3473ad0, except for the tests it added which
now check bare repository behavior of "git worktree add" instead.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/checkout.c | 2 --
 git.c              | 2 +-
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index b1e68b3..5754554 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1218,8 +1218,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 
 	opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
 
-	setup_work_tree();
-
 	if (conflict_style) {
 		opts.merge = 1; /* implied */
 		git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
diff --git a/git.c b/git.c
index f227838..21a6398 100644
--- a/git.c
+++ b/git.c
@@ -383,7 +383,7 @@ static struct cmd_struct commands[] = {
 	{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
 	{ "check-mailmap", cmd_check_mailmap, RUN_SETUP },
 	{ "check-ref-format", cmd_check_ref_format },
-	{ "checkout", cmd_checkout, RUN_SETUP },
+	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout-index", cmd_checkout_index,
 		RUN_SETUP | NEED_WORK_TREE},
 	{ "cherry", cmd_cherry, RUN_SETUP },
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 20/23] worktree: extract basename computation to new function
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (18 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 19/23] checkout: require worktree unconditionally Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 21/23] worktree: add: make -b/-B default to HEAD when <branch> is omitted Eric Sunshine
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

A subsequent patch will also need to compute the basename of the new
worktree, so factor out this logic into a new function.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 builtin/worktree.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 04e6d0f..25fe25b 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -152,6 +152,25 @@ static void remove_junk_on_signal(int signo)
 	raise(signo);
 }
 
+static const char *worktree_basename(const char *path, int *olen)
+{
+	const char *name;
+	int len;
+
+	len = strlen(path);
+	while (len && is_dir_sep(path[len - 1]))
+		len--;
+
+	for (name = path + len - 1; name > path; name--)
+		if (is_dir_sep(*name)) {
+			name++;
+			break;
+		}
+
+	*olen = len;
+	return name;
+}
+
 static int add_worktree(const char *path, const char **child_argv)
 {
 	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
@@ -165,15 +184,7 @@ static int add_worktree(const char *path, const char **child_argv)
 	if (file_exists(path) && !is_empty_dir(path))
 		die(_("'%s' already exists"), path);
 
-	len = strlen(path);
-	while (len && is_dir_sep(path[len - 1]))
-		len--;
-
-	for (name = path + len - 1; name > path; name--)
-		if (is_dir_sep(*name)) {
-			name++;
-			break;
-		}
+	name = worktree_basename(path, &len);
 	strbuf_addstr(&sb_repo,
 		      git_path("worktrees/%.*s", (int)(path + len - name), name));
 	len = sb_repo.len;
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 21/23] worktree: add: make -b/-B default to HEAD when <branch> is omitted
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (19 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 20/23] worktree: extract basename computation to new function Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 17:30 ` [PATCH v3 22/23] worktree: add: auto-vivify new branch " Eric Sunshine
  2015-07-06 17:31 ` [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force Eric Sunshine
  22 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

As a convenience, like "git branch" and "git checkout -b", make
"git worktree add -b <newbranch> <path> <branch>" default to HEAD when
<branch> is omitted.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 1 +
 builtin/worktree.c             | 6 ++++--
 t/t2025-worktree-add.sh        | 5 +++++
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index f44cd78..377ae0f 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -68,6 +68,7 @@ OPTIONS
 -B <new-branch>::
 	With `add`, create a new branch named `<new-branch>` starting at
 	`<branch>`, and check out `<new-branch>` into the new worktree.
+	If `<branch>` 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>`.
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 25fe25b..323d444 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -289,11 +289,13 @@ static int add(int ac, const char **av, const char *prefix)
 	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
 	if (new_branch && new_branch_force)
 		die(_("-b and -B are mutually exclusive"));
-	if (ac != 2)
+	if (ac < 1 || ac > 2)
+		usage_with_options(worktree_usage, options);
+	if (ac < 2 && !new_branch && !new_branch_force)
 		usage_with_options(worktree_usage, options);
 
 	path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
-	branch = av[1];
+	branch = ac < 2 ? "HEAD" : av[1];
 
 	argv_array_push(&cmd, "checkout");
 	if (force)
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 192c936..8964dec 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -140,4 +140,9 @@ test_expect_success '"add" from relative HEAD' '
 	test_cmp expected actual
 '
 
+test_expect_success '"add -b" with <branch> omitted' '
+	git worktree add -b burble flornk &&
+	test_cmp_rev HEAD burble
+'
+
 test_done
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 22/23] worktree: add: auto-vivify new branch when <branch> is omitted
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (20 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 21/23] worktree: add: make -b/-B default to HEAD when <branch> is omitted Eric Sunshine
@ 2015-07-06 17:30 ` Eric Sunshine
  2015-07-06 19:19   ` Junio C Hamano
  2015-07-06 17:31 ` [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force Eric Sunshine
  22 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

As a convenience, when <branch> is omitted from "git worktree <path>
<branch>" and neither -b nor -B is used, automatically create a new
branch named after <path>, as if "-b $(basename <path>)" was specified.
Thus, "git worktree add ../hotfix" creates a new branch named "hotfix"
and associates it with new worktree "../hotfix".

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt | 8 ++++++--
 builtin/worktree.c             | 8 ++++++--
 t/t2025-worktree-add.sh        | 5 +++++
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 377ae0f..da71f50 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] [--detach] [-b <new-branch>] <path> <branch>
+'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
 'git worktree prune' [-n] [-v] [--expire <expire>]
 
 DESCRIPTION
@@ -45,11 +45,15 @@ pruning should be suppressed. See section "DETAILS" for more information.
 
 COMMANDS
 --------
-add <path> <branch>::
+add <path> [<branch>]::
 
 Create `<path>` and checkout `<branch>` into it. The new working directory
 is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc.
++
+If `<branch>` is omitted and neither `-b` nor `-B` is used, then, as a
+convenience, a new branch based at HEAD is created automatically, as if
+`-b $(basename <path>)` was specified.
 
 prune::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 323d444..69248ba 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -291,12 +291,16 @@ static int add(int ac, const char **av, const char *prefix)
 		die(_("-b and -B are mutually exclusive"));
 	if (ac < 1 || ac > 2)
 		usage_with_options(worktree_usage, options);
-	if (ac < 2 && !new_branch && !new_branch_force)
-		usage_with_options(worktree_usage, options);
 
 	path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
 	branch = ac < 2 ? "HEAD" : av[1];
 
+	if (ac < 2 && !new_branch && !new_branch_force) {
+		int n;
+		const char *s = worktree_basename(path, &n);
+		new_branch = xstrndup(s, n);
+	}
+
 	argv_array_push(&cmd, "checkout");
 	if (force)
 		argv_array_push(&cmd, "--ignore-other-worktrees");
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 8964dec..8fe242f 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -145,4 +145,9 @@ test_expect_success '"add -b" with <branch> omitted' '
 	test_cmp_rev HEAD burble
 '
 
+test_expect_success '"add" with <branch> omitted' '
+	git worktree add wiffle/bat &&
+	test_cmp_rev HEAD bat
+'
+
 test_done
-- 
2.5.0.rc1.197.g417e668

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

* [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
                   ` (21 preceding siblings ...)
  2015-07-06 17:30 ` [PATCH v3 22/23] worktree: add: auto-vivify new branch " Eric Sunshine
@ 2015-07-06 17:31 ` Eric Sunshine
  2015-07-06 19:40   ` Junio C Hamano
  22 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-06 17:31 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Duy Nguyen, Mark Levedahl, Mikael Magnusson,
	Eric Sunshine

As a safeguard, checking out a branch already checked out by a different
worktree is disallowed. This behavior can be overridden with
--ignore-other-worktrees, however, this option is neither obvious nor
particularly discoverable. As a common safeguard override, --force is
more likely to come to mind. Therefore, overload it to also suppress the
check for a branch already checked out elsewhere.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---

I plopped this patch at the end of the series so that it can be dropped
easily if desired since Junio indicated[1] that he would "moderately
object" to this change.

[1]: http://thread.gmane.org/gmane.comp.version-control.git/273032/focus=273108

 Documentation/git-checkout.txt | 9 +++------
 builtin/checkout.c             | 8 +++-----
 builtin/worktree.c             | 2 +-
 3 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index efe6a02..6c3085d 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -111,6 +111,9 @@ OPTIONS
 +
 When checking out paths from the index, do not fail upon unmerged
 entries; instead, unmerged entries are ignored.
++
+By default, checking out a branch already checked out in another worktree
+is disallowed. This overrides that safeguard.
 
 --ours::
 --theirs::
@@ -225,12 +228,6 @@ This means that you can use `git checkout -p` to selectively discard
 edits from your current working tree. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
---ignore-other-worktrees::
-	`git checkout` refuses when the wanted ref is already checked
-	out by another worktree. This option makes it check the ref
-	out anyway. In other words, the ref can be held by more than one
-	worktree.
-
 <branch>::
 	Branch to checkout; if it refers to a branch (i.e., a name that,
 	when prepended with "refs/heads/", is a valid ref), then that
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5754554..01c7c30 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -35,7 +35,6 @@ struct checkout_opts {
 	int writeout_stage;
 	int overwrite_ignore;
 	int ignore_skipworktree;
-	int ignore_other_worktrees;
 
 	const char *new_branch;
 	const char *new_branch_force;
@@ -903,7 +902,8 @@ static void check_linked_checkout(struct branch_info *new, const char *id)
 		strbuf_rtrim(&gitdir);
 	} else
 		strbuf_addstr(&gitdir, get_git_common_dir());
-	die(_("'%s' is already checked out at '%s'"), new->name, gitdir.buf);
+	die(_("'%s' is already checked out at '%s'; use --force to override"),
+	    new->name, gitdir.buf);
 done:
 	strbuf_release(&path);
 	strbuf_release(&sb);
@@ -1151,7 +1151,7 @@ static int checkout_branch(struct checkout_opts *opts,
 		char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
 		if (head_ref &&
 		    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
-		    !opts->ignore_other_worktrees)
+		    !opts->force)
 			check_linked_checkouts(new);
 		free(head_ref);
 	}
@@ -1198,8 +1198,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 			 N_("do not limit pathspecs to sparse entries only")),
 		OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
 				N_("second guess 'git checkout no-such-branch'")),
-		OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
-			 N_("do not check if another worktree is holding the given ref")),
 		OPT_END(),
 	};
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 69248ba..050b443 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -303,7 +303,7 @@ static int add(int ac, const char **av, const char *prefix)
 
 	argv_array_push(&cmd, "checkout");
 	if (force)
-		argv_array_push(&cmd, "--ignore-other-worktrees");
+		argv_array_push(&cmd, "--force");
 	if (new_branch)
 		argv_array_pushl(&cmd, "-b", new_branch, NULL);
 	if (new_branch_force)
-- 
2.5.0.rc1.197.g417e668

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

* Re: [PATCH v3 22/23] worktree: add: auto-vivify new branch when <branch> is omitted
  2015-07-06 17:30 ` [PATCH v3 22/23] worktree: add: auto-vivify new branch " Eric Sunshine
@ 2015-07-06 19:19   ` Junio C Hamano
  2015-07-07  1:33     ` Eric Sunshine
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2015-07-06 19:19 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Duy Nguyen, Mark Levedahl, Mikael Magnusson

Eric Sunshine <sunshine@sunshineco.com> writes:

> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> index 377ae0f..da71f50 100644
> --- a/Documentation/git-worktree.txt
> +++ b/Documentation/git-worktree.txt
> @@ -9,7 +9,7 @@ git-worktree - Manage multiple worktrees
>  SYNOPSIS
>  --------
>  [verse]
> -'git worktree add' [-f] [--detach] [-b <new-branch>] <path> <branch>
> +'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]

Ahh, OK, this answers my previous question.

> +	if (ac < 2 && !new_branch && !new_branch_force) {
> +		int n;
> +		const char *s = worktree_basename(path, &n);
> +		new_branch = xstrndup(s, n);
> +	}
> +

and because this is new_branch, not new_branch_force, we will not
accidentally clobber an existing branch.  The "hotfix" time is when
the end-user tends to be less careful, and it is a good thing to
make sure "git worktree add ../hotfix" will not clobber an unrelated
"hotfix" branch.

Good.

Which may be something we would want to have a test for, though.

> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> index 8964dec..8fe242f 100755
> --- a/t/t2025-worktree-add.sh
> +++ b/t/t2025-worktree-add.sh
> @@ -145,4 +145,9 @@ test_expect_success '"add -b" with <branch> omitted' '
>  	test_cmp_rev HEAD burble
>  '
>  
> +test_expect_success '"add" with <branch> omitted' '
> +	git worktree add wiffle/bat &&
> +	test_cmp_rev HEAD bat
> +'
> +
>  test_done

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

* Re: [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-06 17:31 ` [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force Eric Sunshine
@ 2015-07-06 19:40   ` Junio C Hamano
  2015-07-07  8:24     ` Eric Sunshine
  2015-07-08  0:43     ` Mark Levedahl
  0 siblings, 2 replies; 36+ messages in thread
From: Junio C Hamano @ 2015-07-06 19:40 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Duy Nguyen, Mark Levedahl, Mikael Magnusson

Eric Sunshine <sunshine@sunshineco.com> writes:

> As a safeguard, checking out a branch already checked out by a different
> worktree is disallowed. This behavior can be overridden with
> --ignore-other-worktrees, however, this option is neither obvious nor
> particularly discoverable. As a common safeguard override, --force is
> more likely to come to mind. Therefore, overload it to also suppress the
> check for a branch already checked out elsewhere.

I hate to be asking this again but why is it a good idea to allow
'ignore-other-worktrees' in the first place (let alone making it
more discoverable)?  You'll have multiple working trees, either
using the new "git worktree" or using the old contrib/workdir, for
one of the two reasons:

 * You need a separate work area to build a new history.

 * You need a separate work area to expand the contents of a
   specific commit.

Here "create binary by running make" falls into the latter category;
as far as Git is concerned, you are only looking at, not extending
the history of any specific branch.

If you are extending the history of some branch, then you would want
to be on that branch.  Why would you want to have another worktree
that will get into a confusing state once you create that commit on
the checked out branch in this newly created worktree?

Wasn't the whole point of making the primary repository aware of the
secondary worktrees via the "linked checkout" mechanism because that
confusion was the biggest sore point of the old contrib/workdir
implementation?

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

* Re: [PATCH v3 18/23] checkout: retire --to option
  2015-07-06 17:30 ` [PATCH v3 18/23] checkout: retire --to option Eric Sunshine
@ 2015-07-06 19:41   ` Junio C Hamano
  2015-07-07  7:08     ` Eric Sunshine
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2015-07-06 19:41 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Duy Nguyen, Mark Levedahl, Mikael Magnusson

Eric Sunshine <sunshine@sunshineco.com> writes:

> Now that "git worktree add" has achieved user-facing feature-parity with
> "git checkout --to", retire the latter.
>
> Move the actual linked worktree creation functionality,
> prepare_linked_checkout() and its helpers, verbatim from checkout.c to
> worktree.c.
>
> This effectively reverts changes to checkout.c by 529fef2 (checkout:
> support checking out into a new working directory, 2014-11-30) with the
> exception of merge_working_tree() and switch_branches() which still
> require specialized knowledge that a the checkout is occurring in a
> newly-created linked worktree (signaled to them by the private
> GIT_CHECKOUT_NEW_WORKTREE environment variable).


I do not quite understand why we still need the hidden environment
variable.  Is this a sign that the implementation is shared too much
between unrelated codepaths (or to put it another way, perhaps API
functions that are not best fit are being used)?

Stepping back a bit, with or without the new "linked worktree"
feature, when you came across a repository whose working tree does
not have any file (i.e. somebody ran "git ls-files | xargs rm"), you
do not know and care what is in .git/index right now, you do not
know and care what branch its .git/HEAD points at, but you *do* know
what branch you want to be on (or where you want its HEAD detached
at), what would be the command you would use?

The state immediately after a new worktree is constructed by
populating /path/main/.git/worktrees/test-next/ and pointing it from
/path/other/test-next/.git but before the index or the files under
/path/other/test-next/ are populated is exactly that situation, no?
Wouldn't "symbolic-ref HEAD the-branch-i-want" (or "update-ref HEAD
the-commit-i-want" in the detached case) followed by "reset --hard"
the more natural thing to use, instead of merge-working-tree and
switch-branches that are implementation details of "checkout"?

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

* Re: [PATCH v3 22/23] worktree: add: auto-vivify new branch when <branch> is omitted
  2015-07-06 19:19   ` Junio C Hamano
@ 2015-07-07  1:33     ` Eric Sunshine
  2015-07-07 16:10       ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-07  1:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Duy Nguyen, Mark Levedahl, Mikael Magnusson

On Mon, Jul 06, 2015 at 12:19:14PM -0700, Junio C Hamano wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
> > diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> > index 377ae0f..da71f50 100644
> > --- a/Documentation/git-worktree.txt
> > +++ b/Documentation/git-worktree.txt
> > @@ -9,7 +9,7 @@ git-worktree - Manage multiple worktrees
> >  SYNOPSIS
> >  --------
> >  [verse]
> > -'git worktree add' [-f] [--detach] [-b <new-branch>] <path> <branch>
> > +'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
> 
> Ahh, OK, this answers my previous question.

Right. I considered squashing this patch with the previous one, in
which case the synopsis question wouldn't have come up, but kept them
separate since they are (or can be) conceptually distinct, and the one
patch builds upon the other (and keeping them separate makes them a
bit easier to review).

> > +	if (ac < 2 && !new_branch && !new_branch_force) {
> > +		int n;
> > +		const char *s = worktree_basename(path, &n);
> > +		new_branch = xstrndup(s, n);
> > +	}
> > +
> 
> and because this is new_branch, not new_branch_force, we will not
> accidentally clobber an existing branch.  The "hotfix" time is when
> the end-user tends to be less careful, and it is a good thing to
> make sure "git worktree add ../hotfix" will not clobber an unrelated
> "hotfix" branch.
> 
> Good.
> 
> Which may be something we would want to have a test for, though.

Good idea. How about the following as a squash-in?

--- 8< ---
From: Eric Sunshine <sunshine@sunshineco.com>
Subject: [PATCH] fixup! worktree: add: auto-vivify new branch when <branch> is omitted

---
 t/t2025-worktree-add.sh | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 8fe242f..ead8aa2 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -150,4 +150,13 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
+test_expect_success '"add" auto-vivify does not clobber existing branch' '
+	test_commit c1 &&
+	test_commit c2 &&
+	git branch precious HEAD~1 &&
+	test_must_fail git worktree add precious &&
+	test_cmp_rev HEAD~1 precious &&
+	test_path_is_missing precious
+'
+
 test_done
-- 
2.5.0.rc1.201.ga12d9f8

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

* Re: [PATCH v3 18/23] checkout: retire --to option
  2015-07-06 19:41   ` Junio C Hamano
@ 2015-07-07  7:08     ` Eric Sunshine
  2015-07-08 16:58       ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-07  7:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen, Mark Levedahl, Mikael Magnusson

On Mon, Jul 6, 2015 at 3:41 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
>> Now that "git worktree add" has achieved user-facing feature-parity with
>> "git checkout --to", retire the latter.
>> [...]
>> This effectively reverts changes to checkout.c by 529fef2 (checkout:
>> support checking out into a new working directory, 2014-11-30) with the
>> exception of merge_working_tree() and switch_branches() which still
>> require specialized knowledge that a the checkout is occurring in a
>> newly-created linked worktree (signaled to them by the private
>> GIT_CHECKOUT_NEW_WORKTREE environment variable).
>
> I do not quite understand why we still need the hidden environment
> variable.  Is this a sign that the implementation is shared too much
> between unrelated codepaths (or to put it another way, perhaps API
> functions that are not best fit are being used)?

Duy had responded[1][2] to my inquiry about these two remaining bits
of checkout.c code with intimate knowledge of the initial
linked-worktree checkout (merge_working_tree & switch_branches), but I
don't know the checkout code well enough (yet) to fully understand his
responses or to answer your question satisfactorily. This is also why
I was afraid to rip out those final two bits of code, even though in
my own testing, having ripped them out locally, I was unable to
trigger any sort of "bad" behavior, as far as I could tell. Thus, I
wasn't sure if those two bits of code were needed, and was hoping
someone more qualified (Duy, for instance) would be able to provide a
more authoritative answer.

Having now re-read and finally digested Duy's response about
switch_branches(), when I rip out the `new_worktree_mode` check
locally, I find that I can trigger the misleading warning about an
orphaned commit, so that bit of code still serves a practical purpose.
This doesn't justify that such ugly intimacy between git-worktree and
git-checkout is desirable; only that it still seems to be needed until
"git reset --hard" can be swapped in to replace "git checkout".

[1]: http://article.gmane.org/gmane.comp.version-control.git/273225
[2]: http://article.gmane.org/gmane.comp.version-control.git/273226

> Stepping back a bit, with or without the new "linked worktree"
> feature, when you came across a repository whose working tree does
> not have any file (i.e. somebody ran "git ls-files | xargs rm"), you
> do not know and care what is in .git/index right now, you do not
> know and care what branch its .git/HEAD points at, but you *do* know
> what branch you want to be on (or where you want its HEAD detached
> at), what would be the command you would use?
>
> The state immediately after a new worktree is constructed by
> populating /path/main/.git/worktrees/test-next/ and pointing it from
> /path/other/test-next/.git but before the index or the files under
> /path/other/test-next/ are populated is exactly that situation, no?
> Wouldn't "symbolic-ref HEAD the-branch-i-want" (or "update-ref HEAD
> the-commit-i-want" in the detached case) followed by "reset --hard"
> the more natural thing to use, instead of merge-working-tree and
> switch-branches that are implementation details of "checkout"?

It seems so to me. I didn't repeat it in the v3 cover letter, but the
v2 cover letter said this (which still holds true for v3):

    v2 does not attempt either of the suggestions by Junio[*3*] or
    Duy[*4*] for eliminating git-checkout from the equation, which
    would allow us to remove the final couple bits of code in
    git-checkout which require intimate knowledge that the checkout
    is occurring in a newly created linked worktree. This series is
    already too long, and I didn't want it to grow further by
    implementing either of those ideas. Instead, this series leaves
    git-worktree at a state where one or the other of those
    suggestions can be done as follow-on patches touching only the
    underlying machinery, without affecting the user-facing
    interface.

    [*3*]: via private email which suggested using "git-reset --hard"
           rather than "git checkout" to populate the new linked
           worktree.
    [*4*]: http://thread.gmane.org/gmane.comp.version-control.git/273032/focus=273226

In order to use "git reset --hard" in place of "git checkout",
git-worktree will need to handle -b/-B, --detach, --force (and
possibly --track and --orphan) itself. I'm still in the process of
familiarizing myself with the code needed to perform those actions, as
well as whatever else is needed to make "git reset --hard" a reality,
so I am not yet in a position to say now much time or work will be
required to swap out "git checkout" for "git reset --hard". As such, I
didn't want to hold up the series for an unknown amount of time while
studying the issue; and, as the series stands, the remaining ugly
intimate knowledge between git-worktree and git-checkout is
behind-the-scenes and localized (not affecting the user experience).

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

* Re: [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-06 19:40   ` Junio C Hamano
@ 2015-07-07  8:24     ` Eric Sunshine
  2015-07-07  9:41       ` Eric Sunshine
  2015-07-08  0:43     ` Mark Levedahl
  1 sibling, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-07  8:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen, Mark Levedahl, Mikael Magnusson

On Mon, Jul 6, 2015 at 3:40 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
>> As a safeguard, checking out a branch already checked out by a different
>> worktree is disallowed. This behavior can be overridden with
>> --ignore-other-worktrees, however, this option is neither obvious nor
>> particularly discoverable. As a common safeguard override, --force is
>> more likely to come to mind. Therefore, overload it to also suppress the
>> check for a branch already checked out elsewhere.
>
> I hate to be asking this again but why is it a good idea to allow
> 'ignore-other-worktrees' in the first place (let alone making it
> more discoverable)?  You'll have multiple working trees, either
> using the new "git worktree" or using the old contrib/workdir, for
> one of the two reasons:
>
>  * You need a separate work area to build a new history.
>
>  * You need a separate work area to expand the contents of a
>    specific commit.
>
> Here "create binary by running make" falls into the latter category;
> as far as Git is concerned, you are only looking at, not extending
> the history of any specific branch.
>
> If you are extending the history of some branch, then you would want
> to be on that branch.  Why would you want to have another worktree
> that will get into a confusing state once you create that commit on
> the checked out branch in this newly created worktree?
>
> Wasn't the whole point of making the primary repository aware of the
> secondary worktrees via the "linked checkout" mechanism because that
> confusion was the biggest sore point of the old contrib/workdir
> implementation?

Having never used contrib/get-new-workdir, and not being involved in
the choice, nor recall seeing justification for disallowing the a
branch to be checked out in multiple locations, I lack insight to
answer. I do recall Mark pointing out that this restriction posed a
barrier for his migration from git-new-workdir to "git checkout
--to"[1], and Duy adding --ignore-other-worktrees in response. Mark
presented a use-case here [2], but then the discussion petered out.

I likewise probably lack understanding of the finer points to make a
cogent argument for or against.

[1]: http://thread.gmane.org/gmane.comp.version-control.git/260387/focus=260411
[2]: http://article.gmane.org/gmane.comp.version-control.git/260645

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

* Re: [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-07  8:24     ` Eric Sunshine
@ 2015-07-07  9:41       ` Eric Sunshine
  2015-07-07 16:20         ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-07-07  9:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen, Mark Levedahl, Mikael Magnusson

On Tue, Jul 7, 2015 at 4:24 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Mon, Jul 6, 2015 at 3:40 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> If you are extending the history of some branch, then you would want
>> to be on that branch.  Why would you want to have another worktree
>> that will get into a confusing state once you create that commit on
>> the checked out branch in this newly created worktree?
>>
>> Wasn't the whole point of making the primary repository aware of the
>> secondary worktrees via the "linked checkout" mechanism because that
>> confusion was the biggest sore point of the old contrib/workdir
>> implementation?
>
> I [...] probably lack understanding of the finer points to make a
> cogent argument for or against.

Is receive.denyCurrentBranch worth mentioning as an argument? Although
pushing a branch into a non-bare repo where that branch is already
checked out is normally disallowed, receive.denyCurrentBranch
overrides the safeguard. Presumably, the user has experience and
knowledge to know that "git reset --hard" will be required to sync
things up.

Using --force or --ignore-other-worktrees (or whatever) to override
git-checkout's normal safeguard against checking out a branch into
more than one linked-worktree parallels receive.denyCurrentBranch,
doesn't it? There is a certain amount of precedent elsewhere in Git
for allowing a person to shoot himself in the foot.

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

* Re: [PATCH v3 22/23] worktree: add: auto-vivify new branch when <branch> is omitted
  2015-07-07  1:33     ` Eric Sunshine
@ 2015-07-07 16:10       ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2015-07-07 16:10 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Duy Nguyen, Mark Levedahl, Mikael Magnusson

Eric Sunshine <sunshine@sunshineco.com> writes:

>> Which may be something we would want to have a test for, though.
>
> Good idea. How about the following as a squash-in?

Sounds sensible.

At this point we do not have "worktree list", but if we gained that,
we may want to add this as one more postcondition after the failed
"worktree add":

       git worktree list >actual &&
       ! grep precious actual

but that should happen in the series that adds "worktree list" ;-)

> --- 8< ---
> From: Eric Sunshine <sunshine@sunshineco.com>
> Subject: [PATCH] fixup! worktree: add: auto-vivify new branch when <branch> is omitted
>
> ---
>  t/t2025-worktree-add.sh | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> index 8fe242f..ead8aa2 100755
> --- a/t/t2025-worktree-add.sh
> +++ b/t/t2025-worktree-add.sh
> @@ -150,4 +150,13 @@ test_expect_success '"add" with <branch> omitted' '
>  	test_cmp_rev HEAD bat
>  '
>  
> +test_expect_success '"add" auto-vivify does not clobber existing branch' '
> +	test_commit c1 &&
> +	test_commit c2 &&
> +	git branch precious HEAD~1 &&
> +	test_must_fail git worktree add precious &&
> +	test_cmp_rev HEAD~1 precious &&
> +	test_path_is_missing precious
> +'
> +
>  test_done

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

* Re: [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-07  9:41       ` Eric Sunshine
@ 2015-07-07 16:20         ` Junio C Hamano
  2015-07-07 23:10           ` Eric Sunshine
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2015-07-07 16:20 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Duy Nguyen, Mark Levedahl, Mikael Magnusson

Eric Sunshine <sunshine@sunshineco.com> writes:

> Is receive.denyCurrentBranch worth mentioning as an argument? Although
> pushing a branch into a non-bare repo where that branch is already
> checked out is normally disallowed, receive.denyCurrentBranch
> overrides the safeguard. Presumably, the user has experience and
> knowledge to know that "git reset --hard" will be required to sync
> things up.

Or the user knows that he does not have a shell access to the box in
the first place.  I do not see much relevance to this discussion.

I would not mind "git worktree add -f" to disable the "no multiple
checkouts of the same branch" safety, but I do not think it is
sensible to remove "-i-o-w" and conflate everything into "--force".
That would force people to disable other safety measures at the same
time (e.g. protect local changes from differences between the
current and next branches).

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

* Re: [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-07 16:20         ` Junio C Hamano
@ 2015-07-07 23:10           ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-07-07 23:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen, Mark Levedahl, Mikael Magnusson

On Tue, Jul 7, 2015 at 12:20 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
> I would not mind "git worktree add -f" to disable the "no multiple
> checkouts of the same branch" safety, but I do not think it is
> sensible to remove "-i-o-w" and conflate everything into "--force".
> That would force people to disable other safety measures at the same
> time (e.g. protect local changes from differences between the
> current and next branches).

I'm fine with dropping this patch.

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

* Re: [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force
  2015-07-06 19:40   ` Junio C Hamano
  2015-07-07  8:24     ` Eric Sunshine
@ 2015-07-08  0:43     ` Mark Levedahl
  1 sibling, 0 replies; 36+ messages in thread
From: Mark Levedahl @ 2015-07-08  0:43 UTC (permalink / raw)
  To: Junio C Hamano, Eric Sunshine; +Cc: git, Duy Nguyen, Mikael Magnusson

On 07/06/2015 03:40 PM, Junio C Hamano wrote:
> If you are extending the history of some branch, then you would want 
> to be on that branch. Why would you want to have another worktree that 
> will get into a confusing state once you create that commit on the 
> checked out branch in this newly created worktree? Wasn't the whole 
> point of making the primary repository aware of the secondary 
> worktrees via the "linked checkout" mechanism because that confusion 
> was the biggest sore point of the old contrib/workdir implementation? 

The only issue I have with git-new-workdir is that git-gc in one 
worktree is unaware of what is in use in another so can prune things 
away. The linked worktrees here nicely solve that problem.

The main use I have of maintaining multiple checkouts of one branch is 
for testing / analysis (where said tests can take days to weeks to run). 
Disallowing use of git's normal mechanism of tracking what is checked 
out in each such tree forces use of another system to do so, just 
imposing different difficulties for this use case. I note that 1) code 
must be ADDED to git to prevent such duplicate checkouts which otherwise 
cause no difficulty to git itself, and 2) adding those checks requires 
additional work to avoid the fallout. I have yet to hear what the upside 
of such a restriction is, I only see downsides.

Mark

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

* Re: [PATCH v3 18/23] checkout: retire --to option
  2015-07-07  7:08     ` Eric Sunshine
@ 2015-07-08 16:58       ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2015-07-08 16:58 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Duy Nguyen, Mark Levedahl, Mikael Magnusson

Eric Sunshine <sunshine@sunshineco.com> writes:

> ... as the series stands, the remaining ugly intimate knowledge
> between git-worktree and git-checkout is behind-the-scenes and
> localized (not affecting the user experience).

Hopefully.  Let's run with what we have right now.

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

end of thread, other threads:[~2015-07-08 16:58 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-06 17:30 [PATCH v3 00/23] replace "checkout --to" with "worktree add" Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 01/23] Documentation/git-checkout: fix incorrect worktree prune command Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 02/23] Documentation/git-worktree: associate options with commands Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 03/23] Documentation: move linked worktree description from checkout to worktree Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 04/23] Documentation/git-worktree: add BUGS section Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 05/23] Documentation/git-worktree: split technical info from general description Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 06/23] Documentation/git-worktree: add high-level 'lock' overview Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 07/23] Documentation/git-worktree: add EXAMPLES section Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 08/23] checkout: fix bug with --to and relative HEAD Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 09/23] checkout: relocate --to's "no branch specified" check Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 10/23] checkout: prepare_linked_checkout: drop now-unused 'new' argument Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 11/23] checkout: make --to unconditionally verbose Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 12/23] checkout: drop 'checkout_opts' dependency from prepare_linked_checkout Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 13/23] worktree: introduce "add" command Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 14/23] worktree: add --force option Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 15/23] worktree: add --detach option Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 16/23] worktree: add -b/-B options Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 17/23] tests: worktree: retrofit "checkout --to" tests for "worktree add" Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 18/23] checkout: retire --to option Eric Sunshine
2015-07-06 19:41   ` Junio C Hamano
2015-07-07  7:08     ` Eric Sunshine
2015-07-08 16:58       ` Junio C Hamano
2015-07-06 17:30 ` [PATCH v3 19/23] checkout: require worktree unconditionally Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 20/23] worktree: extract basename computation to new function Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 21/23] worktree: add: make -b/-B default to HEAD when <branch> is omitted Eric Sunshine
2015-07-06 17:30 ` [PATCH v3 22/23] worktree: add: auto-vivify new branch " Eric Sunshine
2015-07-06 19:19   ` Junio C Hamano
2015-07-07  1:33     ` Eric Sunshine
2015-07-07 16:10       ` Junio C Hamano
2015-07-06 17:31 ` [PATCH v3 23/23] checkout: retire --ignore-other-worktrees in favor of --force Eric Sunshine
2015-07-06 19:40   ` Junio C Hamano
2015-07-07  8:24     ` Eric Sunshine
2015-07-07  9:41       ` Eric Sunshine
2015-07-07 16:20         ` Junio C Hamano
2015-07-07 23:10           ` Eric Sunshine
2015-07-08  0:43     ` Mark Levedahl

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.