Git

What Is Git Config? Set Up Git Like a Pro

What Is Git Config? Set Up Git Like a Pro

The first thing most people do after installing Git is tell it their name and email. That’s a git config job, and for a lot of developers it’s the only time they think about the command until something breaks.

The command reads, writes, and removes the variables that control how Git behaves for one user, one repository, or an entire machine. Each variable is a key and value pair kept in a plain text file, such as user.name in the global file.

Most tutorials teach three levels (system, global, and local), but the Git manual (git-scm.com, 2026) defines five scopes: those three plus worktree and command.

Setting a commit author is the usual reason to run it. Changing the editor, the default branch name, or an alias tends to come later.

What Is git config?

YouTube player

Every setting Git honors is a variable, and every variable name has two parts joined by a dot. The section comes first and the key follows, as in user.name or core.editor.

The values live in plain text files, so the command is a convenience and not a requirement. Pro Git still calls it the easier route compared to editing the file by hand.

Most developers run it for the first time right after they install Git, to set a name and an email.

Command syntax

The current manual (git-scm.com, last updated for Git 2.56.0 on 2026-09-28) documents a subcommand for each job.

  • git config list prints every variable, and git config get user.email prints a single value
  • git config set user.email "you@example.com" writes one
  • git config unset user.email removes it
  • git config edit opens the file itself

The older forms (git config user.name "Ada", --list, --get, --unset, --add, --edit) sit under “deprecated modes” in the same manual, which recommends migrating.

Almost every tutorial still teaches the old forms. If a subcommand gets rejected, run git --version first.

Why is GitHub the heart of open source?

Uncover GitHub statistics: developer community growth, repository trends, collaboration patterns, and the platform that powers modern software development.

Explore GitHub Data →

Without a scope flag, a read searches the system, global, and local files together. A write goes to the local repository file.

What Are the git config Scopes and Where Are the Files Stored?

YouTube player

Four scopes map to files: system, global, local, and worktree. The fifth, command, comes from environment variables and the -c option.

ScopeFlagApplies toLocation
System–systemEvery user on the machine$(prefix)/etc/gitconfig
Global–globalOne user, all repositories~/.gitconfig or $XDG\_CONFIG\_HOME/git/config
Local–local (write default)One repository.git/config
Worktree–worktreeOne worktree (main or linked)$GIT\_DIR/config.worktree (.git/config.worktree in the main worktree, .git/worktrees/<id>/config.worktree in a linked one)
CommandnoneOne processGIT\_CONFIG\_COUNT variables, git -c

Local and worktree files hold settings for one Git repository, so they never leak into other projects.

Two global files, both read

When both global files exist, Git reads the XDG file first and ~/.gitconfig second. The home file wins any conflict.

Writing with --global targets ~/.gitconfig. The XDG file only receives the write when it exists and the home file does not.

Looking to sharpen your Git skills? Branching, merging, rebasing, and everything else you need - including git rebase, git stash, and commit workflows - is on one page in the Git Cheat Sheet.

Windows has two machine-wide files

The system file is the etc\gitconfig folder inside the Git installation, and the exact path depends on the Git for Windows version. That’s the file --system points at.

The other one is C:\ProgramData\Git\config. Git for Windows reads it before the system file, so it has the lowest precedence, and the --system flag does not point at it.

Skip the guessing. Run git config --list --show-origin and Git prints the file behind every value, the ProgramData file included.

The worktree scope needs a switch

Git searches config.worktree only when extensions.worktreeConfig is present in the repository config (git-config manual). Without it, --worktree behaves exactly like --local.

Variables that move the files

  • GIT\_CONFIG\_GLOBAL and GIT\_CONFIG\_SYSTEM point Git at different files
  • GIT\_CONFIG\_NOSYSTEM skips the system file
  • XDG\_CONFIG\_HOME falls back to $HOME/.config/ when unset or empty

Protected scopes

System, global, and command are the protected scopes. Some options are honored only there and ignored when they show up in a repository file.

