Hands down, my favorite code versioning tool.


Bash Aliases

I have compiled a whole bunch of aliases that let me shorten most of the git commands that I use down to 3 characters. Due to some ambiguity with the three leter aliases there are a few longer aliases near the bottom too. I have tried to choose short aliases that would be intuitive to remember:

WORD_DIFF="" #"--word-diff=plain"

# Aliases to speed up git usage
alias gad='git add'
alias gap='git apply'
alias gbr='git branch'
alias gch='git checkout'
alias gcl='git clone'
alias gco='git commit'
alias gcp='git cherry-pick'
alias gdi="git diff --color --patience $WORD_DIFF"
alias gfe='git fetch'
alias ggr='git grep'
alias glo='git log'
alias glc='git log --cherry'
alias gme='git merge'
alias gmv='git mv'
alias gpl='git fetch && git pull'
alias gpu='git push'
alias grb='git rebase'
alias gre='git reset'
alias grm='git rm'
alias gsh='git show --color --patience'
alias gst='git status -sb'
alias gta='git tag'

alias gstash='git stash'
alias gdic="git diff --color --patience --cached $WORD_DIFF"
alias gcoa='git commit --amend'
alias gplr='git pull --rebase'
alias gplrpu='git pull --rebase && git push'
alias gstat='git diff --numstat'
alias gfpl='git fetch && gpl --rebase'
alias gclf='git clean -fd'
alias gloo='git log --pretty=format:"%C(auto)%h%x09%an %x09%s"'

Tricks

Pushing to multiple URLs:

Set up a new remote to push to multiple URLs at once (i.e. push to both bitbucket and github at the same time). Create a new remote with an appropriate name; the URL used when creating this remote will only be used for fetching. Next run the following command for each push URL you wish to add to the remote:

git remote set-url --add --push <remote-name> <push-url>

Fixing commit authorship on any commits with matching name/email in history:

git filter-branch --env-filter '
    an="$GIT_AUTHOR_NAME"
    am="$GIT_AUTHOR_EMAIL"
    cn="$GIT_COMMITTER_NAME"
    cm="$GIT_COMMITTER_EMAIL"

    if [ "$GIT_COMMITTER_EMAIL" = "" ]
    then
        cn="Your New Committer Name"
        cm="Your New Committer Email"
    fi
    if [ "$GIT_AUTHOR_EMAIL" = "" ]
    then
        an="Your New Author Name"
        am="Your New Author Email"
    fi

    export GIT_AUTHOR_NAME="$an"
    export GIT_AUTHOR_EMAIL="$am"
    export GIT_COMMITTER_NAME="$cn"
    export GIT_COMMITTER_EMAIL="$cm"
    '
Remove a file and all its history from the repo:
git filter-branch --tree-filter 'rm -rf file-to-delete.txt' HEAD
Change Tracking Branch:
git branch --set-upstream branch new_remote/new_branch
Non fast forward updates:

Instead of deleting a branch on the remote and then updating it completely you can use a + to force a non-fast forward update:

git push origin +newbranch:oldbranch

Any commits on oldbranch that are not in newbranch will be dropped.

Scripting

How many changed files?

num_changed=$(git status --porcelain|wc -l)

What sort of change?

Git status’s porcelain output has the first two characters of every line representing the type of change from HEAD that the file represents. To check it you can do something like:

REPO=/home/user/git/my_repository
GIT_DIR=$REPO/.git/
GIT_WORK_TREE=$REPO
git status --porcelain | \
while read change; do
    case ${change:0:2} in
        (" M") echo "Modified: $change";;
        ("??") echo "Untracked: $change";;
        (*) echo "wtf: $change;;
    esac
done;

If you want a more in depth explanation on the meanings of the output codes, search for "Short Format" in the “git status“ man page.

CGIT

Clone the repo with this url http://hjemli.net/git/cgit

" "