git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
@ 2015-06-30  4:56 Eric Sunshine
  2015-06-30  9:23 ` Duy Nguyen
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-06-30  4:56 UTC (permalink / raw)
  To: git; +Cc: Duy Nguyen, Junio C Hamano, Eric Sunshine

The command "git checkout --to <path>" is something of an anachronism,
encompassing functionality somewhere between "checkout" and "clone".
The introduction of the git-worktree command, however, provides a proper
and intuitive place to house such functionality. Consequently,
re-implement "git checkout --to" as "git worktree new".

As a side-effect, linked worktree creation becomes much more
discoverable with its own dedicated command, whereas `--to` was easily
overlooked amid the plethora of options recognized by git-checkout.

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

I've long felt that Duy's linked-worktree functionality was a bit oddly
named as "git checkout --to", but, since I could never come up with a
better name, I never made mention of it. However, with Duy's
introduction of the git-worktree command[1], we now have a much more
appropriate and discoverable place to house the "git checkout --to"
functionality, and upon seeing his patch, I was ready to reply with the
suggestion to relocate "git checkout --to" to "git worktree new",
however, Junio beat me to it[2]. So, in response, this patch does
exactly that. It applies atop [1].

This is primarily a code and documentation relocation patch, with minor
new code added to builtin/worktree.c. Specifically:

* git-checkout.txt:"--to" description moved to git-worktree.txt:"new".

* git-checkout.txt:"MULTIPLE WORKING TREES" moved to
  git-worktree.txt:"DESCRIPTION", with "checkout --to" replaced by
  "worktree new" as necessary. git-worktree.txt could probably use a bit
  of reorganization, but that can be done as a separate patch.

* builtin/checkout.c:remove_junk() and remove_junk_on_signal() moved
  verbatim to builtin/worktree.c.

* builtin/checkout.c:prepare_linked_checkout() moved to
  builtin/worktree.c:new_worktree() nearly verbatim. The following small
  changes were needed (which might possibly be better done as separate
  preparatory patches):

  - The "no branch specified" check was dropped since git-worktree lacks
    the machinery for parsing git-checkout command-line arguments, and
    thus simply doesn't know if a branch/ref was provided, or in what
    form.  I'm not sure yet how to replace this check.

  - checkout.c:prepare_linked_checkout() (temporarily) fakes up a HEAD
    ref with a valid object-id in the new worktree to pacify
    is_git_directory(). It does so using the branch/ref from the
    command-line which it already resolved. worktree.c, however, doesn't
    have access to this information, so I instead added code to resolve
    and use HEAD for the fakement.

  - The "Enter %s (identifier %s)" message is suppressed in checkout.c
    if --quiet is specified, however, worktree.c does not have a --quiet
    option, so the message is printed unconditionally.

  - argv[] for the sub git-checkout invocation is hand-crafted in
    worktree.c rather than merely being re-used from the original "git
    checkout --to" as it was in checkout.c.

* builtin/worktree.c:new() is new. It recognizes a --force option ("git
  worktree new --force <path> <branch>") which allows a branch to be
  checked out in a new worktree even if already checked out in some
  other worktree (thus, mirroring the functionality of "git checkout
  --ignore-other-worktrees").

* t2025-checkout-to.sh became t2025-worktree-new.sh. I'm not sure if the
  test number still makes sense or if it should be changed, however, it
  resides alongside its t2026-prune-linked-checkouts.sh counterpart.

[1]: http://git.661346.n2.nabble.com/PATCH-worktree-new-place-for-git-prune-worktrees-tp7634619.html
[2]: http://git.661346.n2.nabble.com/PATCH-worktree-new-place-for-git-prune-worktrees-tp7634619p7634638.html


 Documentation/git-checkout.txt                    |  72 ----------
 Documentation/git-worktree.txt                    |  79 ++++++++++-
 builtin/checkout.c                                | 152 +--------------------
 builtin/worktree.c                                | 157 ++++++++++++++++++++++
 t/{t2025-checkout-to.sh => t2025-worktree-new.sh} |  44 +++---
 t/t2026-prune-linked-checkouts.sh                 |   2 +-
 6 files changed, 260 insertions(+), 246 deletions(-)
 rename t/{t2025-checkout-to.sh => t2025-worktree-new.sh} (56%)

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index d263a56..e19f03a 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... See "MULTIPLE WORKING
-	TREES" section for more information.
-
 --ignore-other-worktrees::
 	`git checkout` refuses when the wanted ref is already checked
 	out by another worktree. This option makes it check the ref
@@ -401,71 +394,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 prune --worktrees` 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 41103e5..8f13281 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,16 +9,85 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
+'git worktree new' [-f] <path> [<checkout-options>] <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 worktree new` 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 worktree new /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 prune --worktrees` 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
 --------
+new::
+
+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.
+
 prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
@@ -26,6 +95,12 @@ Prune working tree information in $GIT_DIR/worktrees.
 OPTIONS
 -------
 
+-f::
+--force::
+	By default, `git worktree new` refuses to create a new worktree when
+	<branch> is already checked out by another worktree. This option
+	overrides that safeguard.
+
 -n::
 --dry-run::
 	Do not remove anything; just report what it would
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9b49f0e..3dd5694 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -51,8 +51,6 @@ struct checkout_opts {
 	struct pathspec pathspec;
 	struct tree *source_tree;
 
-	const char *new_worktree;
-	const char **saved_argv;
 	int new_worktree_mode;
 };
 
@@ -273,8 +271,8 @@ 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->new_worktree_mode)
+		die(_("'%s' cannot be used with updating paths"), "git worktree new");
 
 	if (opts->patch_mode)
 		return run_add_interactive(revision, "--patch=checkout",
@@ -850,138 +848,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 struct checkout_opts *opts,
-				   struct branch_info *new)
-{
-	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
-	struct strbuf sb = STRBUF_INIT;
-	const char *path = opts->new_worktree, *name;
-	struct stat st;
-	struct child_process cp;
-	int counter = 0, len, ret;
-
-	if (!new->commit)
-		die(_("no branch specified"));
-	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. Any valid
-	 * value would do because this value will be ignored and
-	 * replaced at the next (real) checkout.
-	 */
-	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));
-	strbuf_reset(&sb);
-	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);
-
-	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 = opts->saved_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")) {
@@ -1321,9 +1187,6 @@ static int checkout_branch(struct checkout_opts *opts,
 		die(_("Cannot switch branch to a non-commit '%s'"),
 		    new->name);
 
-	if (opts->new_worktree)
-		return prepare_linked_checkout(opts, new);
-
 	if (!new->commit && opts->new_branch) {
 		unsigned char rev[20];
 		int flag;
@@ -1366,8 +1229,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(),
@@ -1378,9 +1239,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);
 
@@ -1389,13 +1247,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 2a729c6..6486f09 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -2,8 +2,11 @@
 #include "builtin.h"
 #include "dir.h"
 #include "parse-options.h"
+#include "run-command.h"
+#include "sigchain.h"
 
 static const char * const worktree_usage[] = {
+	N_("git worktree new [<options>] <path> [<checkout-options>] <branch>"),
 	N_("git worktree prune [<options>]"),
 	NULL
 };
@@ -119,6 +122,158 @@ 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 new_worktree(const char *path, int force, const char **av)
+{
+	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. Any valid
+	 * value would do because this value will be ignored and
+	 * replaced at the next (real) checkout.
+	 */
+	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;
+	argv_array_push(&cp.args, "checkout");
+	if (force)
+		argv_array_push(&cp.args, "--ignore-other-worktrees");
+	for (; *av; av++)
+		argv_array_push(&cp.args, *av);
+	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 new(int ac, const char **av, const char *prefix)
+{
+	int force = 0;
+	const char *path;
+	struct option options[] = {
+		OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
+		OPT_END()
+	};
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage,
+			   PARSE_OPT_STOP_AT_NON_OPTION);
+	if (ac < 2)
+		usage_with_options(worktree_usage, options);
+	path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
+	return new_worktree(path, force, av + 1);
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -127,6 +282,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], "new"))
+		return new(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "prune"))
 		return prune(ac - 1, av + 1, prefix);
 	usage_with_options(worktree_usage, options);
diff --git a/t/t2025-checkout-to.sh b/t/t2025-worktree-new.sh
similarity index 56%
rename from t/t2025-checkout-to.sh
rename to t/t2025-worktree-new.sh
index f8e4df4..d43b352 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-worktree-new.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='test git checkout --to'
+test_description='test git worktree new'
 
 . ./test-lib.sh
 
