'git worktree list' iterates through the worktree list, and outputs
the worktree dir. By default, only the worktree path is output.
Supported options include:
--skip-bare: do not output bare worktrees
--verbose: include the current head and ref (if applicable), also
decorate bare worktrees
Signed-off-by: Michael Rappazzo <[email protected]>
---
Documentation/git-worktree.txt | 10 +++-
builtin/worktree.c | 63 +++++++++++++++++++++
t/t2027-worktree-list.sh | 122 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+), 1 deletion(-)
create mode 100755 t/t2027-worktree-list.sh
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index fb68156..b9339ed 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' [-v] [--skip-bare]
DESCRIPTION
-----------
@@ -59,6 +60,10 @@ prune::
Prune working tree information in $GIT_DIR/worktrees.
+list::
+
+List the main worktree followed by each of the linked worktrees.
+
OPTIONS
-------
@@ -89,10 +94,14 @@ OPTIONS
-v::
--verbose::
With `prune`, report all removals.
+ With `list`, show more information about each worktree. This includes
+ if the worktree is bare, the revision currently checked out, and the
+ branch currently checked out (or 'detached HEAD' if none).
--expire <time>::
With `prune`, only expire unused working trees older than <time>.
+
DETAILS
-------
Each linked working tree has a private sub-directory in the repository's
@@ -167,7 +176,6 @@ performed manually, such as:
- `remove` to remove a linked working tree and its administrative files (and
warn if the working tree is dirty)
- `mv` to move or rename a working tree and update its administrative files
-- `list` to list linked working trees
- `lock` to prevent automatic pruning of administrative files (for instance,
for a working tree on a portable device)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 71bb770..a0c0fe8 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -8,10 +8,13 @@
#include "run-command.h"
#include "sigchain.h"
#include "refs.h"
+#include "utf8.h"
+#include "worktree.h"
static const char * const worktree_usage[] = {
N_("git worktree add [<options>] <path> <branch>"),
N_("git worktree prune [<options>]"),
+ N_("git worktree list [<options>]"),
NULL
};
@@ -359,6 +362,64 @@ static int add(int ac, const char **av, const char *prefix)
return add_worktree(path, branch, &opts);
}
+static int list(int ac, const char **av, const char *prefix)
+{
+ int no_bare = 0;
+
+ struct option options[] = {
+ OPT_BOOL(0, "skip-bare", &no_bare, N_("exclude bare worktrees
from the list")),
+ OPT__VERBOSE(&verbose, N_("include more worktree details")),
+ OPT_END()
+ };
+
+ ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ if (ac)
+ usage_with_options(worktree_usage, options);
+ else {
+ struct worktree_list *worktree_list = get_worktree_list();
+ struct worktree_list *orig = worktree_list;
+ struct strbuf sb = STRBUF_INIT;
+ int path_maxlen = 0;
+
+ if (verbose) {
+ while (worktree_list) {
+ int cur_len =
strlen(worktree_list->worktree->path);
+ if (cur_len > path_maxlen)
+ path_maxlen = cur_len;
+ worktree_list = worktree_list->next ?
worktree_list->next : NULL;
+ }
+ worktree_list = orig;
+ }
+ while (worktree_list) {
+ /* if this work tree is not bare OR if bare repos are
to be shown (default) */
+ if (!worktree_list->worktree->is_bare || !no_bare) {
+ strbuf_reset(&sb);
+ if (!verbose)
+ strbuf_addstr(&sb,
worktree_list->worktree->path);
+ else {
+ int cur_len =
strlen(worktree_list->worktree->path);
+ int utf8_adj = cur_len -
utf8_strwidth(worktree_list->worktree->path);
+ strbuf_addf(&sb, "%-*s ", 1 +
path_maxlen + utf8_adj, worktree_list->worktree->path);
+ if (worktree_list->worktree->is_bare)
+ strbuf_addstr(&sb, "(bare)");
+ else {
+ strbuf_addf(&sb, "%s ",
find_unique_abbrev(worktree_list->worktree->head_sha1, DEFAULT_ABBREV));
+ if
(!worktree_list->worktree->is_detached)
+ strbuf_addf(&sb,
"[%s]", shorten_unambiguous_ref(worktree_list->worktree->head_ref, 0));
+ else
+ strbuf_addstr(&sb,
"(detached HEAD)");
+ }
+ }
+ printf("%s\n", sb.buf);
+ }
+ worktree_list = worktree_list->next ?
worktree_list->next : NULL;
+ }
+ worktree_list_release(orig);
+ strbuf_release(&sb);
+ }
+ return 0;
+}
+
int cmd_worktree(int ac, const char **av, const char *prefix)
{
struct option options[] = {
@@ -371,5 +432,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..246890c
--- /dev/null
+++ b/t/t2027-worktree-list.sh
@@ -0,0 +1,122 @@
+#!/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_expect_success '"list" all worktrees --verbose from main' '
+ echo "$(git rev-parse --show-toplevel) $(git rev-parse --short
HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
+ git worktree add --detach here master &&
+ echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short
HEAD) (detached HEAD)" >>expect &&
+ git worktree list --verbose >actual &&
+ test_cmp expect actual &&
+ rm -rf here &&
+ git worktree prune
+'
+
+test_expect_success '"list" all worktrees --verbose from linked' '
+ echo "$(git rev-parse --show-toplevel) $(git rev-parse --short
HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
+ git worktree add --detach here master &&
+ echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short
HEAD) (detached HEAD)" >>expect &&
+ git -C here worktree list --verbose >actual &&
+ test_cmp expect actual &&
+ rm -rf here &&
+ git worktree prune
+'
+
+test_expect_success 'bare repo setup' '
+ git init --bare bare1 &&
+ echo "data" > file1 &&
+ git add file1 &&
+ git commit -m"File1: add data" &&
+ git push bare1 master &&
+ git reset --hard HEAD^
+'
+
+test_expect_success '"list" all worktrees from bare main' '
+ git -C bare1 worktree add --detach ../there master &&
+ echo "$(cd bare1 && pwd)" >expect &&
+ echo "$(git -C there rev-parse --show-toplevel)" >>expect &&
+ git -C bare1 worktree list >actual &&
+ test_cmp expect actual &&
+ rm -rf there &&
+ git -C bare1 worktree prune
+'
+
+test_expect_success '"list" all worktrees from bare main --skip-bare' '
+ git -C bare1 worktree add --detach ../there master &&
+ echo "$(git -C there rev-parse --show-toplevel)" >expect &&
+ git -C bare1 worktree list --skip-bare >actual &&
+ test_cmp expect actual &&
+ rm -rf there &&
+ git -C bare1 worktree prune
+'
+
+test_expect_success '"list" all worktrees from worktree with a bare main' '
+ git -C bare1 worktree add --detach ../there master &&
+ echo "$(cd bare1 && pwd)" >expect &&
+ echo "$(git -C there rev-parse --show-toplevel)" >>expect &&
+ git -C there worktree list >actual &&
+ test_cmp expect actual &&
+ rm -rf there &&
+ git -C bare1 worktree prune
+'
+
+test_expect_success '"list" all worktrees from worktree with a bare main
--skip-bare' '
+ git -C bare1 worktree add --detach ../there master &&
+ echo "$(git -C there rev-parse --show-toplevel)" >expect &&
+ git -C there worktree list --skip-bare >actual &&
+ test_cmp expect actual &&
+ rm -rf there &&
+ git -C bare1 worktree prune
+'
+
+test_expect_success '"list" all worktrees --verbose from bare main' '
+ git -C bare1 worktree add --detach ../there master &&
+ echo "$(cd bare1 && pwd) (bare)" >expect &&
+ echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse
--short HEAD) (detached HEAD)" >>expect &&
+ git -C bare1 worktree list --verbose >actual &&
+ test_cmp expect actual &&
+ rm -rf there &&
+ git -C bare1 worktree prune
+'
+
+test_expect_success '"list" all worktrees --verbose from worktree with a bare
main' '
+ git -C bare1 worktree add --detach ../there master &&
+ echo "$(cd bare1 && pwd) (bare)" >expect &&
+ echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse
--short HEAD) (detached HEAD)" >>expect &&
+ git -C there worktree list --verbose >actual &&
+ test_cmp expect actual &&
+ rm -rf there &&
+ git -C bare1 worktree prune
+'
+
+test_expect_success 'bare repo cleanup' '
+ rm -rf bare1
+'
+
+test_done
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html