{"thread":{"id":"39750","subject":"[RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","startedAt":"2015-06-30T04:56:42Z","lastAt":"2015-07-02T22:41:41Z","messageCount":27,"participants":["Eric Sunshine","Duy Nguyen","Junio C Hamano","Mark Levedahl","Mikael Magnusson"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"265201","messageId":"1435640202-95945-1-git-send-email-sunshine@sunshineco.com","threadId":"39750","inReplyTo":null,"subject":"[RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-06-30T04:56:42Z","receivedAt":"2015-06-30T04:56:42Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"The command \"git checkout --to <path>\" is something of an anachronism,\nencompassing functionality somewhere between \"checkout\" and \"clone\".\nThe introduction of the git-worktree command, however, provides a proper\nand intuitive place to house such functionality. Consequently,\nre-implement \"git checkout --to\" as \"git worktree new\".\n\nAs a side-effect, linked worktree creation becomes much more\ndiscoverable with its own dedicated command, whereas `--to` was easily\noverlooked amid the plethora of options recognized by git-checkout.\n\nSigned-off-by: Eric Sunshine <sunshine@sunshineco.com>\n---\n\nI've long felt that Duy's linked-worktree functionality was a bit oddly\nnamed as \"git checkout --to\", but, since I could never come up with a\nbetter name, I never made mention of it. However, with Duy's\nintroduction of the git-worktree command[1], we now have a much more\nappropriate and discoverable place to house the \"git checkout --to\"\nfunctionality, and upon seeing his patch, I was ready to reply with the\nsuggestion to relocate \"git checkout --to\" to \"git worktree new\",\nhowever, Junio beat me to it[2]. So, in response, this patch does\nexactly that. It applies atop [1].\n\nThis is primarily a code and documentation relocation patch, with minor\nnew code added to builtin/worktree.c. Specifically:\n\n* git-checkout.txt:\"--to\" description moved to git-worktree.txt:\"new\".\n\n* git-checkout.txt:\"MULTIPLE WORKING TREES\" moved to\n  git-worktree.txt:\"DESCRIPTION\", with \"checkout --to\" replaced by\n  \"worktree new\" as necessary. git-worktree.txt could probably use a bit\n  of reorganization, but that can be done as a separate patch.\n\n* builtin/checkout.c:remove_junk() and remove_junk_on_signal() moved\n  verbatim to builtin/worktree.c.\n\n* builtin/checkout.c:prepare_linked_checkout() moved to\n  builtin/worktree.c:new_worktree() nearly verbatim. The following small\n  changes were needed (which might possibly be better done as separate\n  preparatory patches):\n\n  - The \"no branch specified\" check was dropped since git-worktree lacks\n    the machinery for parsing git-checkout command-line arguments, and\n    thus simply doesn't know if a branch/ref was provided, or in what\n    form.  I'm not sure yet how to replace this check.\n\n  - checkout.c:prepare_linked_checkout() (temporarily) fakes up a HEAD\n    ref with a valid object-id in the new worktree to pacify\n    is_git_directory(). It does so using the branch/ref from the\n    command-line which it already resolved. worktree.c, however, doesn't\n    have access to this information, so I instead added code to resolve\n    and use HEAD for the fakement.\n\n  - The \"Enter %s (identifier %s)\" message is suppressed in checkout.c\n    if --quiet is specified, however, worktree.c does not have a --quiet\n    option, so the message is printed unconditionally.\n\n  - argv[] for the sub git-checkout invocation is hand-crafted in\n    worktree.c rather than merely being re-used from the original \"git\n    checkout --to\" as it was in checkout.c.\n\n* builtin/worktree.c:new() is new. It recognizes a --force option (\"git\n  worktree new --force <path> <branch>\") which allows a branch to be\n  checked out in a new worktree even if already checked out in some\n  other worktree (thus, mirroring the functionality of \"git checkout\n  --ignore-other-worktrees\").\n\n* t2025-checkout-to.sh became t2025-worktree-new.sh. I'm not sure if the\n  test number still makes sense or if it should be changed, however, it\n  resides alongside its t2026-prune-linked-checkouts.sh counterpart.\n\n[1]: http://git.661346.n2.nabble.com/PATCH-worktree-new-place-for-git-prune-worktrees-tp7634619.html\n[2]: http://git.661346.n2.nabble.com/PATCH-worktree-new-place-for-git-prune-worktrees-tp7634619p7634638.html\n\n\n Documentation/git-checkout.txt                    |  72 ----------\n Documentation/git-worktree.txt                    |  79 ++++++++++-\n builtin/checkout.c                                | 152 +--------------------\n builtin/worktree.c                                | 157 ++++++++++++++++++++++\n t/{t2025-checkout-to.sh => t2025-worktree-new.sh} |  44 +++---\n t/t2026-prune-linked-checkouts.sh                 |   2 +-\n 6 files changed, 260 insertions(+), 246 deletions(-)\n rename t/{t2025-checkout-to.sh => t2025-worktree-new.sh} (56%)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex d263a56..e19f03a 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -225,13 +225,6 @@ This means that you can use `git checkout -p` to selectively discard\n edits from your current working tree. See the ``Interactive Mode''\n section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n \n---to=<path>::\n-\tCheck out a branch in a separate working directory at\n-\t`<path>`. A new working directory is linked to the current\n-\trepository, sharing everything except working directory\n-\tspecific files such as HEAD, index... See \"MULTIPLE WORKING\n-\tTREES\" section for more information.\n-\n --ignore-other-worktrees::\n \t`git checkout` refuses when the wanted ref is already checked\n \tout by another worktree. This option makes it check the ref\n@@ -401,71 +394,6 @@ $ git reflog -2 HEAD # or\n $ git log -g -2 HEAD\n ------------\n \n-MULTIPLE WORKING TREES\n-----------------------\n-\n-A git repository can support multiple working trees, allowing you to check\n-out more than one branch at a time.  With `git checkout --to` a new working\n-tree is associated with the repository.  This new working tree is called a\n-\"linked working tree\" as opposed to the \"main working tree\" prepared by \"git\n-init\" or \"git clone\".  A repository has one main working tree (if it's not a\n-bare repository) and zero or more linked working trees.\n-\n-Each linked working tree has a private sub-directory in the repository's\n-$GIT_DIR/worktrees directory.  The private sub-directory's name is usually\n-the base name of the linked working tree's path, possibly appended with a\n-number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the\n-command `git checkout --to /path/other/test-next next` creates the linked\n-working tree in `/path/other/test-next` and also creates a\n-`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`\n-if `test-next` is already taken).\n-\n-Within a linked working tree, $GIT_DIR is set to point to this private\n-directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and\n-$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR\n-(e.g. `/path/main/.git`). These settings are made in a `.git` file located at\n-the top directory of the linked working tree.\n-\n-Path resolution via `git rev-parse --git-path` uses either\n-$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the\n-linked working tree `git rev-parse --git-path HEAD` returns\n-`/path/main/.git/worktrees/test-next/HEAD` (not\n-`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git\n-rev-parse --git-path refs/heads/master` uses\n-$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,\n-since refs are shared across all working trees.\n-\n-See linkgit:gitrepository-layout[5] for more information. The rule of\n-thumb is do not make any assumption about whether a path belongs to\n-$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something\n-inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.\n-\n-When you are done with a linked working tree you can simply delete it.\n-The working tree's entry in the repository's $GIT_DIR/worktrees\n-directory will eventually be removed automatically (see\n-`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run\n-`git prune --worktrees` in the main or any linked working tree to\n-clean up any stale entries in $GIT_DIR/worktrees.\n-\n-If you move a linked working directory to another file system, or\n-within a file system that does not support hard links, you need to run\n-at least one git command inside the linked working directory\n-(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees\n-so that it does not get automatically removed.\n-\n-To prevent a $GIT_DIR/worktrees entry from from being pruned (which\n-can be useful in some situations, such as when the\n-entry's working tree is stored on a portable device), add a file named\n-'locked' to the entry's directory. The file contains the reason in\n-plain text. For example, if a linked working tree's `.git` file points\n-to `/path/main/.git/worktrees/test-next` then a file named\n-`/path/main/.git/worktrees/test-next/locked` will prevent the\n-`test-next` entry from being pruned.  See\n-linkgit:gitrepository-layout[5] for details.\n-\n-Multiple checkout support for submodules is incomplete. It is NOT\n-recommended to make multiple checkouts of a superproject.\n-\n EXAMPLES\n --------\n \ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 41103e5..8f13281 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -9,16 +9,85 @@ git-worktree - Manage multiple worktrees\n SYNOPSIS\n --------\n [verse]\n+'git worktree new' [-f] <path> [<checkout-options>] <branch>\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n \n DESCRIPTION\n -----------\n \n-Manage multiple worktrees attached to the same repository. These are\n-created by the command `git checkout --to`.\n+Manage multiple worktrees attached to the same repository.\n+\n+A git repository can support multiple working trees, allowing you to check\n+out more than one branch at a time.  With `git worktree new` a new working\n+tree is associated with the repository.  This new working tree is called a\n+\"linked working tree\" as opposed to the \"main working tree\" prepared by \"git\n+init\" or \"git clone\".  A repository has one main working tree (if it's not a\n+bare repository) and zero or more linked working trees.\n+\n+Each linked working tree has a private sub-directory in the repository's\n+$GIT_DIR/worktrees directory.  The private sub-directory's name is usually\n+the base name of the linked working tree's path, possibly appended with a\n+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the\n+command `git worktree new /path/other/test-next next` creates the linked\n+working tree in `/path/other/test-next` and also creates a\n+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`\n+if `test-next` is already taken).\n+\n+Within a linked working tree, $GIT_DIR is set to point to this private\n+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and\n+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR\n+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at\n+the top directory of the linked working tree.\n+\n+Path resolution via `git rev-parse --git-path` uses either\n+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the\n+linked working tree `git rev-parse --git-path HEAD` returns\n+`/path/main/.git/worktrees/test-next/HEAD` (not\n+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git\n+rev-parse --git-path refs/heads/master` uses\n+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,\n+since refs are shared across all working trees.\n+\n+See linkgit:gitrepository-layout[5] for more information. The rule of\n+thumb is do not make any assumption about whether a path belongs to\n+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something\n+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.\n+\n+When you are done with a linked working tree you can simply delete it.\n+The working tree's entry in the repository's $GIT_DIR/worktrees\n+directory will eventually be removed automatically (see\n+`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run\n+`git prune --worktrees` in the main or any linked working tree to\n+clean up any stale entries in $GIT_DIR/worktrees.\n+\n+If you move a linked working directory to another file system, or\n+within a file system that does not support hard links, you need to run\n+at least one git command inside the linked working directory\n+(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees\n+so that it does not get automatically removed.\n+\n+To prevent a $GIT_DIR/worktrees entry from from being pruned (which\n+can be useful in some situations, such as when the\n+entry's working tree is stored on a portable device), add a file named\n+'locked' to the entry's directory. The file contains the reason in\n+plain text. For example, if a linked working tree's `.git` file points\n+to `/path/main/.git/worktrees/test-next` then a file named\n+`/path/main/.git/worktrees/test-next/locked` will prevent the\n+`test-next` entry from being pruned.  See\n+linkgit:gitrepository-layout[5] for details.\n+\n+Multiple checkout support for submodules is incomplete. It is NOT\n+recommended to make multiple checkouts of a superproject.\n \n COMMANDS\n --------\n+new::\n+\n+Check out a branch in a separate working directory at\n+`<path>`. A new working directory is linked to the current\n+repository, sharing everything except working directory\n+specific files such as HEAD, index, etc.\n+\n prune::\n \n Prune working tree information in $GIT_DIR/worktrees.\n@@ -26,6 +95,12 @@ Prune working tree information in $GIT_DIR/worktrees.\n OPTIONS\n -------\n \n+-f::\n+--force::\n+\tBy default, `git worktree new` refuses to create a new worktree when\n+\t<branch> is already checked out by another worktree. This option\n+\toverrides that safeguard.\n+\n -n::\n --dry-run::\n \tDo not remove anything; just report what it would\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 9b49f0e..3dd5694 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -51,8 +51,6 @@ struct checkout_opts {\n \tstruct pathspec pathspec;\n \tstruct tree *source_tree;\n \n-\tconst char *new_worktree;\n-\tconst char **saved_argv;\n \tint new_worktree_mode;\n };\n \n@@ -273,8 +271,8 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tdie(_(\"Cannot update paths and switch to branch '%s' at the same time.\"),\n \t\t    opts->new_branch);\n \n-\tif (opts->new_worktree)\n-\t\tdie(_(\"'%s' cannot be used with updating paths\"), \"--to\");\n+\tif (opts->new_worktree_mode)\n+\t\tdie(_(\"'%s' cannot be used with updating paths\"), \"git worktree new\");\n \n \tif (opts->patch_mode)\n \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n@@ -850,138 +848,6 @@ static int switch_branches(const struct checkout_opts *opts,\n \treturn ret || writeout_error;\n }\n \n-static char *junk_work_tree;\n-static char *junk_git_dir;\n-static int is_junk;\n-static pid_t junk_pid;\n-\n-static void remove_junk(void)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (!is_junk || getpid() != junk_pid)\n-\t\treturn;\n-\tif (junk_git_dir) {\n-\t\tstrbuf_addstr(&sb, junk_git_dir);\n-\t\tremove_dir_recursively(&sb, 0);\n-\t\tstrbuf_reset(&sb);\n-\t}\n-\tif (junk_work_tree) {\n-\t\tstrbuf_addstr(&sb, junk_work_tree);\n-\t\tremove_dir_recursively(&sb, 0);\n-\t}\n-\tstrbuf_release(&sb);\n-}\n-\n-static void remove_junk_on_signal(int signo)\n-{\n-\tremove_junk();\n-\tsigchain_pop(signo);\n-\traise(signo);\n-}\n-\n-static int prepare_linked_checkout(const struct checkout_opts *opts,\n-\t\t\t\t   struct branch_info *new)\n-{\n-\tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *path = opts->new_worktree, *name;\n-\tstruct stat st;\n-\tstruct child_process cp;\n-\tint counter = 0, len, ret;\n-\n-\tif (!new->commit)\n-\t\tdie(_(\"no branch specified\"));\n-\tif (file_exists(path) && !is_empty_dir(path))\n-\t\tdie(_(\"'%s' already exists\"), path);\n-\n-\tlen = strlen(path);\n-\twhile (len && is_dir_sep(path[len - 1]))\n-\t\tlen--;\n-\n-\tfor (name = path + len - 1; name > path; name--)\n-\t\tif (is_dir_sep(*name)) {\n-\t\t\tname++;\n-\t\t\tbreak;\n-\t\t}\n-\tstrbuf_addstr(&sb_repo,\n-\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n-\tlen = sb_repo.len;\n-\tif (safe_create_leading_directories_const(sb_repo.buf))\n-\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n-\t\t\t  sb_repo.buf);\n-\twhile (!stat(sb_repo.buf, &st)) {\n-\t\tcounter++;\n-\t\tstrbuf_setlen(&sb_repo, len);\n-\t\tstrbuf_addf(&sb_repo, \"%d\", counter);\n-\t}\n-\tname = strrchr(sb_repo.buf, '/') + 1;\n-\n-\tjunk_pid = getpid();\n-\tatexit(remove_junk);\n-\tsigchain_push_common(remove_junk_on_signal);\n-\n-\tif (mkdir(sb_repo.buf, 0777))\n-\t\tdie_errno(_(\"could not create directory of '%s'\"), sb_repo.buf);\n-\tjunk_git_dir = xstrdup(sb_repo.buf);\n-\tis_junk = 1;\n-\n-\t/*\n-\t * lock the incomplete repo so prune won't delete it, unlock\n-\t * after the preparation is over.\n-\t */\n-\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"initializing\\n\");\n-\n-\tstrbuf_addf(&sb_git, \"%s/.git\", path);\n-\tif (safe_create_leading_directories_const(sb_git.buf))\n-\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n-\t\t\t  sb_git.buf);\n-\tjunk_work_tree = xstrdup(path);\n-\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"%s\\n\", real_path(sb_git.buf));\n-\twrite_file(sb_git.buf, 1, \"gitdir: %s/worktrees/%s\\n\",\n-\t\t   real_path(get_git_common_dir()), name);\n-\t/*\n-\t * This is to keep resolve_ref() happy. We need a valid HEAD\n-\t * or is_git_directory() will reject the directory. Any valid\n-\t * value would do because this value will be ignored and\n-\t * replaced at the next (real) checkout.\n-\t */\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"%s\\n\", sha1_to_hex(new->commit->object.sha1));\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"../..\\n\");\n-\n-\tif (!opts->quiet)\n-\t\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), path, name);\n-\n-\tsetenv(\"GIT_CHECKOUT_NEW_WORKTREE\", \"1\", 1);\n-\tsetenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);\n-\tsetenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);\n-\tmemset(&cp, 0, sizeof(cp));\n-\tcp.git_cmd = 1;\n-\tcp.argv = opts->saved_argv;\n-\tret = run_command(&cp);\n-\tif (!ret) {\n-\t\tis_junk = 0;\n-\t\tfree(junk_work_tree);\n-\t\tfree(junk_git_dir);\n-\t\tjunk_work_tree = NULL;\n-\t\tjunk_git_dir = NULL;\n-\t}\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n-\tunlink_or_warn(sb.buf);\n-\tstrbuf_release(&sb);\n-\tstrbuf_release(&sb_repo);\n-\tstrbuf_release(&sb_git);\n-\treturn ret;\n-}\n-\n static int git_checkout_config(const char *var, const char *value, void *cb)\n {\n \tif (!strcmp(var, \"diff.ignoresubmodules\")) {\n@@ -1321,9 +1187,6 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tdie(_(\"Cannot switch branch to a non-commit '%s'\"),\n \t\t    new->name);\n \n-\tif (opts->new_worktree)\n-\t\treturn prepare_linked_checkout(opts, new);\n-\n \tif (!new->commit && opts->new_branch) {\n \t\tunsigned char rev[20];\n \t\tint flag;\n@@ -1366,8 +1229,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"do not limit pathspecs to sparse entries only\")),\n \t\tOPT_HIDDEN_BOOL(0, \"guess\", &dwim_new_local_branch,\n \t\t\t\tN_(\"second guess 'git checkout <no-such-branch>'\")),\n-\t\tOPT_FILENAME(0, \"to\", &opts.new_worktree,\n-\t\t\t   N_(\"check a branch out in a separate working directory\")),\n \t\tOPT_BOOL(0, \"ignore-other-worktrees\", &opts.ignore_other_worktrees,\n \t\t\t N_(\"do not check if another worktree is holding the given ref\")),\n \t\tOPT_END(),\n@@ -1378,9 +1239,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \topts.overwrite_ignore = 1;\n \topts.prefix = prefix;\n \n-\topts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));\n-\tmemcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));\n-\n \tgitmodules_config();\n \tgit_config(git_checkout_config, &opts);\n \n@@ -1389,13 +1247,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, checkout_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH);\n \n-\t/* recursive execution from checkout_new_worktree() */\n \topts.new_worktree_mode = getenv(\"GIT_CHECKOUT_NEW_WORKTREE\") != NULL;\n-\tif (opts.new_worktree_mode)\n-\t\topts.new_worktree = NULL;\n \n-\tif (!opts.new_worktree)\n-\t\tsetup_work_tree();\n+\tsetup_work_tree();\n \n \tif (conflict_style) {\n \t\topts.merge = 1; /* implied */\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 2a729c6..6486f09 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -2,8 +2,11 @@\n #include \"builtin.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n+#include \"run-command.h\"\n+#include \"sigchain.h\"\n \n static const char * const worktree_usage[] = {\n+\tN_(\"git worktree new [<options>] <path> [<checkout-options>] <branch>\"),\n \tN_(\"git worktree prune [<options>]\"),\n \tNULL\n };\n@@ -119,6 +122,158 @@ static int prune(int ac, const char **av, const char *prefix)\n \treturn 0;\n }\n \n+static char *junk_work_tree;\n+static char *junk_git_dir;\n+static int is_junk;\n+static pid_t junk_pid;\n+\n+static void remove_junk(void)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tif (!is_junk || getpid() != junk_pid)\n+\t\treturn;\n+\tif (junk_git_dir) {\n+\t\tstrbuf_addstr(&sb, junk_git_dir);\n+\t\tremove_dir_recursively(&sb, 0);\n+\t\tstrbuf_reset(&sb);\n+\t}\n+\tif (junk_work_tree) {\n+\t\tstrbuf_addstr(&sb, junk_work_tree);\n+\t\tremove_dir_recursively(&sb, 0);\n+\t}\n+\tstrbuf_release(&sb);\n+}\n+\n+static void remove_junk_on_signal(int signo)\n+{\n+\tremove_junk();\n+\tsigchain_pop(signo);\n+\traise(signo);\n+}\n+\n+static int new_worktree(const char *path, int force, const char **av)\n+{\n+\tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *name;\n+\tstruct stat st;\n+\tstruct child_process cp;\n+\tint counter = 0, len, ret;\n+\tunsigned char rev[20];\n+\n+\tif (file_exists(path) && !is_empty_dir(path))\n+\t\tdie(_(\"'%s' already exists\"), path);\n+\n+\tlen = strlen(path);\n+\twhile (len && is_dir_sep(path[len - 1]))\n+\t\tlen--;\n+\n+\tfor (name = path + len - 1; name > path; name--)\n+\t\tif (is_dir_sep(*name)) {\n+\t\t\tname++;\n+\t\t\tbreak;\n+\t\t}\n+\tstrbuf_addstr(&sb_repo,\n+\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n+\tlen = sb_repo.len;\n+\tif (safe_create_leading_directories_const(sb_repo.buf))\n+\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n+\t\t\t  sb_repo.buf);\n+\twhile (!stat(sb_repo.buf, &st)) {\n+\t\tcounter++;\n+\t\tstrbuf_setlen(&sb_repo, len);\n+\t\tstrbuf_addf(&sb_repo, \"%d\", counter);\n+\t}\n+\tname = strrchr(sb_repo.buf, '/') + 1;\n+\n+\tjunk_pid = getpid();\n+\tatexit(remove_junk);\n+\tsigchain_push_common(remove_junk_on_signal);\n+\n+\tif (mkdir(sb_repo.buf, 0777))\n+\t\tdie_errno(_(\"could not create directory of '%s'\"), sb_repo.buf);\n+\tjunk_git_dir = xstrdup(sb_repo.buf);\n+\tis_junk = 1;\n+\n+\t/*\n+\t * lock the incomplete repo so prune won't delete it, unlock\n+\t * after the preparation is over.\n+\t */\n+\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"initializing\\n\");\n+\n+\tstrbuf_addf(&sb_git, \"%s/.git\", path);\n+\tif (safe_create_leading_directories_const(sb_git.buf))\n+\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n+\t\t\t  sb_git.buf);\n+\tjunk_work_tree = xstrdup(path);\n+\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"%s\\n\", real_path(sb_git.buf));\n+\twrite_file(sb_git.buf, 1, \"gitdir: %s/worktrees/%s\\n\",\n+\t\t   real_path(get_git_common_dir()), name);\n+\t/*\n+\t * This is to keep resolve_ref() happy. We need a valid HEAD\n+\t * or is_git_directory() will reject the directory. Any valid\n+\t * value would do because this value will be ignored and\n+\t * replaced at the next (real) checkout.\n+\t */\n+\tif (!resolve_ref_unsafe(\"HEAD\", 0, rev, NULL))\n+\t\tdie(_(\"unable to resolve HEAD\"));\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"%s\\n\", sha1_to_hex(rev));\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"../..\\n\");\n+\n+\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), path, name);\n+\n+\tsetenv(\"GIT_CHECKOUT_NEW_WORKTREE\", \"1\", 1);\n+\tsetenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);\n+\tsetenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.git_cmd = 1;\n+\targv_array_push(&cp.args, \"checkout\");\n+\tif (force)\n+\t\targv_array_push(&cp.args, \"--ignore-other-worktrees\");\n+\tfor (; *av; av++)\n+\t\targv_array_push(&cp.args, *av);\n+\tret = run_command(&cp);\n+\tif (!ret) {\n+\t\tis_junk = 0;\n+\t\tfree(junk_work_tree);\n+\t\tfree(junk_git_dir);\n+\t\tjunk_work_tree = NULL;\n+\t\tjunk_git_dir = NULL;\n+\t}\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n+\tunlink_or_warn(sb.buf);\n+\tstrbuf_release(&sb);\n+\tstrbuf_release(&sb_repo);\n+\tstrbuf_release(&sb_git);\n+\treturn ret;\n+}\n+\n+static int new(int ac, const char **av, const char *prefix)\n+{\n+\tint force = 0;\n+\tconst char *path;\n+\tstruct option options[] = {\n+\t\tOPT__FORCE(&force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tac = parse_options(ac, av, prefix, options, worktree_usage,\n+\t\t\t   PARSE_OPT_STOP_AT_NON_OPTION);\n+\tif (ac < 2)\n+\t\tusage_with_options(worktree_usage, options);\n+\tpath = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];\n+\treturn new_worktree(path, force, av + 1);\n+}\n+\n int cmd_worktree(int ac, const char **av, const char *prefix)\n {\n \tstruct option options[] = {\n@@ -127,6 +282,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix)\n \n \tif (ac < 2)\n \t\tusage_with_options(worktree_usage, options);\n+\tif (!strcmp(av[1], \"new\"))\n+\t\treturn new(ac - 1, av + 1, prefix);\n \tif (!strcmp(av[1], \"prune\"))\n \t\treturn prune(ac - 1, av + 1, prefix);\n \tusage_with_options(worktree_usage, options);\ndiff --git a/t/t2025-checkout-to.sh b/t/t2025-worktree-new.sh\nsimilarity index 56%\nrename from t/t2025-checkout-to.sh\nrename to t/t2025-worktree-new.sh\nindex f8e4df4..d43b352 100755\n--- a/t/t2025-checkout-to.sh\n+++ b/t/t2025-worktree-new.sh\n@@ -1,6 +1,6 @@\n #!/bin/sh\n \n-test_description='test git checkout --to'\n+test_description='test git worktree new'\n \n . ./test-lib.sh\n \n@@ -8,29 +8,29 @@ test_expect_success 'setup' '\n \ttest_commit init\n '\n \n-test_expect_success 'checkout --to not updating paths' '\n-\ttest_must_fail git checkout --to -- init.t\n+test_expect_success '\"new\" not updating paths' '\n+\ttest_must_fail git worktree new -- init.t\n '\n \n-test_expect_success 'checkout --to an existing worktree' '\n+test_expect_success '\"new\" an existing worktree' '\n \tmkdir -p existing/subtree &&\n-\ttest_must_fail git checkout --detach --to existing master\n+\ttest_must_fail git worktree new existing --detach master\n '\n \n-test_expect_success 'checkout --to an existing empty worktree' '\n+test_expect_success '\"new\" an existing empty worktree' '\n \tmkdir existing_empty &&\n-\tgit checkout --detach --to existing_empty master\n+\tgit worktree new existing_empty --detach master\n '\n \n-test_expect_success 'checkout --to refuses to checkout locked branch' '\n-\ttest_must_fail git checkout --to zere master &&\n+test_expect_success '\"new\" refuses to checkout locked branch' '\n+\ttest_must_fail git worktree new zere master &&\n \t! test -d zere &&\n \t! test -d .git/worktrees/zere\n '\n \n-test_expect_success 'checkout --to a new worktree' '\n+test_expect_success '\"new\" worktree' '\n \tgit rev-parse HEAD >expect &&\n-\tgit checkout --detach --to here master &&\n+\tgit worktree new here --detach master &&\n \t(\n \t\tcd here &&\n \t\ttest_cmp ../init.t init.t &&\n@@ -41,27 +41,27 @@ test_expect_success 'checkout --to a new worktree' '\n \t)\n '\n \n-test_expect_success 'checkout --to a new worktree from a subdir' '\n+test_expect_success '\"new\" worktree from a subdir' '\n \t(\n \t\tmkdir sub &&\n \t\tcd sub &&\n-\t\tgit checkout --detach --to here master &&\n+\t\tgit worktree new here --detach master &&\n \t\tcd here &&\n \t\ttest_cmp ../../init.t init.t\n \t)\n '\n \n-test_expect_success 'checkout --to from a linked checkout' '\n+test_expect_success '\"new\" from a linked checkout' '\n \t(\n \t\tcd here &&\n-\t\tgit checkout --detach --to nested-here master &&\n+\t\tgit worktree new nested-here --detach master &&\n \t\tcd nested-here &&\n \t\tgit fsck\n \t)\n '\n \n-test_expect_success 'checkout --to a new worktree creating new branch' '\n-\tgit checkout --to there -b newmaster master &&\n+test_expect_success '\"new\" worktree creating new branch' '\n+\tgit worktree new there -b newmaster master &&\n \t(\n \t\tcd there &&\n \t\ttest_cmp ../init.t init.t &&\n@@ -82,7 +82,7 @@ test_expect_success 'die the same branch is already checked out' '\n test_expect_success 'not die the same branch is already checked out' '\n \t(\n \t\tcd here &&\n-\t\tgit checkout --ignore-other-worktrees --to anothernewmaster newmaster\n+\t\tgit worktree new --force anothernewmaster newmaster\n \t)\n '\n \n@@ -93,15 +93,15 @@ test_expect_success 'not die on re-checking out current branch' '\n \t)\n '\n \n-test_expect_success 'checkout --to from a bare repo' '\n+test_expect_success '\"new\" from a bare repo' '\n \t(\n \t\tgit clone --bare . bare &&\n \t\tcd bare &&\n-\t\tgit checkout --to ../there2 -b bare-master master\n+\t\tgit worktree new ../there2 -b bare-master master\n \t)\n '\n \n-test_expect_success 'checkout from a bare repo without --to' '\n+test_expect_success 'checkout from a bare repo without \"worktree new\"' '\n \t(\n \t\tcd bare &&\n \t\ttest_must_fail git checkout master\n@@ -121,7 +121,7 @@ test_expect_success 'checkout with grafts' '\n \tEOF\n \tgit log --format=%s -2 >actual &&\n \ttest_cmp expected actual &&\n-\tgit checkout --detach --to grafted master &&\n+\tgit worktree new grafted --detach master &&\n \tgit --git-dir=grafted/.git log --format=%s -2 >actual &&\n \ttest_cmp expected actual\n '\ndiff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh\nindex e872f02..d50688c 100755\n--- a/t/t2026-prune-linked-checkouts.sh\n+++ b/t/t2026-prune-linked-checkouts.sh\n@@ -88,7 +88,7 @@ test_expect_success 'not prune recent checkouts' '\n \n test_expect_success 'not prune proper checkouts' '\n \ttest_when_finished rm -r .git/worktrees &&\n-\tgit checkout \"--to=$PWD/nop\" --detach master &&\n+\tgit worktree new \"$PWD/nop\" --detach master &&\n \tgit worktree prune &&\n \ttest -d .git/worktrees/nop\n '\n-- \n2.5.0.rc0.203.gd595659\n"},{"id":"265204","messageId":"CACsJy8BYeYq-fQX=M1h2r4daQSsemXQT4Y+ww2Z3Y54brUS3QQ@mail.gmail.com","threadId":"39750","inReplyTo":"1435640202-95945-1-git-send-email-sunshine@sunshineco.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-06-30T09:23:09Z","receivedAt":"2015-06-30T09:23:09Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jun 30, 2015 at 11:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> The command \"git checkout --to <path>\" is something of an anachronism,\n> encompassing functionality somewhere between \"checkout\" and \"clone\".\n> The introduction of the git-worktree command, however, provides a proper\n> and intuitive place to house such functionality. Consequently,\n> re-implement \"git checkout --to\" as \"git worktree new\".\n>\n> As a side-effect, linked worktree creation becomes much more\n> discoverable with its own dedicated command, whereas `--to` was easily\n> overlooked amid the plethora of options recognized by git-checkout.\n>\n> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>\n> ---\n>\n> I've long felt that Duy's linked-worktree functionality was a bit oddly\n> named as \"git checkout --to\", but, since I could never come up with a\n> better name, I never made mention of it. However, with Duy's\n> introduction of the git-worktree command[1], we now have a much more\n> appropriate and discoverable place to house the \"git checkout --to\"\n> functionality, and upon seeing his patch, I was ready to reply with the\n> suggestion to relocate \"git checkout --to\" to \"git worktree new\",\n> however, Junio beat me to it[2].\n\nDidn't know you guys were so eager to move this code around :D Jokes\naside, it's good that it's raised now before --to is set in stone.\n\nI think this is like \"git checkout -b\" vs \"git branch\". We pack so\nmany things in 'checkout' that it's a source of both convenience and\nconfusion. I never use \"git branch\" to create a new branch and if I\nhad a way to tell checkout to \"move away and delete previous branch\",\nI would probably stop using \"git branch -d/-D\" too. \"--to\" is another\n\"-b\" in this sense.\n\n\"git worktree new\" definitely makes sense (maybe stick with verbs like\n\"create\", I'm not sure if we have some convention in existing\ncommands), but should we remove \"git checkout --to\"? I could do \"git\nco -b foo --to bar\" for example. Maybe \"--to\" is not used that often\nthat \"git worktree new\" would feel less convenient as a replacement.\nIf we are not sure about \"--to\" (I'm not), I think we just remove it\nnow because we can always add it back later.\n\n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> index 41103e5..8f13281 100644\n> --- a/Documentation/git-worktree.txt\n> +++ b/Documentation/git-worktree.txt\n> @@ -9,16 +9,85 @@ git-worktree - Manage multiple worktrees\n>  SYNOPSIS\n>  --------\n>  [verse]\n> +'git worktree new' [-f] <path> [<checkout-options>] <branch>\n\nShould we follow clone syntax and put the <path> (as destination)\nafter <branch> (\"source\")? Maybe not, because in the clone case,\nexplicit destination is optional, not like this.. Or.. maybe <branch>\ncould be optional in this case. 'git worktree new' without a branch\nwill create a new branch, named closely after the destination.\nExisting branch can be specified via an option..\n-- \nDuy\n"},{"id":"265249","messageId":"xmqqy4j16tqk.fsf@gitster.dls.corp.google.com","threadId":"39750","inReplyTo":"CACsJy8BYeYq-fQX=M1h2r4daQSsemXQT4Y+ww2Z3Y54brUS3QQ@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-30T16:33:55Z","receivedAt":"2015-06-30T16:33:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> I think this is like \"git checkout -b\" vs \"git branch\". We pack so\n> many things in 'checkout' that it's a source of both convenience and\n> confusion. I never use \"git branch\" to create a new branch and if I\n> had a way to tell checkout to \"move away and delete previous branch\",\n> I would probably stop using \"git branch -d/-D\" too. \"--to\" is another\n> \"-b\" in this sense.\n\nI didn't know \"checkout --to\" included \"create a worktree elsewhere\nand chdir there\"; if that \"and chdir there\" is not something you are\ndoing, then I do not think \"checkout -b\" vs \"branch\" analogy applies.\n\n> \"git worktree new\" definitely makes sense (maybe stick with verbs like\n> \"create\", I'm not sure if we have some convention in existing\n> commands), but should we remove \"git checkout --to\"?\n\nI'm in favor of removing \"--to\" before it escapes the lab.\n\nI am ambivalent about \"new\", but that is only because I know about\nthe 'new-workdir' in contrib/.  If I pretend to be a naive end user,\nI'd think a verb subcommand would be more in line with the rest of\nthe system than \"new\".\n\nI however do not think \"create\" is a good verb.\n\nWouldn't \"git worktree $the-command-in-question\" be a management\ncommand that adds a new worktree to the existing collection, like\n\"remote add\", \"notes add\", etc. do?  Perhaps \"git worktree list\" and\n\"git worktree remove $that_one\" would be in its future?\n\nThat suggests \"add\" may be a better choice for \"worktree\".\n\nThe only subcommand that I can think of offhand that says \"create\"\nis \"bundle\"; after generates a new bundle, its presence is not known\nto the repository the bundle was created out of, so not using \"add\"\nbut calling the operation \"create\" is fine for \"bundle\".\n"},{"id":"265256","messageId":"xmqqioa56rw3.fsf@gitster.dls.corp.google.com","threadId":"39750","inReplyTo":"1435640202-95945-1-git-send-email-sunshine@sunshineco.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-30T17:13:48Z","receivedAt":"2015-06-30T17:13:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> * t2025-checkout-to.sh became t2025-worktree-new.sh. I'm not sure if the\n>   test number still makes sense or if it should be changed, however, it\n>   resides alongside its t2026-prune-linked-checkouts.sh counterpart.\n\nYou'd need to adjust t7410 as well, perhaps like so:\n\ndiff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh\nindex 8f30aed..d037e51 100755\n--- a/t/t7410-submodule-checkout-to.sh\n+++ b/t/t7410-submodule-checkout-to.sh\n@@ -33,7 +33,7 @@ rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q \"HEAD~1\n test_expect_success 'checkout main' \\\n     'mkdir default_checkout &&\n     (cd clone/main &&\n-\tgit checkout --to \"$base_path/default_checkout/main\" \"$rev1_hash_main\")'\n+\tgit worktree new \"$base_path/default_checkout/main\" \"$rev1_hash_main\")'\n \n test_expect_failure 'can see submodule diffs just after checkout' \\\n     '(cd default_checkout/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n@@ -41,7 +41,7 @@ test_expect_failure 'can see submodule diffs just after checkout' \\\n test_expect_success 'checkout main and initialize independed clones' \\\n     'mkdir fully_cloned_submodule &&\n     (cd clone/main &&\n-\tgit checkout --to \"$base_path/fully_cloned_submodule/main\" \"$rev1_hash_main\") &&\n+\tgit worktree new \"$base_path/fully_cloned_submodule/main\" \"$rev1_hash_main\") &&\n     (cd fully_cloned_submodule/main && git submodule update)'\n \n test_expect_success 'can see submodule diffs after independed cloning' \\\n"},{"id":"265275","messageId":"CAPig+cT7X=LOtgYjXWx=EBJpMrytntQHgdSzdN=prqaysanaCw@mail.gmail.com","threadId":"39750","inReplyTo":"CACsJy8BYeYq-fQX=M1h2r4daQSsemXQT4Y+ww2Z3Y54brUS3QQ@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-06-30T22:02:38Z","receivedAt":"2015-06-30T22:02:38Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Jun 30, 2015 at 5:23 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Tue, Jun 30, 2015 at 11:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> The command \"git checkout --to <path>\" is something of an anachronism,\n>> encompassing functionality somewhere between \"checkout\" and \"clone\".\n>> The introduction of the git-worktree command, however, provides a proper\n>> and intuitive place to house such functionality. Consequently,\n>> re-implement \"git checkout --to\" as \"git worktree new\".\n>\n> I think this is like \"git checkout -b\" vs \"git branch\". We pack so\n> many things in 'checkout' that it's a source of both convenience and\n> confusion. I never use \"git branch\" to create a new branch [...]\n>  \"--to\" is another \"-b\" in this sense.\n\nI too always use \"git checkout -b\", but, like Junio, I don't think\nthis is an apt analogy. \"git checkout -b\" is shorthand for two\ncommands \"git branch\" and \"git checkout\", whereas \"git checkout --to\"\nis not.\n\n> \"git worktree new\" definitely makes sense (maybe stick with verbs like\n> \"create\", I'm not sure if we have some convention in existing\n> commands), but should we remove \"git checkout --to\"? I could do \"git\n> co -b foo --to bar\" for example.\n\nYou can still do that with \"git worktree new bar -b foo\", which is\neffectively the same as \"git checkout --to bar -b foo\" (with\ns/checkout/worktree/ and s/--to/new/ applied), though perhaps you\ndon't find it as obvious or natural.\n\n> If we are not sure about \"--to\" (I'm not), I think we just remove it\n> now because we can always add it back later.\n\nI'm not excited about keeping \"git checkout --to\" as an alias for \"git\nworktree new\", however, removing it now should not harm us since, as\nyou say, it can be added back later if needed.\n\n>>  SYNOPSIS\n>>  --------\n>> +'git worktree new' [-f] <path> [<checkout-options>] <branch>\n>\n> Should we follow clone syntax and put the <path> (as destination)\n> after <branch> (\"source\")? Maybe not, because in the clone case,\n> explicit destination is optional, not like this.. Or.. maybe <branch>\n> could be optional in this case. 'git worktree new' without a branch\n> will create a new branch, named closely after the destination.\n> Existing branch can be specified via an option..\n\nI'm not wedded to this particular argument order, though it does have\nthe advantage that it's clear which options belong to \"worktree new\"\nand which to \"checkout\".\n\nAs for making <branch> optional and auto-vivifying a new branch named\nafter <path>, that's something we can consider later (I think).\n"},{"id":"265276","messageId":"CAPig+cT0a201MVTsvvLrndr40GsMkyvtao33Gt=AFhvShtr=Kg@mail.gmail.com","threadId":"39750","inReplyTo":"1435640202-95945-1-git-send-email-sunshine@sunshineco.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-06-30T22:11:46Z","receivedAt":"2015-06-30T22:11:46Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> The command \"git checkout --to <path>\" is something of an anachronism,\n> encompassing functionality somewhere between \"checkout\" and \"clone\".\n> The introduction of the git-worktree command, however, provides a proper\n> and intuitive place to house such functionality. Consequently,\n> re-implement \"git checkout --to\" as \"git worktree new\".\n> [...]\n> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>\n> ---\n> This is primarily a code and documentation relocation patch, with minor\n> new code added to builtin/worktree.c. Specifically:\n>\n> * builtin/worktree.c:new() is new. It recognizes a --force option (\"git\n>   worktree new --force <path> <branch>\") which allows a branch to be\n>   checked out in a new worktree even if already checked out in some\n>   other worktree (thus, mirroring the functionality of \"git checkout\n>   --ignore-other-worktrees\").\n\nSpeaking of \"git worktree new --force\", should we revisit \"git\ncheckout --ignore-other-worktrees\" before it gets set in stone? In\nparticular, I'm wondering if it makes sense to overload git-checkout's\nexisting --force option to encompass the functionality of\n--ignore-other-worktrees as well. I don't think there would be any\nsemantic conflict by overloading --force, and I do think that --force\nis more discoverable and more intuitive.\n"},{"id":"265277","messageId":"xmqqtwtobzn0.fsf@gitster.dls.corp.google.com","threadId":"39750","inReplyTo":"CAPig+cT0a201MVTsvvLrndr40GsMkyvtao33Gt=AFhvShtr=Kg@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-30T22:27:31Z","receivedAt":"2015-06-30T22:27:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote\n> Speaking of \"git worktree new --force\", should we revisit \"git\n> checkout --ignore-other-worktrees\" before it gets set in stone? In\n> particular, I'm wondering if it makes sense to overload git-checkout's\n> existing --force option to encompass the functionality of\n> --ignore-other-worktrees as well. I don't think there would be any\n> semantic conflict by overloading --force, and I do think that --force\n> is more discoverable and more intuitive.\n\n\"git checkout -f\" is to throw-away local changes, which is a very\nsensible thing to do and I can see why that would be useful, but\ndoes --ignore-other-worktrees have the same kind of common-ness?\n\nIt primarily is a safety measure, and if the user wants to jump\naround freely to different commits in multiple worktrees, a more\nsensible thing to do so without getting the \"nono, you have that\nbranch checked out elsewhere\" is to detach HEADs in the non-primary\nworktrees that may want to have the same commit checked out as the\ncurrent branch of the primary worktree.\n\nI would mildly object to make --ignore-other-worktrees more\ndiscoverable and moderately object to make that feature more\naccessible by overloading it into \"--force\".  I personally would not\nmind if we removed \"--ignore-other-worktrees\", but that might be\ngoing too far ;-)\n"},{"id":"265278","messageId":"55931916.9030908@gmail.com","threadId":"39750","inReplyTo":"CAPig+cT0a201MVTsvvLrndr40GsMkyvtao33Gt=AFhvShtr=Kg@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Mark Levedahl","fromEmail":"mlevedahl@gmail.com","sentAt":"2015-06-30T22:32:54Z","receivedAt":"2015-06-30T22:32:54Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"On 06/30/2015 06:11 PM, Eric Sunshine wrote:\n> On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> The command \"git checkout --to <path>\" is something of an anachronism,\n>> encompassing functionality somewhere between \"checkout\" and \"clone\".\n>> The introduction of the git-worktree command, however, provides a proper\n>> and intuitive place to house such functionality. Consequently,\n>> re-implement \"git checkout --to\" as \"git worktree new\".\n>> [...]\n>> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>\n>> ---\n>> This is primarily a code and documentation relocation patch, with minor\n>> new code added to builtin/worktree.c. Specifically:\n>>\n>> * builtin/worktree.c:new() is new. It recognizes a --force option (\"git\n>>    worktree new --force <path> <branch>\") which allows a branch to be\n>>    checked out in a new worktree even if already checked out in some\n>>    other worktree (thus, mirroring the functionality of \"git checkout\n>>    --ignore-other-worktrees\").\n>\n> Speaking of \"git worktree new --force\", should we revisit \"git\n> checkout --ignore-other-worktrees\" before it gets set in stone? In\n> particular, I'm wondering if it makes sense to overload git-checkout's\n> existing --force option to encompass the functionality of\n> --ignore-other-worktrees as well. I don't think there would be any\n> semantic conflict by overloading --force, and I do think that --force\n> is more discoverable and more intuitive.\n>\n\nI agree with -f subsuming --ignore...:  -f/--force should really mean \n\"do this if at all possible\", not just \"ignore some checks\". Similar to \nrm -f, etc.\n\nMaintaining --ignore-other-worktrees, and making that a configurable \noption (worktree.ignoreothers??) would allow selectively ignoring just \nthis one issue, perhaps permanently, but not the others -f already \noverrides. This would make sense if other options were added to ignore \nother subsets of checks that can block a checkout, probably not otherwise.\n\n\nMark\n"},{"id":"265283","messageId":"CAHYJk3QFpaiCvYfZixtKac6nfrYOWrrewy=sLCVe123GTe+zBw@mail.gmail.com","threadId":"39750","inReplyTo":"xmqqtwtobzn0.fsf@gitster.dls.corp.google.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Mikael Magnusson","fromEmail":"mikachu@gmail.com","sentAt":"2015-07-01T04:48:14Z","receivedAt":"2015-07-01T04:48:14Z","isPatch":true,"sender":{"key":"mikachu@gmail.com","avatar":null},"body":"On Wed, Jul 1, 2015 at 12:27 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Sunshine <sunshine@sunshineco.com> writes:\n>\n>> On Tue, Jun 30, 2015 at 12:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote\n>> Speaking of \"git worktree new --force\", should we revisit \"git\n>> checkout --ignore-other-worktrees\" before it gets set in stone? In\n>> particular, I'm wondering if it makes sense to overload git-checkout's\n>> existing --force option to encompass the functionality of\n>> --ignore-other-worktrees as well. I don't think there would be any\n>> semantic conflict by overloading --force, and I do think that --force\n>> is more discoverable and more intuitive.\n>\n> \"git checkout -f\" is to throw-away local changes, which is a very\n> sensible thing to do and I can see why that would be useful, but\n> does --ignore-other-worktrees have the same kind of common-ness?\n>\n> It primarily is a safety measure, and if the user wants to jump\n> around freely to different commits in multiple worktrees, a more\n> sensible thing to do so without getting the \"nono, you have that\n> branch checked out elsewhere\" is to detach HEADs in the non-primary\n> worktrees that may want to have the same commit checked out as the\n> current branch of the primary worktree.\n>\n> I would mildly object to make --ignore-other-worktrees more\n> discoverable and moderately object to make that feature more\n> accessible by overloading it into \"--force\".  I personally would not\n> mind if we removed \"--ignore-other-worktrees\", but that might be\n> going too far ;-)\n\nThis probably falls under \"not common\", but one of my uses for git\nnew-workdir is to check out the current branch in another directory,\nrebase it to upstream, delete that worktree, and then git reset --hard\nin the original checkout. The result is a rebased branch that touches\na minimum of source files so the rebuild is faster. (In some projects\nI have a lot of local commits that get rebased, but maybe upstream\nonly touched a single .c file).\n\n-- \nMikael Magnusson\n"},{"id":"265300","messageId":"CAPig+cSM5VH9e8T_Bee1d_2GB2ZZpvygKh7_19BJHnifiNp5CA@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cT7X=LOtgYjXWx=EBJpMrytntQHgdSzdN=prqaysanaCw@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-01T06:37:25Z","receivedAt":"2015-07-01T06:37:25Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Jun 30, 2015 at 6:02 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Tue, Jun 30, 2015 at 5:23 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> On Tue, Jun 30, 2015 at 11:56 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>>> The command \"git checkout --to <path>\" is something of an anachronism,\n>>> encompassing functionality somewhere between \"checkout\" and \"clone\".\n>>> The introduction of the git-worktree command, however, provides a proper\n>>> and intuitive place to house such functionality. Consequently,\n>>> re-implement \"git checkout --to\" as \"git worktree new\".\n>>\n>> \"git worktree new\" definitely makes sense (maybe stick with verbs like\n>> \"create\", I'm not sure if we have some convention in existing\n>> commands), but should we remove \"git checkout --to\"? I could do \"git\n>> co -b foo --to bar\" for example.\n>\n> You can still do that with \"git worktree new bar -b foo\", which is\n> effectively the same as \"git checkout --to bar -b foo\" (with\n> s/checkout/worktree/ and s/--to/new/ applied), though perhaps you\n> don't find it as obvious or natural.\n\nI had never understood why you chose to plug the linked-worktree\nfunctionality into git-checkout via --to, but this usage pattern\n(creating a new branch and checking it out into a new worktree as one\noperation) goes a long way toward explaining why you consider\ngit-checkout a proper home for linked-worktree creation. I don't think\nthat justification was ever mentioned when the series was being\npresented (or, if it was, I must have missed it). Now it makes much\nmore sense, and I can better appreciate your desire to keep \"git\ncheckout --to\" as an alias for \"git worktree add\". Thanks for\nexplaining it.\n\n(Having said that, replacing \"git checkout --to\" with \"git worktree\nadd\" still seems a preferable first step, while keeping open the door\nto re-add \"git checkout --to\" later if we become convinced that it's\nworthwhile.)\n"},{"id":"265318","messageId":"CACsJy8DaCK3Z4mfVEjkZsALdeNx9LDe=cw=m-qB39a2fmqR80g@mail.gmail.com","threadId":"39750","inReplyTo":"xmqqy4j16tqk.fsf@gitster.dls.corp.google.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-01T10:46:41Z","receivedAt":"2015-07-01T10:46:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jun 30, 2015 at 11:33 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> I think this is like \"git checkout -b\" vs \"git branch\". We pack so\n>> many things in 'checkout' that it's a source of both convenience and\n>> confusion. I never use \"git branch\" to create a new branch and if I\n>> had a way to tell checkout to \"move away and delete previous branch\",\n>> I would probably stop using \"git branch -d/-D\" too. \"--to\" is another\n>> \"-b\" in this sense.\n>\n> I didn't know \"checkout --to\" included \"create a worktree elsewhere\n> and chdir there\"; if that \"and chdir there\" is not something you are\n> doing, then I do not think \"checkout -b\" vs \"branch\" analogy applies.\n\nHeh.. I do want that \"chdir\" (even for git-init and git-clone). We\ncan't issue \"cd\" command back to the parent shell, but we can spawn a\nnew shell with new cwd. But because the target dir is usually at the\nend of the command line (except for \"--to\") and \"cd !$\" is not much to\ntype, it never bothers me enough to do something more. I think this is\nanother reason I prefer \"git worktree add\" to have the target dir at\nthe end.\n-- \nDuy\n"},{"id":"265331","messageId":"xmqqr3orakex.fsf@gitster.dls.corp.google.com","threadId":"39750","inReplyTo":"1435640202-95945-1-git-send-email-sunshine@sunshineco.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-01T16:53:58Z","receivedAt":"2015-07-01T16:53:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Eric Sunshine <sunshine@sunshineco.com>\n\nThe command \"git checkout --to <path>\" is something of an anachronism,\nencompassing functionality somewhere between \"checkout\" and \"clone\".\nThe introduction of the git-worktree command, however, provides a proper\nand intuitive place to house such functionality. Consequently,\nre-implement \"git checkout --to\" as \"git worktree add\".\n\nAs a side-effect, linked worktree creation becomes much more\ndiscoverable with its own dedicated command, whereas `--to` was easily\noverlooked amid the plethora of options recognized by git-checkout.\n\nSigned-off-by: Eric Sunshine <sunshine@sunshineco.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * Duy seems to think \"worktree add\" is coming, too, so here is a\n   trivial tweak of your patch from the last month, with test\n   adjustments to 7410 I sent earlier squashed in.\n\n   I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does\n   not seem to be documented.  Is this something we still need?\n\n   The log message of 529fef20 (checkout: support checking out into\n   a new working directory, 2014-11-30) does not tell us much.\n\n Documentation/git-checkout.txt    |  72 -----------------\n Documentation/git-worktree.txt    |  79 ++++++++++++++++++-\n builtin/checkout.c                | 152 +-----------------------------------\n builtin/worktree.c                | 157 ++++++++++++++++++++++++++++++++++++++\n t/t2025-checkout-to.sh            | 137 ---------------------------------\n t/t2025-worktree-add.sh           | 137 +++++++++++++++++++++++++++++++++\n t/t2026-prune-linked-checkouts.sh |   2 +-\n t/t7410-submodule-checkout-to.sh  |   4 +-\n 8 files changed, 377 insertions(+), 363 deletions(-)\n delete mode 100755 t/t2025-checkout-to.sh\n create mode 100755 t/t2025-worktree-add.sh\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 72def5b..efe6a02 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -225,13 +225,6 @@ This means that you can use `git checkout -p` to selectively discard\n edits from your current working tree. See the ``Interactive Mode''\n section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n \n---to=<path>::\n-\tCheck out a branch in a separate working directory at\n-\t`<path>`. A new working directory is linked to the current\n-\trepository, sharing everything except working directory\n-\tspecific files such as HEAD, index... See \"MULTIPLE WORKING\n-\tTREES\" section for more information.\n-\n --ignore-other-worktrees::\n \t`git checkout` refuses when the wanted ref is already checked\n \tout by another worktree. This option makes it check the ref\n@@ -401,71 +394,6 @@ $ git reflog -2 HEAD # or\n $ git log -g -2 HEAD\n ------------\n \n-MULTIPLE WORKING TREES\n-----------------------\n-\n-A git repository can support multiple working trees, allowing you to check\n-out more than one branch at a time.  With `git checkout --to` a new working\n-tree is associated with the repository.  This new working tree is called a\n-\"linked working tree\" as opposed to the \"main working tree\" prepared by \"git\n-init\" or \"git clone\".  A repository has one main working tree (if it's not a\n-bare repository) and zero or more linked working trees.\n-\n-Each linked working tree has a private sub-directory in the repository's\n-$GIT_DIR/worktrees directory.  The private sub-directory's name is usually\n-the base name of the linked working tree's path, possibly appended with a\n-number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the\n-command `git checkout --to /path/other/test-next next` creates the linked\n-working tree in `/path/other/test-next` and also creates a\n-`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`\n-if `test-next` is already taken).\n-\n-Within a linked working tree, $GIT_DIR is set to point to this private\n-directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and\n-$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR\n-(e.g. `/path/main/.git`). These settings are made in a `.git` file located at\n-the top directory of the linked working tree.\n-\n-Path resolution via `git rev-parse --git-path` uses either\n-$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the\n-linked working tree `git rev-parse --git-path HEAD` returns\n-`/path/main/.git/worktrees/test-next/HEAD` (not\n-`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git\n-rev-parse --git-path refs/heads/master` uses\n-$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,\n-since refs are shared across all working trees.\n-\n-See linkgit:gitrepository-layout[5] for more information. The rule of\n-thumb is do not make any assumption about whether a path belongs to\n-$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something\n-inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.\n-\n-When you are done with a linked working tree you can simply delete it.\n-The working tree's entry in the repository's $GIT_DIR/worktrees\n-directory will eventually be removed automatically (see\n-`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run\n-`git prune --worktrees` in the main or any linked working tree to\n-clean up any stale entries in $GIT_DIR/worktrees.\n-\n-If you move a linked working directory to another file system, or\n-within a file system that does not support hard links, you need to run\n-at least one git command inside the linked working directory\n-(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees\n-so that it does not get automatically removed.\n-\n-To prevent a $GIT_DIR/worktrees entry from from being pruned (which\n-can be useful in some situations, such as when the\n-entry's working tree is stored on a portable device), add a file named\n-'locked' to the entry's directory. The file contains the reason in\n-plain text. For example, if a linked working tree's `.git` file points\n-to `/path/main/.git/worktrees/test-next` then a file named\n-`/path/main/.git/worktrees/test-next/locked` will prevent the\n-`test-next` entry from being pruned.  See\n-linkgit:gitrepository-layout[5] for details.\n-\n-Multiple checkout support for submodules is incomplete. It is NOT\n-recommended to make multiple checkouts of a superproject.\n-\n EXAMPLES\n --------\n \ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 41103e5..94dce6d 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -9,16 +9,85 @@ git-worktree - Manage multiple worktrees\n SYNOPSIS\n --------\n [verse]\n+'git worktree add' [-f] <path> [<checkout-options>] <branch>\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n \n DESCRIPTION\n -----------\n \n-Manage multiple worktrees attached to the same repository. These are\n-created by the command `git checkout --to`.\n+Manage multiple worktrees attached to the same repository.\n+\n+A git repository can support multiple working trees, allowing you to check\n+out more than one branch at a time.  With `git worktree add` a new working\n+tree is created and gets associated with the repository.  This new working tree is called a\n+\"linked working tree\" as opposed to the \"main working tree\" prepared by \"git\n+init\" or \"git clone\".  A repository has one main working tree (if it's not a\n+bare repository) and zero or more linked working trees.\n+\n+Each linked working tree has a private sub-directory in the repository's\n+$GIT_DIR/worktrees directory.  The private sub-directory's name is usually\n+the base name of the linked working tree's path, possibly appended with a\n+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the\n+command `git worktree add /path/other/test-next next` creates the linked\n+working tree in `/path/other/test-next` and also creates a\n+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`\n+if `test-next` is already taken).\n+\n+Within a linked working tree, $GIT_DIR is set to point to this private\n+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and\n+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR\n+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at\n+the top directory of the linked working tree.\n+\n+Path resolution via `git rev-parse --git-path` uses either\n+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the\n+linked working tree `git rev-parse --git-path HEAD` returns\n+`/path/main/.git/worktrees/test-next/HEAD` (not\n+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git\n+rev-parse --git-path refs/heads/master` uses\n+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,\n+since refs are shared across all working trees.\n+\n+See linkgit:gitrepository-layout[5] for more information. The rule of\n+thumb is do not make any assumption about whether a path belongs to\n+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something\n+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.\n+\n+When you are done with a linked working tree you can simply delete it.\n+The working tree's entry in the repository's $GIT_DIR/worktrees\n+directory will eventually be removed automatically (see\n+`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run\n+`git prune --worktrees` in the main or any linked working tree to\n+clean up any stale entries in $GIT_DIR/worktrees.\n+\n+If you move a linked working directory to another file system, or\n+within a file system that does not support hard links, you need to run\n+at least one git command inside the linked working directory\n+(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees\n+so that it does not get automatically removed.\n+\n+To prevent a $GIT_DIR/worktrees entry from from being pruned (which\n+can be useful in some situations, such as when the\n+entry's working tree is stored on a portable device), add a file named\n+'locked' to the entry's directory. The file contains the reason in\n+plain text. For example, if a linked working tree's `.git` file points\n+to `/path/main/.git/worktrees/test-next` then a file named\n+`/path/main/.git/worktrees/test-next/locked` will prevent the\n+`test-next` entry from being pruned.  See\n+linkgit:gitrepository-layout[5] for details.\n+\n+Multiple checkout support for submodules is incomplete. It is NOT\n+recommended to make multiple checkouts of a superproject.\n \n COMMANDS\n --------\n+add::\n+\n+Check out a branch in a separate working directory at\n+`<path>`. A new working directory is linked to the current\n+repository, sharing everything except working directory\n+specific files such as HEAD, index, etc.\n+\n prune::\n \n Prune working tree information in $GIT_DIR/worktrees.\n@@ -26,6 +95,12 @@ Prune working tree information in $GIT_DIR/worktrees.\n OPTIONS\n -------\n \n+-f::\n+--force::\n+\tBy default, `git worktree add` refuses to create a new worktree when\n+\t<branch> is already checked out by another worktree. This option\n+\toverrides that safeguard.\n+\n -n::\n --dry-run::\n \tDo not remove anything; just report what it would\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2079aa4..439c061 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -51,8 +51,6 @@ struct checkout_opts {\n \tstruct pathspec pathspec;\n \tstruct tree *source_tree;\n \n-\tconst char *new_worktree;\n-\tconst char **saved_argv;\n \tint new_worktree_mode;\n };\n \n@@ -255,8 +253,8 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tdie(_(\"Cannot update paths and switch to branch '%s' at the same time.\"),\n \t\t    opts->new_branch);\n \n-\tif (opts->new_worktree)\n-\t\tdie(_(\"'%s' cannot be used with updating paths\"), \"--to\");\n+\tif (opts->new_worktree_mode)\n+\t\tdie(_(\"'%s' cannot be used with updating paths\"), \"git worktree add\");\n \n \tif (opts->patch_mode)\n \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n@@ -825,138 +823,6 @@ static int switch_branches(const struct checkout_opts *opts,\n \treturn ret || writeout_error;\n }\n \n-static char *junk_work_tree;\n-static char *junk_git_dir;\n-static int is_junk;\n-static pid_t junk_pid;\n-\n-static void remove_junk(void)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (!is_junk || getpid() != junk_pid)\n-\t\treturn;\n-\tif (junk_git_dir) {\n-\t\tstrbuf_addstr(&sb, junk_git_dir);\n-\t\tremove_dir_recursively(&sb, 0);\n-\t\tstrbuf_reset(&sb);\n-\t}\n-\tif (junk_work_tree) {\n-\t\tstrbuf_addstr(&sb, junk_work_tree);\n-\t\tremove_dir_recursively(&sb, 0);\n-\t}\n-\tstrbuf_release(&sb);\n-}\n-\n-static void remove_junk_on_signal(int signo)\n-{\n-\tremove_junk();\n-\tsigchain_pop(signo);\n-\traise(signo);\n-}\n-\n-static int prepare_linked_checkout(const struct checkout_opts *opts,\n-\t\t\t\t   struct branch_info *new)\n-{\n-\tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *path = opts->new_worktree, *name;\n-\tstruct stat st;\n-\tstruct child_process cp;\n-\tint counter = 0, len, ret;\n-\n-\tif (!new->commit)\n-\t\tdie(_(\"no branch specified\"));\n-\tif (file_exists(path) && !is_empty_dir(path))\n-\t\tdie(_(\"'%s' already exists\"), path);\n-\n-\tlen = strlen(path);\n-\twhile (len && is_dir_sep(path[len - 1]))\n-\t\tlen--;\n-\n-\tfor (name = path + len - 1; name > path; name--)\n-\t\tif (is_dir_sep(*name)) {\n-\t\t\tname++;\n-\t\t\tbreak;\n-\t\t}\n-\tstrbuf_addstr(&sb_repo,\n-\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n-\tlen = sb_repo.len;\n-\tif (safe_create_leading_directories_const(sb_repo.buf))\n-\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n-\t\t\t  sb_repo.buf);\n-\twhile (!stat(sb_repo.buf, &st)) {\n-\t\tcounter++;\n-\t\tstrbuf_setlen(&sb_repo, len);\n-\t\tstrbuf_addf(&sb_repo, \"%d\", counter);\n-\t}\n-\tname = strrchr(sb_repo.buf, '/') + 1;\n-\n-\tjunk_pid = getpid();\n-\tatexit(remove_junk);\n-\tsigchain_push_common(remove_junk_on_signal);\n-\n-\tif (mkdir(sb_repo.buf, 0777))\n-\t\tdie_errno(_(\"could not create directory of '%s'\"), sb_repo.buf);\n-\tjunk_git_dir = xstrdup(sb_repo.buf);\n-\tis_junk = 1;\n-\n-\t/*\n-\t * lock the incomplete repo so prune won't delete it, unlock\n-\t * after the preparation is over.\n-\t */\n-\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"initializing\\n\");\n-\n-\tstrbuf_addf(&sb_git, \"%s/.git\", path);\n-\tif (safe_create_leading_directories_const(sb_git.buf))\n-\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n-\t\t\t  sb_git.buf);\n-\tjunk_work_tree = xstrdup(path);\n-\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"%s\\n\", real_path(sb_git.buf));\n-\twrite_file(sb_git.buf, 1, \"gitdir: %s/worktrees/%s\\n\",\n-\t\t   real_path(get_git_common_dir()), name);\n-\t/*\n-\t * This is to keep resolve_ref() happy. We need a valid HEAD\n-\t * or is_git_directory() will reject the directory. Any valid\n-\t * value would do because this value will be ignored and\n-\t * replaced at the next (real) checkout.\n-\t */\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"%s\\n\", sha1_to_hex(new->commit->object.sha1));\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n-\twrite_file(sb.buf, 1, \"../..\\n\");\n-\n-\tif (!opts->quiet)\n-\t\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), path, name);\n-\n-\tsetenv(\"GIT_CHECKOUT_NEW_WORKTREE\", \"1\", 1);\n-\tsetenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);\n-\tsetenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);\n-\tmemset(&cp, 0, sizeof(cp));\n-\tcp.git_cmd = 1;\n-\tcp.argv = opts->saved_argv;\n-\tret = run_command(&cp);\n-\tif (!ret) {\n-\t\tis_junk = 0;\n-\t\tfree(junk_work_tree);\n-\t\tfree(junk_git_dir);\n-\t\tjunk_work_tree = NULL;\n-\t\tjunk_git_dir = NULL;\n-\t}\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n-\tunlink_or_warn(sb.buf);\n-\tstrbuf_release(&sb);\n-\tstrbuf_release(&sb_repo);\n-\tstrbuf_release(&sb_git);\n-\treturn ret;\n-}\n-\n static int git_checkout_config(const char *var, const char *value, void *cb)\n {\n \tif (!strcmp(var, \"diff.ignoresubmodules\")) {\n@@ -1295,9 +1161,6 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tfree(head_ref);\n \t}\n \n-\tif (opts->new_worktree)\n-\t\treturn prepare_linked_checkout(opts, new);\n-\n \tif (!new->commit && opts->new_branch) {\n \t\tunsigned char rev[20];\n \t\tint flag;\n@@ -1340,8 +1203,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"do not limit pathspecs to sparse entries only\")),\n \t\tOPT_HIDDEN_BOOL(0, \"guess\", &dwim_new_local_branch,\n \t\t\t\tN_(\"second guess 'git checkout no-such-branch'\")),\n-\t\tOPT_FILENAME(0, \"to\", &opts.new_worktree,\n-\t\t\t   N_(\"check a branch out in a separate working directory\")),\n \t\tOPT_BOOL(0, \"ignore-other-worktrees\", &opts.ignore_other_worktrees,\n \t\t\t N_(\"do not check if another worktree is holding the given ref\")),\n \t\tOPT_END(),\n@@ -1352,9 +1213,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \topts.overwrite_ignore = 1;\n \topts.prefix = prefix;\n \n-\topts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));\n-\tmemcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));\n-\n \tgitmodules_config();\n \tgit_config(git_checkout_config, &opts);\n \n@@ -1363,13 +1221,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, checkout_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH);\n \n-\t/* recursive execution from checkout_new_worktree() */\n \topts.new_worktree_mode = getenv(\"GIT_CHECKOUT_NEW_WORKTREE\") != NULL;\n-\tif (opts.new_worktree_mode)\n-\t\topts.new_worktree = NULL;\n \n-\tif (!opts.new_worktree)\n-\t\tsetup_work_tree();\n+\tsetup_work_tree();\n \n \tif (conflict_style) {\n \t\topts.merge = 1; /* implied */\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 2a729c6..0983003 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -2,8 +2,11 @@\n #include \"builtin.h\"\n #include \"dir.h\"\n #include \"parse-options.h\"\n+#include \"run-command.h\"\n+#include \"sigchain.h\"\n \n static const char * const worktree_usage[] = {\n+\tN_(\"git worktree add [<options>] <path> [<checkout-options>] <branch>\"),\n \tN_(\"git worktree prune [<options>]\"),\n \tNULL\n };\n@@ -119,6 +122,158 @@ static int prune(int ac, const char **av, const char *prefix)\n \treturn 0;\n }\n \n+static char *junk_work_tree;\n+static char *junk_git_dir;\n+static int is_junk;\n+static pid_t junk_pid;\n+\n+static void remove_junk(void)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tif (!is_junk || getpid() != junk_pid)\n+\t\treturn;\n+\tif (junk_git_dir) {\n+\t\tstrbuf_addstr(&sb, junk_git_dir);\n+\t\tremove_dir_recursively(&sb, 0);\n+\t\tstrbuf_reset(&sb);\n+\t}\n+\tif (junk_work_tree) {\n+\t\tstrbuf_addstr(&sb, junk_work_tree);\n+\t\tremove_dir_recursively(&sb, 0);\n+\t}\n+\tstrbuf_release(&sb);\n+}\n+\n+static void remove_junk_on_signal(int signo)\n+{\n+\tremove_junk();\n+\tsigchain_pop(signo);\n+\traise(signo);\n+}\n+\n+static int add_worktree(const char *path, int force, const char **av)\n+{\n+\tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *name;\n+\tstruct stat st;\n+\tstruct child_process cp;\n+\tint counter = 0, len, ret;\n+\tunsigned char rev[20];\n+\n+\tif (file_exists(path) && !is_empty_dir(path))\n+\t\tdie(_(\"'%s' already exists\"), path);\n+\n+\tlen = strlen(path);\n+\twhile (len && is_dir_sep(path[len - 1]))\n+\t\tlen--;\n+\n+\tfor (name = path + len - 1; name > path; name--)\n+\t\tif (is_dir_sep(*name)) {\n+\t\t\tname++;\n+\t\t\tbreak;\n+\t\t}\n+\tstrbuf_addstr(&sb_repo,\n+\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n+\tlen = sb_repo.len;\n+\tif (safe_create_leading_directories_const(sb_repo.buf))\n+\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n+\t\t\t  sb_repo.buf);\n+\twhile (!stat(sb_repo.buf, &st)) {\n+\t\tcounter++;\n+\t\tstrbuf_setlen(&sb_repo, len);\n+\t\tstrbuf_addf(&sb_repo, \"%d\", counter);\n+\t}\n+\tname = strrchr(sb_repo.buf, '/') + 1;\n+\n+\tjunk_pid = getpid();\n+\tatexit(remove_junk);\n+\tsigchain_push_common(remove_junk_on_signal);\n+\n+\tif (mkdir(sb_repo.buf, 0777))\n+\t\tdie_errno(_(\"could not create directory of '%s'\"), sb_repo.buf);\n+\tjunk_git_dir = xstrdup(sb_repo.buf);\n+\tis_junk = 1;\n+\n+\t/*\n+\t * lock the incomplete repo so prune won't delete it, unlock\n+\t * after the preparation is over.\n+\t */\n+\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"initializing\\n\");\n+\n+\tstrbuf_addf(&sb_git, \"%s/.git\", path);\n+\tif (safe_create_leading_directories_const(sb_git.buf))\n+\t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n+\t\t\t  sb_git.buf);\n+\tjunk_work_tree = xstrdup(path);\n+\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"%s\\n\", real_path(sb_git.buf));\n+\twrite_file(sb_git.buf, 1, \"gitdir: %s/worktrees/%s\\n\",\n+\t\t   real_path(get_git_common_dir()), name);\n+\t/*\n+\t * This is to keep resolve_ref() happy. We need a valid HEAD\n+\t * or is_git_directory() will reject the directory. Any valid\n+\t * value would do because this value will be ignored and\n+\t * replaced at the next (real) checkout.\n+\t */\n+\tif (!resolve_ref_unsafe(\"HEAD\", 0, rev, NULL))\n+\t\tdie(_(\"unable to resolve HEAD\"));\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"%s\\n\", sha1_to_hex(rev));\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n+\twrite_file(sb.buf, 1, \"../..\\n\");\n+\n+\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), path, name);\n+\n+\tsetenv(\"GIT_CHECKOUT_NEW_WORKTREE\", \"1\", 1);\n+\tsetenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);\n+\tsetenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.git_cmd = 1;\n+\targv_array_push(&cp.args, \"checkout\");\n+\tif (force)\n+\t\targv_array_push(&cp.args, \"--ignore-other-worktrees\");\n+\tfor (; *av; av++)\n+\t\targv_array_push(&cp.args, *av);\n+\tret = run_command(&cp);\n+\tif (!ret) {\n+\t\tis_junk = 0;\n+\t\tfree(junk_work_tree);\n+\t\tfree(junk_git_dir);\n+\t\tjunk_work_tree = NULL;\n+\t\tjunk_git_dir = NULL;\n+\t}\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n+\tunlink_or_warn(sb.buf);\n+\tstrbuf_release(&sb);\n+\tstrbuf_release(&sb_repo);\n+\tstrbuf_release(&sb_git);\n+\treturn ret;\n+}\n+\n+static int add(int ac, const char **av, const char *prefix)\n+{\n+\tint force = 0;\n+\tconst char *path;\n+\tstruct option options[] = {\n+\t\tOPT__FORCE(&force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tac = parse_options(ac, av, prefix, options, worktree_usage,\n+\t\t\t   PARSE_OPT_STOP_AT_NON_OPTION);\n+\tif (ac < 2)\n+\t\tusage_with_options(worktree_usage, options);\n+\tpath = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];\n+\treturn add_worktree(path, force, av + 1);\n+}\n+\n int cmd_worktree(int ac, const char **av, const char *prefix)\n {\n \tstruct option options[] = {\n@@ -127,6 +282,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix)\n \n \tif (ac < 2)\n \t\tusage_with_options(worktree_usage, options);\n+\tif (!strcmp(av[1], \"add\"))\n+\t\treturn add(ac - 1, av + 1, prefix);\n \tif (!strcmp(av[1], \"prune\"))\n \t\treturn prune(ac - 1, av + 1, prefix);\n \tusage_with_options(worktree_usage, options);\ndiff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh\ndeleted file mode 100755\nindex a8d9336..0000000\n--- a/t/t2025-checkout-to.sh\n+++ /dev/null\n@@ -1,137 +0,0 @@\n-#!/bin/sh\n-\n-test_description='test git checkout --to'\n-\n-. ./test-lib.sh\n-\n-test_expect_success 'setup' '\n-\ttest_commit init\n-'\n-\n-test_expect_success 'checkout --to not updating paths' '\n-\ttest_must_fail git checkout --to -- init.t\n-'\n-\n-test_expect_success 'checkout --to an existing worktree' '\n-\tmkdir -p existing/subtree &&\n-\ttest_must_fail git checkout --detach --to existing master\n-'\n-\n-test_expect_success 'checkout --to an existing empty worktree' '\n-\tmkdir existing_empty &&\n-\tgit checkout --detach --to existing_empty master\n-'\n-\n-test_expect_success 'checkout --to refuses to checkout locked branch' '\n-\ttest_must_fail git checkout --to zere master &&\n-\t! test -d zere &&\n-\t! test -d .git/worktrees/zere\n-'\n-\n-test_expect_success 'checking out paths not complaining about linked checkouts' '\n-\t(\n-\tcd existing_empty &&\n-\techo dirty >>init.t &&\n-\tgit checkout master -- init.t\n-\t)\n-'\n-\n-test_expect_success 'checkout --to a new worktree' '\n-\tgit rev-parse HEAD >expect &&\n-\tgit checkout --detach --to here master &&\n-\t(\n-\t\tcd here &&\n-\t\ttest_cmp ../init.t init.t &&\n-\t\ttest_must_fail git symbolic-ref HEAD &&\n-\t\tgit rev-parse HEAD >actual &&\n-\t\ttest_cmp ../expect actual &&\n-\t\tgit fsck\n-\t)\n-'\n-\n-test_expect_success 'checkout --to a new worktree from a subdir' '\n-\t(\n-\t\tmkdir sub &&\n-\t\tcd sub &&\n-\t\tgit checkout --detach --to here master &&\n-\t\tcd here &&\n-\t\ttest_cmp ../../init.t init.t\n-\t)\n-'\n-\n-test_expect_success 'checkout --to from a linked checkout' '\n-\t(\n-\t\tcd here &&\n-\t\tgit checkout --detach --to nested-here master &&\n-\t\tcd nested-here &&\n-\t\tgit fsck\n-\t)\n-'\n-\n-test_expect_success 'checkout --to a new worktree creating new branch' '\n-\tgit checkout --to there -b newmaster master &&\n-\t(\n-\t\tcd there &&\n-\t\ttest_cmp ../init.t init.t &&\n-\t\tgit symbolic-ref HEAD >actual &&\n-\t\techo refs/heads/newmaster >expect &&\n-\t\ttest_cmp expect actual &&\n-\t\tgit fsck\n-\t)\n-'\n-\n-test_expect_success 'die the same branch is already checked out' '\n-\t(\n-\t\tcd here &&\n-\t\ttest_must_fail git checkout newmaster\n-\t)\n-'\n-\n-test_expect_success 'not die the same branch is already checked out' '\n-\t(\n-\t\tcd here &&\n-\t\tgit checkout --ignore-other-worktrees --to anothernewmaster newmaster\n-\t)\n-'\n-\n-test_expect_success 'not die on re-checking out current branch' '\n-\t(\n-\t\tcd there &&\n-\t\tgit checkout newmaster\n-\t)\n-'\n-\n-test_expect_success 'checkout --to from a bare repo' '\n-\t(\n-\t\tgit clone --bare . bare &&\n-\t\tcd bare &&\n-\t\tgit checkout --to ../there2 -b bare-master master\n-\t)\n-'\n-\n-test_expect_success 'checkout from a bare repo without --to' '\n-\t(\n-\t\tcd bare &&\n-\t\ttest_must_fail git checkout master\n-\t)\n-'\n-\n-test_expect_success 'checkout with grafts' '\n-\ttest_when_finished rm .git/info/grafts &&\n-\ttest_commit abc &&\n-\tSHA1=`git rev-parse HEAD` &&\n-\ttest_commit def &&\n-\ttest_commit xyz &&\n-\techo \"`git rev-parse HEAD` $SHA1\" >.git/info/grafts &&\n-\tcat >expected <<-\\EOF &&\n-\txyz\n-\tabc\n-\tEOF\n-\tgit log --format=%s -2 >actual &&\n-\ttest_cmp expected actual &&\n-\tgit checkout --detach --to grafted master &&\n-\tgit --git-dir=grafted/.git log --format=%s -2 >actual &&\n-\ttest_cmp expected actual\n-'\n-\n-test_done\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nnew file mode 100755\nindex 0000000..a757988\n--- /dev/null\n+++ b/t/t2025-worktree-add.sh\n@@ -0,0 +1,137 @@\n+#!/bin/sh\n+\n+test_description='test git worktree add'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_commit init\n+'\n+\n+test_expect_success '\"add\" not updating paths' '\n+\ttest_must_fail git worktree add -- init.t\n+'\n+\n+test_expect_success '\"add\" an existing worktree' '\n+\tmkdir -p existing/subtree &&\n+\ttest_must_fail git worktree add existing --detach master\n+'\n+\n+test_expect_success '\"add\" an existing empty worktree' '\n+\tmkdir existing_empty &&\n+\tgit worktree add existing_empty --detach master\n+'\n+\n+test_expect_success '\"add\" refuses to checkout locked branch' '\n+\ttest_must_fail git worktree add zere master &&\n+\t! test -d zere &&\n+\t! test -d .git/worktrees/zere\n+'\n+\n+test_expect_success 'checking out paths not complaining about linked checkouts' '\n+\t(\n+\tcd existing_empty &&\n+\techo dirty >>init.t &&\n+\tgit checkout master -- init.t\n+\t)\n+'\n+\n+test_expect_success '\"add\" worktree' '\n+\tgit rev-parse HEAD >expect &&\n+\tgit worktree add here --detach master &&\n+\t(\n+\t\tcd here &&\n+\t\ttest_cmp ../init.t init.t &&\n+\t\ttest_must_fail git symbolic-ref HEAD &&\n+\t\tgit rev-parse HEAD >actual &&\n+\t\ttest_cmp ../expect actual &&\n+\t\tgit fsck\n+\t)\n+'\n+\n+test_expect_success '\"add\" worktree from a subdir' '\n+\t(\n+\t\tmkdir sub &&\n+\t\tcd sub &&\n+\t\tgit worktree add here --detach master &&\n+\t\tcd here &&\n+\t\ttest_cmp ../../init.t init.t\n+\t)\n+'\n+\n+test_expect_success '\"add\" from a linked checkout' '\n+\t(\n+\t\tcd here &&\n+\t\tgit worktree add nested-here --detach master &&\n+\t\tcd nested-here &&\n+\t\tgit fsck\n+\t)\n+'\n+\n+test_expect_success '\"add\" worktree creating new branch' '\n+\tgit worktree add there -b newmaster master &&\n+\t(\n+\t\tcd there &&\n+\t\ttest_cmp ../init.t init.t &&\n+\t\tgit symbolic-ref HEAD >actual &&\n+\t\techo refs/heads/newmaster >expect &&\n+\t\ttest_cmp expect actual &&\n+\t\tgit fsck\n+\t)\n+'\n+\n+test_expect_success 'die the same branch is already checked out' '\n+\t(\n+\t\tcd here &&\n+\t\ttest_must_fail git checkout newmaster\n+\t)\n+'\n+\n+test_expect_success 'not die the same branch is already checked out' '\n+\t(\n+\t\tcd here &&\n+\t\tgit worktree add --force anothernewmaster newmaster\n+\t)\n+'\n+\n+test_expect_success 'not die on re-checking out current branch' '\n+\t(\n+\t\tcd there &&\n+\t\tgit checkout newmaster\n+\t)\n+'\n+\n+test_expect_success '\"add\" from a bare repo' '\n+\t(\n+\t\tgit clone --bare . bare &&\n+\t\tcd bare &&\n+\t\tgit worktree add ../there2 -b bare-master master\n+\t)\n+'\n+\n+test_expect_success 'checkout from a bare repo without \"worktree add\"' '\n+\t(\n+\t\tcd bare &&\n+\t\ttest_must_fail git checkout master\n+\t)\n+'\n+\n+test_expect_success 'checkout with grafts' '\n+\ttest_when_finished rm .git/info/grafts &&\n+\ttest_commit abc &&\n+\tSHA1=`git rev-parse HEAD` &&\n+\ttest_commit def &&\n+\ttest_commit xyz &&\n+\techo \"`git rev-parse HEAD` $SHA1\" >.git/info/grafts &&\n+\tcat >expected <<-\\EOF &&\n+\txyz\n+\tabc\n+\tEOF\n+\tgit log --format=%s -2 >actual &&\n+\ttest_cmp expected actual &&\n+\tgit worktree add grafted --detach master &&\n+\tgit --git-dir=grafted/.git log --format=%s -2 >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\ndiff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh\nindex e872f02..c74c935 100755\n--- a/t/t2026-prune-linked-checkouts.sh\n+++ b/t/t2026-prune-linked-checkouts.sh\n@@ -88,7 +88,7 @@ test_expect_success 'not prune recent checkouts' '\n \n test_expect_success 'not prune proper checkouts' '\n \ttest_when_finished rm -r .git/worktrees &&\n-\tgit checkout \"--to=$PWD/nop\" --detach master &&\n+\tgit worktree add \"$PWD/nop\" --detach master &&\n \tgit worktree prune &&\n \ttest -d .git/worktrees/nop\n '\ndiff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh\nindex 8f30aed..3f609e8 100755\n--- a/t/t7410-submodule-checkout-to.sh\n+++ b/t/t7410-submodule-checkout-to.sh\n@@ -33,7 +33,7 @@ rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q \"HEAD~1\n test_expect_success 'checkout main' \\\n     'mkdir default_checkout &&\n     (cd clone/main &&\n-\tgit checkout --to \"$base_path/default_checkout/main\" \"$rev1_hash_main\")'\n+\tgit worktree add \"$base_path/default_checkout/main\" \"$rev1_hash_main\")'\n \n test_expect_failure 'can see submodule diffs just after checkout' \\\n     '(cd default_checkout/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n@@ -41,7 +41,7 @@ test_expect_failure 'can see submodule diffs just after checkout' \\\n test_expect_success 'checkout main and initialize independed clones' \\\n     'mkdir fully_cloned_submodule &&\n     (cd clone/main &&\n-\tgit checkout --to \"$base_path/fully_cloned_submodule/main\" \"$rev1_hash_main\") &&\n+\tgit worktree add \"$base_path/fully_cloned_submodule/main\" \"$rev1_hash_main\") &&\n     (cd fully_cloned_submodule/main && git submodule update)'\n \n test_expect_success 'can see submodule diffs after independed cloning' \\\n-- \n2.5.0-rc0-209-g5e1f148\n"},{"id":"265333","messageId":"CAPig+cRLpJK-C7MApH1vigZS=gmHNeo6RL3S2wXv4B-TFfnq4g@mail.gmail.com","threadId":"39750","inReplyTo":"xmqqr3orakex.fsf@gitster.dls.corp.google.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-01T17:13:16Z","receivedAt":"2015-07-01T17:13:16Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> From: Eric Sunshine <sunshine@sunshineco.com>\n>\n> The command \"git checkout --to <path>\" is something of an anachronism,\n> encompassing functionality somewhere between \"checkout\" and \"clone\".\n> The introduction of the git-worktree command, however, provides a proper\n> and intuitive place to house such functionality. Consequently,\n> re-implement \"git checkout --to\" as \"git worktree add\".\n>\n> As a side-effect, linked worktree creation becomes much more\n> discoverable with its own dedicated command, whereas `--to` was easily\n> overlooked amid the plethora of options recognized by git-checkout.\n>\n> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>\n>  * Duy seems to think \"worktree add\" is coming, too, so here is a\n>    trivial tweak of your patch from the last month, with test\n>    adjustments to 7410 I sent earlier squashed in.\n\nThanks. I was planning on re-rolling to use the new name (\"add\" rather\nthan \"new\") and to squash in the t7410 fix. Plus, I think the changes\nI had to make to prepare_linked_checkout() in order to move it to\nworktree.c should become separate preparatory patches so that the\nactual relocation can become pure code movement (as much as possible).\n\nAlso, I was planning on including Duy's patch in the re-roll since it\nmissed a s/prune --worktrees/worktree prune/ in\nDocumentation/git-checkout.txt.\n\n>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does\n>    not seem to be documented.  Is this something we still need?\n>    The log message of 529fef20 (checkout: support checking out into\n>    a new working directory, 2014-11-30) does not tell us much.\n\nYes, it's still used for the same purpose as before the conversion: as\na private signal to the sub git-checkout invocation that it's\noperating on a new worktree. When defined, it sets the\n'new_worktree_mode' flag in checkout.c, and there are still a few bits\nof code which apparently need to know about it. It would be nice to\neliminate this special knowledge from checkout.c, however, I'm not yet\nfamiliar enough with the checkout code to determine if doing so is\nviable.\n\nFor the re-roll, I was planning on renaming it to\nGIT_NEW_WORKTREE_MODE or something (or add a private command-line\noption to checkout, but that may be overkill).\n"},{"id":"265334","messageId":"CAPig+cR67ngGVSA_gSB2ydRJHT5ihf7nJzxmHKSzzQ94BMPAig@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cRLpJK-C7MApH1vigZS=gmHNeo6RL3S2wXv4B-TFfnq4g@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-01T17:16:33Z","receivedAt":"2015-07-01T17:16:33Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jul 1, 2015 at 1:13 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> From: Eric Sunshine <sunshine@sunshineco.com>\n>>\n>> The command \"git checkout --to <path>\" is something of an anachronism,\n>> encompassing functionality somewhere between \"checkout\" and \"clone\".\n>> The introduction of the git-worktree command, however, provides a proper\n>> and intuitive place to house such functionality. Consequently,\n>> re-implement \"git checkout --to\" as \"git worktree add\".\n>> ---\n>>\n>>  * Duy seems to think \"worktree add\" is coming, too, so here is a\n>>    trivial tweak of your patch from the last month, with test\n>>    adjustments to 7410 I sent earlier squashed in.\n>\n> Thanks. I was planning on re-rolling...\n\nI forgot to mention that the subject needs a slight update: \"worktree\nadd\" rather than \"worktree new\".\n"},{"id":"265335","messageId":"xmqqk2ujainc.fsf@gitster.dls.corp.google.com","threadId":"39750","inReplyTo":"CAPig+cRLpJK-C7MApH1vigZS=gmHNeo6RL3S2wXv4B-TFfnq4g@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-01T17:32:07Z","receivedAt":"2015-07-01T17:32:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> Thanks. I was planning on re-rolling to use the new name ...\n> ...\n> For the re-roll, I was planning on renaming it to\n> GIT_NEW_WORKTREE_MODE or something (or add a private command-line\n> option to checkout, but that may be overkill).\n\nOK, thanks, then I'll stop worrying about this and instead will wait\nan update from you ;-)\n"},{"id":"265344","messageId":"CAPig+cQ7yT6mGY=hFC5gKE7GSch-_tL0u8H+haJFr3FPXjjhqw@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cRLpJK-C7MApH1vigZS=gmHNeo6RL3S2wXv4B-TFfnq4g@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-01T18:18:53Z","receivedAt":"2015-07-01T18:18:53Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jul 1, 2015 at 1:13 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>>  * Duy seems to think \"worktree add\" is coming, too, so here is a\n>>    trivial tweak of your patch from the last month, with test\n>>    adjustments to 7410 I sent earlier squashed in.\n>\n> Thanks. I was planning on re-rolling to use the new name (\"add\" rather\n> than \"new\") and to squash in the t7410 fix. Plus, I think the changes\n> I had to make to prepare_linked_checkout() in order to move it to\n> worktree.c should become separate preparatory patches so that the\n> actual relocation can become pure code movement (as much as possible).\n>\n> Also, I was planning on including Duy's patch in the re-roll since it\n> missed a s/prune --worktrees/worktree prune/ in\n> Documentation/git-checkout.txt.\n\nHmm, I see that Duy's patch is already in 'next'. Would it be better\nif I fixed the 's/prune --worktrees/worktree prune/' git-checkout.txt\noversight via an incremental patch rather than including a corrected\nversion of his patch with my re-roll?\n"},{"id":"265348","messageId":"xmqqfv57aexx.fsf@gitster.dls.corp.google.com","threadId":"39750","inReplyTo":"CAPig+cQ7yT6mGY=hFC5gKE7GSch-_tL0u8H+haJFr3FPXjjhqw@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-01T18:52:10Z","receivedAt":"2015-07-01T18:52:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Wed, Jul 1, 2015 at 1:13 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> On Wed, Jul 1, 2015 at 12:53 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>>>  * Duy seems to think \"worktree add\" is coming, too, so here is a\n>>>    trivial tweak of your patch from the last month, with test\n>>>    adjustments to 7410 I sent earlier squashed in.\n>>\n>> Thanks. I was planning on re-rolling to use the new name (\"add\" rather\n>> than \"new\") and to squash in the t7410 fix. Plus, I think the changes\n>> I had to make to prepare_linked_checkout() in order to move it to\n>> worktree.c should become separate preparatory patches so that the\n>> actual relocation can become pure code movement (as much as possible).\n>>\n>> Also, I was planning on including Duy's patch in the re-roll since it\n>> missed a s/prune --worktrees/worktree prune/ in\n>> Documentation/git-checkout.txt.\n>\n> Hmm, I see that Duy's patch is already in 'next'. Would it be better\n> if I fixed the 's/prune --worktrees/worktree prune/' git-checkout.txt\n> oversight via an incremental patch rather than including a corrected\n> version of his patch with my re-roll?\n\nI may have mistaken what you said; I thought you were planning an\nincremental for the existing part, with a more complete reroll of\n\"worktree add\" than what I sent today, as separate patches.\n\nThanks.\n"},{"id":"265377","messageId":"CACsJy8BdvLiM8Ki=N1k-fBrqqoEONhjwcN6jzGUk=3NPRRujQw@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cRLpJK-C7MApH1vigZS=gmHNeo6RL3S2wXv4B-TFfnq4g@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-02T01:07:08Z","receivedAt":"2015-07-02T01:07:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jul 2, 2015 at 12:13 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does\n>>    not seem to be documented.  Is this something we still need?\n>>    The log message of 529fef20 (checkout: support checking out into\n>>    a new working directory, 2014-11-30) does not tell us much.\n>\n> Yes, it's still used for the same purpose as before the conversion: as\n> a private signal to the sub git-checkout invocation that it's\n> operating on a new worktree. When defined, it sets the\n> 'new_worktree_mode' flag in checkout.c, and there are still a few bits\n> of code which apparently need to know about it. It would be nice to\n> eliminate this special knowledge from checkout.c, however, I'm not yet\n> familiar enough with the checkout code to determine if doing so is\n> viable.\n\nI think it can go away. When \"--to\" is used, I have to re-execute \"git\ncheckout\" command again after creating the new worktree. I could\nprocess the command line arguments from the first execution, delete\n\"--to\", then use the remaining options to run checkout the second\ntime. But I chose to pass the entire command line to the second\nexecution. The env is used to let the second run know it should ignore\n\"--to\" (or we get infinite recursion). With \"git worktree add\" this\nrecursion disappears and this env var has no reason to exist.\n-- \nDuy\n"},{"id":"265378","messageId":"CAPig+cT=U6LxpJuUMaCd-x=gQPvh89SDNUo12+2_3uYb_q3=Og@mail.gmail.com","threadId":"39750","inReplyTo":"CACsJy8BdvLiM8Ki=N1k-fBrqqoEONhjwcN6jzGUk=3NPRRujQw@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-02T02:52:58Z","receivedAt":"2015-07-02T02:52:58Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jul 1, 2015 at 9:07 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Thu, Jul 2, 2015 at 12:13 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>>>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does\n>>>    not seem to be documented.  Is this something we still need?\n>>>    The log message of 529fef20 (checkout: support checking out into\n>>>    a new working directory, 2014-11-30) does not tell us much.\n>>\n>> Yes, it's still used for the same purpose as before the conversion: as\n>> a private signal to the sub git-checkout invocation that it's\n>> operating on a new worktree. When defined, it sets the\n>> 'new_worktree_mode' flag in checkout.c, and there are still a few bits\n>> of code which apparently need to know about it. It would be nice to\n>> eliminate this special knowledge from checkout.c, however, I'm not yet\n>> familiar enough with the checkout code to determine if doing so is\n>> viable.\n>\n> I think it can go away. When \"--to\" is used, I have to re-execute \"git\n> checkout\" command again after creating the new worktree. I could\n> process the command line arguments from the first execution, delete\n> \"--to\", then use the remaining options to run checkout the second\n> time. But I chose to pass the entire command line to the second\n> execution. The env is used to let the second run know it should ignore\n> \"--to\" (or we get infinite recursion). With \"git worktree add\" this\n> recursion disappears and this env var has no reason to exist.\n\nThe recursion protection is indeed no longer needed and gets removed\nby the \"worktree add\" patch. However, there are still a few bits of\ncode which want to know that the checkout is happening in a new\nworktree. I haven't examined them closely yet to diagnose if this\nspecialized knowledge can be eliminated. Perhaps you can weight in. In\nparticular:\n\ncheckout_paths:\n    if (opts->new_worktree)\n        die(_(\"'%s' cannot be used with updating paths\"), \"--to\");\n\nmerge_working_tree:\n    tree = parse_tree_indirect(old->commit &&\n        !opts->new_worktree_mode ?\n            old->commit->object.sha1 :\n            EMPTY_TREE_SHA1_BIN);\n\nswitch_branches:\n    if (!opts->quiet && !old.path && old.commit &&\n        new->commit != old.commit && !opts->new_worktree_mode)\n            orphaned_commit_warning(old.commit, new->commit);\n"},{"id":"265392","messageId":"CACsJy8Dce4ErwaRM7zTgLmRzcHxKOr4J8St46urettr5R4DbVg@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cT=U6LxpJuUMaCd-x=gQPvh89SDNUo12+2_3uYb_q3=Og@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-02T12:41:44Z","receivedAt":"2015-07-02T12:41:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jul 2, 2015 at 9:52 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Wed, Jul 1, 2015 at 9:07 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> On Thu, Jul 2, 2015 at 12:13 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>>>>    I noticed GIT_CHECKOUT_NEW_WORKTREE environment variabl that does\n>>>>    not seem to be documented.  Is this something we still need?\n>>>>    The log message of 529fef20 (checkout: support checking out into\n>>>>    a new working directory, 2014-11-30) does not tell us much.\n>>>\n>>> Yes, it's still used for the same purpose as before the conversion: as\n>>> a private signal to the sub git-checkout invocation that it's\n>>> operating on a new worktree. When defined, it sets the\n>>> 'new_worktree_mode' flag in checkout.c, and there are still a few bits\n>>> of code which apparently need to know about it. It would be nice to\n>>> eliminate this special knowledge from checkout.c, however, I'm not yet\n>>> familiar enough with the checkout code to determine if doing so is\n>>> viable.\n>>\n>> I think it can go away. When \"--to\" is used, I have to re-execute \"git\n>> checkout\" command again after creating the new worktree. I could\n>> process the command line arguments from the first execution, delete\n>> \"--to\", then use the remaining options to run checkout the second\n>> time. But I chose to pass the entire command line to the second\n>> execution. The env is used to let the second run know it should ignore\n>> \"--to\" (or we get infinite recursion). With \"git worktree add\" this\n>> recursion disappears and this env var has no reason to exist.\n>\n> The recursion protection is indeed no longer needed and gets removed\n> by the \"worktree add\" patch. However, there are still a few bits of\n> code which want to know that the checkout is happening in a new\n> worktree. I haven't examined them closely yet to diagnose if this\n> specialized knowledge can be eliminated. Perhaps you can weight in. In\n> particular:\n>\n> checkout_paths:\n>     if (opts->new_worktree)\n>         die(_(\"'%s' cannot be used with updating paths\"), \"--to\");\n\nThis one is easy, as \"--to\" is gone, no reason to report anything about \"--to\"\n\n> merge_working_tree:\n>     tree = parse_tree_indirect(old->commit &&\n>         !opts->new_worktree_mode ?\n>             old->commit->object.sha1 :\n>             EMPTY_TREE_SHA1_BIN);\n\nI think it's to make sure empty sha-1 is used with --to. If\nold->commit->object.sha1 is used and it's something, a real two way\nmerge may happen probably with not-so-fun consequences. If it's empty\nsha1, the effect is like \"reset --hard\", silent and reliable..\n\n> switch_branches:\n>     if (!opts->quiet && !old.path && old.commit &&\n>         new->commit != old.commit && !opts->new_worktree_mode)\n>             orphaned_commit_warning(old.commit, new->commit);\n\nto suppress misleading warning if old.commit happens to be something.\n-- \nDuy\n"},{"id":"265393","messageId":"CACsJy8CYtey9d6dFhf+bKCPe0aKzm1GNURDR0sJ4NNEmdZeLGQ@mail.gmail.com","threadId":"39750","inReplyTo":"CACsJy8Dce4ErwaRM7zTgLmRzcHxKOr4J8St46urettr5R4DbVg@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-02T12:50:22Z","receivedAt":"2015-07-02T12:50:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jul 2, 2015 at 7:41 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> merge_working_tree:\n>>     tree = parse_tree_indirect(old->commit &&\n>>         !opts->new_worktree_mode ?\n>>             old->commit->object.sha1 :\n>>             EMPTY_TREE_SHA1_BIN);\n>\n> I think it's to make sure empty sha-1 is used with --to. If\n> old->commit->object.sha1 is used and it's something, a real two way\n> merge may happen probably with not-so-fun consequences. If it's empty\n> sha1, the effect is like \"reset --hard\", silent and reliable..\n>\n>> switch_branches:\n>>     if (!opts->quiet && !old.path && old.commit &&\n>>         new->commit != old.commit && !opts->new_worktree_mode)\n>>             orphaned_commit_warning(old.commit, new->commit);\n>\n> to suppress misleading warning if old.commit happens to be something.\n\nActually you may be right about not reverting these. We prepare the\nnew worktree with a valid HEAD, that would make \"old\" valid and may\ntrigger things if \"git checkout\" is used to populate the worktree. To\nsuppress those \"things\", we need new_worktree_mode or something\nsimilar.\n\nUnless we want to borrow fancy checkout options for \"git worktree\nadd\", we probably should just export checkout() function from clone.c\nand use it instead of \"git checkout\". Much more lightweight and\nsimpler (it's one-way merge). Then we can revert checkout.c to the\nversion before \"--to\".\n-- \nDuy\n"},{"id":"265412","messageId":"CAPig+cS+4cbSNZJEHMoj+NRRt3N2guUH_byMb=k9QHeNS--SqQ@mail.gmail.com","threadId":"39750","inReplyTo":"CACsJy8Dce4ErwaRM7zTgLmRzcHxKOr4J8St46urettr5R4DbVg@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-02T16:59:18Z","receivedAt":"2015-07-02T16:59:18Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jul 2, 2015 at 8:41 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Thu, Jul 2, 2015 at 9:52 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> The recursion protection is indeed no longer needed and gets removed\n>> by the \"worktree add\" patch. However, there are still a few bits of\n>> code which want to know that the checkout is happening in a new\n>> worktree. I haven't examined them closely yet to diagnose if this\n>> specialized knowledge can be eliminated. Perhaps you can weight in. In\n>> particular:\n>>\n>> checkout_paths:\n>>     if (opts->new_worktree)\n>>         die(_(\"'%s' cannot be used with updating paths\"), \"--to\");\n>\n> This one is easy, as \"--to\" is gone, no reason to report anything about \"--to\"\n\nIn the \"worktree add\" patch, I kept this one (with s/--to/worktree\nadd/) assuming that your intention was that a new worktree should\nnever start with a partial checkout due to specifying paths. Looking\nat it more closely, I'm still not convinced that it can be removed.\nGiven:\n\n    git worktree new <path> <branch> -- <file>\n\nit creates <path> and checks out <file> (and only <file>) into <path>,\nhowever, the resulting worktree is \"not on any branch\". The latter, I\nthink is because switch_branches() doesn't get called in this case;\ninstead, it's just at whatever HEAD was faked up to appease\nis_git_directory().\n"},{"id":"265414","messageId":"CAPig+cR1uLa7yiDn9EnTzfkDTOoToc6BTDRn5sYr12yPr6rXPg@mail.gmail.com","threadId":"39750","inReplyTo":"CACsJy8CYtey9d6dFhf+bKCPe0aKzm1GNURDR0sJ4NNEmdZeLGQ@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-02T17:06:25Z","receivedAt":"2015-07-02T17:06:25Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jul 2, 2015 at 8:50 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Thu, Jul 2, 2015 at 7:41 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>>> merge_working_tree:\n>>>     tree = parse_tree_indirect(old->commit &&\n>>>         !opts->new_worktree_mode ?\n>>>             old->commit->object.sha1 :\n>>>             EMPTY_TREE_SHA1_BIN);\n>>\n>> I think it's to make sure empty sha-1 is used with --to. If\n>> old->commit->object.sha1 is used and it's something, a real two way\n>> merge may happen probably with not-so-fun consequences. If it's empty\n>> sha1, the effect is like \"reset --hard\", silent and reliable..\n>>\n>>> switch_branches:\n>>>     if (!opts->quiet && !old.path && old.commit &&\n>>>         new->commit != old.commit && !opts->new_worktree_mode)\n>>>             orphaned_commit_warning(old.commit, new->commit);\n>>\n>> to suppress misleading warning if old.commit happens to be something.\n>\n> Actually you may be right about not reverting these. We prepare the\n> new worktree with a valid HEAD, that would make \"old\" valid and may\n> trigger things if \"git checkout\" is used to populate the worktree. To\n> suppress those \"things\", we need new_worktree_mode or something\n> similar.\n\nIndeed. Since this is merely a private implementation detail, we don't\nnecessarily have to resolve the issue fully for the \"checkout --to\" to\n\"worktree add\" conversion. It can be dealt with in a follow-on patch.\n\n> Unless we want to borrow fancy checkout options for \"git worktree\n> add\", we probably should just export checkout() function from clone.c\n> and use it instead of \"git checkout\". Much more lightweight and\n> simpler (it's one-way merge). Then we can revert checkout.c to the\n> version before \"--to\".\n\nInteresting idea, but doesn't this lose the ability to create a new\nbranch (\"worktree add foo -b bar\") and other useful options like\n--track?\n"},{"id":"265436","messageId":"CAPig+cR2tn6G0N1sSsrkP_Lo_U_hjLYi08qEsMr+gcsjheaX7A@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cT=U6LxpJuUMaCd-x=gQPvh89SDNUo12+2_3uYb_q3=Og@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-02T18:45:23Z","receivedAt":"2015-07-02T18:45:23Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jul 1, 2015 at 10:52 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> However, there are still a few bits of\n> code which want to know that the checkout is happening in a new\n> worktree. I haven't examined them closely yet to diagnose if this\n> specialized knowledge can be eliminated. Perhaps you can weight in. In\n> particular:\n>\n> checkout_paths:\n>     if (opts->new_worktree)\n>         die(_(\"'%s' cannot be used with updating paths\"), \"--to\");\n>\n> merge_working_tree:\n>     tree = parse_tree_indirect(old->commit &&\n>         !opts->new_worktree_mode ?\n>             old->commit->object.sha1 :\n>             EMPTY_TREE_SHA1_BIN);\n>\n> switch_branches:\n>     if (!opts->quiet && !old.path && old.commit &&\n>         new->commit != old.commit && !opts->new_worktree_mode)\n>             orphaned_commit_warning(old.commit, new->commit);\n\nThere's another instance: 3473ad0 (checkout: don't require a work tree\nwhen checking out into a new one, 2014-11-30) added this:\n\n    if (!new_worktree)\n        setup_work_tree();\n\nwhich the \"worktree add\" patch changed to:\n\n    setup_work_tree();\n\nwhich doesn't hurt (since setup_work_tree() protects itself against\nmultiple invocations) but isn't semantically clean. If I understand\ncorrectly, I think a better approach would be to move the\nsetup_work_tree() call to worktree.c just before it invokes\ngit-checkout, and revert 3473ad0 entirely (including this bit):\n\n    - { \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n    +{ \"checkout\", cmd_checkout, RUN_SETUP },\n\nso that git-checkout once again requires a worktree.\n"},{"id":"265437","messageId":"CAPig+cTm7Qzxr_E+_p6UYmPrsQzTFCN-Mouu-FigNqRH=gSPKg@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cR2tn6G0N1sSsrkP_Lo_U_hjLYi08qEsMr+gcsjheaX7A@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-02T19:00:45Z","receivedAt":"2015-07-02T19:00:45Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jul 2, 2015 at 2:45 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> There's another instance: 3473ad0 (checkout: don't require a work tree\n> when checking out into a new one, 2014-11-30) added this:\n>\n>     if (!new_worktree)\n>         setup_work_tree();\n>\n> which the \"worktree add\" patch changed to:\n>\n>     setup_work_tree();\n>\n> which doesn't hurt (since setup_work_tree() protects itself against\n> multiple invocations) but isn't semantically clean. If I understand\n> correctly, I think a better approach would be to move the\n> setup_work_tree() call to worktree.c just before it invokes\n> git-checkout, and revert 3473ad0 entirely (including this bit):\n>\n>     - { \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n>     +{ \"checkout\", cmd_checkout, RUN_SETUP },\n>\n> so that git-checkout once again requires a worktree.\n\nI mis-stated that a bit. The bit about \"multiple invocations\" isn't\nrelevant. The point is that I think that 3473ad0 can simply be\nreverted as long as worktree.c calls setup_work_tree() before invoking\ngit-checkout.\n"},{"id":"265438","messageId":"CAPig+cSBimLTn5_6AmjLndoevVN80AOTzHj6bXOq2MS47zimkg@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cTm7Qzxr_E+_p6UYmPrsQzTFCN-Mouu-FigNqRH=gSPKg@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-02T19:19:49Z","receivedAt":"2015-07-02T19:19:49Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jul 2, 2015 at 3:00 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Thu, Jul 2, 2015 at 2:45 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> There's another instance: 3473ad0 (checkout: don't require a work tree\n>> when checking out into a new one, 2014-11-30) added this:\n>>\n>>     if (!new_worktree)\n>>         setup_work_tree();\n>>\n>> which the \"worktree add\" patch changed to:\n>>\n>>     setup_work_tree();\n>>\n>> which doesn't hurt (since setup_work_tree() protects itself against\n>> multiple invocations) but isn't semantically clean. If I understand\n>> correctly, I think a better approach would be to move the\n>> setup_work_tree() call to worktree.c just before it invokes\n>> git-checkout, and revert 3473ad0 entirely (including this bit):\n>>\n>>     - { \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n>>     +{ \"checkout\", cmd_checkout, RUN_SETUP },\n>>\n>> so that git-checkout once again requires a worktree.\n>\n> I mis-stated that a bit. The bit about \"multiple invocations\" isn't\n> relevant. The point is that I think that 3473ad0 can simply be\n> reverted as long as worktree.c calls setup_work_tree() before invoking\n> git-checkout.\n\nPlease ignore my idiocy. Of course worktree.c can't call\nsetup_work_tree() on behalf of the sub git-checkout invocation.\nReverting 3473ad0 is the correct thing to do with the introduction of\n\"worktree add\" since it removes the special case of having to be able\nto run git-checkout without a worktree.\n"},{"id":"265439","messageId":"CACsJy8CwnWj80=4GGY4VnHnbxb_tL1Vg8S16rybmwGpgbSEexQ@mail.gmail.com","threadId":"39750","inReplyTo":"CAPig+cR1uLa7yiDn9EnTzfkDTOoToc6BTDRn5sYr12yPr6rXPg@mail.gmail.com","subject":"Re: [RFC/PATCH] worktree: replace \"checkout --to\" with \"worktree new\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-02T22:41:41Z","receivedAt":"2015-07-02T22:41:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jul 3, 2015 at 12:06 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> Unless we want to borrow fancy checkout options for \"git worktree\n>> add\", we probably should just export checkout() function from clone.c\n>> and use it instead of \"git checkout\". Much more lightweight and\n>> simpler (it's one-way merge). Then we can revert checkout.c to the\n>> version before \"--to\".\n>\n> Interesting idea, but doesn't this lose the ability to create a new\n> branch (\"worktree add foo -b bar\") and other useful options like\n> --track?\n\nThose are what I call \"fancy checkout options\". I think we could start\nsimple with clone.c:checkout.c() and maybe libify switch_branches()\nlater on to gain --detach and stuff. There's another thing I missed,\nwhen the new worktree is set up, HEAD contains a dummy value. It's\nexpected that the second checkout will update it with proper value (a\nref, detached HEAD....). So if you avoid running \"git chckout\" in\n\"worktree add\" and use clone.c:checkout(), you have to re-do something\nsimilar.\n-- \nDuy\n"}]}