{"thread":{"id":"40038","subject":"[PATCH] worktree: list operation","startedAt":"2015-08-08T20:34:56Z","lastAt":"2015-08-09T00:12:17Z","messageCount":3,"participants":["Michael Rappazzo","Mike Rappazzo"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"267657","messageId":"1439066097-85217-1-git-send-email-rappazzo@gmail.com","threadId":"40038","inReplyTo":null,"subject":"[PATCH] worktree: list operation","fromName":"Michael Rappazzo","fromEmail":"rappazzo@gmail.com","sentAt":"2015-08-08T20:34:56Z","receivedAt":"2015-08-08T20:34:56Z","isPatch":true,"sender":{"key":"rappazzo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/525287?v=4"},"body":"I am attempting to add the 'git worktree list' command.  \n\nI don't have a lot of c experience, so please double check that I am \nnot missing something important.\n\nMichael Rappazzo (1):\n  worktree:  list operation\n\n Documentation/git-worktree.txt |  9 ++++-\n builtin/worktree.c             | 80 ++++++++++++++++++++++++++++++++++++++----\n t/t2027-worktree-list.sh       | 68 +++++++++++++++++++++++++++++++++++\n 3 files changed, 150 insertions(+), 7 deletions(-)\n create mode 100755 t/t2027-worktree-list.sh\n\n-- \n2.5.0\n"},{"id":"267658","messageId":"1439066097-85217-2-git-send-email-rappazzo@gmail.com","threadId":"40038","inReplyTo":"1439066097-85217-1-git-send-email-rappazzo@gmail.com","subject":"[PATCH] worktree: list operation","fromName":"Michael Rappazzo","fromEmail":"rappazzo@gmail.com","sentAt":"2015-08-08T20:34:57Z","receivedAt":"2015-08-08T20:34:57Z","isPatch":true,"sender":{"key":"rappazzo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/525287?v=4"},"body":"'git worktree list' will list the main worktree followed by any linked\nworktrees which were created using 'git worktree add'.  The option\n'--main-only' will restrict the list to only the main worktree.\n---\n Documentation/git-worktree.txt |  9 ++++-\n builtin/worktree.c             | 80 ++++++++++++++++++++++++++++++++++++++----\n t/t2027-worktree-list.sh       | 68 +++++++++++++++++++++++++++++++++++\n 3 files changed, 150 insertions(+), 7 deletions(-)\n create mode 100755 t/t2027-worktree-list.sh\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 3387e2f..39b1330 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -11,6 +11,7 @@ SYNOPSIS\n [verse]\n 'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n+'git worktree list' [--primary]\n \n DESCRIPTION\n -----------\n@@ -59,6 +60,10 @@ prune::\n \n Prune working tree information in $GIT_DIR/worktrees.\n \n+list::\n+\n+List the primary worktree followed by all of the linked worktrees.\n+\n OPTIONS\n -------\n \n@@ -86,6 +91,9 @@ OPTIONS\n \tWith `prune`, do not remove anything; just report what it would\n \tremove.\n \n+--primary::\n+\tWith `list`, only list the primary worktree.\n+\n -v::\n --verbose::\n \tWith `prune`, report all removals.\n@@ -167,7 +175,6 @@ performed manually, such as:\n - `remove` to remove a linked worktree and its administrative files (and\n   warn if the worktree is dirty)\n - `mv` to move or rename a worktree and update its administrative files\n-- `list` to list linked worktrees\n - `lock` to prevent automatic pruning of administrative files (for instance,\n   for a worktree on a portable device)\n \ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 6a264ee..1ac1776 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -10,6 +10,7 @@\n static const char * const worktree_usage[] = {\n \tN_(\"git worktree add [<options>] <path> <branch>\"),\n \tN_(\"git worktree prune [<options>]\"),\n+\tN_(\"git worktree list [<options>]\"),\n \tNULL\n };\n \n@@ -36,7 +37,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n \tfd = open(git_path(\"worktrees/%s/gitdir\", id), O_RDONLY);\n \tif (fd < 0) {\n \t\tstrbuf_addf(reason, _(\"Removing worktrees/%s: unable to read gitdir file (%s)\"),\n-\t\t\t    id, strerror(errno));\n+\t\t\t\t id, strerror(errno));\n \t\treturn 1;\n \t}\n \tlen = st.st_size;\n@@ -59,7 +60,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n \t\t * accessed since?\n \t\t */\n \t\tif (!stat(git_path(\"worktrees/%s/link\", id), &st_link) &&\n-\t\t    st_link.st_nlink > 1)\n+\t\t\t st_link.st_nlink > 1)\n \t\t\treturn 0;\n \t\tif (st.st_mtime <= expire) {\n \t\t\tstrbuf_addf(reason, _(\"Removing worktrees/%s: gitdir file points to non-existent location\"), id);\n@@ -187,7 +188,7 @@ static int add_worktree(const char *path, const char **child_argv)\n \n \tname = worktree_basename(path, &len);\n \tstrbuf_addstr(&sb_repo,\n-\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n+\t\t\t\tgit_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@@ -225,7 +226,7 @@ static int add_worktree(const char *path, const char **child_argv)\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\t\treal_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. Moreover, HEAD\n@@ -280,9 +281,9 @@ static int add(int ac, const char **av, const char *prefix)\n \tstruct option options[] = {\n \t\tOPT__FORCE(&force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n \t\tOPT_STRING('b', NULL, &new_branch, N_(\"branch\"),\n-\t\t\t   N_(\"create a new branch\")),\n+\t\t\t\tN_(\"create a new branch\")),\n \t\tOPT_STRING('B', NULL, &new_branch_force, N_(\"branch\"),\n-\t\t\t   N_(\"create or reset a branch\")),\n+\t\t\t\tN_(\"create or reset a branch\")),\n \t\tOPT_BOOL(0, \"detach\", &detach, N_(\"detach HEAD at named commit\")),\n \t\tOPT_END()\n \t};\n@@ -316,6 +317,71 @@ static int add(int ac, const char **av, const char *prefix)\n \treturn add_worktree(path, cmd.argv);\n }\n \n+static int list(int ac, const char **av, const char *prefix)\n+{\n+\tint primary = 0;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL(0, \"primary\", &primary, N_(\"only list the primary worktree\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n+\tif (ac)\n+\t\tusage_with_options(worktree_usage, options);\n+\n+\tconst char *work_tree;\n+\twork_tree = get_git_work_tree();\n+\tif (!work_tree)\n+\t\tdie(\"This operation must be run in a work tree\");\n+\n+\tstruct strbuf worktree_git_path = STRBUF_INIT;\n+\tstrbuf_addf(&worktree_git_path, _(\"%s/.git\"), work_tree);\n+\n+\tstruct strbuf primary_work_tree = STRBUF_INIT;\n+\tif (is_directory(worktree_git_path.buf)) {\n+\t\t/* This is the primary tree */\n+\t\tstrbuf_addstr(&primary_work_tree, work_tree);\n+\t} else {\n+\t\tconst char *git_dir = get_git_dir();\n+\t\tstrbuf_addf(&primary_work_tree, \"%.*s\", (int)(strstr(git_dir, \"/.git/\") - git_dir), git_dir);\n+\t}\n+\tprintf(\"%s\\n\", primary_work_tree.buf);\n+\n+\tif (!primary) {\n+\t\tchdir( primary_work_tree.buf );\n+\t\tif ( is_directory(git_path(\"worktrees\")) ) {\n+\t\t\tDIR *dir = opendir( git_path(\"worktrees\") );\n+\t\t\tif (dir != NULL) {\n+\t\t   \tstruct dirent *d;\n+\t\t\t\tstruct stat st;\n+\t\t\t\tchar *path;\n+\t\t\t\tint fd, len;\n+\t\t\t\twhile ((d = readdir(dir)) != NULL) {\n+\t\t\t\t\tif (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n+\t\t\t\t\t\tcontinue;\n+\t\t\t\t\tif (stat(git_path(\"worktrees/%s/gitdir\", d->d_name), &st))\n+\t\t\t\t\t\tcontinue;\n+\t\t\t\t\tfd = open(git_path(\"worktrees/%s/gitdir\", d->d_name), O_RDONLY);\n+\t\t\t\t\tif (fd < 0)\n+\t\t\t\t\t\tcontinue;\n+\t\n+\t\t\t\t\tlen = st.st_size;\n+\t\t\t\t\tpath = xmalloc(len + 1);\n+\t\t\t\t\tread_in_full(fd, path, len);\n+\t\t\t\t\tclose(fd);\n+\n+\t\t\t\t\tprintf(\"%.*s\\n\", (int)(strstr(path, \"/.git\") - path), path);\n+\t\t\t\t\tfree(path);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tclosedir(dir);\n+\t\t}\n+\t}\n+\tstrbuf_release(&primary_work_tree);\n+\tstrbuf_release(&worktree_git_path);\n+\treturn 0;\n+}\n+\n int cmd_worktree(int ac, const char **av, const char *prefix)\n {\n \tstruct option options[] = {\n@@ -328,5 +394,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)\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+\tif (!strcmp(av[1], \"list\"))\n+\t\treturn list(ac - 1, av + 1, prefix);\n \tusage_with_options(worktree_usage, options);\n }\ndiff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh\nnew file mode 100755\nindex 0000000..ff48d72\n--- /dev/null\n+++ b/t/t2027-worktree-list.sh\n@@ -0,0 +1,68 @@\n+#!/bin/sh\n+\n+test_description='test git worktree list'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_commit init\n+'\n+\n+\n+test_expect_success '\"list\" all worktrees from primary' '\n+\torig_path=$PWD &&\n+\tgit rev-parse --show-toplevel >expect &&\n+\tgit worktree add --detach here master &&\n+\t(\n+\t\tcd here &&\n+\t\tgit rev-parse --show-toplevel >>\"$orig_path/expect\" &&\n+\t\tcd \"$orig_path\" &&\n+\t\tgit worktree list >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\trm -rf here &&\n+\t\tgit worktree prune\n+\t)\n+'\n+test_expect_success '\"list\" all worktrees from linked' '\n+\torig_path=$PWD &&\n+\tgit rev-parse --show-toplevel >expect &&\n+\tgit worktree add --detach here master &&\n+\t(\n+\t\tcd here &&\n+\t\tgit rev-parse --show-toplevel >>\"$orig_path/expect\" &&\n+\t\tgit worktree list >actual &&\n+\t\ttest_cmp \"$orig_path/expect\" actual &&\n+\t\tcd \"$orig_path\" &&\n+\t\trm -rf here &&\n+\t\tgit worktree prune\n+\t)\n+'\n+\n+test_expect_success '\"list\" main worktree from primary' '\n+\torig_path=$PWD &&\n+\tgit rev-parse --show-toplevel >expect &&\n+\tgit worktree add --detach here master &&\n+\t(\n+\t\tcd here &&\n+\t\tcd \"$orig_path\" &&\n+\t\tgit worktree list --primary >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\trm -rf here &&\n+\t\tgit worktree prune\n+\t)\n+'\n+test_expect_success '\"list\" main worktree from linked' '\n+\torig_path=$PWD &&\n+\tgit rev-parse --show-toplevel >expect &&\n+\tgit worktree add --detach here master &&\n+\t(\n+\t\tcd here &&\n+\t\tgit worktree list --primary >actual &&\n+\t\ttest_cmp \"$orig_path/expect\" actual &&\n+\t\tcd \"$orig_path\" &&\n+\t\trm -rf here &&\n+\t\tgit worktree prune\n+\t)\n+'\n+\n+test_done\n-- \n2.5.0\n"},{"id":"267661","messageId":"CANoM8SV2mrvAkfi1-zVpc3ZWUNYdnygmqG=KMpkVmous0iKung@mail.gmail.com","threadId":"40038","inReplyTo":"1439066097-85217-2-git-send-email-rappazzo@gmail.com","subject":"Re: [PATCH] worktree: list operation","fromName":"Mike Rappazzo","fromEmail":"rappazzo@gmail.com","sentAt":"2015-08-09T00:12:17Z","receivedAt":"2015-08-09T00:12:17Z","isPatch":true,"sender":{"key":"rappazzo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/525287?v=4"},"body":"Withdrawn -- I staged but did not amend the final commit.   I will\nadjust and resend.\n\nOn Sat, Aug 8, 2015 at 4:34 PM, Michael Rappazzo <rappazzo@gmail.com> wrote:\n> 'git worktree list' will list the main worktree followed by any linked\n> worktrees which were created using 'git worktree add'.  The option\n> '--main-only' will restrict the list to only the main worktree.\n> ---\n>  Documentation/git-worktree.txt |  9 ++++-\n>  builtin/worktree.c             | 80 ++++++++++++++++++++++++++++++++++++++----\n>  t/t2027-worktree-list.sh       | 68 +++++++++++++++++++++++++++++++++++\n>  3 files changed, 150 insertions(+), 7 deletions(-)\n>  create mode 100755 t/t2027-worktree-list.sh\n>\n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> index 3387e2f..39b1330 100644\n> --- a/Documentation/git-worktree.txt\n> +++ b/Documentation/git-worktree.txt\n> @@ -11,6 +11,7 @@ SYNOPSIS\n>  [verse]\n>  'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]\n>  'git worktree prune' [-n] [-v] [--expire <expire>]\n> +'git worktree list' [--primary]\n>\n>  DESCRIPTION\n>  -----------\n> @@ -59,6 +60,10 @@ prune::\n>\n>  Prune working tree information in $GIT_DIR/worktrees.\n>\n> +list::\n> +\n> +List the primary worktree followed by all of the linked worktrees.\n> +\n>  OPTIONS\n>  -------\n>\n> @@ -86,6 +91,9 @@ OPTIONS\n>         With `prune`, do not remove anything; just report what it would\n>         remove.\n>\n> +--primary::\n> +       With `list`, only list the primary worktree.\n> +\n>  -v::\n>  --verbose::\n>         With `prune`, report all removals.\n> @@ -167,7 +175,6 @@ performed manually, such as:\n>  - `remove` to remove a linked worktree and its administrative files (and\n>    warn if the worktree is dirty)\n>  - `mv` to move or rename a worktree and update its administrative files\n> -- `list` to list linked worktrees\n>  - `lock` to prevent automatic pruning of administrative files (for instance,\n>    for a worktree on a portable device)\n>\n> diff --git a/builtin/worktree.c b/builtin/worktree.c\n> index 6a264ee..1ac1776 100644\n> --- a/builtin/worktree.c\n> +++ b/builtin/worktree.c\n> @@ -10,6 +10,7 @@\n>  static const char * const worktree_usage[] = {\n>         N_(\"git worktree add [<options>] <path> <branch>\"),\n>         N_(\"git worktree prune [<options>]\"),\n> +       N_(\"git worktree list [<options>]\"),\n>         NULL\n>  };\n>\n> @@ -36,7 +37,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n>         fd = open(git_path(\"worktrees/%s/gitdir\", id), O_RDONLY);\n>         if (fd < 0) {\n>                 strbuf_addf(reason, _(\"Removing worktrees/%s: unable to read gitdir file (%s)\"),\n> -                           id, strerror(errno));\n> +                                id, strerror(errno));\n>                 return 1;\n>         }\n>         len = st.st_size;\n> @@ -59,7 +60,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n>                  * accessed since?\n>                  */\n>                 if (!stat(git_path(\"worktrees/%s/link\", id), &st_link) &&\n> -                   st_link.st_nlink > 1)\n> +                        st_link.st_nlink > 1)\n>                         return 0;\n>                 if (st.st_mtime <= expire) {\n>                         strbuf_addf(reason, _(\"Removing worktrees/%s: gitdir file points to non-existent location\"), id);\n> @@ -187,7 +188,7 @@ static int add_worktree(const char *path, const char **child_argv)\n>\n>         name = worktree_basename(path, &len);\n>         strbuf_addstr(&sb_repo,\n> -                     git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n> +                               git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n>         len = sb_repo.len;\n>         if (safe_create_leading_directories_const(sb_repo.buf))\n>                 die_errno(_(\"could not create leading directories of '%s'\"),\n> @@ -225,7 +226,7 @@ static int add_worktree(const char *path, const char **child_argv)\n>         strbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n>         write_file(sb.buf, 1, \"%s\\n\", real_path(sb_git.buf));\n>         write_file(sb_git.buf, 1, \"gitdir: %s/worktrees/%s\\n\",\n> -                  real_path(get_git_common_dir()), name);\n> +                       real_path(get_git_common_dir()), name);\n>         /*\n>          * This is to keep resolve_ref() happy. We need a valid HEAD\n>          * or is_git_directory() will reject the directory. Moreover, HEAD\n> @@ -280,9 +281,9 @@ static int add(int ac, const char **av, const char *prefix)\n>         struct option options[] = {\n>                 OPT__FORCE(&force, N_(\"checkout <branch> even if already checked out in other worktree\")),\n>                 OPT_STRING('b', NULL, &new_branch, N_(\"branch\"),\n> -                          N_(\"create a new branch\")),\n> +                               N_(\"create a new branch\")),\n>                 OPT_STRING('B', NULL, &new_branch_force, N_(\"branch\"),\n> -                          N_(\"create or reset a branch\")),\n> +                               N_(\"create or reset a branch\")),\n>                 OPT_BOOL(0, \"detach\", &detach, N_(\"detach HEAD at named commit\")),\n>                 OPT_END()\n>         };\n> @@ -316,6 +317,71 @@ static int add(int ac, const char **av, const char *prefix)\n>         return add_worktree(path, cmd.argv);\n>  }\n>\n> +static int list(int ac, const char **av, const char *prefix)\n> +{\n> +       int primary = 0;\n> +       struct option options[] = {\n> +               OPT_BOOL(0, \"primary\", &primary, N_(\"only list the primary worktree\")),\n> +               OPT_END()\n> +       };\n> +\n> +       ac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n> +       if (ac)\n> +               usage_with_options(worktree_usage, options);\n> +\n> +       const char *work_tree;\n> +       work_tree = get_git_work_tree();\n> +       if (!work_tree)\n> +               die(\"This operation must be run in a work tree\");\n> +\n> +       struct strbuf worktree_git_path = STRBUF_INIT;\n> +       strbuf_addf(&worktree_git_path, _(\"%s/.git\"), work_tree);\n> +\n> +       struct strbuf primary_work_tree = STRBUF_INIT;\n> +       if (is_directory(worktree_git_path.buf)) {\n> +               /* This is the primary tree */\n> +               strbuf_addstr(&primary_work_tree, work_tree);\n> +       } else {\n> +               const char *git_dir = get_git_dir();\n> +               strbuf_addf(&primary_work_tree, \"%.*s\", (int)(strstr(git_dir, \"/.git/\") - git_dir), git_dir);\n> +       }\n> +       printf(\"%s\\n\", primary_work_tree.buf);\n> +\n> +       if (!primary) {\n> +               chdir( primary_work_tree.buf );\n> +               if ( is_directory(git_path(\"worktrees\")) ) {\n> +                       DIR *dir = opendir( git_path(\"worktrees\") );\n> +                       if (dir != NULL) {\n> +                       struct dirent *d;\n> +                               struct stat st;\n> +                               char *path;\n> +                               int fd, len;\n> +                               while ((d = readdir(dir)) != NULL) {\n> +                                       if (!strcmp(d->d_name, \".\") || !strcmp(d->d_name, \"..\"))\n> +                                               continue;\n> +                                       if (stat(git_path(\"worktrees/%s/gitdir\", d->d_name), &st))\n> +                                               continue;\n> +                                       fd = open(git_path(\"worktrees/%s/gitdir\", d->d_name), O_RDONLY);\n> +                                       if (fd < 0)\n> +                                               continue;\n> +\n> +                                       len = st.st_size;\n> +                                       path = xmalloc(len + 1);\n> +                                       read_in_full(fd, path, len);\n> +                                       close(fd);\n> +\n> +                                       printf(\"%.*s\\n\", (int)(strstr(path, \"/.git\") - path), path);\n> +                                       free(path);\n> +                               }\n> +                       }\n> +                       closedir(dir);\n> +               }\n> +       }\n> +       strbuf_release(&primary_work_tree);\n> +       strbuf_release(&worktree_git_path);\n> +       return 0;\n> +}\n> +\n>  int cmd_worktree(int ac, const char **av, const char *prefix)\n>  {\n>         struct option options[] = {\n> @@ -328,5 +394,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)\n>                 return add(ac - 1, av + 1, prefix);\n>         if (!strcmp(av[1], \"prune\"))\n>                 return prune(ac - 1, av + 1, prefix);\n> +       if (!strcmp(av[1], \"list\"))\n> +               return list(ac - 1, av + 1, prefix);\n>         usage_with_options(worktree_usage, options);\n>  }\n> diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh\n> new file mode 100755\n> index 0000000..ff48d72\n> --- /dev/null\n> +++ b/t/t2027-worktree-list.sh\n> @@ -0,0 +1,68 @@\n> +#!/bin/sh\n> +\n> +test_description='test git worktree list'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup' '\n> +       test_commit init\n> +'\n> +\n> +\n> +test_expect_success '\"list\" all worktrees from primary' '\n> +       orig_path=$PWD &&\n> +       git rev-parse --show-toplevel >expect &&\n> +       git worktree add --detach here master &&\n> +       (\n> +               cd here &&\n> +               git rev-parse --show-toplevel >>\"$orig_path/expect\" &&\n> +               cd \"$orig_path\" &&\n> +               git worktree list >actual &&\n> +               test_cmp expect actual &&\n> +               rm -rf here &&\n> +               git worktree prune\n> +       )\n> +'\n> +test_expect_success '\"list\" all worktrees from linked' '\n> +       orig_path=$PWD &&\n> +       git rev-parse --show-toplevel >expect &&\n> +       git worktree add --detach here master &&\n> +       (\n> +               cd here &&\n> +               git rev-parse --show-toplevel >>\"$orig_path/expect\" &&\n> +               git worktree list >actual &&\n> +               test_cmp \"$orig_path/expect\" actual &&\n> +               cd \"$orig_path\" &&\n> +               rm -rf here &&\n> +               git worktree prune\n> +       )\n> +'\n> +\n> +test_expect_success '\"list\" main worktree from primary' '\n> +       orig_path=$PWD &&\n> +       git rev-parse --show-toplevel >expect &&\n> +       git worktree add --detach here master &&\n> +       (\n> +               cd here &&\n> +               cd \"$orig_path\" &&\n> +               git worktree list --primary >actual &&\n> +               test_cmp expect actual &&\n> +               rm -rf here &&\n> +               git worktree prune\n> +       )\n> +'\n> +test_expect_success '\"list\" main worktree from linked' '\n> +       orig_path=$PWD &&\n> +       git rev-parse --show-toplevel >expect &&\n> +       git worktree add --detach here master &&\n> +       (\n> +               cd here &&\n> +               git worktree list --primary >actual &&\n> +               test_cmp \"$orig_path/expect\" actual &&\n> +               cd \"$orig_path\" &&\n> +               rm -rf here &&\n> +               git worktree prune\n> +       )\n> +'\n> +\n> +test_done\n> --\n> 2.5.0\n>\n"}]}