Configuration levels
Beginner Git CLI
Why this matters
You set user.email once, and yet one project commits with a different address; VS Code and the terminal disagree about the editor; a colleague's laptop behaves differently with the same commands. All three puzzles have the same answer: Git reads settings from several files and layers them.
The three levels
| Level | Flag | File | Applies to | Set by |
|---|---|---|---|---|
| System | --system |
/etc/gitconfig; on Windows C:\Program Files\Git\etc\gitconfig; Apple's Git ships one under Xcode |
every user on the computer | installers, administrators |
| Global | --global |
~/.gitconfig (your home folder) |
every repository of yours | you, in lesson 3.3 |
| Local | (default inside a repository) | .git/config in the project |
that repository only | git clone/git init, and you |
There is also a fourth, worktree, for advanced setups (lesson 18.2).
Precedence: when the same key is set at several levels, the most specific wins: local beats global beats system. Git reads all three files, in that order of increasing priority, every time it runs.
See where a value comes from
$ git config --list --show-originfile:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig credential.helper=osxkeychain
file:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig init.defaultbranch=main
file:/Users/you/.gitconfig user.name=Ana Lopez
file:/Users/you/.gitconfig user.email=ana@northwind-trails.example
file:/Users/you/.gitconfig init.defaultbranch=main
file:/Users/you/.gitconfig core.editor=code --wait
file:/Users/you/.gitconfig pull.rebase=false
file:/Users/you/.gitconfig push.autosetupremote=true
file:.git/config core.repositoryformatversion=0
file:.git/config core.filemode=true
file:.git/config core.bare=false
file:.git/config core.logallrefupdates=true
file:.git/config core.ignorecase=true
file:.git/config core.precomposeunicode=trueThe first column is the file (system, then global, then local .git/config). Here Apple's system file sets the credential helper and a default branch; the global file sets identity and preferences; the local file holds the repository's own bookkeeping (and, after a clone, the remote "origin" section).
To ask about one key at one level: git config --global user.email. To ask which value wins: git config user.email (no flag: Git resolves the layers).
A different identity for one project
Inside the repository, omit --global:
$ git config user.email "ana@personal.example"
$ git config user.emailana@personal.example$ git config --global user.emailana@northwind-trails.exampleCommits in this repository now use the personal address; every other repository keeps the work address. Typical use: an open-source project where you contribute under a personal email, or a client project with a client email.
The file itself
Configuration files are plain text in a simple [section] format. Your global file after lesson 3.3:
[user]
name = Ana Lopez
email = ana@northwind-trails.example
[init]
defaultBranch = main
[core]
editor = code --wait
[pull]
rebase = false
[push]
autoSetupRemote = truegit config --global --edit opens it in your editor; editing by hand is fine and sometimes quicker. git config --global --unset core.editor removes one key.
Common mistakes
- Setting a value in the wrong level.
git config user.nameinside a repository changes only that repository. Use--globalfor "everywhere". - Expecting a global change to alter existing commits. Configuration affects future commits only.
- Editing
.git/configfor something that belongs in.gitignore. Ignore rules are files in the working tree, not configuration. - Two Gits, two system files. Homebrew's Git and Apple's Git read different system files; global and local files are shared. If a system-level value seems to vanish,
--show-originshows why.
Try it yourself
Goal: override one setting locally, observe the precedence, then remove the override.
- In the playground, run
git config user.name(global value). - Run
git config user.name "Playground Tester", thengit config user.nameagain, thengit config --global user.name. - Run
git config --list --show-origin | grep user.nameto see both lines. - Remove the override:
git config --unset user.name, and check again.
Expected result: step 2 shows the local name winning while the global stays; step 3 lists both files; after step 4 only the global remains.
Show solution
The local value in .git/config shadows the global one inside this repository. --unset deletes the local key, and Git falls back to the global. On Windows Git Bash, grep works the same; in PowerShell use | Select-String user.name.