The manual gives the reason. Whoever controls those scopes can do serious damage without touching Git, so Git trusts them more.

Which Setting Wins When Scopes Conflict?

Whichever scope is read last wins. Git goes through system, global, local, and worktree in that order, and the last value found takes precedence.

From weakest to strongest:

  1. System file
  2. Global files
  3. Local file
  4. Worktree file, when enabled
  5. Command scope, where GIT_CONFIG_COUNT variables override every file and an explicit git -c overrides those

Pro Git describes three levels. The manual lists five, and the order of the three they share is identical.

Worktree and command only matter if you use linked worktrees or run Git from scripts (the manual points to scripts as the use case for the environment variables).

Worked example with two emails

Say your personal address is the default and your work repositories need a different one.

  1. Set the default: git config --global user.email "me@example.com"
  2. Inside a work repository, override it: git config --local user.email "work@example.com"

After that, git config get user.email returns work@example.com in that repository and me@example.com everywhere else.

To see which file supplied a value, add --show-origin. The --show-scope flag prints the scope name instead (worktree, local, global, system, or command).

Multi-valued keys ignore the last-one-wins rule

Some keys can appear several times. For those, Git uses every value from every file, not only the final one.

Plain get returns the last value. Add --all to see the full list.

How to Set Identity and Common Settings

YouTube player

A first-time setup is short. Name, email, editor, default branch, and a quick check that it all stuck.

  1. Set the author name: git config --global user.name "Your Name"
  2. Set the author email: git config --global user.email "you@example.com"
  3. Pick an editor: git config --global core.editor "code --wait"
  4. Name the first branch of new repositories: git config --global init.defaultBranch main
  5. Check the result: git config --global --list

On a current build the same steps work with the subcommand form, for example git config set --global user.name "Your Name".

Identity settings

Git stamps user.name and user.email into every commit it creates, so set them before running your first git commit.

Global scope covers the default identity. A local override changes the author for one repository only.

Editor and default branch

YouTube player

For the editor, Git reads the VISUAL or EDITOR environment variable and falls back to vi (Pro Git). Setting core.editor overrides both. The --wait flag in the VS Code value keeps the command open until you close the file.

Left unset, init.defaultBranch gives you master. The manual says that default will change to main when Git 3.0 is released.

Git 2.28, released July 27, 2020, introduced the variable (GitHub Blog, 2020). It affects new repositories only, existing branches keep their names, and git clone follows the HEAD of the source repository.

Pull and line-ending behavior

An earlier release, Git 2.27 (June 1, 2020), began warning whenever pull.rebase is unset and you pass none of --rebase, --no-rebase, or --ff-only, according to the Git 2.27 release notes. The variable decides what git pull does when both your branch and the remote have new commits.

Setting pull.rebase to false merges, and true rebases your commits on top. Setting pull.ff to only fast-forwards or refuses.

For a global default, pull.ff only is the safest pick. It never creates a merge commit or rewrites history without being asked.

The cost is a “not possible to fast-forward” failure when histories diverge (Git Tower), and then you choose git pull --rebase or a merge by hand.

Line endings are the other setting worth deciding early. Windows uses CRLF and macOS and Linux use LF, which is why core.autocrlf exists.

SituationValueEffect
Windows machinetrueCRLF on checkout, LF on add
macOS or LinuxinputCRLF to LF on commit only
Windows-only projectfalseCarriage returns stored as written

How to View, Edit, and Remove git config Values

YouTube player

Reading uses list and get, changing uses set, and removing uses unset. Each takes a scope flag.

Without one, reads search every file, while writes and removals hit the local file.

Reading values

  • git config list --name-only prints keys without values
  • git config get --default main init.defaultBranch returns main when the key is missing
  • Adding --type=bool turns yes, on, true, and any positive number into the literal true
  • git config get --all --show-names --regexp "^user\." lists every key that matches a pattern

Changing values

A plain set replaces one line. The options below change what it touches.

