Skip to main content

Overview

Git configuration controls how Git behaves. GitHub Desktop manages most Git configuration automatically, but understanding how it works helps you customize behavior when needed.

Global Config

Settings that apply to all repositories

Local Config

Repository-specific settings

User Identity

Name and email for commits

Behavior Settings

Line endings, merge strategies, and more

Configuration Levels

Git configuration exists at three levels:

System Level

# Applies to all users on the system
/etc/gitconfig  (Linux/macOS)
C:\ProgramData\Git\config  (Windows)
Rarely used in GitHub Desktop workflows.

Global Level

# Applies to all repositories for current user
~/.gitconfig  (Linux/macOS)
C:\Users\<username>\.gitconfig  (Windows)
This is where GitHub Desktop stores most settings.

Local Level

# Applies only to specific repository
<repository>/.git/config
Repository-specific overrides.

Configuration Priority

When Git looks for a setting:
  1. Local (repository-specific) - Highest priority
  2. Global (user-level)
  3. System (machine-wide) - Lowest priority
Local settings override global, which override system.

Reading Configuration

GitHub Desktop provides functions to read Git configuration:
// From app/src/lib/git/config.ts
export function getConfigValue(
  repository: Repository,
  name: string,
  onlyLocal: boolean = false
): Promise<string | null> {
  return getConfigValueInPath(name, repository.path, onlyLocal)
}

export function getGlobalConfigValue(
  name: string,
  env?: { HOME: string }
): Promise<string | null> {
  return getConfigValueInPath(name, null, false, undefined, env)
}

async function getConfigValueInPath(
  name: string,
  path: string | null,
  onlyLocal: boolean = false,
  type?: 'bool' | 'int' | 'path',
  env?: { HOME: string }
): Promise<string | null> {
  const flags = ['config', '-z']
  
  if (!path) {
    flags.push('--global')
  } else if (onlyLocal) {
    flags.push('--local')
  }
  
  if (type !== undefined) {
    flags.push('--type', type)
  }
  
  flags.push(name)
  
  const result = await git(flags, path || __dirname, 'getConfigValueInPath', {
    successExitCodes: new Set([0, 1]),
    env,
  })
  
  // Git exits with 1 if the value isn't found
  if (result.exitCode === 1) {
    return null
  }
  
  const output = result.stdout
  const pieces = output.split('\0')
  return pieces[0]
}
Usage Examples:
// Read global user name
const name = await getGlobalConfigValue('user.name')

// Read repository-specific email
const email = await getConfigValue(repository, 'user.email')

// Read boolean value
const value = await getBooleanConfigValue(repository, 'core.bare')
GitHub Desktop uses the -z flag with git config for null-terminated output, which safely handles values containing newlines.

Writing Configuration

Setting Values

export async function setConfigValue(
  repository: Repository,
  name: string,
  value: string,
  env?: { HOME: string }
): Promise<void> {
  return setConfigValueInPath(name, value, repository.path, env)
}

export async function setGlobalConfigValue(
  name: string,
  value: string,
  env?: { HOME: string }
): Promise<void> {
  return setConfigValueInPath(name, value, null, env)
}

async function setConfigValueInPath(
  name: string,
  value: string,
  path: string | null,
  env?: { HOME: string }
): Promise<void> {
  const flags = ['config']
  
  if (!path) {
    flags.push('--global')
  }
  
  flags.push('--replace-all', name, value)
  
  await git(flags, path || __dirname, 'setConfigValueInPath', { env })
}
Example:
// Set global user name
await setGlobalConfigValue('user.name', 'Jane Doe')

// Set repository-specific email
await setConfigValue(repository, 'user.email', '[email protected]')

Adding Multiple Values

Some settings can have multiple values:
export async function addGlobalConfigValue(
  name: string,
  value: string
): Promise<void> {
  await git(
    ['config', '--global', '--add', name, value],
    __dirname,
    'addGlobalConfigValue'
  )
}
Example:
# Add multiple safe directories
git config --global --add safe.directory /path/to/repo1
git config --global --add safe.directory /path/to/repo2

