From 3c30abc25f9798a649cd7410555252dc7c952106 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Tue, 4 Aug 2026 10:52:23 +0100 Subject: [PATCH] Add script to list ignored files that exist --- _git-ls-ignored | 41 ++++++++++++++++++++++++++ git-ls-ignored | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 _git-ls-ignored create mode 100755 git-ls-ignored diff --git a/_git-ls-ignored b/_git-ls-ignored new file mode 100644 index 0000000..646e0d9 --- /dev/null +++ b/_git-ls-ignored @@ -0,0 +1,41 @@ +#compdef git-ls-ignored +#description List files which exist and are ignored by this repository. + +# Offer the paths the script would actually list, so the candidates match its +# rules rather than the --exclude-standard set used by zsh's own +# __git_ignored_other_files. _multi_parts descends one component at a time, so +# a directory holding ignored files completes as a way to narrow the listing. +__git-ls-ignored_files() { + local common_dir expl + local -a excludes files + + if (( $+opt_args[-g] + $+opt_args[--global] )); then + excludes=(--exclude-standard) + else + common_dir=$(_call_program common-dir git rev-parse --git-common-dir 2>/dev/null) + [[ -n $common_dir ]] || return 1 + [[ $common_dir == /* ]] || common_dir=$PWD/$common_dir + excludes=(--exclude-per-directory=.gitignore) + [[ -f $common_dir/info/exclude ]] && + excludes+=(--exclude-from=$common_dir/info/exclude) + fi + + files=(${(0)"$(_call_program ignored-files git ls-files -z --others --ignored \ + ${(q)excludes} 2>/dev/null)"}) + (( $#files )) || return 1 + + _wanted ignored-files expl 'ignored file' _multi_parts -f - / files +} + +_git-ls-ignored() { + _arguments -s -S \ + '(-d --directory)'{-d,--directory}'[list an ignored directory by name instead of its contents]' \ + '(-g --global)'{-g,--global}'[also apply the global core.excludesfile]' \ + '(-z)-z[terminate entries with NUL instead of newline]' \ + '(- *)'{-h,--help}'[show usage information]' \ + '*:pathspec:__git-ls-ignored_files' +} + +_git-ls-ignored "$@" + +# vim: ft=zsh diff --git a/git-ls-ignored b/git-ls-ignored new file mode 100755 index 0000000..6114866 --- /dev/null +++ b/git-ls-ignored @@ -0,0 +1,77 @@ +#!/bin/bash +# List files which exist in the working tree and are ignored by this +# repository's own rules: any .gitignore file, plus $GIT_DIR/info/exclude. +# +# Unlike `git status --ignored`, the global core.excludesfile is not consulted +# unless --global is given, so the output only contains paths this repository +# chose to ignore. +# +# Works inside a linked worktree, where .git is a file and info/exclude lives in +# the common git directory rather than next to the worktree. +# +# Usage: git-ls-ignored [] [--] [...] +# +# -d, --directory list an ignored directory by name instead of its contents +# -g, --global also apply the global core.excludesfile +# -z terminate entries with NUL instead of newline +# -h, --help show this message +# +# Paths are relative to the top of the working tree. Without a the +# whole working tree is listed, not just the current directory. + +# Print the comment block above, minus the shebang, as the help text. +usage() { + awk 'NR == 1 { next } /^#/ { sub(/^# ?/, ""); print; next } { exit }' "$0" +} + +global=false +options=() +paths=() + +while [ $# -gt 0 ]; do + case "$1" in + -d | --directory) options+=(--directory) ;; + -g | --global) global=true ;; + -z) options+=(-z) ;; + -h | --help) + usage + exit 0 + ;; + --) + shift + paths+=("$@") + break + ;; + -*) + echo "error: unknown option: $1" >&2 + usage >&2 + exit 1 + ;; + *) paths+=("$1") ;; + esac + shift +done + +# In a worktree .git is a file pointing at .git/worktrees/, which has no +# info/exclude of its own; Git reads the one in the common directory, so that is +# the file to point --exclude-from at. The common directory is reported relative +# to the current directory unless it happens to be absolute. +common_dir=$(git rev-parse --git-common-dir) || exit $? +case "$common_dir" in + /*) ;; + *) common_dir="$PWD/$common_dir" ;; +esac + +if $global; then + # .gitignore, info/exclude and core.excludesfile. + excludes=(--exclude-standard) +else + excludes=(--exclude-per-directory=.gitignore) + # --exclude-from is fatal on a missing file, and info/exclude is optional. + if [ -f "$common_dir/info/exclude" ]; then + excludes+=("--exclude-from=$common_dir/info/exclude") + fi +fi + +git ls-files --others --ignored --full-name "${excludes[@]}" "${options[@]}" \ + -- "${paths[@]:-:/}"