OptionUsed withEffect
–appendsetAdds a line, keeps existing ones
–allget, set, unsetCovers every value of a multi-valued key
–value=PATTERNget, set, unsetMatches only values that fit the regex
–fixed-valuewith –valueTreats the pattern as an exact string
–comment MESSAGEsetAppends a comment to the written line

The older spellings map one to one. --add became set --append, and --unset-all became unset --all, according to the manual’s deprecated modes list.

--replace-all still appears in the options list. It rewrites every line matching the key instead of at most one.

Editing and removing

YouTube player

git config edit opens the file for the chosen scope in an editor. Pass --system, --global, --local (the default), --worktree, or --file to pick which one.

The command changes one file at a time. Running git config unset user.email inside a repository deletes only the local line, and the global value shows through again.

Whole sections go with git config remove-section NAME, and rename-section relabels one.

How to Use a Different Identity per Directory With includeIf

YouTube player

The includeIf directive loads another config file only when a condition matches. Put the condition in the global file, point it at a work-only file, and every repository under that directory picks up the work identity.

Its unconditional sibling, include.path, pulls a file in every time. A relative path resolves against the file that holds the directive, and a leading tilde expands to the home directory.

  1. Create the work file: git config --file ~/.gitconfig-work user.email "work@example.com"
  2. Open the global file: git config edit --global
  3. Add the condition [includeIf "gitdir:~/work/"] and, on the next line, path = ~/.gitconfig-work
  4. Check from a repository under ~/work: git config get --show-origin user.email

The origin in step 4 should name .gitconfig-work. If it names .gitconfig, the condition did not match.

Order inside the file matters

Git inserts the included lines at the spot where the directive sits, as if they had been typed there (git-config manual).

So place the includeIf block below any user.email already in the global file. Above it, the global value is read last and wins.

Pattern rules for gitdir

  • A trailing slash appends **, so ~/work/ covers every repository inside
  • Without the slash there is no wildcard, and the pattern matches only that exact .git location
  • A leading ~/ becomes the home directory, and ./ becomes the folder of the current config file
  • A pattern with no prefix gets **/ prepended
  • ../ is literal, not a parent reference

Other conditions

Beyond gitdir, the manual lists gitdir/i, worktree, worktree/i, onbranch, and hasconfig:remote.\*.url.

The onbranch condition matches against the currently checked out Git branch. A trailing slash covers a whole prefix such as feature/.

The hasconfig:remote.\*.url condition matches when at least one remote repository URL fits the pattern. Files included this way cannot declare remote URLs themselves.

The worktree keyword matches the directory where files are checked out, not the .git folder. It never matches in a bare repository, and the /i variants ignore case.

Version note

includeIf shipped in Git v2.13.0, and that first release matched only the real path of a directory (git-config manual). Later versions also match the symlink spelling outside the .git folder.

If a config file has to work on both, write the real path or list both spellings.

The per-clone alternative

Setting a local email in each clone works, until the day you forget one. A directory-level includeIf removes the step.

The manual draws a similar contrast between extensions.worktreeConfig and includeIf "worktree:...". The first route needs git config --worktree run inside every worktree, while an includeIf in the global file applies to every repository at once.

How to Create Git Aliases

An alias is a config entry named alias.NAME whose value Git substitutes for the command you type. Setting alias.ci to commit makes git ci run git commit.

Pro Git’s starter set maps co to checkout, br to branch, ci to commit, and st to status, all written with --global.

The command form is git config --global alias.co checkout. After alias.st status, typing git st gives you git status output.

Aliases also invent commands that Git lacks. git config --global alias.unstage 'reset HEAD --' makes git unstage fileA identical to git reset HEAD -- fileA.

Another popular one is alias.last 'log -1 HEAD', which prints the newest entry from git log.

Aliases that run external commands

Start the value with an exclamation mark and Git runs it as an external command instead of a Git subcommand. Pro Git’s example is git config --global alias.visual '!gitk'.

Listing and removing aliases

To list them, run git config get --global --all --show-names --regexp "^alias\.". To remove one, run git config unset --global alias.co.

Quote any value that contains a space. Keep the set small, too. Five or six aliases you type daily beat forty you forget.

When git config Does Not Behave as Expected

YouTube player

Most surprises trace back to a narrower scope overriding a value, a key holding several values, a scope nobody switched on, or an environment variable masking a file.

SymptomCauseFix
Wrong value shows upNarrower or command scope winsRun git config list --show-scope
–worktree wrote to .git/configextensions.worktreeConfig is offEnable the extension
set or unset exits with 5Key has several valuesAdd –all or –value=PATTERN
includeIf has no effectNo trailing slash, or symlinked pathAdd the slash, use the real path
Write or –local read fails in a plain folderNo repository config fileMove into a repository or pass –global

A value whose scope reads command comes from the environment, not from a file. Check GIT_CONFIG_COUNT and git -c before editing anything.

Turning on worktree config

git config extensions.worktreeConfig true activates the file. From then on --worktree reads and writes config.worktree.

Before flipping it, move a few settings out of the shared config and into the main worktree’s config.worktree (git-worktree manual). That covers core.worktree, which should never be shared, core.bare when its value is true, and core.sparseCheckout unless every worktree uses sparse checkout.

Older Git versions refuse to open a repository that carries this extension, so upgrade every client first.

Exit codes in scripts

The manual documents these non-zero exit codes:

  • 1 for an invalid section or key
  • 2 when no section or name is given
  • 3 for an invalid config file
  • 4 when the config file cannot be written
  • 5 for an unset of a missing option, or a set or unset matching several lines
  • 6 for an invalid regular expression

get also exits 1 when a key is absent. A script that tests only for 1 cannot tell a typo from a missing value, so pair it with --default.

git config FAQ

How do I reset git config to its defaults?

Delete the entries you added, or delete the file that holds them. Git ignores missing global and system files, so removing ~/.gitconfig is safe, though it also erases your name and email.

For a single repository, run git config unset on each key, or use remove-section for a whole block.

Does git clone copy the source repository’s config?

No. A clone builds its own local config, starting with remote.origin.url and remote.origin.fetch (git-clone manual).

The -c key=value option seeds extra keys before the first fetch. Your global file still applies to the new clone.

How does git config differ from .gitignore and .gitattributes?

Config stores settings as key and value pairs. The .gitignore file lists path patterns Git should leave untracked, while .gitattributes assigns attributes such as text or eol to paths.

Config also wires up the shared versions. core.excludesfile points to a global .gitignore, and core.attributesFile points to a global attributes file.

How do I store Git credentials so I stop retyping them?

Set credential.helper in the global scope, for example git config –global credential.helper cache. Pro Git lists 4 built-in choices: cache, store, osxkeychain on macOS, and Git Credential Manager on Windows.

Cache holds credentials in memory for 15 minutes by default. Store writes them to a plain-text file that never expires.

Can I turn off the pager for git config output?

Yes. Set pager.config to false and list and get output stop paging, or set core.pager to an empty string to disable the pager for every command.

A single command works too, as in git config –global pager.branch false.

Keeping git config Consistent Across Machines

The simplest way to keep git config consistent across machines is one shared global file kept in version control, with platform-specific values split into a machine-local file pulled in through include.path. Run list with –show-origin on each machine afterward to confirm what Git actually reads.

The split matters because core.autocrlf and credential.helper are OS-bound. Both take different values on Windows and macOS, so a file copied unchanged breaks one platform.

The price is a second file per machine, and an error in the shared file reaches every machine at the next sync.

As of October 2026, the includeIf conditions (gitdir, worktree, onbranch, hasconfig) test no operating system, so the local file stays necessary. A new OS keyword would retire it.

Once settings hold everywhere, the everyday Git commands that read them are the natural next stop.

Bogdan Sandu

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.