# Git's Magic Files

[[nesbitt-io|Andrew Nesbitt]] catalogs the committed files that control how git behaves for everyone who clones a repository. Unlike `.git/` configuration, these files travel with the code and take effect automatically.

## The core seven

**.gitignore** is the one everyone knows — pattern-based exclusion of untracked files. Git evaluates ignore rules from multiple locations: per-directory `.gitignore` files, `.git/info/exclude` for local-only patterns, and a global ignore file. The `**` glob matches nested directories. One common gotcha: `.gitignore` only affects untracked files. If a file is already tracked, adding it to `.gitignore` does nothing until you `git rm --cached` it.

**.gitattributes** does far more than most teams realize. It configures LFS filters (`*.psd filter=lfs diff=lfs merge=lfs`), line ending normalization (`*.sh text eol=lf`), merge strategies (`package-lock.json merge=ours` to auto-resolve lockfile conflicts), and GitHub Linguist overrides (`vendor/* linguist-vendored` to exclude vendored code from language stats). Marking files as `binary` prevents git from attempting diffs or three-way merges on them.

**.mailmap** maps messy author identities to canonical ones. If someone committed under three different email addresses, mailmap collapses them into one for `git log`, `shortlog`, and `blame`. GitHub's contributor graphs ignore mailmap, though, so duplicates persist in the web UI.

**.git-blame-ignore-revs** lists commits that `git blame` should skip — the classic use case is a bulk formatting run that touches every file but changes no logic. GitHub, GitLab (since 15.4), and Gitea read this file automatically. Locally you need `git config blame.ignoreRevsFile .git-blame-ignore-revs`.

**.gitmodules** is created automatically by `git submodule add` and defines where submodule repos live and which branch to track.

**.lfsconfig** stores Git LFS endpoint URLs and transfer settings so LFS works without per-clone configuration.

**.gitmessage** is a commit message template, but unlike the others it requires manual setup (`git config commit.template .gitmessage`) per clone — it won't activate just by being in the repo.

## Forge-specific folders

Each git forge has its own config directory for CI workflows, issue templates, and CODEOWNERS: `.github/`, `.gitlab/`, `.gitea/`, `.forgejo/`, `.bitbucket/`. The interesting bit is the fallback chains — Forgejo checks `.forgejo/` then `.gitea/` then `.github/`, and Gitea checks `.gitea/` then `.github/`. SourceHut skips the folder convention entirely and uses `.build.yml` at the root.

## Minor conventions

`.gitkeep` is a community convention (not a git feature) to force-track empty directories. `.gitconfig` files in repos are suggested configs that developers manually `include` — git won't auto-load them for security reasons. `.gitsigners` tracks trusted GPG/SSH signing keys. `.gitreview` configures Gerrit integration. `.gitlint` configures commit message linting.

Nesbitt also notes that Jujutsu (`.jj/`) coexists with `.git/` and respects all of these magic files.

## Advice for tool authors

If you're building tools that traverse git repos, respect the magic files: read `.gitignore` when walking the tree, check `.gitattributes` to identify binary/vendored/generated files, use `.mailmap` for author info, and handle `.gitmodules` for submodules. Git's config format (`[section "subsection"] key = value`) has parsers available in most languages through their git libraries.

## Related conventions outside git

`.editorconfig` standardizes indentation and line endings across editors. Language version files (`.ruby-version`, `.node-version`, `.python-version`, `.tool-versions`) tell version managers which runtime to use. `.dockerignore` uses the same syntax as `.gitignore` but applies to Docker build contexts.

For a different angle on git internals — querying the full commit/blob/path history with SQL rather than config files — see [[linux-kernel-pgit]] and [[pgit]]. For tooling that rewrites that history safely rather than reading it, see [[git-history-command]].
