Skip to content
masterclass Buddy

Git · Command

git config

git config reads, writes, and removes Git settings. These settings live in system, global (per-user), repository, and worktree config files, and they change how other Git commands behave.

Last updated

How it works

Each setting has a dotted name. The last dot-separated part is the variable, and everything before it is the section, optionally with a quoted subsection, for example remote.origin.url. When you read a setting without naming a scope, Git merges the system, global, local and worktree files in that order, and the last value it finds wins. When you write a setting, Git uses the repository's .git/config unless you pass --global, --system, --worktree or --file. Modern Git splits the work into subcommands: list, get, set, unset, rename-section, remove-section and edit. Flags such as --type, --value, --all and --show-origin refine how values are matched and printed.

Syntax

git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<pattern>] [--fixed-value] [--default=<default>] [--url=<url>] <name>
git config set [<file-option>] [--type=<type>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>
git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>
git config list [<file-option>] [<display-option>] [--includes]

Parameters

NameTypeDescription
<name>stringThe setting's key, written as the section name and the variable name joined by a dot, with an optional subsection, for example core.filemode or http.<url>.sslVerify.
<value>stringThe value to store with set. Git escapes it when writing it to the file.
--global / --system / --local / --worktree / --file <config-file>flagPicks which config file to read from or write to. Writes go to the local repository file unless you choose another one.
--value=<pattern>string (extended regex)Limits get, set and unset to entries whose current value matches the pattern. With --fixed-value the pattern must match the value exactly.
--allflagWith get, prints every value of a multi-valued key. With set or unset, replaces or removes all of them.
--type=<type>bool | int | bool-or-int | path | expiry-date | colorChecks values against the given type and converts them to its standard form, for example normalizing yes/on/1 to true.
--default=<value>stringWith get, prints this value when the key is not set anywhere.
--show-origin / --show-scopeflagShows the file (or other source) and the scope that each printed value came from.

Returns

Exit code 0 on success. Failures return a non-zero code: 1 for an invalid or missing key, 2 when no section or name is given, 3 for an invalid config file, 4 when the file cannot be written, 5 when unsetting a key that does not exist or when several lines match, and 6 for an invalid regexp. get prints the value (or values) to stdout.

Key points

  • A key named in several files, or several times in one file, normally resolves to the occurrence Git reads last. This ordering is why a repository setting overrides your personal default.
  • get exits with status 1 when the key is missing, so a shell script can check whether a setting exists just by testing the exit code.
  • --show-origin labels each value with where it came from (a file path, standard input, a blob or the command line). This is the quickest way to find out which file is overriding a setting.
  • Some security-sensitive options are only honored when they come from the system, global or command scope. If such an option is set in a repository's own .git/config, Git ignores it.
  • GIT_CONFIG_COUNT together with GIT_CONFIG_KEY_<n>/GIT_CONFIG_VALUE_<n> injects settings for a single process without editing any file. Settings passed with git -c still take priority over them.
  • -z ends each value with a NUL character instead of a newline. Use it when a script parses the output and some values may contain line breaks.
  • Section and variable names ignore case, but subsection names (such as a remote's name or a URL) are case-sensitive.

Common mistakes

  • set and unset refuse to work on a key that has several values unless you add --all or narrow it down with --value. Commands that ran fine on a single-value key can therefore fail on a multivar.
  • Each run edits exactly one file. Unsetting a key locally does not remove a global or system copy of it, so the key can still have a value afterwards.
  • The old forms, such as git config <name>, --get, --add, --unset and --list, are deprecated. Prefer the get, set, unset and list subcommands in new scripts.
  • --type=path only expands ~ when reading. Setting a value with that type does not expand the path, so you have to let the shell expand it.

Example: Set identity, inspect overrides, and work with a multi-valued key

#!/usr/bin/env bash
set -euo pipefail

# Per-user defaults (written to ~/.gitconfig or $XDG_CONFIG_HOME/git/config)
git config set --global user.name "Ada Lovelace"
git config set --global user.email ada@example.com
git config set --global init.defaultBranch main

# Repo-specific override (written to .git/config by default)
git config set user.email ada@work.example.com

# Which value wins, and from where?
git config list --show-origin --show-scope | grep user.email
git config get user.email

# Typed read with a fallback when unset
git config get --type=bool --default=false commit.gpgSign

# Multi-valued key: append, read all, remove one by exact value
git config set --append remote.origin.fetch '+refs/tags/*:refs/tags/*'
git config get --all remote.origin.fetch
git config unset --fixed-value --value='+refs/tags/*:refs/tags/*' remote.origin.fetch

# Script-safe existence check (exit code 1 = not set)
if ! git config get core.editor >/dev/null; then
  echo "core.editor not set"
fi

Run inside a repository that has an origin remote: the script sets global and local values, shows which one wins and where it is stored, reads a typed value with a fallback, works with a multi-valued key, and checks whether a key exists using get's exit code.

When to use it

First-time machine setup

Set your name, email, editor and default branch once with --global so every repository on the machine uses them.

Per-repository identity

Use a work email in one client repository by setting user.email locally, which overrides your personal global address.

Debugging surprising behavior

Run list --show-origin --show-scope to find out which config file is setting an unexpected pull, editor or credential option.

CI and automation scripts

Read settings with get --type and --default, or supply them through GIT_CONFIG_COUNT environment variables, so pipelines don't depend on a user's config files.

Interview questions

QIf user.email is set in /etc/gitconfig, ~/.gitconfig and .git/config, which value does a commit use, and why?

It uses the value in .git/config. Git reads the system file first, then the global (per-user) files, then the repository's file, and the last value it reads wins. A worktree's config.worktree is read after .git/config when worktree config is enabled, and settings passed with -c on the command line or through GIT_CONFIG_* variables override all of these files.

Follow-up: How would you prove which file supplied the value? Run git config get --show-origin --show-scope user.email (or list with the same flags). The output shows the file path and the scope for each value.

QWhat is a multi-valued variable, and how do you safely change just one of its values?

It is a key that appears on several lines, such as remote.origin.fetch or core.gitproxy. set and unset refuse to touch such a key by default. To target one line, pass --value=<pattern> (an extended regex), or add --fixed-value to match the value exactly. --append adds a new line without changing the existing ones.

Follow-up: How do you replace every line except one specific value? Put ! at the start of the --value pattern to match lines that do not match it, as in --value='! for '. This only works when --fixed-value is not used.

QWhy might a setting in a cloned repository's .git/config be ignored even though git config get shows it?

Some options are only honored when they come from protected configuration, meaning the system, global or command scope. Git treats those scopes as controlled by the user or a trusted administrator, while a repository's own config may come from somewhere less trustworthy. To make such an option take effect, set it with --global or --system, or pass it with -c.

Follow-up: How can a script inject config without touching any file? Set GIT_CONFIG_COUNT and the zero-indexed GIT_CONFIG_KEY_<n>/GIT_CONFIG_VALUE_<n> pairs. A missing key or value causes an error, and settings passed with git -c still take priority.

  • git
  • git-worktree
  • git-help
  • gitrevisions
  • git-init
  • git-commit

Source: Git - git-config Documentation. Checked 2026-11-02.