when we have a file structure like that
/foo
/bar
a.json
/baz
b.json
and then you run git ls-files foo/bar/**/*
it return both a.json and b.json
but if you write a script to do that
import { spawnSync } from 'node:child_process';
const pattern = 'foo/bar/**/*';
const lsFiles = spawnSync(
`git`,
['ls-files', pattern],
{
encoding: 'utf8',
},
).stdout;
console.log(lsFiles);
it only return b.json
but not a.json
you can test it here https://github.com/robertIsaac/spawn-reprod
When using spawnSync
, any arguments that you pass to the executable won't be expanded by your shell, which means that you're running the equivalent of this command:
git ls-files 'foo/bar/**/*'
(notice the single quotes around the glob pattern)
The expansion is then done by git
, which follows the rules as documented in the gitignore
documentation, and those rules work differently from how a typical shell works.
In this case, foo/bar/**/*
will not match files in foo/bar
, only files in subdirectories (or subdirectories of subdirectories) of foo/bar
, which results in the response that you see:
$ git ls-files 'foo/bar/**/*'
foo/bar/baz/b.json
If you change the pattern to foo/bar/**
, it will work similarly to your shell pattern:
$ git ls-files 'foo/bar/**'
foo/bar/a.json
foo/bar/baz/b.json