As you note indirectly, these aren't semantically equivalent since they act differently if /dir
is a file. However, if you somehow "know" that /dir
will in fact be a directory, /dir
and /dir/
would be the "efficient" ways to list these as they will omit opening-and-reading the directory.
Whether /dir/
is less efficient or just as efficient as /dir
depends on your OS and its readdir
implementation: when Git reads the directory /
(the top of the working tree), it gets the name components .
, ..
, README.txt
(assuming there is such a file), abc
(maybe a file, maybe a directory, we'll just assume there is something named abc
), dir
(a directory), and whatever else. It may also get a useful d_type
field: POSIX only requires a d_name
and d_ino
, but Linux and the BSDs have a d_type
field. The OS will fill in d_type
with one of:
Git will use this value, if it's available. If it is DT_DIR
, Git will know that dir
is a directory and won't need to call lstat
on the path when deciding whether the /dir/
entity matches. If it is DT_UNKNOWN
, Git won't know what kind of entity dir
represents and will need to call lstat
. However, for the /dir
anchored gitignore entry, Git doesn't care what kind of entity dir
represents, so it definitely won't need to call lstat
. But maybe it doesn't need to call lstat
anyway, so that this gains nothing.
(Should /dir
name a file and you want Git to store that file if it exists, or complain about it as untracked as appropriate, you should use /dir/
here and not worry about the cost of a single lstat
system call, even though it may be measured in hundreds of microseconds, or even low-digit milliseconds, rather than nanoseconds. But milliseconds do add up eventually, of course.)