Repository navigation
Conversation
Lists a tree-ish with -r, -d, -t, --name-only, --name-status, --full-tree, -z and --abbrev, using git's literal path matching, cwd-relative paths and C-style quoting.
Covers gitlinks, quoted names, subdirectory cwds and every supported flag against the real binary.
Replaces the trailing-slash string encoding with a { path, listContents } filter so the matching rule lives in the type.
…s and -- before the tree-ish From a nested cwd, trees that contain the cwd now print as ../ (and ./), not ..; an empty path is fatal like git; the tree-ish may follow --, and no tree-ish prints usage with exit 129. Errors follow git's order. The walk reuses readTreeEntries (now exported) so a tree entry pointing at a blob fails instead of listing nothing.
Contributor
Author
|
@blindmansion could you review this when you have a moment? It adds |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #12 (#12)
Summary
git ls-treenow works. Before this change it sat inKNOWN_UNIMPLEMENTED_COMMANDS, sogit ls-tree -r HEADprinted "'ls-tree' is not implemented" and exited 1. Scripts and agents that check a committed file's mode or list files at a revision had to fall back tols-files -s(index only) orgit show <rev>:<dir>.Supported surface:
The tree-ish can be a commit, an annotated tag or a tree id, and
<rev>^{tree}works too. Output is<mode> SP <type> SP <object> TAB <path>, with040000 tree,160000 commitfor gitlinks, and100755/120000blobs.Before and after
How it works
src/commands/ls-tree.tsresolves the tree-ish withresolveRevisionand peels tags and commits down to a tree. It then walks the tree withreadTreeEntriesfromtree-ops.ts, the readerdiffTreesalready uses, which this PR exports.flattenTreecan't serve-tand-dbecause it drops directory entries. Going throughreadTreeEntriesalso means a tree entry that points at a blob stops the walk with "Expected tree object, got blob" and exit 1. Git exits 1 there too, witherror: Object <id> not a tree.The tree-ish is the first operand whether it comes before or after
--, sogit ls-tree -- HEADandgit ls-tree -r -- HEADwork like git. With no tree-ish at all it printsusage: git ls-tree [<options>] <tree-ish> [<path>...]and exits 129. Git prints the option list after that line. just-git prints the usage line only, like itsmergeandrebaseusage errors.Errors come in git's order. An unknown tree-ish fails first. An empty path comes next (
fatal: empty string is not a valid pathspec. please use . instead if you meant to match all paths, 128), checked across every path before any of them is resolved. A path outside the repository comes after that, andnot a tree objectcomes last.Path handling follows
builtin/ls-tree.crather than the shared pathspec code, because ls-tree treats paths differently from other commands:git ls-tree HEAD 'sp*'matches nothing, same as git.srcshows thesrctree entry itself.src/lists its contents.-r, the walk still descends into a tree when a path points inside it (git'sshow_recursive).git ls-tree HEAD src/lib/math.tsprints the blob, and-tadds thesrcandsrc/libtrees above it.-ddrops blobs but keeps gitlinks.-r -dimplies-t.../run.sh). A tree that contains the cwd prints with a trailing slash, so fromsrc/libthesrc/libtree is./and thesrctree is../.--full-treelists from the root with full paths.Paths are C-quoted the way git does with
core.quotePathon ("q\"uote.txt","\303\251.txt","tab\tname"), and printed raw under-z.--abbrevusesuniqueAbbrev,--abbrev=<n>clamps to 4, and--abbrev=0prints full ids, all matching git.Outside the command file, the PR exports
readTreeEntriesfromsrc/lib/tree-ops.ts. Registration touchessrc/commands/git.ts(registry entry, removal fromKNOWN_UNIMPLEMENTED_COMMANDS) and adds| "ls-tree"to theGitCommandNameunion insrc/git.ts. The registry is typedRecord<GitCommandName, ...>, so the command can't register without that one line.Tests
test/commands/ls-tree.test.tshas 31 in-memory tests with exact stdout, stderr and exit codes. They cover the root listing,-r,-d,-r -d,-r -t,--name-only/--name-status, a directory path with and without a trailing slash, a file path after--,-twith a nested path, literal (non-glob) paths, a subdirectory cwd with and without--full-tree,../paths,./and../for trees that contain the cwd,-z,--abbrevand--abbrev=4, a tree id as the tree-ish, the tree-ish after--, no tree-ish (usage, 129), an invalid tree-ish (fatal: Not a valid object name bogus, 128), a blob (fatal: not a tree object, 128), an empty path, a path outside the repository, and the order of those errors.test/interop/ls-tree.test.tsbuilds a repo with real git (executable, symlink, gitlink viaupdate-index --cacheinfo 160000, names with a space, a quote, a tab andé, an annotated tag). It then runs 50 invocations through both real git and just-git and asserts identical stdout, stderr and exit code. I checked that it catches defects by breaking quoting and the gitlink type. 17 of the first 40 cases failed. A separate test writes a tree whose040000entry points at a blob and checks that-rfails with exit 1, as git does.--and the bad tree entry failed before its fix.bun test: 3570 pass, 29 skip, 0 fail (baseline 3488 pass).Not included
<rev>:<path>as a tree-ish fails withfatal: Not a valid object name HEAD:dir(exit 128).resolveRevisiondoesn't parse<rev>:<path>at all.git showparses it on its own and only finds blobs, sogit show HEAD:dirhas the same gap. The fix belongs in the shared rev-parse code.4b825dc642cb6eb9a060e54bf8d69288fbee4904is built into git but doesn't resolve as a revision in just-git, sogit ls-tree 4b825dc...printsfatal: Not a valid object name 4b825dc...where git prints nothing and exits 0. This is already true on main.git rev-parseandgit difffail on it the same way.git ls-tree '') exits 1 with anEISDIRerror from ref lookup, where git printsfatal: Not a valid object nameand exits 128.git show ''does the same on main, so this also belongs in the shared rev-parse code.-l/--long,--full-name,--object-onlyand--formatare not implemented and fail as unknown options.core.quotePath=falseis not read. Non-ASCII names are always octal-quoted.