The fastest way to create a git alias is git config --global alias.<name> <command>. So git config --global alias.co checkout makes git co mean git checkout everywhere on your machine. That one command is the whole mechanism. The rest of this page is which aliases are worth having, where they live, and the one case where a plain alias is not enough and you need the shell form.
git config --global alias.co checkout
git config --global alias.st "status -sb"
# Now `git co main` and `git st` work in any repo.Aliases set with --global are written to ~/.gitconfig under an [alias] section. You can open that file and edit them directly, which is faster than running ten git config commands and easier to keep in your dotfiles:
[alias]
co = checkout
st = status -sb
br = branchDrop --global and the alias goes into the current repo's .git/config instead, which is rarely what you want for a shortcut. Keep aliases global and let every repo inherit them.
A curated set worth having
Here is the set I actually use, every day, after years of trimming the list down. Each line is one git config --global command. They are short on purpose: an alias you have to think about is an alias you will not reach for.
git config --global alias.st "status -sb"
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.last "show HEAD"
git config --global alias.unstage "restore --staged"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.undo "reset --soft HEAD~1"What each one buys you:
git strunsstatus -sb: the short status format plus the branch line. It is the same information as plainstatusin a fraction of the vertical space, so the whole picture fits on one screen.git lgis a compact, colored commit graph across all branches. The mnemonic for the four switches is "a dog": all, decorate, oneline, graph. This is the single alias people copy after seeing it on someone else's terminal.git lastshows the most recent commit, message and diff, without typinggit show HEAD.git unstage <file>wraps the moderngit restore --staged, the clear way to take a file back out of the index while keeping your edits. (The old form wasgit reset HEAD <file>.)git amendfolds your staged changes into the previous commit and reuses its message, no editor pop-up, because of--no-edit. Do not amend a commit you have already pushed to a shared branch.git undomovesHEADback one commit but leaves the changes staged, so a wrong commit becomes uncommitted-but-not-lost work. For the full set of undo moves (working tree, staged, committed, pushed) see how to undo things in git.
You can alias an alias since git 2.20, so git config --global alias.unst unstage is legal if you want a shorter handle.
Shell aliases vs git aliases (the ! prefix)
Everything above is a plain git alias: the alias name expands to a git subcommand. That covers most of what you want. But a plain alias can only run a git command. The moment you need a pipe, a shell built-in, more than one command, or to put an argument anywhere other than the end, you need the shell form: prefix the expansion with !.
With a leading !, git hands the whole expansion to your shell instead of treating it as a git subcommand:
git config --global alias.cleanup "!git branch --merged | grep -v '\*' | xargs -r git branch -d"git cleanup now deletes every local branch already merged into the current one. None of that is possible without !: it has a pipe and an xargs, which are shell features, not git.
The catch with shell aliases is argument handling. Git appends any extra arguments you pass to the end of the expansion. That is fine when the argument belongs at the end, but breaks the moment you need it in the middle. The fix is the function form: wrap the body in a throwaway shell function (named f by convention) and call it. Git still appends the extra arguments, but now they land as arguments to the f call at the end, where they do no harm, while the "$1" inside the function resolves to the real first argument. This is the exact pattern the git-config docs recommend for the problem:
git config --global alias.diffmain '!f() { git diff "$1" main; }; f'Now git diffmain feature/login diffs the branch you name against main. The "$1" sits in the middle of the command, with the fixed main after it, which a plain alias cannot do: a plain alias only ever appends your argument to the end, so it could not slot a branch name in before main. The same pattern handles any alias that needs more than one argument, or an argument followed by more command:
git config --global alias.search '!f() { git log --all --oneline --grep "$1"; }; f'Here git search timeout greps every branch's commit messages for "timeout". The grep term does sit at the end, so this one could almost be a plain alias, but wrapping it in the function lets you quote "$1" so a multi-word search like git search "connection reset" is passed as a single pattern instead of being split.
A couple of things to know about the shell form. The shell command runs from the top level of the repository, not your current directory, and git sets GIT_PREFIX to where you actually were if you need it. And inside the function, the arguments are plain shell positional parameters, so quote them ("$1") to survive spaces.
Shell-level aliases as a complement
Git aliases live inside git, so you still type the word git every time. A shell alias removes even that. In your ~/.zshrc or ~/.bashrc:
alias g=gitNow g st runs git status -sb, combining the shell alias with the git alias. This is a nice complement rather than a replacement: the git alias is portable (it travels in ~/.gitconfig and works in any shell), while the shell alias is the extra keystroke shave that only your shell knows about. I keep g and let the git aliases carry the real shortcuts, so a teammate copying my ~/.gitconfig gets the useful part without my shell config.
If you maintain custom hooks alongside these shortcuts, see the practical guide to git hooks; for the branch verbs the aliases above wrap, the essential git branch commands reference covers switch, --show-current, and deleting local and remote branches.
FAQ
See also
- How to undo things in git: restore, reset, revert, and amend, the full decision table behind the undo and unstage aliases above.
- A practical guide to git hooks: run scripts before commit and after checkout, and share them with your team.
- Essential git branch commands: current, default, and previous branch, plus deleting local and remote branches.
Sources
Authoritative references this article was fact-checked against.
- git-config: alias.* (official documentation)git-scm.com
- Pro Git: Git Aliases (official book)git-scm.com





