Is there a way to make tree not show files that are ignored in .gitignore?
- 1,677
- 4
- 27
- 35
- 413
- 4
- 6
-
3If you really want to consider all possible ignored files, try to parse the output of [`git ls-files`](https://git-scm.com/docs/git-ls-files). – Franklin Yu Jun 22 '16 at 07:31
6 Answers
Another way is possible if you're using tree 1.8.0
since it supports the --fromfile flag:
--fromfileReads a directory listing from a file rather than the file-system. Paths provided on the command line are files to read from rather than directories to search. The dot (
.) directory indicates that tree should read paths from standard input.
We could use git ls-tree to get all non-git-ignored files in a project, and pipe the output to tree.
Assuming we have a git repository, where ignored files are ignored in .gitignore:
git_repo
├── .gitignore
├── bar
│ ├── b.txt
│ └── ignored
├── foo
│ ├── a.txt
│ └── ignored
└── ignored
The following command:
git ls-tree -r --name-only HEAD | tree --fromfile
Gives:
.
├── .gitignore
├── bar
│ └── b.txt
└── foo
└── a.txt
2 directories, 3 files
Or if you need a specific path:
git ls-tree -r --name-only HEAD foo | tree --fromfile
Gives:
.
└── a.txt
0 directories, 1 file
Caveats
- Beware that changes such as deleted or renamed files that haven't already been committed can cause
git ls-treeto appear out of sync.
- 22,130
- 27
- 68
- 117
- 309
- 2
- 4
Ripgrep respects .gitignore (and some other 'ignore' files) by default and can be used as an alternative to git commands. The difference is that all files (except hidden files) are listed even if they haven't been commited to version control yet:
rg --files | tree --fromfile
This can be used to create a shell function that sorts directories first and allows for more flexible usage (specifying the directory path and adding ripgrep flags):
rg,tree() { rg --files $@|tree --fromfile --dirsfirst }
Requires tree > 1.8 as pointed out in another answer.
- 117
- 1
- 6
-
+1 for Ripgrep if you can get it. I like this solution as it's more elegant, presumably faster, and aligns better with expected behavior in comparison to my answer. – Zephyro Jun 29 '21 at 21:45
-
1This answer ignores "hidden" (for example files that start with '.') files tracked by git. Fortunately, it's easily modified to fix this - https://unix.stackexchange.com/a/691245/185953 – Ben Feb 18 '22 at 17:25
Tree supports the -I flag.
-I patternDo not list those files that match the wild-card pattern.
Tree supports a single pattern which will exclude all files/directories that match it.
Git's ignore files are a bit more complicated:
Exclusion can come from multiple files, $HOME/.config/git/ignore, the output of git config --get core.excludesfile , .gitignore (per directory), ~/.gitignore, and more (see man gitignore).
Another problem is the patterns that tree supports differs from what git does (as noted by @Brad Urani).
But we can get close-ish ...
tree -I "$(grep -hvE '^$|^#' {~/,,$(git rev-parse --show-toplevel)/}.gitignore|sed 's:/$::'|tr \\n '\|')"
Or as a function:
function gtree {
git_ignore_files=("$(git config --get core.excludesfile)" .gitignore ~/.gitignore)
ignore_pattern="$(grep -hvE '^$|^#' "${git_ignore_files[@]}" 2>/dev/null|sed 's:/$::'|tr '\n' '\|')"
if git status &> /dev/null && [[ -n "${ignore_pattern}" ]]; then
tree -I "${ignore_pattern}" "${@}"
else
tree "${@}"
fi
}
- 22,130
- 27
- 68
- 117
-
Nice! Am I correct that the fact that this is not removing comment lines from .gitignore will cause problems? – Brad Urani Jun 22 '16 at 05:56
-
I guess it's also not going to respect .gitignore files outside the home dir – Brad Urani Jun 22 '16 at 06:23
-
@BradUrani - i've updated my answer to use `git` commands to try find the file. What that returns will depend on what setting you have. – Jun 22 '16 at 07:18
-
This isn't working for me, I think because my `~/.gitignore` is a symlink. I've been trying to find a way to rely on `git` to tell me what's ignored, but all my efforts to find the right combination keep running into difficulties or ambiguous situations. – Brad Urani Jun 22 '16 at 21:31
-
Also it looks like `tree -I` does respect all the globbing options that `.gitignore` does which makes me think there's no perfect solution. Best approximation I came up with last night is `echo "node_modules|tmp|_build" > ~/.treeignore` and `tree -I "$(cat ~/.treeignore)"` – Brad Urani Jun 22 '16 at 21:33
-
This doesn't work correctly if your `.gitignore` has directories with a trailing slash. Adding `sed 's_/|_|_g'` to the end of the `grep` pipeline fixed it for me. – Michael Mior May 14 '18 at 17:52
-
Very nice. Thanks. Just one question: If the global gitignore file is _not_ ~/.gitignore, the script will output `grep:
/.gitignore: No such file or directory` - how do I use a different filename? – friederbluemle Nov 08 '18 at 06:27
This might help: list git ignored files in an almost-compatible way for tree filter:
function tree-git-ignore {
# tree respecting gitignore
local ignored=$(git ls-files -ci --others --directory --exclude-standard)
local ignored_filter=$(echo "$ignored" \
| egrep -v "^#.*$|^[[:space:]]*$" \
| sed 's~^/~~' \
| sed 's~/$~~' \
| tr "\\n" "|")
tree --prune -I ".git|${ignored_filter: : -1}" "$@"
}
- 194
- 1
- 4
tree has a --gitignore option as of version 2.0.0, released Dec 2021.
https://gitlab.com/OldManProgrammer/unix-tree/-/blob/master/CHANGES
- 189
- 2
- 10
- 51
- 1
- 2
This is a modification of @adigitoleo's answer that also lists hidden files (for example, files starting with '.' on Unix) tracked by Git:
# --files : Print files that would be searched
# --hidden : Print files starting with '.'
# --ignore : Respect .gitignore
# --glob '!.git/' : ignore .git/ directory
tree-git-seen() {
rg --files --hidden --ignore --glob '!.git/' "$@" \
| tree --fromfile -a
}
- 267
- 2
- 14
- 238
- 1
- 10
-
1Pending edit: I rearranged the parameters to make it more readable. The previous arrangement `--ignore --hidden --files` reads like it does the the exact opposite! – Iain Samuel McLean Elder Apr 20 '22 at 15:21