@@ -8,29 +8,29 @@ 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 '"new" not updating paths' '
+	test_must_fail git worktree new -- init.t
 '
 
-test_expect_success 'checkout --to an existing worktree' '
+test_expect_success '"new" an existing worktree' '
 	mkdir -p existing/subtree &&
-	test_must_fail git checkout --detach --to existing master
+	test_must_fail git worktree new existing --detach master
 '
 
-test_expect_success 'checkout --to an existing empty worktree' '
+test_expect_success '"new" an existing empty worktree' '
 	mkdir existing_empty &&
-	git checkout --detach --to existing_empty master
+	git worktree new existing_empty --detach master
 '
 
-test_expect_success 'checkout --to refuses to checkout locked branch' '
-	test_must_fail git checkout --to zere master &&
+test_expect_success '"new" refuses to checkout locked branch' '
+	test_must_fail git worktree new zere master &&
 	! test -d zere &&
 	! test -d .git/worktrees/zere
 '
 
-test_expect_success 'checkout --to a new worktree' '
+test_expect_success '"new" worktree' '
 	git rev-parse HEAD >expect &&
-	git checkout --detach --to here master &&
+	git worktree new here --detach master &&
 	(
 		cd here &&
 		test_cmp ../init.t init.t &&
@@ -41,27 +41,27 @@ test_expect_success 'checkout --to a new worktree' '
 	)
 '
 
-test_expect_success 'checkout --to a new worktree from a subdir' '
+test_expect_success '"new" worktree from a subdir' '
 	(
 		mkdir sub &&
 		cd sub &&
-		git checkout --detach --to here master &&
+		git worktree new here --detach master &&
 		cd here &&
 		test_cmp ../../init.t init.t
 	)
 '
 
-test_expect_success 'checkout --to from a linked checkout' '
+test_expect_success '"new" from a linked checkout' '
 	(
 		cd here &&
-		git checkout --detach --to nested-here master &&
+		git worktree new nested-here --detach 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 '"new" worktree creating new branch' '
+	git worktree new there -b newmaster master &&
 	(
 		cd there &&
 		test_cmp ../init.t init.t &&
@@ -82,7 +82,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 new --force anothernewmaster newmaster
 	)
 '
 
@@ -93,15 +93,15 @@ test_expect_success 'not die on re-checking out current branch' '
 	)
 '
 
-test_expect_success 'checkout --to from a bare repo' '
+test_expect_success '"new" from a bare repo' '
 	(
 		git clone --bare . bare &&
 		cd bare &&
-		git checkout --to ../there2 -b bare-master master
+		git worktree new ../there2 -b bare-master master
 	)
 '
 
