git config

TL;DR: git config is the command-line interface used to manage Git’s configuration variables. These configurations are stored as plain text files structured in an INI format across three main scopes: system-wide, user-global, and repository-local. Git parses these files sequentially, applying a cascading inheritance model where the most specific repository-level setting overrides broader global configurations.


What Does git config Actually Do?

Many developers treat git config as a command that updates a hidden system registry or contacts a remote database. In reality, Git’s configuration system is simple: it is a collection of flat, plain text files stored on your hard drive. The git config command is a command-line wrapper for writing, reading, and deleting key-value pairs in those text files.

The Cascading Precedence Model

When you execute a Git command, Git checks for configuration variables in a strict hierarchy. If a setting is defined in multiple files, Git resolves the conflict by using the value from the most specific configuration file it reads.

graph TD
    System[System Level: /etc/gitconfig] -->|Overridden by| Global[Global Level: ~/.gitconfig]
    Global -->|Overridden by| Local[Local Level: .git/config]
    Local -->|Overridden by| Env[Environment Variables e.g., GIT_AUTHOR_NAME]
    Env -->|Overridden by| Cmd[Command Line Flags e.g., -c user.name]
    style System fill:#f2f2f2,stroke:#333
    style Global fill:#e1f5fe,stroke:#0288d1
    style Local fill:#e8f5e9,stroke:#388e3c
    style Env fill:#fff9c4,stroke:#fbc02d
    style Cmd fill:#ffe0b2,stroke:#f57c00
  1. System Level (--system): Applies to all users and all repositories on the machine.
    • Path: /etc/gitconfig (Unix) or C:\Program Files\Git\etc\gitconfig (Windows).
    • Access: Requires administrative/root permissions to modify.
  2. Global Level (--global): Applies to the active operating system user account. This is where you configure settings that should apply across all of your repositories (such as your default commit author identity).
    • Path: ~/.gitconfig or ~/.config/git/config (Unix) or C:\Users\Username\.gitconfig (Windows).
  3. Local Level (--local): Applies to the active repository. This is stored directly inside the repository’s .git/ folder and overrides all global and system settings.
    • Path: .git/config
    • Note: This is the default scope for the git config command if no scope flag is provided.
  4. Worktree Level (--worktree): Applies to a specific Git worktree. Useful when managing multiple active checkouts of a single repository.
    • Path: .git/worktrees/<id>/config.worktree
  5. Environment Variables: You can temporarily override any configuration file variable using environment variables, such as GIT_AUTHOR_NAME or GIT_COMMITTER_EMAIL.
  6. Command-Line Parameters: You can pass one-off settings directly to commands using the -c flag (e.g., git -c user.email="temp@example.com" commit).

What Happens Inside .git/ (Hands-on exploration)

Let’s initialize a Git repository and inspect how configurations are written and resolved at the filesystem level.

Step 1: Inspect a Fresh Local Configuration

Initialize a new Git repository:

$ mkdir config-internals && cd config-internals
$ git init
Initialized empty Git repository in /home/admin/Code/config-internals/.git/

When git init is run, Git creates a default local configuration file at .git/config. Let’s view the default contents using cat:

$ cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true

These core variables define how Git interacts with your filesystem:

  • repositoryformatversion = 0: Defines the repository’s database format version. If Git encounters a repository version higher than it supports, it will refuse to read it.
  • filemode = true: Tells Git to track POSIX file executable bit changes (e.g., if you make a script executable via chmod +x).
  • bare = false: Declares that this is a standard working repository containing checked-out files on disk. A “bare” repository contains only the Git administrative directory (usually for remote hosting servers) and has this set to true.
  • logallrefupdates = true: Instructs Git to maintain the reflog (a detailed history tracking where branch tips and HEAD have pointed over time, stored in .git/logs/).

Step 2: Write and Verify Local Configuration

Let’s write a local setting using the git config command:

$ git config --local user.email "local-dev@dotgit.dev"

Now let’s check .git/config to see what changed:

$ cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[user]
	email = local-dev@dotgit.dev

The command created a new block: [user] with email = local-dev@dotgit.dev.

Step 3: Observe Cascading Resolution

Let’s configure our global identity so we have settings at both levels:

$ git config --global user.name "Ada Lovelace"
$ git config --global user.email "ada@example.com"

Let’s run git config --list --show-origin to see how Git lists these configurations along with the files they are stored in:

$ git config --list --show-origin
file:/home/admin/.gitconfig     user.name=Ada Lovelace
file:/home/admin/.gitconfig     user.email=ada@example.com
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                user.email=local-dev@dotgit.dev

When you commit a change in this directory:

  1. Git queries the configuration keys.
  2. It reads user.name from /home/admin/.gitconfig (Ada Lovelace).
  3. It reads user.email from both /home/admin/.gitconfig and .git/config. Because .git/config is read last, its value (local-dev@dotgit.dev) overrides the global setting.

Let’s verify the resolved configuration that Git uses for commits:

$ git config user.name
Ada Lovelace

$ git config user.email
local-dev@dotgit.dev

Detailed Command Options & Advanced Usage

1. The Structure of gitconfig Files

All gitconfig files are plain-text INI files. The syntax consists of sections, variables (keys), and values:

[section]
    key = value
    boolean-flag = true      ; semicolons indicate comments
    # hashtags also indicate comments

[section "subsection"]       ; subsections must be double-quoted
    nested-key = nested-value

