Aliases and config
git config tunes git to your hands. Aliases shorten commands (alias.co checkout, a graph-log alias, shell aliases with !). Settings like pull.rebase and push.autoSetupRemote remove daily friction. Config has three scopes — system, global, local — and the most specific wins.
You type git checkout, git status, and a long git log --oneline --graph --decorate --all dozens of times a day. You also re-fix the same annoyances on every machine: a noisy merge bubble on every pull, having to spell out --set-upstream on the first push of each branch. All of it is configurable once and forgotten. The tool is git config, and learning it turns git from something you fight into something shaped to your hands.
By the end of this lesson you will be able to write aliases (including shell-powered ones), set the config options that remove daily friction, and reason about which of git’s three config scopes actually applies.
After this lesson you can create git aliases for common and shell-backed commands, set ergonomic config options like pull.rebase and push.autoSetupRemote, and explain git’s three config scopes — system, global, local — and which one wins.
An alias is a config entry that renames a command — write it with git config. Under the hood an alias is just a key under the alias. section. The classic short forms:
git config --global alias.co checkout
git config --global alias.st status
git config --global alias.br branch
git config --global alias.cm commitNow git co main runs git checkout main. These live in your global config, so they follow you across every repo on the machine. Define them once and the savings compound over thousands of invocations.
Aliases can expand into multi-flag commands — the famous one is a graph log. An alias value can be a whole argument string, which is how everyone ends up with a one-word pretty history:
git config --global alias.lg "log --oneline --graph --decorate --all"
git lg # the full annotated commit graph, in two lettersThis is the single highest-value alias most engineers add: a readable, branch-aware history view that would be tedious to type in full every time you want to see where things stand.
Prefix an alias with ! to run a shell command, not just a git subcommand. When you start an alias value with !, git runs it through the shell, so you can chain commands, call other tools, or build small scripts:
git config --global alias.last "log -1 HEAD" # plain git subcommand
git config --global alias.unstage "reset HEAD --" # plain git subcommand
git config --global alias.pushup "!git push -u origin HEAD" # shell: works on any branchThe ! form unlocks anything the shell can do, but it also means the alias is no longer a pure git command — it runs from the repository root and can call non-git programs, so keep these readable.
A handful of config options remove most daily friction. These are the settings experienced engineers set on a fresh machine before doing anything else:
git config --global pull.rebase true # rebase on pull instead of making merge bubbles
git config --global rebase.autostash true # auto-stash dirty changes around a rebase
git config --global push.autoSetupRemote true # first push sets upstream automatically
git config --global init.defaultBranch main # new repos start on 'main'
git config --global rerere.enabled true # remember how you resolved a conflict, replay it
git config --global column.ui auto # tidy multi-column output for lists
git config --global core.editor "code --wait" # use your editor for commit messagesEach one quietly deletes a recurring annoyance: no more merge bubbles from routine pulls, no manual --set-upstream, no re-resolving the same conflict twice (rerere).
▸Why this works
Why does git have three config scopes? Because different settings belong at different lifetimes. System (/etc/gitconfig, set with --system) applies to every user on the machine — rare, usually set by an admin. Global (~/.gitconfig, --global) is your personal default across all your repos — where your name, email, and aliases live. Local (.git/config, --local, the default) is per-repository — where a work email or a project-specific setting overrides your global one. Splitting them lets a single setting (say, your commit email) be a personal default globally but be overridden for one client’s repo locally.
A per-repo email that overrides your personal default.
Your global config uses your personal email for everything. For one client’s repository you must commit with your work email instead. Set it locally — inside that repo — and confirm which value wins:
git config --global user.email "me@personal.dev" # your default, set once globally
cd ~/work/client-repo
git config --local user.email "me@client.com" # override, only in THIS repo
git config user.email
# me@client.com <- local beats global
git config --list --show-origin | grep user.email
# file:/home/me/.gitconfig user.email=me@personal.dev
# file:.git/config user.email=me@client.comgit config --list --show-origin is the tool that ends every “which value is actually in effect?” argument: it prints every setting and the exact file it came from, so the precedence is visible rather than guessed. In this repo the local me@client.com wins; everywhere else your global personal email applies.
▸Common mistake
The classic confusion is setting something with --global and being surprised a particular repo ignores it — or vice versa. The cause is almost always a more specific local value overriding the global one. When git “won’t use my config,” do not guess: run git config --list --show-origin (or git config --show-origin <key>) and read which file the effective value comes from. The other trap is setting user.email only globally and accidentally committing to a work repo with a personal address — set the local override deliberately per repo when it matters.
user.email is set to one value with --global and a different value with --local inside a specific repo. Which value does a commit in that repo use?
git config tunes git to your hands. Aliases (alias.co checkout, a log --oneline --graph --decorate --all alias, and !-prefixed shell aliases) cut typing on commands you run all day. A few ergonomic settings — pull.rebase, rebase.autostash, push.autoSetupRemote, init.defaultBranch, rerere.enabled, core.editor — delete recurring friction on every machine. Config lives in three scopes — system, global (~/.gitconfig), and local (.git/config) — and the most specific wins, so local overrides global overrides system. When a setting seems ignored, git config --list --show-origin shows exactly which file the effective value came from. You have now built a daily-power-tools kit: stash, cherry-pick, tags, worktrees, and a git shaped to you.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.