]> git.ipfire.org Git - thirdparty/git.git/commitdiff
ls-tree: fix expansion of repeated %(path)
authorRené Scharfe <l.s.r@web.de>
Sat, 14 Jan 2023 14:37:53 +0000 (15:37 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sun, 15 Jan 2023 03:22:26 +0000 (19:22 -0800)
expand_show_tree() borrows the base strbuf given to us by read_tree() to
build the full path of the current entry when handling %(path).  Only
its indirect caller, show_tree_fmt(), removes the added entry name.
That works fine as long as %(path) is only included once in the format
string, but accumulates duplicates if it's repeated:

   $ git ls-tree --format='%(path) %(path) %(path)' HEAD M*
   Makefile MakefileMakefile MakefileMakefileMakefile

Reset the length after each use to get the same expansion every time;
here's the behavior with this patch:

   $ ./git ls-tree --format='%(path) %(path) %(path)' HEAD M*
   Makefile Makefile Makefile

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/ls-tree.c
t/t3104-ls-tree-format.sh

index 8a1bf2fa4d97fa7e32121f9ae74d1f4f75dd34ac..c3284610ddc6a6231b61d0050bb4d931e8d4abda 100644 (file)
@@ -97,9 +97,12 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
                const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
                struct strbuf quoted = STRBUF_INIT;
                struct strbuf sbuf = STRBUF_INIT;
+               size_t baselen = data->base->len;
+
                strbuf_addstr(data->base, data->pathname);
                name = relative_path(data->base->buf, prefix, &sbuf);
                quote_c_style(name, &quoted, NULL, 0);
+               strbuf_setlen(data->base, baselen);
                strbuf_addbuf(sb, &quoted);
                strbuf_release(&sbuf);
                strbuf_release(&quoted);
@@ -143,7 +146,6 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
 static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
                         const char *pathname, unsigned mode, void *context)
 {
-       size_t baselen;
        int recurse = 0;
        struct strbuf sb = STRBUF_INIT;
        enum object_type type = object_type(mode);
@@ -163,12 +165,10 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
        if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
                return 0;
 
-       baselen = base->len;
        strbuf_expand(&sb, format, expand_show_tree, &data);
        strbuf_addch(&sb, line_termination);
        fwrite(sb.buf, sb.len, 1, stdout);
        strbuf_release(&sb);
-       strbuf_setlen(base, baselen);
        return recurse;
 }
 
index 7f1eb699d3ed6ed4afadc3f682c9ae8b79aef0e5..7e6c4dc5dadaa1941e6646a4f79db932d71b3f4a 100755 (executable)
@@ -37,6 +37,12 @@ test_ls_tree_format () {
        '
 }
 
+test_expect_success "ls-tree --format='%(path) %(path) %(path)' HEAD top-file" '
+       git ls-tree --format="%(path) %(path) %(path)" HEAD top-file.t >actual &&
+       echo top-file.t top-file.t top-file.t >expect &&
+       test_cmp expect actual
+'
+
 test_ls_tree_format \
        "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
        ""