You can manipulate these variables programmatically using the following commands:

  • Set a value: git config [--scope] key value
  • Read a value: git config [--scope] key
  • Unset/Delete a value: git config [--scope] --unset key
  • Edit the configuration file in your editor: git config [--scope] --edit

2. Advanced Configuration Variables

Beyond setting your author name and email, Git allows customization of core behaviors:

A. Staging and Line Endings (core.autocrlf)

This setting manages carriage returns across platforms, as discussed in installing-git:

# Force Unix line endings globally
$ git config --global core.autocrlf input

B. Merge conflict helper caching (rerere.enabled)

“Rerere” stands for Reuse Recorded Resolution. When active, Git records how you resolved a merge conflict and automatically applies that exact resolution if it encounters the same conflict again.

# Enable conflict resolution recording
$ git config --global rerere.enabled true

C. Setting a Global Ignore File (core.excludesfile)

If you want to ignore certain files (like .DS_Store or .idea/ folders) in all repositories on your system without adding them to each project’s .gitignore file:

$ git config --global core.excludesfile ~/.gitignore_global

3. Shell Script Command Aliases

Git lets you create shortcuts (aliases) for complex commands.

# Create a shortcut for short log status
$ git config --global alias.st status -sb

Now, typing git st executes git status -sb.

You can also run external system shell commands instead of Git subcommands by prefixing the alias with an exclamation point (!):

# Commit and push in a single command alias
$ git config --global alias.sync "!git pull && git push"

When Git encounters the !, it starts a subshell (typically /bin/sh) and passes the rest of the alias string to it, allowing you to run custom bash scripts directly from the git binary.


Real-World Scenario: Conditional Configuration Inclusion

Many developers use the same laptop for both personal projects and corporate work. Committing to a corporate repository with a personal email (or to a personal GitHub project with a corporate email) is a common mistake.

To solve this, Git provides conditional configuration inclusion via includeIf.

Step 1: Create Organization-Specific Directories

Organize your workspace so that all work repositories are in one folder, and personal ones are in another:

  • ~/personal/
  • ~/work/

Step 2: Create Custom Git Config Files

Create a file at ~/.gitconfig-personal:

[user]
    email = alex@personaldomain.com
    signingkey = B2837C9F

Create another file at ~/.gitconfig-work:

[user]
    email = alex.developer@corporation.com
    signingkey = D827C11A

Step 3: Configure includeIf in your Global Git Config

Open your main ~/.gitconfig and configure it to dynamically load the appropriate configuration based on the directory path of the active repository:

[user]
    name = Alex Developer  ; Default name used everywhere

[includeIf "gitdir:~/personal/"]
    path = ~/.gitconfig-personal

[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig-work

When you work on projects inside ~/work/, Git matches the directory pattern and overrides the default configuration with your corporate email and GPG key. When working inside ~/personal/, it applies your personal settings automatically.


Common Pitfalls and Mistakes

1. Unsetting or Editing the Wrong Scope

The Mistake: You run git config --unset user.email inside a repository to update a global setting, but the command runs locally and unsets the local config instead. The Fix: Always specify the scope (--global, --local, --system) when writing or deleting settings to prevent writing files to the wrong scope.

2. Typographical Errors in Aliases

The Mistake: Creating an alias with a typo:

$ git config --global alias.cmmit "commit -m"

Now, git cmmit works, but you cannot edit or delete it without knowing how to reference it. The Fix: You can delete the alias by running:

$ git config --global --unset alias.cmmit

Alternatively, open the global configuration file directly using your editor:

$ git config --global --edit

You can clean up any typographical errors under the [alias] section of the configuration file.

3. Permission Errors When Using --system

The Mistake: Running git config --system core.editor nano returns a permission denied error. The Fix: The system-level configuration is stored in root-protected files like /etc/gitconfig. To modify them, you must run the command with administrator rights:

$ sudo git config --system core.editor nano

Command Quick Reference

CommandAction ScopeTarget File
git config --listList all resolved configurationsMerged view of all files
git config --list --show-originList configurations with source file pathsMerged view of all files
git config --global user.name "Name"Set global commit author name~/.gitconfig
git config --global user.email "Email"Set global commit author email~/.gitconfig
git config --local user.email "Email"Set local repository author email.git/config
git config --global --unset alias.nameDelete a global alias shortcut~/.gitconfig
git config --global --editOpen global config file in system editor~/.gitconfig
git config --local --editOpen local config file in system editor.git/config

FAQ (People Also Ask)

Where are Git configurations saved?

Git configuration files are saved as plain text files in three locations based on their scope:

  • System: /etc/gitconfig (Unix) or C:\Program Files\Git\etc\gitconfig (Windows).
  • Global: ~/.gitconfig or ~/.config/git/config (Unix) or C:\Users\Username\.gitconfig (Windows).
  • Local: .git/config within the root directory of the specific repository.

How do I configure Git to use a custom text editor?

You can configure Git’s default text editor (such as VS Code or Sublime Text) by setting the core.editor variable globally:

# For Visual Studio Code
$ git config --global core.editor "code --wait"

# For Notepad++ (on Windows)
$ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"

The --wait flag tells Git to pause the terminal prompt until you close the editor window where you write your commit message.

How do I check where a Git setting is inherited from?

To identify the file path that configured a specific setting, run git config with the --show-origin and --show-scope flags:

$ git config --show-origin --show-scope user.email

This returns the file path (e.g., file:.git/config) and scope level (e.g., local) that resolved the requested setting.


Test Your Knowledge

Loading quiz…