From: "Phillip Wood via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Eric Sunshine <sunshine@sunshineco.com>,
Phillip Wood <phillip.wood@dunelm.org.uk>,
Phillip Wood <phillip.wood@dunelm.org.uk>
Subject: [PATCH] worktree: add -z option for list subcommand
Date: Fri, 25 Feb 2022 15:08:47 +0000 [thread overview]
Message-ID: <pull.1164.git.1645801727732.gitgitgadget@gmail.com> (raw)
From: Phillip Wood <phillip.wood@dunelm.org.uk>
Add a -z option to be used in conjunction with --porcelain that gives
NUL-terminated output. This enables 'worktree list --porcelain' to
handle worktree paths that contain newlines.
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---
worktree: add -z option for list subcommand
Add a -z option to be used in conjunction with --porcelain that gives
NUL-terminated output. This enables 'worktree list --porcelain' to
handle worktree paths that contain newlines.
For a previous discussion of the merits of adding a -z option vs quoting
the worktree path see
https://lore.kernel.org/git/CAPig+cT-9sjmkdWFEcFS=rg9ziV9b6uWNMpQ8BTYP-a258La6Q@mail.gmail.com/
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1164%2Fphillipwood%2Fwip%2Fworktree-list-nul-termination-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1164/phillipwood/wip/worktree-list-nul-termination-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1164
Documentation/git-worktree.txt | 15 +++++++++++----
builtin/worktree.c | 33 +++++++++++++++++++++------------
t/t2402-worktree-list.sh | 21 +++++++++++++++++++++
3 files changed, 53 insertions(+), 16 deletions(-)
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 9e862fbcf79..a3fcd498df7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]] [-b <new-branch>] <path> [<commit-ish>]
-'git worktree list' [-v | --porcelain]
+'git worktree list' [-v | --porcelain [-z]]
'git worktree lock' [--reason <string>] <worktree>
'git worktree move' <worktree> <new-path>
'git worktree prune' [-n] [-v] [--expire <expire>]
@@ -223,7 +223,13 @@ This can also be set up as the default behaviour by using the
--porcelain::
With `list`, output in an easy-to-parse format for scripts.
This format will remain stable across Git versions and regardless of user
- configuration. See below for details.
+ configuration. It is recommended to combine this with `-z`.
+ See below for details.
+
+-z::
+ When `--porcelain` is specified with `list` terminate each line with a
+ NUL rather than a newline. This makes it possible to parse the output
+ when a worktree path contains a newline character.
-q::
--quiet::
@@ -411,7 +417,8 @@ working tree itself.
Porcelain Format
~~~~~~~~~~~~~~~~
-The porcelain format has a line per attribute. Attributes are listed with a
+The porcelain format has a line per attribute. If `-z` is given then the lines
+are terminated with NUL rather than a newline. Attributes are listed with a
label and value separated by a single space. Boolean attributes (like `bare`
and `detached`) are listed as a label only, and are present only
if the value is true. Some attributes (like `locked`) can be listed as a label
@@ -449,7 +456,7 @@ prunable gitdir file points to non-existent location
------------
-If the lock reason contains "unusual" characters such as newline, they
+Unless `-z` is used any "unusual" characters in the lock reason such as newlines
are escaped and the entire reason is quoted as explained for the
configuration variable `core.quotePath` (see linkgit:git-config[1]).
For Example:
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 0d0809276fe..b4cc586f5c5 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -575,35 +575,38 @@ static int add(int ac, const char **av, const char *prefix)
return add_worktree(path, branch, &opts);
}
-static void show_worktree_porcelain(struct worktree *wt)
+static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
{
const char *reason;
- printf("worktree %s\n", wt->path);
+ printf("worktree %s%c", wt->path, line_terminator);
if (wt->is_bare)
- printf("bare\n");
+ printf("bare%c", line_terminator);
else {
- printf("HEAD %s\n", oid_to_hex(&wt->head_oid));
+ printf("HEAD %s%c", oid_to_hex(&wt->head_oid), line_terminator);
if (wt->is_detached)
- printf("detached\n");
+ printf("detached%c", line_terminator);
else if (wt->head_ref)
- printf("branch %s\n", wt->head_ref);
+ printf("branch %s%c", wt->head_ref, line_terminator);
}
reason = worktree_lock_reason(wt);
if (reason && *reason) {
struct strbuf sb = STRBUF_INIT;
- quote_c_style(reason, &sb, NULL, 0);
- printf("locked %s\n", sb.buf);
+ if (line_terminator) {
+ quote_c_style(reason, &sb, NULL, 0);
+ reason = sb.buf;
+ }
+ printf("locked %s%c", reason, line_terminator);
strbuf_release(&sb);
} else if (reason)
- printf("locked\n");
+ printf("locked%c", line_terminator);
reason = worktree_prune_reason(wt, expire);
if (reason)
- printf("prunable %s\n", reason);
+ printf("prunable %s%c", reason, line_terminator);
- printf("\n");
+ fputc(line_terminator, stdout);
}
static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
@@ -681,12 +684,15 @@ static void pathsort(struct worktree **wt)
static int list(int ac, const char **av, const char *prefix)
{
int porcelain = 0;
+ int line_terminator = '\n';
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_SET_INT('z', NULL, &line_terminator,
+ N_("fields are separated with NUL character"), '\0'),
OPT_END()
};
@@ -696,6 +702,8 @@ static int list(int ac, const char **av, const char *prefix)
usage_with_options(worktree_usage, options);
else if (verbose && porcelain)
die(_("options '%s' and '%s' cannot be used together"), "--verbose", "--porcelain");
+ else if (!line_terminator && !porcelain)
+ die(_("'-z' requires '--porcelain'"));
else {
struct worktree **worktrees = get_worktrees();
int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
@@ -708,7 +716,8 @@ static int list(int ac, const char **av, const char *prefix)
for (i = 0; worktrees[i]; i++) {
if (porcelain)
- show_worktree_porcelain(worktrees[i]);
+ show_worktree_porcelain(worktrees[i],
+ line_terminator);
else
show_worktree(worktrees[i], path_maxlen, abbrev);
}
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index c8a5a0aac6d..48d5d30d709 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -64,6 +64,27 @@ test_expect_success '"list" all worktrees --porcelain' '
test_cmp expect actual
'
+test_expect_success '"list" all worktrees --porcelain -z' '
+ test_when_finished "rm -rf here _actual actual expect &&
+ git worktree prune" &&
+ printf "worktree %sQHEAD %sQbranch %sQQ" \
+ "$(git rev-parse --show-toplevel)" \
+ $(git rev-parse HEAD --symbolic-full-name HEAD) >expect &&
+ git worktree add --detach here main &&
+ printf "worktree %sQHEAD %sQdetachedQQ" \
+ "$(git -C here rev-parse --show-toplevel)" \
+ "$(git rev-parse HEAD)" >>expect &&
+ git worktree list --porcelain -z >_actual &&
+ cat _actual | tr "\0" Q >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '"list" -z fails without --porcelain' '
+ test_when_finished "rm -rf here && git worktree prune" &&
+ git worktree add --detach here main &&
+ test_must_fail git worktree list -z
+'
+
test_expect_success '"list" all worktrees with locked annotation' '
test_when_finished "rm -rf locked unlocked out && git worktree prune" &&
git worktree add --detach locked main &&
base-commit: dab1b7905d0b295f1acef9785bb2b9cbb0fdec84
--
gitgitgadget
next reply other threads:[~2022-02-25 15:08 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-25 15:08 Phillip Wood via GitGitGadget [this message]
2022-02-25 17:59 ` [PATCH] worktree: add -z option for list subcommand Junio C Hamano
2022-02-28 8:35 ` Eric Sunshine
2022-02-28 16:10 ` Phillip Wood
2022-02-28 17:16 ` Junio C Hamano
2022-02-28 16:00 ` Phillip Wood
2022-02-28 8:16 ` Eric Sunshine
2022-02-28 11:08 ` Phillip Wood
2022-02-28 9:47 ` Jean-Noël Avila
2022-02-28 10:57 ` Phillip Wood
2022-03-31 16:21 ` [PATCH v2] " Phillip Wood via GitGitGadget
2022-03-31 20:37 ` Junio C Hamano
2022-04-04 15:47 ` Phillip Wood
2023-05-11 4:11 ` Eric Sunshine
-- strict thread matches above, loose matches on Subject: below --
2021-01-05 10:29 [PATCH 5/7] worktree: `list` escape lock reason in --porcelain Phillip Wood
2021-01-05 11:02 ` [PATCH] worktree: add -z option for list subcommand Phillip Wood
2021-01-07 3:34 ` Eric Sunshine
2021-01-08 10:33 ` Phillip Wood
2021-01-10 7:27 ` Eric Sunshine
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.1164.git.1645801727732.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=phillip.wood@dunelm.org.uk \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).