"git worktree list" porcelain format shows one attribute per line, each
attribute is listed with a label and value separated by a single space.
If any worktree is locked, a "locked" attribute is listed followed by the
reason, if available, otherwise only "locked" is shown.
In case the lock reason contains newline characters (i.e: LF or CRLF)
this will cause the format to break as each line should correspond to
one attribute. This leads to unwanted behavior, specially as the
porcelain is intended to be machine-readable. To address this shortcoming
let's teach "git worktree list" to escape any newline character before
outputting the locked reason for porcelain format.
Signed-off-by: Rafael Silva <redacted>
---
builtin/worktree.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index dedd4089e5..9156ccd67e 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -567,6 +567,24 @@ static int add(int ac, const char **av, const char *prefix)
return add_worktree(path, branch, &opts);
}
+static char *worktree_escape_reason(char *reason)
+{
+ struct strbuf escaped = STRBUF_INIT;
+ char *r;
+
+ for (r = reason; *r; r++) {
+ if (*r == '\r' && *(r + 1) && *(r + 1) == '\n') {
+ strbuf_addstr(&escaped, "\\r\\n");
+ r++;
+ } else if (*r == '\n')
+ strbuf_addstr(&escaped, "\\n");
+ else
+ strbuf_addch(&escaped, *r);
+ }
+
+ return strbuf_detach(&escaped, NULL);
+}
+
static void show_worktree_porcelain(struct worktree *wt)
{
printf("worktree %s\n", wt->path);@@ -580,9 +598,11 @@ static void show_worktree_porcelain(struct worktree *wt)
printf("branch %s\n", wt->head_ref);
if (worktree_lock_reason(wt)) {
- if (*wt->lock_reason)
- printf("locked %s\n", wt->lock_reason);
- else
+ if (*wt->lock_reason) {
+ char *reason = worktree_escape_reason(wt->lock_reason);
+ printf("locked %s\n", reason);
+ free(reason);
+ } else
printf("locked\n");
}
--
2.30.0.391.g469bf2a980