Removing Values

export async function removeConfigValue(
  repository: Repository,
  name: string,
  env?: { HOME: string }
): Promise<void> {
  return removeConfigValueInPath(name, repository.path, env)
}

async function removeConfigValueInPath(
  name: string,
  path: string | null,
  env?: { HOME: string }
): Promise<void> {
  const flags = ['config']
  
  if (!path) {
    flags.push('--global')
  }
  
  flags.push('--unset-all', name)
  
  await git(flags, path || __dirname, 'removeConfigValueInPath', { env })
}

Common Git Configuration

User Identity

# Set your name
git config --global user.name "Your Name"

# Set your email
git config --global user.email "[email protected]"
GitHub Desktop sets these through File > Options > Git.

Default Branch

# Set default branch name for new repositories
git config --global init.defaultBranch main
Configurable in GitHub Desktop preferences.

Line Endings

# Windows - convert LF to CRLF on checkout, CRLF to LF on commit
git config --global core.autocrlf true

# macOS/Linux - convert CRLF to LF on commit, no conversion on checkout
git config --global core.autocrlf input

# No conversion (use .gitattributes instead)
git config --global core.autocrlf false
Use .gitattributes for fine-grained control over line endings instead of relying solely on core.autocrlf.

Editor

# Set default editor for commit messages
git config --global core.editor "code --wait"
GitHub Desktop handles commit messages in the UI, so this mainly affects command-line Git.

Merge Tool

# Set merge conflict resolution tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

Credential Storage

# Store credentials in OS credential manager
git config --global credential.helper manager  # Windows
git config --global credential.helper osxkeychain  # macOS
git config --global credential.helper libsecret  # Linux
GitHub Desktop uses OS credential storage automatically.

Safe Directories

Git 2.35.2+ requires repositories to be marked as “safe”:
export async function addSafeDirectory(path: string) {
  // UNC paths on Windows need special prefix
  if (__WIN32__ && path[0] === '/') {
    path = `%(prefix)/${path}`
  }
  
  await addGlobalConfigValueIfMissing('safe.directory', path)
}

export async function addGlobalConfigValueIfMissing(
  name: string,
  value: string
): Promise<void> {
  const { stdout, exitCode } = await git(
    ['config', '--global', '-z', '--get-all', name, value],
    __dirname,
    'addGlobalConfigValue',
    { successExitCodes: new Set([0, 1]) }
  )
  
  // Only add if not already present
  if (exitCode === 1 || !stdout.split('\0').includes(value)) {
    await addGlobalConfigValue(name, value)
  }
}
This prevents Git from refusing to work in repositories owned by other users.

Getting Global Config Path

export const getGlobalConfigPath = (env?: { HOME: string }) =>
  git(['config', '--edit', '--global'], __dirname, 'getGlobalConfigPath', {
    // Use printf instead of echo to avoid escape sequence issues
    env: { ...env, GIT_EDITOR: 'printf %s' },
  }).then(x => normalize(x.stdout))
Returns the path to .gitconfig, creating it if it doesn’t exist.

Repository-Specific Configuration

Override global settings for a specific repository:

Via GitHub Desktop

1

Open Repository Settings

Right-click repository > Repository Settings
2

Configure Identity

Set name and email specific to this repository
3

Additional Settings

Use terminal for advanced configuration

Via Command Line

# In the repository directory
cd /path/to/repo

# Set repository-specific email
git config user.email [email protected]

# Set repository-specific name
git config user.name "Work Name"

# View local config
git config --local --list

Common Configuration Scenarios

Work vs. Personal Repositories

# Global defaults (personal)
git config --global user.name "Personal Name"
git config --global user.email "[email protected]"

