Skip to content

Instantly share code, notes, and snippets.

@mwhite
Last active October 17, 2024 20:51
Show Gist options
  • Save mwhite/6887990 to your computer and use it in GitHub Desktop.
Save mwhite/6887990 to your computer and use it in GitHub Desktop.
The Ultimate Git Alias Setup

The Ultimate Git Alias Setup

If you use git on the command-line, you'll eventually find yourself wanting aliases for your most commonly-used commands. It's incredibly useful to be able to explore your repos with only a few keystrokes that eventually get hardcoded into muscle memory.

Some people don't add aliases because they don't want to have to adjust to not having them on a remote server. Personally, I find that having aliases doesn't mean I that forget the underlying commands, and aliases provide such a massive improvement to my workflow that it would be crazy not to have them.

The simplest way to add an alias for a specific git command is to use a standard bash alias.

# .bashrc

alias s="git status -s"

The disadvantage of this is that it isn't integrated with git's own alias system, which lets you define git commands or external shell commands that you call with git <alias>. This has some nice advantages:

  • integration with git's default bash completion for subcommand arguments
  • ability to store your git aliases separately from your bash aliases
  • ability to see all your aliases and their corresponding commands using git config

If you add the following code to your .bashrc on a system with the default git bash completion scripts installed, it will automatically create completion-aware g<alias> bash aliases for each of your git aliases.

if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
    . /etc/bash_completion                                                                                                                                                                
fi


function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

for al in `__git_aliases`; do
    alias g$al="git $al"
    
    complete_func=_git_$(__git_aliased_command $al)
    function_exists $complete_fnc && __git_complete g$al $complete_func
done

The main downside to this approach is that it will make your terminal take a little longer to load.

My aliases

Here are the aliases I use constantly in my workflow. I'm lazy about remembering many other aliases that I've decided I should be using, which this setup is great for because I can always list them all using gla.

[alias]
    # one-line log
    l = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --date=short

    a = add
    ap = add -p
    c = commit --verbose
    ca = commit -a --verbose
    cm = commit -m
    cam = commit -a -m
    m = commit --amend --verbose
    
    d = diff
    ds = diff --stat
    dc = diff --cached

    s = status -s
    co = checkout
    cob = checkout -b
    # list branches sorted by last modified
    b = "!git for-each-ref --sort='-authordate' --format='%(authordate)%09%(objectname:short)%09%(refname)' refs/heads | sed -e 's-refs/heads/--'"

    # list aliases
    la = "!git config -l | grep alias | cut -c 7-"

See Must Have Git Aliases for more.

@lulcat
Copy link

lulcat commented Dec 14, 2016

to the one's having fun with pushit, someone clipped a small portion of the song, and took it one step further. Need mpg123 installed and gnu coreutils, aka linux;

bash <(curl -s http://sprunge.us/ADKW)

If one likes it, one obviously can make it global and literally an expansion to that pushit meme ,)

@adrianojn
Copy link

adrianojn commented Jan 8, 2017

interactive commit, new branch, update submodules

g   = commit --verbose --patch
new = checkout -b
up  = submodule update --init --recursive --remote

@travellingprog
Copy link

Here's some useful ones I have that haven't been mentioned yet

# branch delete: This checks out your local master branch and deletes all local branches
#                that have already been merged to master
brd = !sh -c \"git checkout master && git branch --merged | grep -v '\\*' | xargs -n 1 git branch -d\"

# branch delete here: Deletes all local branches that have already been merged to the branch
#                     that you're currently on
brdhere = !sh -c \"git branch --merged | grep -v '\\*' | xargs -n 1 git branch -d\"

# diff status: A git diff, but with only the filenames (which reminds me of git status)
diffst = diff --name-only

# forced pull: You have a local branch (e.g. for reviewing), but someone else did a forced push
#              update on the remote branch. A regular git pull will fail, but this will just set
#              the local branch to match the remote branch. BEWARE: this will overwrite any local
#              commits you have made on this branch that haven't been pushed.
pullf = !sh -c \"git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)\"

# quick amend: Amend my staged changes to the last commit, keeping the same commit message
amend = commit --amend -C HEAD

# history: This is pretty much the only way I look at my log. Aside from providing one-line logs,
#          it also shows the branching in/out
hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short

@sureshshrestha
Copy link

This one is also usefule to run merge test before merge to check for any conflicts.
mergetest = "!f(){ git merge --no-commit --no-ff \"$1\"; git merge --abort; echo \"Merge aborted\"; };f "

@ErwanAliasr1
Copy link

Simple simple but really efficient to minimize the size of a diff. It uses color to inline the differences.

wdiff = diff --word-diff

@RichardBronosky
Copy link

@make-github-pseudonymous-again

To extend on @ErwanAliasr1

