git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] ls-tree: test for the regression in 9c4d58ff2c3

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
May 31, 2022, 17:21 UTC
Message-ID
<patch-1.1-0fdfec624eb-20220531T171908Z-avarab@gmail.com>
In-Reply-To
<xmqqee28spni.fsf@gitster.g>

Add a test for the regression introduced in my 9c4d58ff2c3 (ls-tree: split up "fast path" callbacks, 2022-03-23) and fixed in 350296cc789 (ls-tree: `-l` should not imply recursive listing, 2022-04-04), and test for the test of ls-tree option/mode combinations to make sure we don't have other blind spots.

The setup for these tests can be shared with those added in the 1041d58b4d9 (Merge branch 'tl/ls-tree-oid-only', 2022-04-04) topic, so let's create a new t/lib-t3100.sh to help them share data.

The existing tests in "t3104-ls-tree-format.sh" didn't deal with a submodule, which they'll now encounter with as the setup_basic_ls_tree_data() sets one up.

This extensive testing should give us confidence that there were no further regressions in this area. The lack of testing was noted back in [1], but unfortunately we didn't cover that blind-spot before 9c4d58ff2c3.

1. https://lore.kernel.org/git/211115.86o86lqe3c.gmgdl@evledraar.gmail.com/
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
On Thu, Apr 07 2022, Junio C Hamano wrote:
Show 30 quoted lines
> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>>>>> Let's not go too cute like this.  This forces the caller to remember
>>>>> which among 6, 7, and 8 corresponds to which option.  It is too ugly
>>>>> to live.
>>>>
>>>> I think it's rather elegant actually, but to be fair it would, per:
>>>>
>>>>    git grep '<&[1-9]| [1-9]<<-'
>>>>
>>>> Be the user with the most FD's using this sort of pattern.
>>>
>>> Please give a clear explanation why "-d" has to be 6, "-r" 7 and
>>> "-t" 8, that can be used by developers as a memory aid to help them
>>> write new tests using the helper.
>>
>> It's documented when test-lib.sh does the redirection, since Fabian
>> Stelzer's a6714088e0c (test-lib: make BAIL_OUT() work in tests and
>> prereq, 2021-12-01).
>
> Sorry, but that is not what I asked.  I know what we use lower file
> descriptors for, and I didn't ask why we start from 6 (as opposed to
> 3).
>
> The updated helper forces our developers to know that the expected
> result for "-d" has to go to #6 (not #7 or #8), and "-r" to #7 (not
> #6 or #8), etc., in order to write new tests using it, and in order
> to spot a mistake while reviewing such new tests.
>
> It is an invitation to unmaintainable mess.  Don't encourage it.

I came up with this at the time, but didn't submit it since we were in the rc period.

But since we're past that I think it makes sense to have a test for the regression we fixed, the below is a lot less magical, but larger by line count. I think this alternate test implementation should address the concerns you had.

Range-diff:
1:  ed83b3b74ab ! 1:  0fdfec624eb ls-tree: fix --long implying -r regression in 9c4d58ff2c3
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    ls-tree: fix --long implying -r regression in 9c4d58ff2c3
    +    ls-tree: test for the regression in 9c4d58ff2c3
     
    -    Fix a regression introduced in 9c4d58ff2c3 (ls-tree: split up "fast
    -    path" callbacks, 2022-03-23), and improve the tests added in the
    -    1041d58b4d9 (Merge branch 'tl/ls-tree-oid-only', 2022-04-04) topic it
    -    was merged as part of to test the full expected output of various
    -    "ls-tree" options with and without -r.
    +    Add a test for the regression introduced in my 9c4d58ff2c3 (ls-tree:
    +    split up "fast path" callbacks, 2022-03-23) and fixed in
    +    350296cc789 (ls-tree: `-l` should not imply recursive listing,
    +    2022-04-04), and test for the test of ls-tree option/mode combinations
    +    to make sure we don't have other blind spots.
     
    -    Let's fix it, and also add tests not only for that blindspot, but also
    -    any other potential blindspots. To that end test the "modes" of -d, -r
    -    and -t (as well as "no mode") against all of the format options.
    +    The setup for these tests can be shared with those added in the
    +    1041d58b4d9 (Merge branch 'tl/ls-tree-oid-only', 2022-04-04) topic, so
    +    let's create a new t/lib-t3100.sh to help them share data.
     
    -    These tests all pass with that topic reverted (except those that would
    -    fail because they're testing the new --object-only feature introduced
    -    in that topic), which should give us confidence that there were no
    -    further regressions in this area.
    +    The existing tests in "t3104-ls-tree-format.sh" didn't deal with a
    +    submodule, which they'll now encounter with as the
    +    setup_basic_ls_tree_data() sets one up.
    +
    +    This extensive testing should give us confidence that there were no
    +    further regressions in this area. The lack of testing was noted back
    +    in [1], but unfortunately we didn't cover that blind-spot before
    +    9c4d58ff2c3.
    +
    +    1. https://lore.kernel.org/git/211115.86o86lqe3c.gmgdl@evledraar.gmail.com/
     
    -    Reported-By: Josh Steadmon <steadmon@google.com>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    - ## builtin/ls-tree.c ##
    -@@ builtin/ls-tree.c: static int show_tree_long(const struct object_id *oid, struct strbuf *base,
    - 	printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
    - 	       find_unique_abbrev(data.oid, abbrev), size_text);
    - 	show_tree_common_default_long(base, pathname, data.base->len);
    --	return 1;
    -+	return recurse;
    - }
    - 
    - static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
    + ## t/lib-t3100.sh (new) ##
    +@@
    ++#!/bin/sh
    ++
    ++setup_basic_ls_tree_data () {
    ++	mkdir dir &&
    ++	test_commit dir/sub-file &&
    ++	test_commit top-file &&
    ++	git clone . submodule &&
    ++	git submodule add ./submodule &&
    ++	git commit -m"add submodule"
    ++}
     
      ## t/t3104-ls-tree-format.sh ##
    -@@ t/t3104-ls-tree-format.sh: test_ls_tree_format () {
    - 	fmtopts=$3 &&
    - 	shift 2 &&
    +@@ t/t3104-ls-tree-format.sh: test_description='ls-tree --format'
    + 
    + TEST_PASSES_SANITIZE_LEAK=true
    + . ./test-lib.sh
    ++. "$TEST_DIRECTORY"/lib-t3100.sh
    + 
    + test_expect_success 'ls-tree --format usage' '
    + 	test_expect_code 129 git ls-tree --format=fmt -l HEAD &&
    +@@ t/t3104-ls-tree-format.sh: test_expect_success 'ls-tree --format usage' '
    + '
    + 
    + test_expect_success 'setup' '
    +-	mkdir dir &&
    +-	test_commit dir/sub-file &&
    +-	test_commit top-file
    ++	setup_basic_ls_tree_data
    + '
      
    + test_ls_tree_format () {
    +
    + ## t/t3105-ls-tree-output.sh (new) ##
    +@@
    ++#!/bin/sh
    ++
    ++test_description='ls-tree output'
    ++
    ++TEST_PASSES_SANITIZE_LEAK=true
    ++. ./test-lib.sh
    ++. "$TEST_DIRECTORY"/lib-t3100.sh
    ++
    ++test_expect_success 'ls-tree --format usage' '
    ++	test_expect_code 129 git ls-tree --format=fmt -l HEAD &&
    ++	test_expect_code 129 git ls-tree --format=fmt --name-only HEAD &&
    ++	test_expect_code 129 git ls-tree --format=fmt --name-status HEAD
    ++'
    ++
    ++test_expect_success 'setup' '
    ++	setup_basic_ls_tree_data
    ++'
    ++
    ++test_ls_tree_format_mode_output () {
    ++	local opts=$1 &&
    ++	shift &&
     +	cat >expect &&
    -+	cat <&6 >expect.-d &&
    -+	cat <&7 >expect.-r &&
    -+	cat <&8 >expect.-t &&
     +
    -+	for opt in '' '-d' '-r' '-t'
    ++	while test $# -gt 0
     +	do
    -+		test_expect_success "'ls-tree $opts${opt:+ $opt}' output" '
    -+			git ls-tree ${opt:+$opt }$opts $opt HEAD >actual &&
    -+			test_cmp expect${opt:+.$opt} actual
    ++		local mode="$1" &&
    ++		shift &&
    ++
    ++		test_expect_success "'ls-tree $opts${mode:+ $mode}' output" '
    ++			git ls-tree ${mode:+$mode }$opts HEAD >actual &&
    ++			test_cmp expect actual
     +		'
    ++
    ++		case "$opts" in
    ++		--full-tree)
    ++			test_expect_success "'ls-tree $opts${mode:+ $mode}' output (via subdir, fails)" '
    ++				test_must_fail git -C dir ls-tree --full-name ${mode:+$mode }$opts HEAD -- ../
    ++			'
    ++			;;
    ++		*)
    ++			test_expect_success "'ls-tree $opts${mode:+ $mode}' output (via subdir)" '
    ++				git -C dir ls-tree --full-name ${mode:+$mode }$opts HEAD -- ../ >actual &&
    ++				test_cmp expect actual
    ++			'
    ++			;;
    ++		esac
     +	done
    ++}
     +
    - 	test_expect_success "ls-tree '--format=<$format>' is like options '$opts $fmtopts'" '
    - 		git ls-tree $opts -r HEAD >expect &&
    - 		git ls-tree --format="$format" -r $fmtopts HEAD >actual &&
    -@@ t/t3104-ls-tree-format.sh: test_ls_tree_format () {
    - 
    - test_ls_tree_format \
    - 	"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
    --	""
    -+	"" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	OUT_D
    -+	100644 blob $(git rev-parse HEAD:dir/sub-file.t)	dir/sub-file.t
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_R
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)" \
    --	"--long"
    -+	"--long" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	040000 tree $(git rev-parse HEAD:dir)       -	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)       9	top-file.t
    -+	OUT
    -+	040000 tree $(git rev-parse HEAD:dir)       -	dir
    -+	OUT_D
    -+	100644 blob $(git rev-parse HEAD:dir/sub-file.t)      13	dir/sub-file.t
    -+	100644 blob $(git rev-parse HEAD:top-file.t)       9	top-file.t
    -+	OUT_R
    -+	040000 tree $(git rev-parse HEAD:dir)       -	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)       9	top-file.t
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(path)" \
    --	"--name-only"
    -+	"--name-only" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    ++# test exact output of option (none, --long, ...) and mode (none and
    ++# -d, -r -t) and combinations
    ++test_expect_success 'setup: HEAD_* variables' '
    ++	HEAD_gitmodules=$(git rev-parse HEAD:.gitmodules) &&
    ++	HEAD_dir=$(git rev-parse HEAD:dir) &&
    ++	HEAD_top_file=$(git rev-parse HEAD:top-file.t) &&
    ++	HEAD_submodule=$(git rev-parse HEAD:submodule) &&
    ++	HEAD_dir_sub_file=$(git rev-parse HEAD:dir/sub-file.t)
    ++'
    ++## opt =
    ++test_ls_tree_format_mode_output "" "" "-t" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++test_ls_tree_format_mode_output "" "-d" <<-EOF
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "" "-r" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	100644 blob $HEAD_dir_sub_file	dir/sub-file.t
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++## opt = --long
    ++test_ls_tree_format_mode_output "--long" "" "-t" <<-EOF
    ++	100644 blob $HEAD_gitmodules      61	.gitmodules
    ++	040000 tree $HEAD_dir       -	dir
    ++	160000 commit $HEAD_submodule       -	submodule
    ++	100644 blob $HEAD_top_file       9	top-file.t
    ++	EOF
    ++test_ls_tree_format_mode_output "--long" "-d" <<-EOF
    ++	040000 tree $HEAD_dir       -	dir
    ++	160000 commit $HEAD_submodule       -	submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "--long" "-r" <<-EOF
    ++	100644 blob $HEAD_gitmodules      61	.gitmodules
    ++	100644 blob $HEAD_dir_sub_file      13	dir/sub-file.t
    ++	160000 commit $HEAD_submodule       -	submodule
    ++	100644 blob $HEAD_top_file       9	top-file.t
    ++	EOF
    ++## opt = --name-only
    ++test_ls_tree_format_mode_output "--name-only" "" "-t" <<-EOF
    ++	.gitmodules
     +	dir
    ++	submodule
     +	top-file.t
    -+	OUT
    ++	EOF
    ++test_ls_tree_format_mode_output "--name-only" "-d" <<-EOF
     +	dir
    -+	OUT_D
    ++	submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "--name-only" "-r" <<-EOF
    ++	.gitmodules
     +	dir/sub-file.t
    ++	submodule
     +	top-file.t
    -+	OUT_R
    -+	dir
    -+	top-file.t
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(objectname)" \
    --	"--object-only"
    -+	"--object-only" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	$(git rev-parse HEAD:dir)
    -+	$(git rev-parse HEAD:top-file.t)
    -+	OUT
    -+	$(git rev-parse HEAD:dir)
    -+	OUT_D
    -+	$(git rev-parse HEAD:dir/sub-file.t)
    -+	$(git rev-parse HEAD:top-file.t)
    -+	OUT_R
    -+	$(git rev-parse HEAD:dir)
    -+	$(git rev-parse HEAD:top-file.t)
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(objectname)" \
    - 	"--object-only --abbrev" \
    --	"--abbrev"
    -+	"--abbrev" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	$(git rev-parse HEAD:dir | test_copy_bytes 7)
    -+	$(git rev-parse HEAD:top-file.t| test_copy_bytes 7)
    -+	OUT
    -+	$(git rev-parse HEAD:dir | test_copy_bytes 7)
    -+	OUT_D
    -+	$(git rev-parse HEAD:dir/sub-file.t | test_copy_bytes 7)
    -+	$(git rev-parse HEAD:top-file.t | test_copy_bytes 7)
    -+	OUT_R
    -+	$(git rev-parse HEAD:dir | test_copy_bytes 7)
    -+	$(git rev-parse HEAD:top-file.t | test_copy_bytes 7)
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
    - 	"-t" \
    --	"-t"
    -+	"-t" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	OUT_D
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:dir/sub-file.t)	dir/sub-file.t
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_R
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
    - 	"--full-name" \
    --	"--full-name"
    -+	"--full-name" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	OUT_D
    -+	100644 blob $(git rev-parse HEAD:dir/sub-file.t)	dir/sub-file.t
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_R
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_T
    - 
    - test_ls_tree_format \
    - 	"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
    - 	"--full-tree" \
    --	"--full-tree"
    -+	"--full-tree" \
    -+	<<-OUT 6<<-OUT_D 7<<-OUT_R 8<<-OUT_T
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	OUT_D
    -+	100644 blob $(git rev-parse HEAD:dir/sub-file.t)	dir/sub-file.t
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_R
    -+	040000 tree $(git rev-parse HEAD:dir)	dir
    -+	100644 blob $(git rev-parse HEAD:top-file.t)	top-file.t
    -+	OUT_T
    - 
    - test_done
    ++	EOF
    ++## opt = --object-only
    ++test_ls_tree_format_mode_output "--object-only" "" "-t" <<-EOF
    ++	$HEAD_gitmodules
    ++	$HEAD_dir
    ++	$HEAD_submodule
    ++	$HEAD_top_file
    ++	EOF
    ++test_ls_tree_format_mode_output "--object-only" "-d" <<-EOF
    ++	$HEAD_dir
    ++	$HEAD_submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "--object-only" "-r" <<-EOF
    ++	$HEAD_gitmodules
    ++	$HEAD_dir_sub_file
    ++	$HEAD_submodule
    ++	$HEAD_top_file
    ++	EOF
    ++## opt = --object-only --abbrev
    ++test_expect_success 'setup: HEAD_short_* variables' '
    ++	HEAD_short_gitmodules=$(git rev-parse --short HEAD:.gitmodules) &&
    ++	HEAD_short_dir=$(git rev-parse --short HEAD:dir) &&
    ++	HEAD_short_top_file=$(git rev-parse --short HEAD:top-file.t) &&
    ++	HEAD_short_submodule=$(git rev-parse --short HEAD:submodule) &&
    ++	HEAD_short_dir_sub_file=$(git rev-parse --short HEAD:dir/sub-file.t)
    ++'
    ++test_ls_tree_format_mode_output "--object-only --abbrev" "" "-t" <<-EOF
    ++	$HEAD_short_gitmodules
    ++	$HEAD_short_dir
    ++	$HEAD_short_submodule
    ++	$HEAD_short_top_file
    ++	EOF
    ++test_ls_tree_format_mode_output "--object-only --abbrev" "-d" <<-EOF
    ++	$HEAD_short_dir
    ++	$HEAD_short_submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "--object-only --abbrev" "-r" <<-EOF
    ++	$HEAD_short_gitmodules
    ++	$HEAD_short_dir_sub_file
    ++	$HEAD_short_submodule
    ++	$HEAD_short_top_file
    ++	EOF
    ++## opt = --full-name
    ++test_ls_tree_format_mode_output "--full-name" "" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++test_ls_tree_format_mode_output "--full-name" "-d" <<-EOF
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "--full-name" "-r" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	100644 blob $HEAD_dir_sub_file	dir/sub-file.t
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++test_ls_tree_format_mode_output "--full-name" "-t" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++## opt = --full-tree
    ++test_ls_tree_format_mode_output "--full-tree" "" "-t" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++test_ls_tree_format_mode_output "--full-tree" "-d" <<-EOF
    ++	040000 tree $HEAD_dir	dir
    ++	160000 commit $HEAD_submodule	submodule
    ++	EOF
    ++test_ls_tree_format_mode_output "--full-tree" "-r" <<-EOF
    ++	100644 blob $HEAD_gitmodules	.gitmodules
    ++	100644 blob $HEAD_dir_sub_file	dir/sub-file.t
    ++	160000 commit $HEAD_submodule	submodule
    ++	100644 blob $HEAD_top_file	top-file.t
    ++	EOF
    ++
    ++test_done
 t/lib-t3100.sh            |  10 ++
 t/t3104-ls-tree-format.sh |   5 +-
 t/t3105-ls-tree-output.sh | 192 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 204 insertions(+), 3 deletions(-)
 create mode 100644 t/lib-t3100.sh
 create mode 100755 t/t3105-ls-tree-output.sh
diff --git a/t/lib-t3100.sh b/t/lib-t3100.sh
new file mode 100644
index 00000000000..eabb5fd8034
--- /dev/null
+++ b/t/lib-t3100.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+setup_basic_ls_tree_data () {
+	mkdir dir &&
+	test_commit dir/sub-file &&
+	test_commit top-file &&
+	git clone . submodule &&
+	git submodule add ./submodule &&
+	git commit -m"add submodule"
+}
diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh
index 0769a933d69..383896667b6 100755
--- a/t/t3104-ls-tree-format.sh
+++ b/t/t3104-ls-tree-format.sh
@@ -4,6 +4,7 @@ test_description='ls-tree --format'
 
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-t3100.sh
 
 test_expect_success 'ls-tree --format usage' '
 	test_expect_code 129 git ls-tree --format=fmt -l HEAD &&
@@ -12,9 +13,7 @@ test_expect_success 'ls-tree --format usage' '
 '
 
 test_expect_success 'setup' '
-	mkdir dir &&
-	test_commit dir/sub-file &&
-	test_commit top-file
+	setup_basic_ls_tree_data
 '
 
 test_ls_tree_format () {
diff --git a/t/t3105-ls-tree-output.sh b/t/t3105-ls-tree-output.sh
new file mode 100755
index 00000000000..29511d9331b
--- /dev/null
+++ b/t/t3105-ls-tree-output.sh
@@ -0,0 +1,192 @@
+#!/bin/sh
+
+test_description='ls-tree output'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-t3100.sh
+
+test_expect_success 'ls-tree --format usage' '
+	test_expect_code 129 git ls-tree --format=fmt -l HEAD &&
+	test_expect_code 129 git ls-tree --format=fmt --name-only HEAD &&
+	test_expect_code 129 git ls-tree --format=fmt --name-status HEAD
+'
+
+test_expect_success 'setup' '
+	setup_basic_ls_tree_data
+'
+
+test_ls_tree_format_mode_output () {
+	local opts=$1 &&
+	shift &&
+	cat >expect &&
+
+	while test $# -gt 0
+	do
+		local mode="$1" &&
+		shift &&
+
+		test_expect_success "'ls-tree $opts${mode:+ $mode}' output" '
+			git ls-tree ${mode:+$mode }$opts HEAD >actual &&
+			test_cmp expect actual
+		'
+
+		case "$opts" in
+		--full-tree)
+			test_expect_success "'ls-tree $opts${mode:+ $mode}' output (via subdir, fails)" '
+				test_must_fail git -C dir ls-tree --full-name ${mode:+$mode }$opts HEAD -- ../
+			'
+			;;
+		*)
+			test_expect_success "'ls-tree $opts${mode:+ $mode}' output (via subdir)" '
+				git -C dir ls-tree --full-name ${mode:+$mode }$opts HEAD -- ../ >actual &&
+				test_cmp expect actual
+			'
+			;;
+		esac
+	done
+}
+
+# test exact output of option (none, --long, ...) and mode (none and
+# -d, -r -t) and combinations
+test_expect_success 'setup: HEAD_* variables' '
+	HEAD_gitmodules=$(git rev-parse HEAD:.gitmodules) &&
+	HEAD_dir=$(git rev-parse HEAD:dir) &&
+	HEAD_top_file=$(git rev-parse HEAD:top-file.t) &&
+	HEAD_submodule=$(git rev-parse HEAD:submodule) &&
+	HEAD_dir_sub_file=$(git rev-parse HEAD:dir/sub-file.t)
+'
+## opt =
+test_ls_tree_format_mode_output "" "" "-t" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+test_ls_tree_format_mode_output "" "-d" <<-EOF
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	EOF
+test_ls_tree_format_mode_output "" "-r" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	100644 blob $HEAD_dir_sub_file	dir/sub-file.t
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+## opt = --long
+test_ls_tree_format_mode_output "--long" "" "-t" <<-EOF
+	100644 blob $HEAD_gitmodules      61	.gitmodules
+	040000 tree $HEAD_dir       -	dir
+	160000 commit $HEAD_submodule       -	submodule
+	100644 blob $HEAD_top_file       9	top-file.t
+	EOF
+test_ls_tree_format_mode_output "--long" "-d" <<-EOF
+	040000 tree $HEAD_dir       -	dir
+	160000 commit $HEAD_submodule       -	submodule
+	EOF
+test_ls_tree_format_mode_output "--long" "-r" <<-EOF
+	100644 blob $HEAD_gitmodules      61	.gitmodules
+	100644 blob $HEAD_dir_sub_file      13	dir/sub-file.t
+	160000 commit $HEAD_submodule       -	submodule
+	100644 blob $HEAD_top_file       9	top-file.t
+	EOF
+## opt = --name-only
+test_ls_tree_format_mode_output "--name-only" "" "-t" <<-EOF
+	.gitmodules
+	dir
+	submodule
+	top-file.t
+	EOF
+test_ls_tree_format_mode_output "--name-only" "-d" <<-EOF
+	dir
+	submodule
+	EOF
+test_ls_tree_format_mode_output "--name-only" "-r" <<-EOF
+	.gitmodules
+	dir/sub-file.t
+	submodule
+	top-file.t
+	EOF
+## opt = --object-only
+test_ls_tree_format_mode_output "--object-only" "" "-t" <<-EOF
+	$HEAD_gitmodules
+	$HEAD_dir
+	$HEAD_submodule
+	$HEAD_top_file
+	EOF
+test_ls_tree_format_mode_output "--object-only" "-d" <<-EOF
+	$HEAD_dir
+	$HEAD_submodule
+	EOF
+test_ls_tree_format_mode_output "--object-only" "-r" <<-EOF
+	$HEAD_gitmodules
+	$HEAD_dir_sub_file
+	$HEAD_submodule
+	$HEAD_top_file
+	EOF
+## opt = --object-only --abbrev
+test_expect_success 'setup: HEAD_short_* variables' '
+	HEAD_short_gitmodules=$(git rev-parse --short HEAD:.gitmodules) &&
+	HEAD_short_dir=$(git rev-parse --short HEAD:dir) &&
+	HEAD_short_top_file=$(git rev-parse --short HEAD:top-file.t) &&
+	HEAD_short_submodule=$(git rev-parse --short HEAD:submodule) &&
+	HEAD_short_dir_sub_file=$(git rev-parse --short HEAD:dir/sub-file.t)
+'
+test_ls_tree_format_mode_output "--object-only --abbrev" "" "-t" <<-EOF
+	$HEAD_short_gitmodules
+	$HEAD_short_dir
+	$HEAD_short_submodule
+	$HEAD_short_top_file
+	EOF
+test_ls_tree_format_mode_output "--object-only --abbrev" "-d" <<-EOF
+	$HEAD_short_dir
+	$HEAD_short_submodule
+	EOF
+test_ls_tree_format_mode_output "--object-only --abbrev" "-r" <<-EOF
+	$HEAD_short_gitmodules
+	$HEAD_short_dir_sub_file
+	$HEAD_short_submodule
+	$HEAD_short_top_file
+	EOF
+## opt = --full-name
+test_ls_tree_format_mode_output "--full-name" "" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+test_ls_tree_format_mode_output "--full-name" "-d" <<-EOF
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	EOF
+test_ls_tree_format_mode_output "--full-name" "-r" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	100644 blob $HEAD_dir_sub_file	dir/sub-file.t
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+test_ls_tree_format_mode_output "--full-name" "-t" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+## opt = --full-tree
+test_ls_tree_format_mode_output "--full-tree" "" "-t" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+test_ls_tree_format_mode_output "--full-tree" "-d" <<-EOF
+	040000 tree $HEAD_dir	dir
+	160000 commit $HEAD_submodule	submodule
+	EOF
+test_ls_tree_format_mode_output "--full-tree" "-r" <<-EOF
+	100644 blob $HEAD_gitmodules	.gitmodules
+	100644 blob $HEAD_dir_sub_file	dir/sub-file.t
+	160000 commit $HEAD_submodule	submodule
+	100644 blob $HEAD_top_file	top-file.t
+	EOF
+
+test_done
-- 
2.36.1.1100.g16130010d07
Previous: Junio C HamanoNext: Johannes Schindelin
Message 91 of 107 in “ls-tree: "--object-only" and "--format" opts”
  1. 00/13 ls-tree: "--object-only" and "--format" optsTeng Long, Feb 8, 2022
  2. 01/13 ls-tree: remove commented-out codeTeng Long, Feb 8, 2022
  3. 03/13 ls-tree: use "enum object_type", not {blob,tree,commit}_typeTeng Long, Feb 8, 2022
  4. 12/13 ls-tree: introduce function "fast_path()"Teng Long, Feb 8, 2022
  5. Ævar Arnfjörð BjarmasonFeb 19, 2022
  6. 13/13 ls-tree.c: support --object-only option for "git-ls-tree"Teng Long, Feb 8, 2022
  7. Ævar Arnfjörð BjarmasonFeb 19, 2022
  8. 04/13 ls-tree: use "size_t", not "int" for "struct strbuf"'s "len"Teng Long, Feb 8, 2022
  9. 02/13 ls-tree: add missing braces to "else" armsTeng Long, Feb 8, 2022
  10. 06/13 ls-tree: simplify nesting if/else logic in "show_tree()"Teng Long, Feb 8, 2022
  11. Ævar Arnfjörð BjarmasonFeb 19, 2022
  12. 05/13 ls-tree: rename "retval" to "recurse" in "show_tree()"Teng Long, Feb 8, 2022
  13. 07/13 ls-tree: fix "--name-only" and "--long" combined use bugTeng Long, Feb 8, 2022
  14. Ævar Arnfjörð BjarmasonFeb 19, 2022
  15. 08/13 ls-tree: slightly refactor `show_tree()`Teng Long, Feb 8, 2022
  16. Ævar Arnfjörð BjarmasonFeb 19, 2022
  17. 10/13 cocci: allow padding with `strbuf_addf()`Teng Long, Feb 8, 2022
  18. 09/13 ls-tree: introduce struct "show_tree_data"Teng Long, Feb 8, 2022
  19. 11/13 ls-tree.c: introduce "--format" optionTeng Long, Feb 8, 2022
  20. Ævar Arnfjörð BjarmasonFeb 19, 2022
  21. 00/12 ls-tree: "--object-only" and "--format" optsTeng Long, Mar 4, 2022
  22. 01/12 ls-tree: remove commented-out codeTeng Long, Mar 4, 2022
  23. 02/12 ls-tree: add missing braces to "else" armsTeng Long, Mar 4, 2022
  24. 03/12 ls-tree: use "enum object_type", not {blob,tree,commit}_typeTeng Long, Mar 4, 2022
  25. 04/12 ls-tree: use "size_t", not "int" for "struct strbuf"'s "len"Teng Long, Mar 4, 2022
  26. 05/12 ls-tree: rename "retval" to "recurse" in "show_tree()"Teng Long, Mar 4, 2022
  27. 06/12 ls-tree: simplify nesting if/else logic in "show_tree()"Teng Long, Mar 4, 2022
  28. 07/12 ls-tree: fix "--name-only" and "--long" combined use bugTeng Long, Mar 4, 2022
  29. 08/12 ls-tree: slightly refactor `show_tree()`Teng Long, Mar 4, 2022
  30. 09/12 ls-tree: introduce struct "show_tree_data"Teng Long, Mar 4, 2022
  31. 10/12 cocci: allow padding with `strbuf_addf()`Teng Long, Mar 4, 2022
  32. 11/12 ls-tree: introduce "--format" optionTeng Long, Mar 4, 2022
  33. 12/12 ls-tree: support --object-only option for "git-ls-tree"Teng Long, Mar 4, 2022
  34. 0/7 fixups/suggestions/musings for tl/ls-tree-oid-onlyÆvar Arnfjörð Bjarmason, Mar 10, 2022
  35. 1/7 ls-tree tests: add tests for --name-statusÆvar Arnfjörð Bjarmason, Mar 10, 2022
  36. 2/7 ls-tree tests: exhaustively test fast & slow path for --formatÆvar Arnfjörð Bjarmason, Mar 10, 2022
  37. 5/7 ls-tree: detect and error on --name-only --name-statusÆvar Arnfjörð Bjarmason, Mar 10, 2022
  38. 4/7 ls-tree: remove unused "MODE_UNSPECIFIED"Ævar Arnfjörð Bjarmason, Mar 10, 2022
  39. 3/7 ls-tree: remove dead labelsÆvar Arnfjörð Bjarmason, Mar 10, 2022
  40. 6/7 ls-tree: remove FIELD_*, just use MODE_*Ævar Arnfjörð Bjarmason, Mar 10, 2022
  41. 7/7 ls-tree: split up "fast path" callbacksÆvar Arnfjörð Bjarmason, Mar 10, 2022
  42. Teng LongMar 17, 2022
  43. Ævar Arnfjörð BjarmasonMar 17, 2022
  44. 00/16 ls-tree: "--object-only" and "--format" optsTeng Long, Mar 21, 2022
  45. 01/16 ls-tree: remove commented-out codeTeng Long, Mar 21, 2022
  46. 02/16 ls-tree: add missing braces to "else" armsTeng Long, Mar 21, 2022
  47. 03/16 ls-tree: use "enum object_type", not {blob,tree,commit}_typeTeng Long, Mar 21, 2022
  48. 04/16 ls-tree: use "size_t", not "int" for "struct strbuf"'s "len"Teng Long, Mar 21, 2022
  49. 05/16 ls-tree: rename "retval" to "recurse" in "show_tree()"Teng Long, Mar 21, 2022
  50. 06/16 ls-tree: simplify nesting if/else logic in "show_tree()"Teng Long, Mar 21, 2022
  51. 07/16 ls-tree: fix "--name-only" and "--long" combined use bugTeng Long, Mar 21, 2022
  52. 08/16 ls-tree: slightly refactor `show_tree()`Teng Long, Mar 21, 2022
  53. 09/16 ls-tree: introduce struct "show_tree_data"Teng Long, Mar 21, 2022
  54. 10/16 cocci: allow padding with `strbuf_addf()`Teng Long, Mar 21, 2022
  55. 11/16 ls-tree: introduce "--format" optionTeng Long, Mar 21, 2022
  56. Ævar Arnfjörð BjarmasonMar 21, 2022
  57. 12/16 ls-tree: support --object-only option for "git-ls-tree"Teng Long, Mar 21, 2022
  58. 13/16 ls-tree tests: add tests for --name-statusTeng Long, Mar 21, 2022
  59. Ævar Arnfjörð BjarmasonMar 21, 2022
  60. 14/16 ls-tree: detect and error on --name-only --name-statusTeng Long, Mar 21, 2022
  61. 15/16 ls-tree: remove FIELD_*, just use MODE_*Teng Long, Mar 21, 2022
  62. Ævar Arnfjörð BjarmasonMar 21, 2022
  63. 16/16 ls-tree: split up "fast path" callbacksTeng Long, Mar 21, 2022
  64. Ævar Arnfjörð BjarmasonMar 21, 2022
  65. Teng LongMar 23, 2022
  66. Junio C HamanoMar 21, 2022
  67. 00/15 ls-tree: "--object-only" and "--format" optsTeng Long, Mar 23, 2022
  68. 01/15 ls-tree tests: add tests for --name-statusTeng Long, Mar 23, 2022
  69. 02/15 ls-tree: remove commented-out codeTeng Long, Mar 23, 2022
  70. 03/15 ls-tree: add missing braces to "else" armsTeng Long, Mar 23, 2022
  71. 04/15 ls-tree: use "enum object_type", not {blob,tree,commit}_typeTeng Long, Mar 23, 2022
  72. 05/15 ls-tree: use "size_t", not "int" for "struct strbuf"'s "len"Teng Long, Mar 23, 2022
  73. 06/15 ls-tree: rename "retval" to "recurse" in "show_tree()"Teng Long, Mar 23, 2022
  74. 07/15 ls-tree: simplify nesting if/else logic in "show_tree()"Teng Long, Mar 23, 2022
  75. 08/15 ls-tree: fix "--name-only" and "--long" combined use bugTeng Long, Mar 23, 2022
  76. 09/15 ls-tree: slightly refactor `show_tree()`Teng Long, Mar 23, 2022
  77. 10/15 ls-tree: introduce struct "show_tree_data"Teng Long, Mar 23, 2022
  78. 11/15 cocci: allow padding with `strbuf_addf()`Teng Long, Mar 23, 2022
  79. 12/15 ls-tree: introduce "--format" optionTeng Long, Mar 23, 2022
  80. 13/15 ls-tree: support --object-only option for "git-ls-tree"Teng Long, Mar 23, 2022
  81. 14/15 ls-tree: detect and error on --name-only --name-statusTeng Long, Mar 23, 2022
  82. 15/15 ls-tree: split up "fast path" callbacksTeng Long, Mar 23, 2022
  83. Josh SteadmonApr 4, 2022
  84. ls-tree: `-l` should not imply recursive listingJosh Steadmon, Apr 4, 2022
  85. ls-tree: fix --long implying -r regression in 9c4d58ff2c3Ævar Arnfjörð Bjarmason, Apr 4, 2022
  86. Junio C HamanoApr 6, 2022
  87. Ævar Arnfjörð BjarmasonApr 6, 2022
  88. Junio C HamanoApr 6, 2022
  89. Ævar Arnfjörð BjarmasonApr 7, 2022
  90. Junio C HamanoApr 7, 2022
  91. ls-tree: test for the regression in 9c4d58ff2c3Ævar Arnfjörð Bjarmason, May 31, 2022
  92. Johannes SchindelinJun 2, 2022
  93. Junio C HamanoJun 2, 2022
  94. js/ci-github-workflow-markup output regression (was: [PATCH] ls-tree: test for the regression in 9c4d58ff2c3)Ævar Arnfjörð Bjarmason, Jun 3, 2022
  95. Junio C HamanoJun 3, 2022
  96. Ævar Arnfjörð BjarmasonJun 3, 2022
  97. Junio C HamanoJun 7, 2022
  98. Ævar Arnfjörð BjarmasonJun 7, 2022
  99. Johannes SchindelinJun 8, 2022
  100. Ævar Arnfjörð BjarmasonJun 9, 2022
  101. ls-tree: test for the regression in 9c4d58ff2c3Ævar Arnfjörð Bjarmason, Jun 3, 2022
  102. Johannes SchindelinJun 8, 2022
  103. Teng LongApr 7, 2022
  104. Junio C HamanoApr 6, 2022
  105. Junio C HamanoMar 23, 2022
  106. Teng LongMar 24, 2022
  107. Ævar Arnfjörð BjarmasonFeb 28, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.