# Override for work repositories
cd ~/work/company-repo
git config user.email "[email protected]"
git config user.name "Professional Name"

GPG Signing

# Set GPG key
git config --global user.signingkey <key-id>

# Enable automatic signing
git config --global commit.gpgsign true

# Enable for tags too
git config --global tag.gpgsign true

Proxy Settings

# Set HTTP proxy
git config --global http.proxy http://proxy.example.com:8080

# Set HTTPS proxy
git config --global https.proxy https://proxy.example.com:8080

# Bypass proxy for specific domain
git config --global http.https://github.com.proxy ""
See Proxies for more details.

Large File Storage (LFS)

# Enable LFS
git lfs install

# Track specific file types
git lfs track "*.psd"
git lfs track "*.mp4"

# View LFS config
git config --list | grep lfs

Viewing All Configuration

List All Settings

# View all config (system, global, local)
git config --list

# View global config only
git config --global --list

# View local config only
git config --local --list

# Show origin of each setting
git config --list --show-origin

View Specific Section

# All user settings
git config --get-regexp user

# All core settings
git config --get-regexp core

# All remote settings
git config --get-regexp remote

Advanced Configuration

Aliases

Create shortcuts for common commands:
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit

# Now you can use:
git st  # instead of git status
git co main  # instead of git checkout main

Diff and Merge Settings

# Better diff algorithm
git config --global diff.algorithm histogram

# Show moved lines in diffs
git config --global diff.colorMoved zebra

# Default merge strategy
git config --global pull.rebase false  # merge (default)
git config --global pull.rebase true   # rebase

Performance

# Enable parallel index preload
git config --global core.preloadindex true

# Enable file system cache (Windows)
git config --global core.fscache true

# Limit delta compression
git config --global pack.windowMemory 256m

Troubleshooting

If commits show the wrong author:
# Check current config
git config user.name
git config user.email

# Check global config
git config --global user.name
git config --global user.email

# Set correct values
git config --global user.name "Correct Name"
git config --global user.email "[email protected]"
If configuration changes don’t work:
  • Check config priority (local > global > system)
  • Verify you’re setting the right level
  • Restart GitHub Desktop after changes
  • Check for typos in config names
# See which value is being used and where it's from
git config --show-origin user.email
If config commands fail:
  • Check file permissions on .gitconfig
  • Ensure Git is in PATH
  • Try running as administrator (Windows)
  • Check for file locks
# Edit config file directly
git config --global --edit
To start fresh:
# Backup current config
cp ~/.gitconfig ~/.gitconfig.backup

# Remove config file
rm ~/.gitconfig

# Reconfigure
git config --global user.name "Your Name"
git config --global user.email "[email protected]"

Best Practices

Use .gitattributes for line endings: Instead of relying on core.autocrlf, define line endings per file type in .gitattributes for consistent behavior across all contributors.
  1. Set Identity First
    • Always configure user.name and user.email before committing
    • Use work email for work repositories
    • Use personal email for open-source contributions
  2. Document Custom Configuration
    • Keep notes on non-standard settings
    • Share team configuration in repository README
    • Use consistent settings across team
  3. Use .gitattributes
    • Define line endings per file type
    • More reliable than core.autocrlf
    • Committed to repository (shared with team)
  4. Review Regularly
    • Audit config occasionally: git config --list
    • Remove obsolete settings
    • Update deprecated options
  5. Avoid System-Level Config
    • Use global or local instead
    • System config affects all users
    • Can cause confusion

Configuration Files

Example .gitconfig

[user]
    name = Jane Doe
    email = [email protected]
[core]
    autocrlf = input
    editor = code --wait
[init]
    defaultBranch = main
[pull]
    rebase = false
[credential]
    helper = osxkeychain
[alias]
    st = status
    co = checkout
    br = branch
    ci = commit

Example .git/config (Local)

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = https://github.com/user/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main
[user]
    email = [email protected]

Build docs developers (and LLMs) love