Some Git sugar for your .bashrc



I'm one of those people that use Git command line quite a lot and have not really adopted any Git GUI clients. To make make life in the terminal more efficient I have added some sugar to my .bashrc.

Make "g" an alias for "git"

alias g='git'
__git_complete g __git_main

The first line creates the alias g for git. Sadly tab completion stops working and the second line takes care of re-adding that. At the time of writing I'm running Git version 2.11.0 on macOS installed via Brew.

Branch Shortcuts

alias bm='git checkout master'
alias bd='git checkout develop'
alias bb='git checkout -'

alias b='git checkout'
__git_complete b _git_checkout

alias bn='git checkout -b'
__git_complete bn _git_checkout

function bs() {
    local branch="$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')"

    if [[ "${branch}" == "" ]] ; then
        echo "No branch found!"
        return 1
    fi

    echo "${branch}" > ~/savedbranch.txt
}

function bl() {
    local branch="$(cat ~/savedbranch.txt)"
    git checkout "${branch}"
}

Jumping between branches is so common I've added aliases that even allow me to omit the initial g. The functions bs and bl stands for "branch save" and "branch load" and allow me to save a certain branch name that I can later on jump back to.

Gitty Git Aliases

# http://durdn.com/blog/2012/11/22/must-have-git-aliases-advanced-examples/
  
# Clone
git config --global alias.cl 'clone'
  
# Branch
git config --global alias.b 'branch'
git config --global alias.br 'branch'
git config --global alias.bdl 'branch --delete'
git config --global alias.bdr 'push origin --delete'
git config --global alias.bd '!f() { read -r -p "Delete the branch ${1} both locally and remotely? [y/N]" response; if [[ "${response}" =~ ^([yY][eE][sS]|[yY])$ ]]; then echo "... deleting local branch ${1} ..."; git branch --delete "${1}"; echo "... deleting remote branch ${1} ..."; git push origin --delete "${1}"; echo "... done."; else echo "aborted"; fi }; f'
  
# Check Out
git config --global alias.co 'checkout'
  
# Status
git config --global alias.s 'status'
git config --global alias.d 'diff'
  
# Add
git config --global alias.a 'add'
git config --global alias.aa 'add --all'
  
# Commit
git config --global alias.c 'commit'
git config --global alias.ci 'commit'
git config --global alias.ca 'commit --amend'
git config --global alias.cia 'commit --amend'
  
# Merge
git config --global alias.m 'merge'
  
# External Tools
git config --global alias.mt 'mergetool'
git config --global alias.dt 'difftool'
 
# Pull
  
# Pushing
git config --global alias.p 'push'
git config --global alias.pf 'push --force'
  
# Fetching
git config --global alias.f 'fetch'
git config --global alias.fa 'fetch --all'
  
# Reset
git config --global alias.r 'reset'
git config --global alias.r1 'reset HEAD^'
git config --global alias.r2 'reset HEAD^^'
git config --global alias.rh 'reset --hard'
git config --global alias.rh1 'reset HEAD^ --hard'
git config --global alias.rh2 'reset HEAD^^ --hard'
  
# Cherry Pick
git config --global alias.cp 'cherry-pick'
  
# Stash
git config --global alias.sl 'stash list'
git config --global alias.sa 'stash apply'
git config --global alias.ss 'stash save'

Of course you should throw in some regular "git git aliases" as well.

Bulk Actions on Many Repositories

# Buffer and Eachdir
buffer ()
{
    local buffer="$(cat; echo 'x')"
    printf '%s' "${buffer%x}"
}
eachdir ()
{
    local cmd="${@}"
    local directories=($(find . -mindepth 1 -maxdepth 1 -type d))
    for directory in "${directories[@]}" ; do
        local directory="${directory:2}"
        {(cd "${directory}"; echo -e "\e[92m[ ${directory} ]\e[0m"; eval "${cmd}") 2>&1 | buffer &} 2>/dev/null
    done
    wait 2>/dev/null
}

Behold mein bulk action tool! Assume you wanted to git add everything in all repositories placed within the directory you are currently standing. This is how you would do it:

eachdir 'git add --all'
eachdir 'git commit -m "I made this same change to many repositories"'
eachdir 'git push'

And the beauty of it is that the work is done asynchronously.