'git worktree list' will list the main worktree followed by any linked
worktrees which were created using 'git worktree add'.

Signed-off-by: Michael Rappazzo <rappa...@gmail.com>
---
 Documentation/git-worktree.txt |  6 +++-
 builtin/worktree.c             | 67 ++++++++++++++++++++++++++++++++++++++++++
 t/t2027-worktree-list.sh       | 30 +++++++++++++++++++
 3 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100755 t/t2027-worktree-list.sh

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 3387e2f..efb8e9d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -11,6 +11,7 @@ SYNOPSIS
 [verse]
 'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
 'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree list'
 
 DESCRIPTION
 -----------
@@ -59,6 +60,10 @@ prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
 
+list::
+
+List the main worktree followed by all of the linked worktrees.
+
 OPTIONS
 -------
 
@@ -167,7 +172,6 @@ performed manually, such as:
 - `remove` to remove a linked worktree and its administrative files (and
   warn if the worktree is dirty)
 - `mv` to move or rename a worktree and update its administrative files
-- `list` to list linked worktrees
 - `lock` to prevent automatic pruning of administrative files (for instance,
   for a worktree on a portable device)
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 6a264ee..d90bdee 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -10,6 +10,7 @@
 static const char * const worktree_usage[] = {
        N_("git worktree add [<options>] <path> <branch>"),
        N_("git worktree prune [<options>]"),
+       N_("git worktree list [<options>]"),
        NULL
 };
 
@@ -316,6 +317,70 @@ static int add(int ac, const char **av, const char *prefix)
        return add_worktree(path, cmd.argv);
 }
 
+static int list(int ac, const char **av, const char *prefix)
+{
+       int main_only = 0;
+       struct option options[] = {
+               OPT_BOOL(0, "main-only", &main_only, N_("only list the main 
worktree")),
+               OPT_END()
+       };
+
+       ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+       if (ac)
+               usage_with_options(worktree_usage, options);
+
+       struct strbuf main_path = STRBUF_INIT;
+       const char* common_dir = get_git_common_dir();
+       int is_bare = is_bare_repository();
+       if (is_bare) {
+               strbuf_addstr(&main_path, absolute_path(common_dir));
+               strbuf_strip_suffix(&main_path, "/.");
+       } else if (!strcmp(common_dir, ".git")) {
+               /* within a worktree, the common dir only returns ".git" */
+               strbuf_addstr(&main_path, get_git_work_tree());
+       } else {
+               strbuf_addstr(&main_path, common_dir);
+               strbuf_strip_suffix(&main_path, "/.git");
+       }
+
+       printf("%s\n", main_path.buf);
+
+       if (!is_bare) {
+               strbuf_addstr(&main_path, "/.git");
+       }
+       strbuf_addstr(&main_path, "/worktrees");
+
+       if (is_directory(main_path.buf)) {
+               DIR *dir = opendir(main_path.buf);
+               if (dir) {
+                       struct dirent *d;
+                       struct stat st;
+                       struct strbuf path = STRBUF_INIT;
+                       struct strbuf other_worktree_path = STRBUF_INIT;
+                       while ((d = readdir(dir)) != NULL) {
+                               if (!strcmp(d->d_name, ".") || 
!strcmp(d->d_name, ".."))
+                                       continue;
+                               strbuf_reset(&other_worktree_path);
+                               strbuf_addf(&other_worktree_path, 
"%s/%s/gitdir", main_path.buf, d->d_name);
+
+                               if (stat(other_worktree_path.buf, &st))
+                                       continue;
+
+                               strbuf_reset(&path);
+                               strbuf_read_file(&path, 
other_worktree_path.buf, st.st_size);
+                               strbuf_strip_suffix(&path, "/.git\n");
+
+                               printf("%s\n", path.buf);
+                       }
+                       strbuf_release(&other_worktree_path);
+                       strbuf_release(&path);
+               }
+               closedir(dir);
+       }
+       strbuf_release(&main_path);
+       return 0;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
        struct option options[] = {
@@ -328,5 +393,7 @@ int cmd_worktree(int ac, const char **av, const char 
*prefix)
                return add(ac - 1, av + 1, prefix);
        if (!strcmp(av[1], "prune"))
                return prune(ac - 1, av + 1, prefix);
+       if (!strcmp(av[1], "list"))
+               return list(ac - 1, av + 1, prefix);
        usage_with_options(worktree_usage, options);
 }
diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh
new file mode 100755
index 0000000..8e3dbbc
--- /dev/null
+++ b/t/t2027-worktree-list.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='test git worktree list'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit init
+'
+
+test_expect_success '"list" all worktrees from main' '
+       git rev-parse --show-toplevel >expect &&
+       git worktree add --detach here master &&
+       git -C here rev-parse --show-toplevel >>expect &&
+       git worktree list >actual &&
+       test_cmp expect actual &&
+       rm -rf here &&
+       git worktree prune
+'
+test_expect_success '"list" all worktrees from linked' '
+       git rev-parse --show-toplevel >expect &&
+       git worktree add --detach here master &&
+       git -C here rev-parse --show-toplevel >>expect &&
+       git -C here worktree list >actual &&
+       test_cmp expect actual &&
+       rm -rf here &&
+       git worktree prune
+'
+
+test_done
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to