31

I'm using msysgit (1.7.9), and I'm looking for the right invocation of the git ls-files command to show just the (tracked) files and directories at the current level, either from the index, or the current working directory if that's easier.

Essentially it would give a directory listing similar that that you would see on Github. Coming from Windows, I'm not too familiar with the right way of doing the globbing(?).

Philip Oakley
  • 12,527
  • 9
  • 46
  • 67

7 Answers7

27

I think you want git ls-tree HEAD sed'd to taste. The second word of ls-tree's output will be tree for directories, blob for files, commit for submodules, the filename is everything after the ascii tab.

Edit: adapting from @iegik's comment and to better fit the question as asked,

git ls-files . | sed s,/.*,/, | uniq

will list the indexed files starting at the current level and collapse directories to their first component.

jthill
  • 48,781
  • 4
  • 72
  • 120
  • 3
    `git ls-files | awk -F / '{print $1}' | uniq | xargs ls -dl --color=auto` – iegik Jul 23 '16 at 08:34
  • @iegik This is much better. I'd `sed s,/.*,,` instead of the awk, just 'cause it's shorter. Make this an answer, please? I'll bounty it. – jthill Jul 23 '16 at 10:00
  • Doesn't work on macOS — `ls: illegal option -- -`. I think you want, at least on macOS, `… | xargs 'ls' -Gdl` — someone else can check if that works on Linux, too? – ELLIOTTCABLE Jul 21 '17 at 23:38
  • Also, how to set this as a git alias? Non-shell aliases don't seem to support piping, but shell-aliases are run at the repository root, instead of the current directory (`git config --global alias.ls "\!git ls-files | awk -F / '{print $1}' | uniq | xargs 'ls' -Gdl"` is a start, but …) – ELLIOTTCABLE Jul 21 '17 at 23:47
19

I believe git ls-tree --name-only [branch] will do what you're looking for.

David Cain
  • 15,340
  • 11
  • 64
  • 73
  • 2
    Thanks, that's 95% the way there. Your `git ls-tree --name-only [branch]` lists both the directories and files in the same list (i.e. no trailing `/` for directories). I found `git ls-tree -d --name-only [branch]` will list just the directories. Part of the 'problem' is to spot submodule directories. – Philip Oakley May 04 '12 at 18:34
  • This should probably be the accepted answer! That, or it's a very good start towards one. :D – ELLIOTTCABLE Jul 21 '17 at 23:35
  • @PhilipOakley I was trying to do a similar thing, except with `git ls-files` rather than `git ls-tree`. With `git ls-files`, it looks like the equivalent option is `--directory` ( in that command, `-d` is short for `--deleted`). – Tyler Rick Feb 07 '18 at 22:23
6

To just list the files in the current working directory that are tracked by git, I found that the following is several times faster than using git ls-tree...:

ls | grep -f <(git ls-files)

It would take a little messing around with sed if you also wanted to include directories, something along the lines of:

ls | grep -f <(git ls-files | sed 's/\/.*//g' | sort | uniq)  

assuming you don't have any '/' characters in the names of your files. As well as...

ls -a | grep -f <(git ls-files | sed 's/\/.*//g' | sort | uniq)

in order to also list "invisible" (yet-tracked) files.

Alex Gray
  • 15,328
  • 9
  • 93
  • 115
AlexJWR
  • 111
  • 1
  • 5
  • This is nice... I wonder why I cannot add it as an `[alias]`?? `ls-tracked = "! f(){ ls | grep -f `fatal: bad config file` – Alex Gray Feb 16 '16 at 00:59
6

git ls-tree <tree-ish> is good and all, but I can't figure out how to specify the index as the <tree-ish>. (Although I'm sure there's bound to be some all-caps reference to do just that.)

Anyhow, ls-files implicitly works on the index so I might as well use that:

$ git ls-files | cut -d/ -f1 | uniq

This shows files and directories only in the current directory.

Change cut's -f argument to control depth. For instance, -f-2 (that's dash two) shows files and directories up to two levels deep:

$ git ls-files | cut -d/ -f-2 | uniq

IF you specify the <path> argument to ls-files, make sure to increase -f to accommodate the leading directories:

$ git ls-files foo/bar | cut -d/ -f-3 | uniq
antak
  • 17,411
  • 8
  • 64
  • 77
  • You can get a tree for the index with [`git write-tree`](https://git-scm.com/docs/git-write-tree). – jthill Jul 23 '17 at 02:50
2

I'm surprised this is so hard... but don't get me started on my griping about git.

A variant on jthill's answer seems to be aliasable (hey, I'm a linguist, I have a license to make new words). The variant is

ls -d `git ls-tree HEAD | sed -e "s/^.*\t//"`

This uses 'ls' to format the output, so you get color coding (if you use that), etc. It also works as an alias:

alias gitls='ls -d `git ls-tree HEAD | sed -e "s/^.*\t//"`'

FWIW, you can also alias the recursive command, so that you used the 'ls' formatting (e.g. if your path+filenames aren't too long, you'll get two column output, color coding of executables, etc.)

alias gitls-r='ls `git ls-files`'
Mike Maxwell
  • 469
  • 4
  • 9
  • Smart trick getting coloring through 'ls'. I personally prefer 'ls -ld', but that's me. Instead of piping through sed, you could use the --name-only (probably new) flag. – Uri Sep 02 '18 at 12:39
  • @Uri: right, --name-only is simpler, thanks! And using -ld is certainly simpler than some of the methods above for getting full info. – Mike Maxwell Sep 03 '18 at 15:41
  • For aliases using `--name-only`, see https://stackoverflow.com/a/57342429/10850071 – baltakatei Mar 05 '21 at 21:24
0

The simplest solution I have found, believe it or not, is to simply cd into the directory you want in your terminal. Running git ls-files in /project/src will give you results from only that directory, versus running it in /project

Not the most technical answer, but hey, it works!

Ryan
  • 150
  • 6
  • is simple and effective =), if you don't have any more folders in that folder you cd into, only issue is that if you have folders and other files will march down down those as well – pelos Aug 12 '21 at 18:59
-1

use this simple bash script for define subdirectory any level

dpolyakov
  • 240
  • 1
  • 3
  • 9