-test_expect_success 'checkout from a bare repo without --to' '
+test_expect_success 'checkout from a bare repo without "worktree new"' '
 	(
 		cd bare &&
 		test_must_fail git checkout master
@@ -121,7 +121,7 @@ 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 new grafted --detach master &&
 	git --git-dir=grafted/.git log --format=%s -2 >actual &&
 	test_cmp expected actual
 '
diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh
index e872f02..d50688c 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 new "$PWD/nop" --detach master &&
 	git worktree prune &&
 	test -d .git/worktrees/nop
 '
-- 
2.5.0.rc0.203.gd595659

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30  4:56 [RFC/PATCH] worktree: replace "checkout --to" with "worktree new" Eric Sunshine
@ 2015-06-30  9:23 ` Duy Nguyen
  2015-06-30 16:33   ` Junio C Hamano
  2015-06-30 22:02   ` Eric Sunshine
  2015-06-30 17:13 ` Junio C Hamano
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 27+ messages in thread
From: Duy Nguyen @ 2015-06-30  9:23 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git Mailing List, Junio C Hamano

On Tue, Jun 30, 2015 at 11:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> The command "git checkout --to <path>" is something of an anachronism,
> encompassing functionality somewhere between "checkout" and "clone".
> The introduction of the git-worktree command, however, provides a proper
> and intuitive place to house such functionality. Consequently,
> re-implement "git checkout --to" as "git worktree new".
>
> As a side-effect, linked worktree creation becomes much more
> discoverable with its own dedicated command, whereas `--to` was easily
> overlooked amid the plethora of options recognized by git-checkout.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>
> I've long felt that Duy's linked-worktree functionality was a bit oddly
> named as "git checkout --to", but, since I could never come up with a
> better name, I never made mention of it. However, with Duy's
> introduction of the git-worktree command[1], we now have a much more
> appropriate and discoverable place to house the "git checkout --to"
> functionality, and upon seeing his patch, I was ready to reply with the
> suggestion to relocate "git checkout --to" to "git worktree new",
> however, Junio beat me to it[2].

Didn't know you guys were so eager to move this code around :D Jokes
aside, it's good that it's raised now before --to is set in stone.

I think this is like "git checkout -b" vs "git branch". We pack so
many things in 'checkout' that it's a source of both convenience and
confusion. I never use "git branch" to create a new branch and if I
had a way to tell checkout to "move away and delete previous branch",
I would probably stop using "git branch -d/-D" too. "--to" is another
"-b" in this sense.

"git worktree new" definitely makes sense (maybe stick with verbs like
"create", I'm not sure if we have some convention in existing
commands), but should we remove "git checkout --to"? I could do "git
co -b foo --to bar" for example. Maybe "--to" is not used that often
that "git worktree new" would feel less convenient as a replacement.
If we are not sure about "--to" (I'm not), I think we just remove it
now because we can always add it back later.

> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> index 41103e5..8f13281 100644
> --- a/Documentation/git-worktree.txt
> +++ b/Documentation/git-worktree.txt
> @@ -9,16 +9,85 @@ git-worktree - Manage multiple worktrees
>  SYNOPSIS
>  --------
>  [verse]
> +'git worktree new' [-f] <path> [<checkout-options>] <branch>

Should we follow clone syntax and put the <path> (as destination)
after <branch> ("source")? Maybe not, because in the clone case,
explicit destination is optional, not like this.. Or.. maybe <branch>
could be optional in this case. 'git worktree new' without a branch
will create a new branch, named closely after the destination.
Existing branch can be specified via an option..
-- 
Duy

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30  9:23 ` Duy Nguyen
@ 2015-06-30 16:33   ` Junio C Hamano
  2015-07-01 10:46     ` Duy Nguyen
  2015-06-30 22:02   ` Eric Sunshine
  1 sibling, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2015-06-30 16:33 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Eric Sunshine, Git Mailing List

Duy Nguyen <pclouds@gmail.com> writes:

> I think this is like "git checkout -b" vs "git branch". We pack so
> many things in 'checkout' that it's a source of both convenience and
> confusion. I never use "git branch" to create a new branch and if I
> had a way to tell checkout to "move away and delete previous branch",
> I would probably stop using "git branch -d/-D" too. "--to" is another
> "-b" in this sense.

I didn't know "checkout --to" included "create a worktree elsewhere
and chdir there"; if that "and chdir there" is not something you are
doing, then I do not think "checkout -b" vs "branch" analogy applies.

> "git worktree new" definitely makes sense (maybe stick with verbs like
> "create", I'm not sure if we have some convention in existing
> commands), but should we remove "git checkout --to"?

I'm in favor of removing "--to" before it escapes the lab.

I am ambivalent about "new", but that is only because I know about
the 'new-workdir' in contrib/.  If I pretend to be a naive end user,
I'd think a verb subcommand would be more in line with the rest of
the system than "new".

I however do not think "create" is a good verb.

Wouldn't "git worktree $the-command-in-question" be a management
command that adds a new worktree to the existing collection, like
"remote add", "notes add", etc. do?  Perhaps "git worktree list" and
"git worktree remove $that_one" would be in its future?

That suggests "add" may be a better choice for "worktree".

The only subcommand that I can think of offhand that says "create"
is "bundle"; after generates a new bundle, its presence is not known
to the repository the bundle was created out of, so not using "add"
but calling the operation "create" is fine for "bundle".

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30  4:56 [RFC/PATCH] worktree: replace "checkout --to" with "worktree new" Eric Sunshine
  2015-06-30  9:23 ` Duy Nguyen
@ 2015-06-30 17:13 ` Junio C Hamano
  2015-06-30 22:11 ` Eric Sunshine
  2015-07-01 16:53 ` Junio C Hamano
  3 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2015-06-30 17:13 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Duy Nguyen

Eric Sunshine <sunshine@sunshineco.com> writes:

> * t2025-checkout-to.sh became t2025-worktree-new.sh. I'm not sure if the
>   test number still makes sense or if it should be changed, however, it
>   resides alongside its t2026-prune-linked-checkouts.sh counterpart.

You'd need to adjust t7410 as well, perhaps like so:

diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
index 8f30aed..d037e51 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 new "$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 new "$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' \

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30  9:23 ` Duy Nguyen
  2015-06-30 16:33   ` Junio C Hamano
@ 2015-06-30 22:02   ` Eric Sunshine
  2015-07-01  6:37     ` Eric Sunshine
  1 sibling, 1 reply; 27+ messages in thread
From: Eric Sunshine @ 2015-06-30 22:02 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List, Junio C Hamano

On Tue, Jun 30, 2015 at 5:23 AM, Duy Nguyen <pclouds@gmail.com> wrote:
> On Tue, Jun 30, 2015 at 11:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> The command "git checkout --to <path>" is something of an anachronism,
>> encompassing functionality somewhere between "checkout" and "clone".
>> The introduction of the git-worktree command, however, provides a proper
>> and intuitive place to house such functionality. Consequently,
>> re-implement "git checkout --to" as "git worktree new".
>
> I think this is like "git checkout -b" vs "git branch". We pack so
> many things in 'checkout' that it's a source of both convenience and
> confusion. I never use "git branch" to create a new branch [...]
>  "--to" is another "-b" in this sense.

I too always use "git checkout -b", but, like Junio, I don't think
this is an apt analogy. "git checkout -b" is shorthand for two
commands "git branch" and "git checkout", whereas "git checkout --to"
is not.

> "git worktree new" definitely makes sense (maybe stick with verbs like
> "create", I'm not sure if we have some convention in existing
> commands), but should we remove "git checkout --to"? I could do "git
> co -b foo --to bar" for example.

You can still do that with "git worktree new bar -b foo", which is
effectively the same as "git checkout --to bar -b foo" (with
s/checkout/worktree/ and s/--to/new/ applied), though perhaps you
don't find it as obvious or natural.

> If we are not sure about "--to" (I'm not), I think we just remove it
> now because we can always add it back later.

I'm not excited about keeping "git checkout --to" as an alias for "git
worktree new", however, removing it now should not harm us since, as
you say, it can be added back later if needed.

>>  SYNOPSIS
>>  --------
>> +'git worktree new' [-f] <path> [<checkout-options>] <branch>
>
> Should we follow clone syntax and put the <path> (as destination)
> after <branch> ("source")? Maybe not, because in the clone case,
> explicit destination is optional, not like this.. Or.. maybe <branch>
> could be optional in this case. 'git worktree new' without a branch
> will create a new branch, named closely after the destination.
> Existing branch can be specified via an option..

I'm not wedded to this particular argument order, though it does have
the advantage that it's clear which options belong to "worktree new"
and which to "checkout".

As for making <branch> optional and auto-vivifying a new branch named
after <path>, that's something we can consider later (I think).

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30  4:56 [RFC/PATCH] worktree: replace "checkout --to" with "worktree new" Eric Sunshine
  2015-06-30  9:23 ` Duy Nguyen
  2015-06-30 17:13 ` Junio C Hamano
@ 2015-06-30 22:11 ` Eric Sunshine
  2015-06-30 22:27   ` Junio C Hamano
  2015-06-30 22:32   ` Mark Levedahl
  2015-07-01 16:53 ` Junio C Hamano
  3 siblings, 2 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-06-30 22:11 UTC (permalink / raw)
  To: Git List; +Cc: Duy Nguyen, Junio C Hamano, Eric Sunshine

On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> The command "git checkout --to <path>" is something of an anachronism,
> encompassing functionality somewhere between "checkout" and "clone".
> The introduction of the git-worktree command, however, provides a proper
> and intuitive place to house such functionality. Consequently,
> re-implement "git checkout --to" as "git worktree new".
> [...]
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
> This is primarily a code and documentation relocation patch, with minor
> new code added to builtin/worktree.c. Specifically:
>
> * builtin/worktree.c:new() is new. It recognizes a --force option ("git
>   worktree new --force <path> <branch>") which allows a branch to be
>   checked out in a new worktree even if already checked out in some
>   other worktree (thus, mirroring the functionality of "git checkout
>   --ignore-other-worktrees").

Speaking of "git worktree new --force", should we revisit "git
checkout --ignore-other-worktrees" before it gets set in stone? In
particular, I'm wondering if it makes sense to overload git-checkout's
existing --force option to encompass the functionality of
--ignore-other-worktrees as well. I don't think there would be any
semantic conflict by overloading --force, and I do think that --force
is more discoverable and more intuitive.

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30 22:11 ` Eric Sunshine
@ 2015-06-30 22:27   ` Junio C Hamano
  2015-07-01  4:48     ` Mikael Magnusson
  2015-06-30 22:32   ` Mark Levedahl
  1 sibling, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2015-06-30 22:27 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Duy Nguyen

Eric Sunshine <sunshine@sunshineco.com> writes:

> On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote
> Speaking of "git worktree new --force", should we revisit "git
> checkout --ignore-other-worktrees" before it gets set in stone? In
> particular, I'm wondering if it makes sense to overload git-checkout's
> existing --force option to encompass the functionality of
> --ignore-other-worktrees as well. I don't think there would be any
> semantic conflict by overloading --force, and I do think that --force
> is more discoverable and more intuitive.

"git checkout -f" is to throw-away local changes, which is a very
sensible thing to do and I can see why that would be useful, but
does --ignore-other-worktrees have the same kind of common-ness?

It primarily is a safety measure, and if the user wants to jump
around freely to different commits in multiple worktrees, a more
sensible thing to do so without getting the "nono, you have that
branch checked out elsewhere" is to detach HEADs in the non-primary
worktrees that may want to have the same commit checked out as the
current branch of the primary worktree.

I would mildly object to make --ignore-other-worktrees more
discoverable and moderately object to make that feature more
accessible by overloading it into "--force".  I personally would not
mind if we removed "--ignore-other-worktrees", but that might be
going too far ;-)

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30 22:11 ` Eric Sunshine
  2015-06-30 22:27   ` Junio C Hamano
@ 2015-06-30 22:32   ` Mark Levedahl
  1 sibling, 0 replies; 27+ messages in thread
From: Mark Levedahl @ 2015-06-30 22:32 UTC (permalink / raw)
  To: Eric Sunshine, Git List; +Cc: Duy Nguyen, Junio C Hamano

On 06/30/2015 06:11 PM, Eric Sunshine wrote:
> On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> The command "git checkout --to <path>" is something of an anachronism,
>> encompassing functionality somewhere between "checkout" and "clone".
>> The introduction of the git-worktree command, however, provides a proper
>> and intuitive place to house such functionality. Consequently,
>> re-implement "git checkout --to" as "git worktree new".
>> [...]
>> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
>> ---
>> This is primarily a code and documentation relocation patch, with minor
>> new code added to builtin/worktree.c. Specifically:
>>
>> * builtin/worktree.c:new() is new. It recognizes a --force option ("git
>>    worktree new --force <path> <branch>") which allows a branch to be
>>    checked out in a new worktree even if already checked out in some
>>    other worktree (thus, mirroring the functionality of "git checkout
>>    --ignore-other-worktrees").
>
> Speaking of "git worktree new --force", should we revisit "git
> checkout --ignore-other-worktrees" before it gets set in stone? In
> particular, I'm wondering if it makes sense to overload git-checkout's
> existing --force option to encompass the functionality of
> --ignore-other-worktrees as well. I don't think there would be any
> semantic conflict by overloading --force, and I do think that --force
> is more discoverable and more intuitive.
>

I agree with -f subsuming --ignore...:  -f/--force should really mean 
"do this if at all possible", not just "ignore some checks". Similar to 
rm -f, etc.

Maintaining --ignore-other-worktrees, and making that a configurable 
option (worktree.ignoreothers??) would allow selectively ignoring just 
this one issue, perhaps permanently, but not the others -f already 
overrides. This would make sense if other options were added to ignore 
other subsets of checks that can block a checkout, probably not otherwise.


Mark

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30 22:27   ` Junio C Hamano
@ 2015-07-01  4:48     ` Mikael Magnusson
  0 siblings, 0 replies; 27+ messages in thread
From: Mikael Magnusson @ 2015-07-01  4:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Eric Sunshine, Git List, Duy Nguyen

On Wed, Jul 1, 2015 at 12:27 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
>
>> On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote
>> Speaking of "git worktree new --force", should we revisit "git
>> checkout --ignore-other-worktrees" before it gets set in stone? In
>> particular, I'm wondering if it makes sense to overload git-checkout's
>> existing --force option to encompass the functionality of
>> --ignore-other-worktrees as well. I don't think there would be any
>> semantic conflict by overloading --force, and I do think that --force
>> is more discoverable and more intuitive.
>
> "git checkout -f" is to throw-away local changes, which is a very
> sensible thing to do and I can see why that would be useful, but
> does --ignore-other-worktrees have the same kind of common-ness?
>
> It primarily is a safety measure, and if the user wants to jump
> around freely to different commits in multiple worktrees, a more
> sensible thing to do so without getting the "nono, you have that
> branch checked out elsewhere" is to detach HEADs in the non-primary
> worktrees that may want to have the same commit checked out as the
> current branch of the primary worktree.
>
> I would mildly object to make --ignore-other-worktrees more
> discoverable and moderately object to make that feature more
> accessible by overloading it into "--force".  I personally would not
> mind if we removed "--ignore-other-worktrees", but that might be
> going too far ;-)

This probably falls under "not common", but one of my uses for git
new-workdir is to check out the current branch in another directory,
rebase it to upstream, delete that worktree, and then git reset --hard
in the original checkout. The result is a rebased branch that touches
a minimum of source files so the rebuild is faster. (In some projects
I have a lot of local commits that get rebased, but maybe upstream
only touched a single .c file).

-- 
Mikael Magnusson

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30 22:02   ` Eric Sunshine
@ 2015-07-01  6:37     ` Eric Sunshine
  0 siblings, 0 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-07-01  6:37 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List, Junio C Hamano

On Tue, Jun 30, 2015 at 6:02 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Tue, Jun 30, 2015 at 5:23 AM, Duy Nguyen <pclouds@gmail.com> wrote:
>> On Tue, Jun 30, 2015 at 11:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>>> The command "git checkout --to <path>" is something of an anachronism,
>>> encompassing functionality somewhere between "checkout" and "clone".
>>> The introduction of the git-worktree command, however, provides a proper
>>> and intuitive place to house such functionality. Consequently,
>>> re-implement "git checkout --to" as "git worktree new".
>>
>> "git worktree new" definitely makes sense (maybe stick with verbs like
>> "create", I'm not sure if we have some convention in existing
>> commands), but should we remove "git checkout --to"? I could do "git
>> co -b foo --to bar" for example.
>
> You can still do that with "git worktree new bar -b foo", which is
> effectively the same as "git checkout --to bar -b foo" (with
> s/checkout/worktree/ and s/--to/new/ applied), though perhaps you
> don't find it as obvious or natural.

I had never understood why you chose to plug the linked-worktree
functionality into git-checkout via --to, but this usage pattern
(creating a new branch and checking it out into a new worktree as one
operation) goes a long way toward explaining why you consider
git-checkout a proper home for linked-worktree creation. I don't think
that justification was ever mentioned when the series was being
presented (or, if it was, I must have missed it). Now it makes much
more sense, and I can better appreciate your desire to keep "git
checkout --to" as an alias for "git worktree add". Thanks for
explaining it.

(Having said that, replacing "git checkout --to" with "git worktree
add" still seems a preferable first step, while keeping open the door
to re-add "git checkout --to" later if we become convinced that it's
worthwhile.)

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30 16:33   ` Junio C Hamano
@ 2015-07-01 10:46     ` Duy Nguyen
  0 siblings, 0 replies; 27+ messages in thread
From: Duy Nguyen @ 2015-07-01 10:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Eric Sunshine, Git Mailing List

On Tue, Jun 30, 2015 at 11:33 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Duy Nguyen <pclouds@gmail.com> writes:
>
>> I think this is like "git checkout -b" vs "git branch". We pack so
>> many things in 'checkout' that it's a source of both convenience and
>> confusion. I never use "git branch" to create a new branch and if I
>> had a way to tell checkout to "move away and delete previous branch",
>> I would probably stop using "git branch -d/-D" too. "--to" is another
>> "-b" in this sense.
>
> I didn't know "checkout --to" included "create a worktree elsewhere
> and chdir there"; if that "and chdir there" is not something you are
> doing, then I do not think "checkout -b" vs "branch" analogy applies.

Heh.. I do want that "chdir" (even for git-init and git-clone). We
can't issue "cd" command back to the parent shell, but we can spawn a
new shell with new cwd. But because the target dir is usually at the
end of the command line (except for "--to") and "cd !$" is not much to
type, it never bothers me enough to do something more. I think this is
another reason I prefer "git worktree add" to have the target dir at
the end.
-- 
Duy

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-06-30  4:56 [RFC/PATCH] worktree: replace "checkout --to" with "worktree new" Eric Sunshine
                   ` (2 preceding siblings ...)
  2015-06-30 22:11 ` Eric Sunshine
@ 2015-07-01 16:53 ` Junio C Hamano
  2015-07-01 17:13   ` Eric Sunshine
  3 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2015-07-01 16:53 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Duy Nguyen

From: Eric Sunshine <sunshine@sunshineco.com>

The command "git checkout --to <path>" is something of an anachronism,
encompassing functionality somewhere between "checkout" and "clone".
The introduction of the git-worktree command, however, provides a proper
and intuitive place to house such functionality. Consequently,
re-implement "git checkout --to" as "git worktree add".

As a side-effect, linked worktree creation becomes much more
discoverable with its own dedicated command, whereas `--to` was easily
overlooked amid the plethora of options recognized by git-checkout.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

 * Duy seems to think "worktree add" is coming, too, so here is a
   trivial tweak of your patch from the last month, with test
   adjustments to 7410 I sent earlier squashed in.

   I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does
   not seem to be documented.  Is this something we still need?

   The log message of 529fef20 (checkout: support checking out into
   a new working directory, 2014-11-30) does not tell us much.

 Documentation/git-checkout.txt    |  72 -----------------
 Documentation/git-worktree.txt    |  79 ++++++++++++++++++-
 builtin/checkout.c                | 152 +-----------------------------------
 builtin/worktree.c                | 157 ++++++++++++++++++++++++++++++++++++++
 t/t2025-checkout-to.sh            | 137 ---------------------------------
 t/t2025-worktree-add.sh           | 137 +++++++++++++++++++++++++++++++++
 t/t2026-prune-linked-checkouts.sh |   2 +-
 t/t7410-submodule-checkout-to.sh  |   4 +-
 8 files changed, 377 insertions(+), 363 deletions(-)
 delete mode 100755 t/t2025-checkout-to.sh
 create mode 100755 t/t2025-worktree-add.sh

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 72def5b..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... See "MULTIPLE WORKING
-	TREES" section for more information.
-
 --ignore-other-worktrees::
 	`git checkout` refuses when the wanted ref is already checked
 	out by another worktree. This option makes it check the ref
@@ -401,71 +394,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 prune --worktrees` 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 41103e5..94dce6d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,16 +9,85 @@ git-worktree - Manage multiple worktrees
 SYNOPSIS
 --------
 [verse]
+'git worktree add' [-f] <path> [<checkout-options>] <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 worktree add` a new working
+tree is created and gets 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 worktree add /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 prune --worktrees` 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
 --------
+add::
+
+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.
+
 prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
@@ -26,6 +95,12 @@ Prune working tree information in $GIT_DIR/worktrees.
 OPTIONS
 -------
 
+-f::
+--force::
+	By default, `git worktree add` refuses to create a new worktree when
+	<branch> is already checked out by another worktree. This option
+	overrides that safeguard.
+
 -n::
 --dry-run::
 	Do not remove anything; just report what it would
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2079aa4..439c061 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -51,8 +51,6 @@ struct checkout_opts {
 	struct pathspec pathspec;
 	struct tree *source_tree;
 
-	const char *new_worktree;
-	const char **saved_argv;
 	int new_worktree_mode;
 };
 
@@ -255,8 +253,8 @@ 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->new_worktree_mode)
+		die(_("'%s' cannot be used with updating paths"), "git worktree add");
 
 	if (opts->patch_mode)
 		return run_add_interactive(revision, "--patch=checkout",
@@ -825,138 +823,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 struct checkout_opts *opts,
-				   struct branch_info *new)
-{
-	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
-	struct strbuf sb = STRBUF_INIT;
-	const char *path = opts->new_worktree, *name;
-	struct stat st;
-	struct child_process cp;
-	int counter = 0, len, ret;
-
-	if (!new->commit)
-		die(_("no branch specified"));
-	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. Any valid
-	 * value would do because this value will be ignored and
-	 * replaced at the next (real) checkout.
-	 */
-	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));
-	strbuf_reset(&sb);
-	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);
-
-	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 = opts->saved_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")) {
@@ -1295,9 +1161,6 @@ static int checkout_branch(struct checkout_opts *opts,
 		free(head_ref);
 	}
 
-	if (opts->new_worktree)
-		return prepare_linked_checkout(opts, new);
-
 	if (!new->commit && opts->new_branch) {
 		unsigned char rev[20];
 		int flag;
@@ -1340,8 +1203,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(),
@@ -1352,9 +1213,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);
 
@@ -1363,13 +1221,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 2a729c6..0983003 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -2,8 +2,11 @@
 #include "builtin.h"
 #include "dir.h"
 #include "parse-options.h"
+#include "run-command.h"
+#include "sigchain.h"
 
 static const char * const worktree_usage[] = {
+	N_("git worktree add [<options>] <path> [<checkout-options>] <branch>"),
 	N_("git worktree prune [<options>]"),
 	NULL
 };
@@ -119,6 +122,158 @@ 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, int force, const char **av)
+{
+	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. Any valid
+	 * value would do because this value will be ignored and
+	 * replaced at the next (real) checkout.
+	 */
+	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;
+	argv_array_push(&cp.args, "checkout");
+	if (force)
+		argv_array_push(&cp.args, "--ignore-other-worktrees");
+	for (; *av; av++)
+		argv_array_push(&cp.args, *av);
+	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)
+{
+	int force = 0;
+	const char *path;
+	struct option options[] = {
+		OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
+		OPT_END()
+	};
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage,
+			   PARSE_OPT_STOP_AT_NON_OPTION);
+	if (ac < 2)
+		usage_with_options(worktree_usage, options);
+	path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
+	return add_worktree(path, force, av + 1);
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -127,6 +282,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);
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
deleted file mode 100755
index a8d9336..0000000
--- a/t/t2025-checkout-to.sh
+++ /dev/null
@@ -1,137 +0,0 @@
-#!/bin/sh
-
-test_description='test git checkout --to'
-
-. ./test-lib.sh
-
-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' '
-	mkdir -p existing/subtree &&
-	test_must_fail git checkout --detach --to existing master
-'
-
-test_expect_success 'checkout --to an existing empty worktree' '
-	mkdir existing_empty &&
-	git checkout --detach --to existing_empty master
-'
-
-test_expect_success 'checkout --to refuses to checkout locked branch' '
-	test_must_fail git checkout --to zere master &&
-	! test -d zere &&
-	! test -d .git/worktrees/zere
-'
-
-test_expect_success 'checking out paths not complaining about linked checkouts' '
-	(
-	cd existing_empty &&
-	echo dirty >>init.t &&
-	git checkout master -- init.t
-	)
-'
-
-test_expect_success 'checkout --to a new worktree' '
-	git rev-parse HEAD >expect &&
-	git checkout --detach --to here master &&
-	(
-		cd here &&
-		test_cmp ../init.t init.t &&
-		test_must_fail git symbolic-ref HEAD &&
-		git rev-parse HEAD >actual &&
-		test_cmp ../expect actual &&
-		git fsck
-	)
-'
-
-test_expect_success 'checkout --to a new worktree from a subdir' '
-	(
-		mkdir sub &&
-		cd sub &&
-		git checkout --detach --to here master &&
-		cd here &&
-		test_cmp ../../init.t init.t
-	)
-'
-
-test_expect_success 'checkout --to from a linked checkout' '
-	(
-		cd here &&
-		git checkout --detach --to 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 &&
-	(
-		cd there &&
-		test_cmp ../init.t init.t &&
-		git symbolic-ref HEAD >actual &&
-		echo refs/heads/newmaster >expect &&
-		test_cmp expect actual &&
-		git fsck
-	)
-'
-
-test_expect_success 'die the same branch is already checked out' '
-	(
-		cd here &&
-		test_must_fail git checkout newmaster
-	)
-'
-
-test_expect_success 'not die the same branch is already checked out' '
-	(
-		cd here &&
-		git checkout --ignore-other-worktrees --to anothernewmaster newmaster
-	)
-'
-
-test_expect_success 'not die on re-checking out current branch' '
-	(
-		cd there &&
-		git checkout newmaster
-	)
-'
-
-test_expect_success 'checkout --to from a bare repo' '
-	(
-		git clone --bare . bare &&
-		cd bare &&
-		git checkout --to ../there2 -b bare-master master
-	)
-'
-
-test_expect_success 'checkout from a bare repo without --to' '
-	(
-		cd bare &&
-		test_must_fail git checkout master
-	)
-'
-
-test_expect_success 'checkout with grafts' '
-	test_when_finished rm .git/info/grafts &&
-	test_commit abc &&
-	SHA1=`git rev-parse HEAD` &&
-	test_commit def &&
-	test_commit xyz &&
-	echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts &&
-	cat >expected <<-\EOF &&
-	xyz
-	abc
-	EOF
-	git log --format=%s -2 >actual &&
-	test_cmp expected actual &&
-	git checkout --detach --to grafted master &&
-	git --git-dir=grafted/.git log --format=%s -2 >actual &&
-	test_cmp expected actual
-'
-
-test_done
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
new file mode 100755
index 0000000..a757988
--- /dev/null
+++ b/t/t2025-worktree-add.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+
+test_description='test git worktree add'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit init
+'
+
+test_expect_success '"add" not updating paths' '
+	test_must_fail git worktree add -- init.t
+'
+
+test_expect_success '"add" an existing worktree' '
+	mkdir -p existing/subtree &&
+	test_must_fail git worktree add existing --detach master
+'
+
+test_expect_success '"add" an existing empty worktree' '
+	mkdir existing_empty &&
+	git worktree add existing_empty --detach 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
+'
+
+test_expect_success 'checking out paths not complaining about linked checkouts' '
+	(
+	cd existing_empty &&
+	echo dirty >>init.t &&
+	git checkout master -- init.t
+	)
+'
+
+test_expect_success '"add" worktree' '
+	git rev-parse HEAD >expect &&
+	git worktree add here --detach master &&
+	(
+		cd here &&
+		test_cmp ../init.t init.t &&
+		test_must_fail git symbolic-ref HEAD &&
+		git rev-parse HEAD >actual &&
+		test_cmp ../expect actual &&
+		git fsck
+	)
+'
+
+test_expect_success '"add" worktree from a subdir' '
+	(
+		mkdir sub &&
+		cd sub &&
+		git worktree add here --detach master &&
+		cd here &&
+		test_cmp ../../init.t init.t
+	)
+'
+
+test_expect_success '"add" from a linked checkout' '
+	(
+		cd here &&
+		git worktree add nested-here --detach master &&
+		cd nested-here &&
+		git fsck
+	)
+'
+
+test_expect_success '"add" worktree creating new branch' '
+	git worktree add there -b newmaster master &&
+	(
+		cd there &&
+		test_cmp ../init.t init.t &&
+		git symbolic-ref HEAD >actual &&
+		echo refs/heads/newmaster >expect &&
+		test_cmp expect actual &&
+		git fsck
+	)
+'
+
+test_expect_success 'die the same branch is already checked out' '
+	(
+		cd here &&
+		test_must_fail git checkout newmaster
+	)
+'
+
+test_expect_success 'not die the same branch is already checked out' '
+	(
+		cd here &&
+		git worktree add --force anothernewmaster newmaster
+	)
+'
+
+test_expect_success 'not die on re-checking out current branch' '
+	(
+		cd there &&
+		git checkout newmaster
+	)
+'
+
+test_expect_success '"add" from a bare repo' '
+	(
+		git clone --bare . bare &&
+		cd bare &&
+		git worktree add ../there2 -b bare-master master
+	)
+'
+
+test_expect_success 'checkout from a bare repo without "worktree add"' '
+	(
+		cd bare &&
+		test_must_fail git checkout master
+	)
+'
+
+test_expect_success 'checkout with grafts' '
+	test_when_finished rm .git/info/grafts &&
+	test_commit abc &&
+	SHA1=`git rev-parse HEAD` &&
+	test_commit def &&
+	test_commit xyz &&
+	echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts &&
+	cat >expected <<-\EOF &&
+	xyz
+	abc
+	EOF
+	git log --format=%s -2 >actual &&
+	test_cmp expected actual &&
+	git worktree add grafted --detach master &&
+	git --git-dir=grafted/.git log --format=%s -2 >actual &&
+	test_cmp expected actual
+'
+
+test_done
diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh
index e872f02..c74c935 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 "$PWD/nop" --detach 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-rc0-209-g5e1f148

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-01 16:53 ` Junio C Hamano
@ 2015-07-01 17:13   ` Eric Sunshine
  2015-07-01 17:16     ` Eric Sunshine
                       ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-07-01 17:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen

On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:
> From: Eric Sunshine <sunshine@sunshineco.com>
>
> The command "git checkout --to <path>" is something of an anachronism,
> encompassing functionality somewhere between "checkout" and "clone".
> The introduction of the git-worktree command, however, provides a proper
> and intuitive place to house such functionality. Consequently,
> re-implement "git checkout --to" as "git worktree add".
>
> As a side-effect, linked worktree creation becomes much more
> discoverable with its own dedicated command, whereas `--to` was easily
> overlooked amid the plethora of options recognized by git-checkout.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
>  * Duy seems to think "worktree add" is coming, too, so here is a
>    trivial tweak of your patch from the last month, with test
>    adjustments to 7410 I sent earlier squashed in.

Thanks. I was planning on re-rolling to use the new name ("add" rather
than "new") and to squash in the t7410 fix. Plus, I think the changes
I had to make to prepare_linked_checkout() in order to move it to
worktree.c should become separate preparatory patches so that the
actual relocation can become pure code movement (as much as possible).

Also, I was planning on including Duy's patch in the re-roll since it
missed a s/prune --worktrees/worktree prune/ in
Documentation/git-checkout.txt.

>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does
>    not seem to be documented.  Is this something we still need?
>    The log message of 529fef20 (checkout: support checking out into
>    a new working directory, 2014-11-30) does not tell us much.

Yes, it's still used for the same purpose as before the conversion: as
a private signal to the sub git-checkout invocation that it's
operating on a new worktree. When defined, it sets the
'new_worktree_mode' flag in checkout.c, and there are still a few bits
of code which apparently need to know about it. It would be nice to
eliminate this special knowledge from checkout.c, however, I'm not yet
familiar enough with the checkout code to determine if doing so is
viable.

For the re-roll, I was planning on renaming it to
GIT_NEW_WORKTREE_MODE or something (or add a private command-line
option to checkout, but that may be overkill).

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-01 17:13   ` Eric Sunshine
@ 2015-07-01 17:16     ` Eric Sunshine
  2015-07-01 17:32     ` Junio C Hamano
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-07-01 17:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen

On Wed, Jul 1, 2015 at 1:13 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> From: Eric Sunshine <sunshine@sunshineco.com>
>>
>> The command "git checkout --to <path>" is something of an anachronism,
>> encompassing functionality somewhere between "checkout" and "clone".
>> The introduction of the git-worktree command, however, provides a proper
>> and intuitive place to house such functionality. Consequently,
>> re-implement "git checkout --to" as "git worktree add".
>> ---
>>
>>  * Duy seems to think "worktree add" is coming, too, so here is a
>>    trivial tweak of your patch from the last month, with test
>>    adjustments to 7410 I sent earlier squashed in.
>
> Thanks. I was planning on re-rolling...

I forgot to mention that the subject needs a slight update: "worktree
add" rather than "worktree new".

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-01 17:13   ` Eric Sunshine
  2015-07-01 17:16     ` Eric Sunshine
@ 2015-07-01 17:32     ` Junio C Hamano
  2015-07-01 18:18     ` Eric Sunshine
  2015-07-02  1:07     ` Duy Nguyen
  3 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2015-07-01 17:32 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Duy Nguyen

Eric Sunshine <sunshine@sunshineco.com> writes:

> Thanks. I was planning on re-rolling to use the new name ...
> ...
> For the re-roll, I was planning on renaming it to
> GIT_NEW_WORKTREE_MODE or something (or add a private command-line
> option to checkout, but that may be overkill).

OK, thanks, then I'll stop worrying about this and instead will wait
an update from you ;-)

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-01 17:13   ` Eric Sunshine
  2015-07-01 17:16     ` Eric Sunshine
  2015-07-01 17:32     ` Junio C Hamano
@ 2015-07-01 18:18     ` Eric Sunshine
  2015-07-01 18:52       ` Junio C Hamano
  2015-07-02  1:07     ` Duy Nguyen
  3 siblings, 1 reply; 27+ messages in thread
From: Eric Sunshine @ 2015-07-01 18:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Duy Nguyen

On Wed, Jul 1, 2015 at 1:13 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>  * Duy seems to think "worktree add" is coming, too, so here is a
>>    trivial tweak of your patch from the last month, with test
>>    adjustments to 7410 I sent earlier squashed in.
>
> Thanks. I was planning on re-rolling to use the new name ("add" rather
> than "new") and to squash in the t7410 fix. Plus, I think the changes
> I had to make to prepare_linked_checkout() in order to move it to
> worktree.c should become separate preparatory patches so that the
> actual relocation can become pure code movement (as much as possible).
>
> Also, I was planning on including Duy's patch in the re-roll since it
> missed a s/prune --worktrees/worktree prune/ in
> Documentation/git-checkout.txt.

Hmm, I see that Duy's patch is already in 'next'. Would it be better
if I fixed the 's/prune --worktrees/worktree prune/' git-checkout.txt
oversight via an incremental patch rather than including a corrected
version of his patch with my re-roll?

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-01 18:18     ` Eric Sunshine
@ 2015-07-01 18:52       ` Junio C Hamano
  0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2015-07-01 18:52 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Duy Nguyen

Eric Sunshine <sunshine@sunshineco.com> writes:

> On Wed, Jul 1, 2015 at 1:13 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>>  * Duy seems to think "worktree add" is coming, too, so here is a
>>>    trivial tweak of your patch from the last month, with test
>>>    adjustments to 7410 I sent earlier squashed in.
>>
>> Thanks. I was planning on re-rolling to use the new name ("add" rather
>> than "new") and to squash in the t7410 fix. Plus, I think the changes
>> I had to make to prepare_linked_checkout() in order to move it to
>> worktree.c should become separate preparatory patches so that the
>> actual relocation can become pure code movement (as much as possible).
>>
>> Also, I was planning on including Duy's patch in the re-roll since it
>> missed a s/prune --worktrees/worktree prune/ in
>> Documentation/git-checkout.txt.
>
> Hmm, I see that Duy's patch is already in 'next'. Would it be better
> if I fixed the 's/prune --worktrees/worktree prune/' git-checkout.txt
> oversight via an incremental patch rather than including a corrected
> version of his patch with my re-roll?

I may have mistaken what you said; I thought you were planning an
incremental for the existing part, with a more complete reroll of
"worktree add" than what I sent today, as separate patches.

Thanks.

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-01 17:13   ` Eric Sunshine
                       ` (2 preceding siblings ...)
  2015-07-01 18:18     ` Eric Sunshine
@ 2015-07-02  1:07     ` Duy Nguyen
  2015-07-02  2:52       ` Eric Sunshine
  3 siblings, 1 reply; 27+ messages in thread
From: Duy Nguyen @ 2015-07-02  1:07 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 12:13 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does
>>    not seem to be documented.  Is this something we still need?
>>    The log message of 529fef20 (checkout: support checking out into
>>    a new working directory, 2014-11-30) does not tell us much.
>
> Yes, it's still used for the same purpose as before the conversion: as
> a private signal to the sub git-checkout invocation that it's
> operating on a new worktree. When defined, it sets the
> 'new_worktree_mode' flag in checkout.c, and there are still a few bits
> of code which apparently need to know about it. It would be nice to
> eliminate this special knowledge from checkout.c, however, I'm not yet
> familiar enough with the checkout code to determine if doing so is
> viable.

I think it can go away. When "--to" is used, I have to re-execute "git
checkout" command again after creating the new worktree. I could
process the command line arguments from the first execution, delete
"--to", then use the remaining options to run checkout the second
time. But I chose to pass the entire command line to the second
execution. The env is used to let the second run know it should ignore
"--to" (or we get infinite recursion). With "git worktree add" this
recursion disappears and this env var has no reason to exist.
-- 
Duy

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02  1:07     ` Duy Nguyen
@ 2015-07-02  2:52       ` Eric Sunshine
  2015-07-02 12:41         ` Duy Nguyen
  2015-07-02 18:45         ` Eric Sunshine
  0 siblings, 2 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-07-02  2:52 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Junio C Hamano, Git List

On Wed, Jul 1, 2015 at 9:07 PM, Duy Nguyen <pclouds@gmail.com> wrote:
> On Thu, Jul 2, 2015 at 12:13 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>>>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does
>>>    not seem to be documented.  Is this something we still need?
>>>    The log message of 529fef20 (checkout: support checking out into
>>>    a new working directory, 2014-11-30) does not tell us much.
>>
>> Yes, it's still used for the same purpose as before the conversion: as
>> a private signal to the sub git-checkout invocation that it's
>> operating on a new worktree. When defined, it sets the
>> 'new_worktree_mode' flag in checkout.c, and there are still a few bits
>> of code which apparently need to know about it. It would be nice to
>> eliminate this special knowledge from checkout.c, however, I'm not yet
>> familiar enough with the checkout code to determine if doing so is
>> viable.
>
> I think it can go away. When "--to" is used, I have to re-execute "git
> checkout" command again after creating the new worktree. I could
> process the command line arguments from the first execution, delete
> "--to", then use the remaining options to run checkout the second
> time. But I chose to pass the entire command line to the second
> execution. The env is used to let the second run know it should ignore
> "--to" (or we get infinite recursion). With "git worktree add" this
> recursion disappears and this env var has no reason to exist.

The recursion protection is indeed no longer needed and gets removed
by the "worktree add" patch. However, there are still a few bits of
code which want to know that the checkout is happening in a new
worktree. I haven't examined them closely yet to diagnose if this
specialized knowledge can be eliminated. Perhaps you can weight in. In
particular:

checkout_paths:
    if (opts->new_worktree)
        die(_("'%s' cannot be used with updating paths"), "--to");

merge_working_tree:
    tree = parse_tree_indirect(old->commit &&
        !opts->new_worktree_mode ?
            old->commit->object.sha1 :
            EMPTY_TREE_SHA1_BIN);

switch_branches:
    if (!opts->quiet && !old.path && old.commit &&
        new->commit != old.commit && !opts->new_worktree_mode)
            orphaned_commit_warning(old.commit, new->commit);

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02  2:52       ` Eric Sunshine
@ 2015-07-02 12:41         ` Duy Nguyen
  2015-07-02 12:50           ` Duy Nguyen
  2015-07-02 16:59           ` Eric Sunshine
  2015-07-02 18:45         ` Eric Sunshine
  1 sibling, 2 replies; 27+ messages in thread
From: Duy Nguyen @ 2015-07-02 12:41 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 9:52 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Wed, Jul 1, 2015 at 9:07 PM, Duy Nguyen <pclouds@gmail.com> wrote:
>> On Thu, Jul 2, 2015 at 12:13 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>>>>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does
>>>>    not seem to be documented.  Is this something we still need?
>>>>    The log message of 529fef20 (checkout: support checking out into
>>>>    a new working directory, 2014-11-30) does not tell us much.
>>>
>>> Yes, it's still used for the same purpose as before the conversion: as
>>> a private signal to the sub git-checkout invocation that it's
>>> operating on a new worktree. When defined, it sets the
>>> 'new_worktree_mode' flag in checkout.c, and there are still a few bits
>>> of code which apparently need to know about it. It would be nice to
>>> eliminate this special knowledge from checkout.c, however, I'm not yet
>>> familiar enough with the checkout code to determine if doing so is
>>> viable.
>>
>> I think it can go away. When "--to" is used, I have to re-execute "git
>> checkout" command again after creating the new worktree. I could
>> process the command line arguments from the first execution, delete
>> "--to", then use the remaining options to run checkout the second
>> time. But I chose to pass the entire command line to the second
>> execution. The env is used to let the second run know it should ignore
>> "--to" (or we get infinite recursion). With "git worktree add" this
>> recursion disappears and this env var has no reason to exist.
>
> The recursion protection is indeed no longer needed and gets removed
> by the "worktree add" patch. However, there are still a few bits of
> code which want to know that the checkout is happening in a new
> worktree. I haven't examined them closely yet to diagnose if this
> specialized knowledge can be eliminated. Perhaps you can weight in. In
> particular:
>
> checkout_paths:
>     if (opts->new_worktree)
>         die(_("'%s' cannot be used with updating paths"), "--to");

This one is easy, as "--to" is gone, no reason to report anything about "--to"

> merge_working_tree:
>     tree = parse_tree_indirect(old->commit &&
>         !opts->new_worktree_mode ?
>             old->commit->object.sha1 :
>             EMPTY_TREE_SHA1_BIN);

I think it's to make sure empty sha-1 is used with --to. If
old->commit->object.sha1 is used and it's something, a real two way
merge may happen probably with not-so-fun consequences. If it's empty
sha1, the effect is like "reset --hard", silent and reliable..

> switch_branches:
>     if (!opts->quiet && !old.path && old.commit &&
>         new->commit != old.commit && !opts->new_worktree_mode)
>             orphaned_commit_warning(old.commit, new->commit);

to suppress misleading warning if old.commit happens to be something.
-- 
Duy

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02 12:41         ` Duy Nguyen
@ 2015-07-02 12:50           ` Duy Nguyen
  2015-07-02 17:06             ` Eric Sunshine
  2015-07-02 16:59           ` Eric Sunshine
  1 sibling, 1 reply; 27+ messages in thread
From: Duy Nguyen @ 2015-07-02 12:50 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 7:41 PM, Duy Nguyen <pclouds@gmail.com> wrote:
>> merge_working_tree:
>>     tree = parse_tree_indirect(old->commit &&
>>         !opts->new_worktree_mode ?
>>             old->commit->object.sha1 :
>>             EMPTY_TREE_SHA1_BIN);
>
> I think it's to make sure empty sha-1 is used with --to. If
> old->commit->object.sha1 is used and it's something, a real two way
> merge may happen probably with not-so-fun consequences. If it's empty
> sha1, the effect is like "reset --hard", silent and reliable..
>
>> switch_branches:
>>     if (!opts->quiet && !old.path && old.commit &&
>>         new->commit != old.commit && !opts->new_worktree_mode)
>>             orphaned_commit_warning(old.commit, new->commit);
>
> to suppress misleading warning if old.commit happens to be something.

Actually you may be right about not reverting these. We prepare the
new worktree with a valid HEAD, that would make "old" valid and may
trigger things if "git checkout" is used to populate the worktree. To
suppress those "things", we need new_worktree_mode or something
similar.

Unless we want to borrow fancy checkout options for "git worktree
add", we probably should just export checkout() function from clone.c
and use it instead of "git checkout". Much more lightweight and
simpler (it's one-way merge). Then we can revert checkout.c to the
version before "--to".
-- 
Duy

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02 12:41         ` Duy Nguyen
  2015-07-02 12:50           ` Duy Nguyen
@ 2015-07-02 16:59           ` Eric Sunshine
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-07-02 16:59 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 8:41 AM, Duy Nguyen <pclouds@gmail.com> wrote:
> On Thu, Jul 2, 2015 at 9:52 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> The recursion protection is indeed no longer needed and gets removed
>> by the "worktree add" patch. However, there are still a few bits of
>> code which want to know that the checkout is happening in a new
>> worktree. I haven't examined them closely yet to diagnose if this
>> specialized knowledge can be eliminated. Perhaps you can weight in. In
>> particular:
>>
>> checkout_paths:
>>     if (opts->new_worktree)
>>         die(_("'%s' cannot be used with updating paths"), "--to");
>
> This one is easy, as "--to" is gone, no reason to report anything about "--to"

In the "worktree add" patch, I kept this one (with s/--to/worktree
add/) assuming that your intention was that a new worktree should
never start with a partial checkout due to specifying paths. Looking
at it more closely, I'm still not convinced that it can be removed.
Given:

    git worktree new <path> <branch> -- <file>

it creates <path> and checks out <file> (and only <file>) into <path>,
however, the resulting worktree is "not on any branch". The latter, I
think is because switch_branches() doesn't get called in this case;
instead, it's just at whatever HEAD was faked up to appease
is_git_directory().

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02 12:50           ` Duy Nguyen
@ 2015-07-02 17:06             ` Eric Sunshine
  2015-07-02 22:41               ` Duy Nguyen
  0 siblings, 1 reply; 27+ messages in thread
From: Eric Sunshine @ 2015-07-02 17:06 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 8:50 AM, Duy Nguyen <pclouds@gmail.com> wrote:
> On Thu, Jul 2, 2015 at 7:41 PM, Duy Nguyen <pclouds@gmail.com> wrote:
>>> merge_working_tree:
>>>     tree = parse_tree_indirect(old->commit &&
>>>         !opts->new_worktree_mode ?
>>>             old->commit->object.sha1 :
>>>             EMPTY_TREE_SHA1_BIN);
>>
>> I think it's to make sure empty sha-1 is used with --to. If
>> old->commit->object.sha1 is used and it's something, a real two way
>> merge may happen probably with not-so-fun consequences. If it's empty
>> sha1, the effect is like "reset --hard", silent and reliable..
>>
>>> switch_branches:
>>>     if (!opts->quiet && !old.path && old.commit &&
>>>         new->commit != old.commit && !opts->new_worktree_mode)
>>>             orphaned_commit_warning(old.commit, new->commit);
>>
>> to suppress misleading warning if old.commit happens to be something.
>
> Actually you may be right about not reverting these. We prepare the
> new worktree with a valid HEAD, that would make "old" valid and may
> trigger things if "git checkout" is used to populate the worktree. To
> suppress those "things", we need new_worktree_mode or something
> similar.

Indeed. Since this is merely a private implementation detail, we don't
necessarily have to resolve the issue fully for the "checkout --to" to
"worktree add" conversion. It can be dealt with in a follow-on patch.

> Unless we want to borrow fancy checkout options for "git worktree
> add", we probably should just export checkout() function from clone.c
> and use it instead of "git checkout". Much more lightweight and
> simpler (it's one-way merge). Then we can revert checkout.c to the
> version before "--to".

Interesting idea, but doesn't this lose the ability to create a new
branch ("worktree add foo -b bar") and other useful options like
--track?

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02  2:52       ` Eric Sunshine
  2015-07-02 12:41         ` Duy Nguyen
@ 2015-07-02 18:45         ` Eric Sunshine
  2015-07-02 19:00           ` Eric Sunshine
  1 sibling, 1 reply; 27+ messages in thread
From: Eric Sunshine @ 2015-07-02 18:45 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Junio C Hamano, Git List

On Wed, Jul 1, 2015 at 10:52 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> However, there are still a few bits of
> code which want to know that the checkout is happening in a new
> worktree. I haven't examined them closely yet to diagnose if this
> specialized knowledge can be eliminated. Perhaps you can weight in. In
> particular:
>
> checkout_paths:
>     if (opts->new_worktree)
>         die(_("'%s' cannot be used with updating paths"), "--to");
>
> merge_working_tree:
>     tree = parse_tree_indirect(old->commit &&
>         !opts->new_worktree_mode ?
>             old->commit->object.sha1 :
>             EMPTY_TREE_SHA1_BIN);
>
> switch_branches:
>     if (!opts->quiet && !old.path && old.commit &&
>         new->commit != old.commit && !opts->new_worktree_mode)
>             orphaned_commit_warning(old.commit, new->commit);

There's another instance: 3473ad0 (checkout: don't require a work tree
when checking out into a new one, 2014-11-30) added this:

    if (!new_worktree)
        setup_work_tree();

which the "worktree add" patch changed to:

    setup_work_tree();

which doesn't hurt (since setup_work_tree() protects itself against
multiple invocations) but isn't semantically clean. If I understand
correctly, I think a better approach would be to move the
setup_work_tree() call to worktree.c just before it invokes
git-checkout, and revert 3473ad0 entirely (including this bit):

    - { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
    +{ "checkout", cmd_checkout, RUN_SETUP },

so that git-checkout once again requires a worktree.

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02 18:45         ` Eric Sunshine
@ 2015-07-02 19:00           ` Eric Sunshine
  2015-07-02 19:19             ` Eric Sunshine
  0 siblings, 1 reply; 27+ messages in thread
From: Eric Sunshine @ 2015-07-02 19:00 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 2:45 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> There's another instance: 3473ad0 (checkout: don't require a work tree
> when checking out into a new one, 2014-11-30) added this:
>
>     if (!new_worktree)
>         setup_work_tree();
>
> which the "worktree add" patch changed to:
>
>     setup_work_tree();
>
> which doesn't hurt (since setup_work_tree() protects itself against
> multiple invocations) but isn't semantically clean. If I understand
> correctly, I think a better approach would be to move the
> setup_work_tree() call to worktree.c just before it invokes
> git-checkout, and revert 3473ad0 entirely (including this bit):
>
>     - { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
>     +{ "checkout", cmd_checkout, RUN_SETUP },
>
> so that git-checkout once again requires a worktree.

I mis-stated that a bit. The bit about "multiple invocations" isn't
relevant. The point is that I think that 3473ad0 can simply be
reverted as long as worktree.c calls setup_work_tree() before invoking
git-checkout.

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02 19:00           ` Eric Sunshine
@ 2015-07-02 19:19             ` Eric Sunshine
  0 siblings, 0 replies; 27+ messages in thread
From: Eric Sunshine @ 2015-07-02 19:19 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Junio C Hamano, Git List

On Thu, Jul 2, 2015 at 3:00 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Thu, Jul 2, 2015 at 2:45 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> There's another instance: 3473ad0 (checkout: don't require a work tree
>> when checking out into a new one, 2014-11-30) added this:
>>
>>     if (!new_worktree)
>>         setup_work_tree();
>>
>> which the "worktree add" patch changed to:
>>
>>     setup_work_tree();
>>
>> which doesn't hurt (since setup_work_tree() protects itself against
>> multiple invocations) but isn't semantically clean. If I understand
>> correctly, I think a better approach would be to move the
>> setup_work_tree() call to worktree.c just before it invokes
>> git-checkout, and revert 3473ad0 entirely (including this bit):
>>
>>     - { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
>>     +{ "checkout", cmd_checkout, RUN_SETUP },
>>
>> so that git-checkout once again requires a worktree.
>
> I mis-stated that a bit. The bit about "multiple invocations" isn't
> relevant. The point is that I think that 3473ad0 can simply be
> reverted as long as worktree.c calls setup_work_tree() before invoking
> git-checkout.

Please ignore my idiocy. Of course worktree.c can't call
setup_work_tree() on behalf of the sub git-checkout invocation.
Reverting 3473ad0 is the correct thing to do with the introduction of
"worktree add" since it removes the special case of having to be able
to run git-checkout without a worktree.

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

* Re: [RFC/PATCH] worktree: replace "checkout --to" with "worktree new"
  2015-07-02 17:06             ` Eric Sunshine
@ 2015-07-02 22:41               ` Duy Nguyen
  0 siblings, 0 replies; 27+ messages in thread
From: Duy Nguyen @ 2015-07-02 22:41 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Junio C Hamano, Git List

On Fri, Jul 3, 2015 at 12:06 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
>> Unless we want to borrow fancy checkout options for "git worktree
>> add", we probably should just export checkout() function from clone.c
>> and use it instead of "git checkout". Much more lightweight and
>> simpler (it's one-way merge). Then we can revert checkout.c to the
>> version before "--to".
>
> Interesting idea, but doesn't this lose the ability to create a new
> branch ("worktree add foo -b bar") and other useful options like
> --track?

Those are what I call "fancy checkout options". I think we could start
simple with clone.c:checkout.c() and maybe libify switch_branches()
later on to gain --detach and stuff. There's another thing I missed,
when the new worktree is set up, HEAD contains a dummy value. It's
expected that the second checkout will update it with proper value (a
ref, detached HEAD....). So if you avoid running "git chckout" in
"worktree add" and use clone.c:checkout(), you have to re-do something
similar.
-- 
Duy

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

end of thread, other threads:[~2015-07-02 22:42 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-30  4:56 [RFC/PATCH] worktree: replace "checkout --to" with "worktree new" Eric Sunshine
2015-06-30  9:23 ` Duy Nguyen
2015-06-30 16:33   ` Junio C Hamano
2015-07-01 10:46     ` Duy Nguyen
2015-06-30 22:02   ` Eric Sunshine
2015-07-01  6:37     ` Eric Sunshine
2015-06-30 17:13 ` Junio C Hamano
2015-06-30 22:11 ` Eric Sunshine
2015-06-30 22:27   ` Junio C Hamano
2015-07-01  4:48     ` Mikael Magnusson
2015-06-30 22:32   ` Mark Levedahl
2015-07-01 16:53 ` Junio C Hamano
2015-07-01 17:13   ` Eric Sunshine
2015-07-01 17:16     ` Eric Sunshine
2015-07-01 17:32     ` Junio C Hamano
2015-07-01 18:18     ` Eric Sunshine
2015-07-01 18:52       ` Junio C Hamano
2015-07-02  1:07     ` Duy Nguyen
2015-07-02  2:52       ` Eric Sunshine
2015-07-02 12:41         ` Duy Nguyen
2015-07-02 12:50           ` Duy Nguyen
2015-07-02 17:06             ` Eric Sunshine
2015-07-02 22:41               ` Duy Nguyen
2015-07-02 16:59           ` Eric Sunshine
2015-07-02 18:45         ` Eric Sunshine
2015-07-02 19:00           ` Eric Sunshine
2015-07-02 19:19             ` Eric Sunshine

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

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

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