You have files that you want to ignore, but that have no business being in the project's .gitignore: a a local test script, some draft assets. Adding them to .gitignore would mean committing your personal clutter for everyone. Leaving them alone means git status keeps nagging about untracked files.
Git has a built-in answer for this, .git/info/exclude, but it's tucked away inside .git/ where I never look, and I tend to forget what's in it. I wanted something visible, right at the root of the repo, that works the same way in all my local repositories.
Step 1: a global excludes file
Git lets you define an additional ignore file with core.excludesfile. Most people point it to a global file in their home directory. The trick here is to give it a relative path instead:
git config --global core.excludesfile .gitignore-local
Every repo now can have its own optional .gitignore-local, read just like a regular .gitignore, but never shared.
There's one catch: the .gitignore-local file itself shows up as untracked. The fix is to make it ignore itself, by having .gitignore-local as its first line:
.gitignore-local
# local files you want to ignore but not share via regular .gitignore:
test-script.py
assets/img/test-logo.png
Doing that by hand in every repo gets old fast.
Step 2: a git ignore-local alias
So here's an alias that takes care of it:
git config --global alias.ignore-local '!f() {
file=.gitignore-local
grep -qxF "$file" "$file" 2>/dev/null || echo "$file" >> "$file"
[ $# -eq 0 ] && { cat "$file"; return; }
for p in "$@"; do
grep -qxF -- "$p" "$file" || echo "$p" >> "$file"
done
}; f'
What it does:
- Shell aliases (the ones starting with
!) always run from the root of the repository, so the file lands in the right place even if you call the alias from a subdirectory. - If
.gitignore-localdoesn't exist yet, or exists without its self-ignoring line, that line is added. - Each pattern is appended only once, so no duplicates.
- Called without arguments, it just prints the current list.
Usage
git ignore-local omgyes "*.mp3" # ignore stuff locally
git ignore-local # show what's ignored
And git status stays clean:
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
If you ever wonder why a file is ignored, git check-ignore -v <file> tells you which rule matched and in which file.