# Diff line-wise
d = diff

# Diff staged line-wise
ds = diff --staged

# Diff word-wise
dw = diff --color-words

# Diff staged word-wise
dws = diff --color-words --staged

# Diff character-wise
dt = diff --word-diff-regex=.

# Diff staged character-wise
dts = diff --word-diff-regex=. --staged

@make-github-pseudonymous-again

And for the fish shell:

abbr g git

# Alias all git aliases
for al in (git config -l | grep '^alias\.' | cut -d'=' -f1 | cut -d'.' -f2)
    abbr g$al "git $al"
end

@conformist-mw
Copy link

Now in git 2.18.0 there are no __git_aliases command. How to deal with it?

@conformist-mw
Copy link

conformist-mw commented Aug 8, 2018

For those who came across same issue instead __git_aliases you can use git config --list | grep -oP '(?<=alias\.)\w+'.

@plegay
Copy link

plegay commented Oct 12, 2018

alias to show all aliases
git config --global alias.aliases "config --get-regex 'alias*'"

@natewind
Copy link

natewind commented Oct 14, 2018

For easy commits:

gcommit()
{
	if test $# -eq 0; then
		message=' '

	elif test $# -eq 1; then
		message=$1
	else
		echo "Error: Wrong number of arguments!"
		return
	fi

	git add -A :/
	git commit -m "$message"
}

alias gpush='git push'

@NotSoShaby
Copy link

I copy the exact function:

if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
    . /etc/bash_completion
fi


function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

for al in `__git_aliases`; do
    alias g$al="git $al"

    complete_func=_git_$(__git_aliased_command $al)
    function_exists $complete_fnc && __git_complete g$al $complete_func
done

to my .zshrc file, and I get:
parse error near \n'`
in the line where this function ends (the last lkine, where the 'end' is).

Any ideas what im doing wrong?

@dasong
Copy link

dasong commented Feb 5, 2019

As of git 2.18.0, __git_aliases has been replace with git --list-cmds=alias

@dlopezdev
Copy link

If anyone wants this solution for Windows, the following works for me on Windows 10 64-bits with Git for Windows v2.21.0 with optional Unix tools installed (standard installation location):

if [ -f "C:\Program Files\Git\etc\bash_completion" ] && ! shopt -oq posix; then
    . "C:\Program Files\Git\etc\bash_completion"                                                                                                                                                                
fi

function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

for al in `git --list-cmds=alias`; do
    alias g$al="git $al"
    
    complete_func=_git_$(__git_aliased_command $al)
    function_exists $complete_fnc && __git_complete g$al $complete_func
done

Also, just FYI, the .bashrc file should be located in C:\Users\<username>\.bashrc

@aasutossh
Copy link

I am getting

__git_aliased_command: command not found
__git_complete: command not found

on bash.
Any ideas?

@astropanic
Copy link

astropanic commented Mar 3, 2020

git config --global alias.col 'checkout @{-1}'

Check out the last branch you were on

git checkout -

just works

@dlopezdev
Copy link

I am getting

__git_aliased_command: command not found
__git_complete: command not found

on bash.
Any ideas?

A bit late with the reply, but try to check if regular git autocompletion works. Otherwise you might need to do this:
https://stackoverflow.com/questions/36795816/git-auto-complete-not-working-in-bash

I had the same error in Debian, did sudo apt-get install git bash-completion and then aliases worked. Just make sure you are using the updated script since, as explained by @dasong, __git_aliases no longer exists.

@nicolas-t
Copy link

Using git --list-cmds=alias instead of __git_aliases fixed it for me.
Related commit :
git/git@3301d36

@SangamSwadiK
Copy link

Thanks!

@robertcatgithub
Copy link

because I can always list them all using gla.

you mean "git la" ?

@korthout
Copy link

For those looking to use this on zsh:

for al in `git --list-cmds=alias`; do
    alias g$al="git $al"
done

@jtunhag
Copy link

jtunhag commented Dec 12, 2023

The completion function for cherry-pick is _git_cherry_pick (not _git_cherry-pick), so there needs to be a replacement like

aliased_command=$(__git_aliased_command $al)
complete_func="_git_${aliased_command/-/_}"

to handle such commands as well.

@ABD-01
Copy link

ABD-01 commented Jan 10, 2024

[alias]
	fb = !sh -c \"git branch -a | grep -v remotes | grep $1\"
	cb = !sh -c \"git branch -a | grep -v remotes | grep $1 | head -n 1 | xargs git checkout\"

To find a branch, mostly my work involves jumping to branch based on issue no.
so for branch: falcon/ABD-01/2972-TCP-socket-initialization-failed where 2972 is issue no. so I just do:

gfb 2972  ## I find the branch else I create it

Reference: https://stackoverflow.com/a/11388904

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment