summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-worktree.txt20
-rw-r--r--builtin/worktree.c14
-rwxr-xr-xt/t2402-worktree-list.sh31
3 files changed, 63 insertions, 2 deletions
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 240c3fd76b..f1bb1fa5f5 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -232,6 +232,8 @@ This can also be set up as the default behaviour by using the
-v::
--verbose::
With `prune`, report all removals.
++
+With `list`, output additional information about worktrees (see below).
--expire <time>::
With `prune`, only expire unused working trees older than `<time>`.
@@ -389,6 +391,24 @@ $ git worktree list
/path/to/prunable-worktree 5678abc (detached HEAD) prunable
------------
+For these annotations, a reason might also be available and this can be
+seen using the verbose mode. The annotation is then moved to the next line
+indented followed by the additional information.
+
+------------
+$ git worktree list --verbose
+/path/to/linked-worktree abcd1234 [master]
+/path/to/locked-worktree-no-reason abcd5678 (detached HEAD) locked
+/path/to/locked-worktree-with-reason 1234abcd (brancha)
+ locked: working tree path is mounted on a portable device
+/path/to/prunable-worktree 5678abc1 (detached HEAD)
+ prunable: gitdir file points to non-existent location
+------------
+
+Note that the annotation is moved to the next line if the additional
+information is available, otherwise it stays on the same line as the
+working tree itself.
+
Porcelain Format
~~~~~~~~~~~~~~~~
The porcelain format has a line per attribute. Attributes are listed with a
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 20944c266e..1cd5c2016e 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -604,6 +604,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
struct strbuf sb = STRBUF_INIT;
int cur_path_len = strlen(wt->path);
int path_adj = cur_path_len - utf8_strwidth(wt->path);
+ const char *reason;
strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, wt->path);
if (wt->is_bare)
@@ -621,10 +622,16 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_addstr(&sb, "(error)");
}
- if (worktree_lock_reason(wt))
+ reason = worktree_lock_reason(wt);
+ if (verbose && reason && *reason)
+ strbuf_addf(&sb, "\n\tlocked: %s", reason);
+ else if (reason)
strbuf_addstr(&sb, " locked");
- if (worktree_prune_reason(wt, expire))
+ reason = worktree_prune_reason(wt, expire);
+ if (verbose && reason)
+ strbuf_addf(&sb, "\n\tprunable: %s", reason);
+ else if (reason)
strbuf_addstr(&sb, " prunable");
printf("%s\n", sb.buf);
@@ -670,6 +677,7 @@ static int list(int ac, const char **av, const char *prefix)
struct option options[] = {
OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+ OPT__VERBOSE(&verbose, N_("show extended annotations and reasons, if available")),
OPT_EXPIRY_DATE(0, "expire", &expire,
N_("add 'prunable' annotation to worktrees older than <time>")),
OPT_END()
@@ -679,6 +687,8 @@ static int list(int ac, const char **av, const char *prefix)
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
if (ac)
usage_with_options(worktree_usage, options);
+ else if (verbose && porcelain)
+ die(_("--verbose and --porcelain are mutually exclusive"));
else {
struct worktree **worktrees = get_worktrees();
int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index 69342b7280..39a339e636 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -136,6 +136,37 @@ test_expect_success '"list" all worktrees with prunable consistent with "prune"'
test_i18ngrep ! "^Removing worktrees/unprunable" out
'
+test_expect_success '"list" --verbose and --porcelain mutually exclusive' '
+ test_must_fail git worktree list --verbose --porcelain
+'
+
+test_expect_success '"list" all worktrees --verbose with locked' '
+ test_when_finished "rm -rf locked1 locked2 out actual expect && git worktree prune" &&
+ git worktree add locked1 --detach &&
+ git worktree add locked2 --detach &&
+ git worktree lock locked1 &&
+ test_when_finished "git worktree unlock locked1" &&
+ git worktree lock locked2 --reason "with reason" &&
+ test_when_finished "git worktree unlock locked2" &&
+ echo "$(git -C locked2 rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >expect &&
+ printf "\tlocked: with reason\n" >>expect &&
+ git worktree list --verbose >out &&
+ grep "/locked1 *[0-9a-f].* locked$" out &&
+ sed -n "s/ */ /g;/\/locked2 *[0-9a-f].*$/,/locked: .*$/p" <out >actual &&
+ test_cmp actual expect
+'
+
+test_expect_success '"list" all worktrees --verbose with prunable' '
+ test_when_finished "rm -rf prunable out actual expect && git worktree prune" &&
+ git worktree add prunable --detach &&
+ echo "$(git -C prunable rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >expect &&
+ printf "\tprunable: gitdir file points to non-existent location\n" >>expect &&
+ rm -rf prunable &&
+ git worktree list --verbose >out &&
+ sed -n "s/ */ /g;/\/prunable *[0-9a-f].*$/,/prunable: .*$/p" <out >actual &&
+ test_i18ncmp actual expect
+'
+
test_expect_success 'bare repo setup' '
git init --bare bare1 &&
echo "data" >file1 &&