Troubleshooting Git Configuration Problems: Common Fixes and Best Practices
Fix Git config problems by tracing setting origins, resolving identity, alias, hook, line-ending, pull, and credential issues.
Troubleshooting Git Configuration Problems: Common Fixes and Best Practices
Most Git configuration problems feel stranger than they are. Git is usually doing exactly what one of its config files told it to do. The hard part is finding which file, because the setting may live in the repository, your user config, a system config, an included file, or a conditional include that only applies under one directory.
The command I reach for first is this:
git config --list --show-origin --show-scope
If your Git version does not support --show-scope, use:
git config --list --show-origin
The origin tells you which file supplied each value. That matters more than the value alone. Seeing [email protected] is not enough; you need to know whether it came from .git/config, ~/.gitconfig, /etc/gitconfig, or an included work profile.
Git config has a priority order. Local repository config normally beats global user config, and global config beats system config. Command-line options and environment variables can override all of them for one command. Conditional includes add another layer: a global file can say, "When I am inside this directory, load this other config too."
You can inspect one setting with its source:
git config --show-origin --get user.email
git config --show-origin --get core.autocrlf
git config --show-origin --get-regexp '^alias\.'
That habit prevents a lot of wasted editing. If a repository has user.email set locally, changing git config --global user.email will not affect commits in that repository.
Wrong Name or Email on Commits
The symptom is simple: commits show the wrong author. This often happens when you use the same laptop for work and personal projects, or when you clone a company repository before setting your work email.
Check what Git will use in the current repository:
git config user.name
git config user.email
git config --show-origin --get user.email
Set your default identity globally:
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
For one repository, set it locally:
git config --local user.name "Your Name"
git config --local user.email "[email protected]"
If you want Git to refuse commits when identity is not configured explicitly, use:
git config --global user.useConfigOnly true
That setting is useful for people who switch between identities. It can annoy beginners because Git will stop guessing from the system username and hostname. Use it when you would rather fail a commit than create one under the wrong address.
For a cleaner work/personal split, use conditional includes:
# ~/.gitconfig
[user]
name = Your Name
email = [email protected]
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
Then put this in ~/.gitconfig-work:
[user]
email = [email protected]
The trailing slash in gitdir:~/work/ matters because it means repositories under that directory. If it does not trigger, run git config --list --show-origin from inside a work repository and check whether the included file appears.
If you already made commits with the wrong email, changing config only fixes future commits. For unpublished commits, you can amend or rebase. For commits already pushed to a shared branch, ask before rewriting history.
Aliases That Do Not Work
Git aliases are stored under alias.*. List them like this:
git config --get-regexp '^alias\.'
A normal alias expands to a Git subcommand:
git config --global alias.st 'status -sb'
git st
If the alias needs a shell pipeline, variable expansion, cd, or another non-Git command, it must begin with !:
git config --global alias.recent '!git for-each-ref --sort=-committerdate --count=10 --format="%(refname:short)" refs/heads/'
Without !, Git tries to treat the first word as a Git command. ls -la becomes "run the Git command named ls," which is not what you meant.
Quoting is the other common failure. If you define aliases from the shell, use single quotes around the whole alias when possible, then double quotes inside it as needed. Different shells handle quoting differently, especially PowerShell and cmd.exe. If a complex alias keeps breaking, edit the config file directly:
git config --global --edit
A practical debug trick is to start with the command outside Git. Once it works, paste it into the alias. If it is a shell alias, prefix it with ! and test again.
Also watch for aliases that shadow mental models. An alias named pull or merge can make Git behavior surprising. Git does not let aliases override built-in commands directly, but shell aliases and wrapper scripts can. If git pull behaves oddly, check your shell configuration too:
type git
alias | grep git
Hooks That Never Run
Hooks fail for three boring reasons: Git is looking in a different hooks directory, the file is not executable, or the script assumes an environment it does not have.
Check the configured hooks path:
git config --show-origin --get core.hooksPath
If this prints .githooks, Git will use .githooks/pre-commit, not .git/hooks/pre-commit. If it prints nothing, Git uses .git/hooks.
On macOS and Linux, check permissions:
ls -l .git/hooks/pre-commit .githooks/pre-commit 2>/dev/null
chmod +x .githooks/pre-commit
A hook that exits with a non-zero status blocks the Git operation. Add temporary tracing near the top:
#!/usr/bin/env bash
set -x
pwd
env | sort
Do not leave noisy tracing in a shared hook. It becomes unreadable quickly.
Path issues are common with GUI clients. A hook that works in your terminal may fail in an IDE because the IDE did not load your shell profile. Prefer project-local commands where possible:
./node_modules/.bin/eslint .
or check for the command and print a useful message:
if ! command -v npm >/dev/null 2>&1; then
echo "npm is required for this hook but was not found in PATH."
exit 1
fi
Line Endings Keep Changing
Line-ending problems show up as files that appear modified immediately after checkout, large diffs where every line changed, or scripts that fail on Linux after being edited on Windows.
Check your setting:
git config --show-origin --get core.autocrlf
git config --show-origin --get core.eol
Common choices are:
# Windows-friendly checkout, LF in repository
git config --global core.autocrlf true
# macOS/Linux-friendly: convert CRLF to LF on commit only
git config --global core.autocrlf input
# No automatic conversion
git config --global core.autocrlf false
For a team, .gitattributes is more reliable than telling every developer to set globals correctly. Put project rules in the repository:
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary
*.pdf binary
After adding or changing .gitattributes, normalize files deliberately:
git add --renormalize .
git status
Review that diff carefully. It can touch many files, and you do not want to mix line-ending normalization with feature work.
Pull, Push, or Merge Uses the Wrong Default
Sometimes the config problem is not identity or line endings. It is Git choosing a pull strategy you did not expect.
Check pull-related settings:
git config --show-origin --get pull.rebase
git config --show-origin --get pull.ff
git config --show-origin --get branch.main.rebase
If git pull keeps rebasing when you expected a merge, pull.rebase or a branch-specific setting may be enabled. If it refuses non-fast-forward pulls, pull.ff=only may be set. These settings are not wrong by themselves; they just need to match the team's workflow.
Set an explicit default instead of living with warnings and surprises:
# Merge on pull
git config --global pull.rebase false
# Rebase on pull
git config --global pull.rebase true
# Only allow fast-forward pulls
git config --global pull.ff only
For one branch:
git config branch.main.rebase true
Credential Helper Confusion
Authentication issues often look like remote problems but come from local config. Git may use a credential helper that has an old token cached.
Check helpers:
git config --show-origin --get-all credential.helper
You may see osxkeychain, manager, manager-core, store, or cache. Multiple helpers can exist. If Git keeps sending the wrong credential, remove it from the OS keychain or credential manager rather than changing random remote URLs.
Also check the remote:
git remote -v
SSH and HTTPS use different authentication paths. If one repository uses [email protected]:org/repo.git and another uses https://github.com/org/repo.git, they will not necessarily use the same credentials.
A Reliable Debugging Routine
When Git configuration feels inconsistent, use a routine instead of guessing:
- Run the failing command from the repository root.
- Inspect the exact setting with
git config --show-origin --get <name>. - List related settings with
git config --list --show-origin --show-scope. - Check local config in
.git/configbefore changing global config. - Check conditional includes if the problem only happens under one directory.
- Make the smallest config change and rerun the original command.
Git config is powerful because it can be layered. That is also why it gets confusing. The fix is to make the layers visible, then change the layer that is actually winning.
When Configuration Is Different Inside an IDE
A confusing class of Git problems appears only inside an editor or GUI. The terminal uses one identity, but the IDE commits with another. A hook passes in your shell, but fails from the commit panel. A credential prompt appears in the terminal, while the GUI silently retries with an old token.
The reason is usually environment. Your interactive shell may load .bashrc, .zshrc, SDK managers, language version managers, and custom PATH entries. A GUI launched from the desktop may not load any of that. Git itself reads the same config files, but hooks and credential helpers may see a different world.
To debug it, create a temporary hook that prints the environment to a local file:
#!/usr/bin/env bash
{
date
pwd
git --version
git config --list --show-origin
env | sort
} > /tmp/git-hook-debug.log
exit 1
Run the Git action from the IDE, then inspect /tmp/git-hook-debug.log. Remove the hook afterward. This tells you what Git and the hook actually saw, instead of what your terminal sees.
For identity problems in GUI clients, check whether the tool has its own Git settings. Some clients use system Git; others bundle Git or store user identity in application preferences. If the client is committing through Git, git log --format=fuller -1 will show the resulting author and committer. That helps separate "Git config was wrong" from "the GUI used its own setting."
When in doubt, make repository-local settings explicit for projects that matter:
git config --local user.email "[email protected]"
git config --local core.hooksPath .githooks
Local config reduces surprises because it travels with the repository metadata on that machine. It still does not get committed, so shared rules should live in tracked files such as .gitattributes, .editorconfig, hook scripts, and project documentation.
Keep a Known-Good Baseline
When config problems keep returning, save a small known-good baseline for your own machines. It does not need to be fancy. A commented ~/.gitconfig with your identity, editor, default branch behavior, credential helper, and includes is enough. Then, when a new laptop behaves differently, you can compare instead of rediscovering every setting.
Useful baseline checks include:
git config --global --list --show-origin
git config --global --get core.editor
git config --global --get init.defaultBranch
git config --global --get-all credential.helper
Be careful about copying config from the internet or from a coworker. Aliases may assume tools you do not have. Credential helpers are platform-specific. Line-ending settings may be right for their OS and wrong for yours. Treat Git config like shell config: borrow ideas, but understand each line before keeping it.
For project maintainers, the best fix is moving shared expectations out of personal config. Put line endings in .gitattributes, formatting in the formatter config, ignored files in .gitignore, and required checks in CI. The less a project depends on invisible global settings, the fewer configuration tickets it creates.
When you change a setting to fix a problem, write down whether it was local or global. Many future Git mysteries start with a good temporary local fix that nobody remembers six months later.