My Git Configuration

I have been using Git extensively since 2011. Over the years, I have configured it to make myself more productive. In this post, I would like to share and explain my Git configuration with you. Hopefully, you will find some nice tweaks in there that will help you to speed up your workflow.

In the present post, I assume that you are using Git from a shell. If you are using it from your IDE, most of the tips will not be useful for you. That being said, let us start with shell configuration.

Shell Alias

git is one of my most used commands. Therefore, it has earned its place in my list of one-letter shell aliases:

alias g='git'

This alias should be put into your shell configuration file. For Bash, it is ~/.bashrc. With this alias, every Git command is shorter by two characters because instead of git, you can write just g.

Shell Completion

It is very useful to enable Git completion in your shell. This will make TAB complete Git commands, parameters, branch names etc. For example, to check out the my-branch-with-long-name branch, you can write just g checkout my and then press TAB. When there is more than one branch starting with my, a menu will be shown to you.

To enable this completion in your shell, you can either install a package from your distribution that does this for you (provided that your distribution has such a package), or do it manually. For example, for Bash, you can download the completion file:

wget https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash -O ~/.git-completion.bash

and add the following piece of code into your ~/.bashrc:

if [[ -f ~/.git-completion.bash ]]; then
	source ~/.git-completion.bash
fi

If you have setup the one-letter g shell alias (highly recommended), make completion also work for it by adding the following line into your ~/.bashrc:

complete -o default -o nospace -F _git g

Of course, the above way is Bash-specific, so for other shells, you have to do this differently.

Git Extensions

I use the following two third-party extensions that are not part of the standard Git.

git up

git up is a great addition to git pull. It has the following advantages:

  • git up updates all branches, not just the branch you are currently on.
  • git up shows you a list of new commits on each locally tracked branch after it finishes.
  • git up automatically stashes local changes before pulling new commits.
  • git up rebases upstream changes instead of merging them, which makes the commit graph clearer. No more pesky "Merge branch 'master' of ssh://login@server/git/repo" commits (merge of a branch into itself)!

git edit-index

git edit-index allows you to stage or unstage files from the index in an editor, just like when you perform an interactive rebase. It thus represents a faster alternative to git add -i or git gui. See my blog post for more details about it.

Git Aliases

All the aliases below belong to the [alias] section in your ~/.gitconfig. They allow you to write just e.g. git s instead of git status -bs. And, if you are using the g alias, you can write just g s, which is even faster.

a = add
aa = add --update
aaa = add --all
ap = add --patch

Staging of files. a stages the given file(s), aa stages all modified files, and aaa stages all files (even files that are not tracked by git). Finally, ap allows you to stage just parts of files (this is useful when you want to commit only some of the changes in the files).

authors = "!git log --pretty=format:%aN | sort | uniq -c | sort -rn"

Lists all commit authors in the repository, ordered by the number of commits.

br = branch -vv
bra = branch --all -vv

Lists branches in the repository with more information (-vv). bra also includes remote branches.

This is how the output of g bra looks like:

Example of git bra

c = commit --verbose
ca = commit --verbose --all

Committing. The --verbose parameter includes the diff into the editor, so you can see what you are committing. It also enables you to perform completion when writing the commit message (e.g. Ctrl-p/n in Vim). ca commits all tracked files, which is faster than staging them manually.

amend = commit --verbose --amend --reset-author

Amend of the latest commit. This is handy when you realize that you forgot to do something in the last commit (e.g. made a typo or forgot to commit a file).

clear = reset --hard
undo = reset --soft HEAD^

Reset. clear throws away all changes in the working tree. undo removes the last commit but leaves the changed files in the index. This is useful when you want to remove the last commit but would like to keep the changes so you can make a different commit.

conflicts = diff --name-only --diff-filter=U --relative

Lists all files with conflicts, relative to the current working directory.

co = checkout
cob = checkout -b
cot = checkout -t

Checkout. cob creates a new local branch and checkouts it. cot checkouts and starts tracking the given remote branch.

d = diff
da = diff HEAD
ds = diff --staged

Diffing. da shows all changes since the last commit (both staged and unstaged). ds shows what changes are staged to be commited.

ignored = ls-files --exclude-standard --ignored --others

Lists files in the current directory (and subdirectories) that are ignored by Git.

l = "!git --no-pager log -20 --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s'; echo"
ll = log --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s'
lf = log --name-status --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s'
lg = log --graph --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s'
lga = log --graph --branches --remotes --tags --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s'

Display of commits in a pretty format. l lists the topmost 20 commits without a pager. ll lists all commits (linearized). lf lists files that were changed in the commits. lg displays a commit graph. lga displays also a commit graph but includes info about all branches.

This is how the output of g l looks like:

Example of git l

m = merge --no-ff

Merging. The --no-ff parameter ensures that a merge commit is created. This is useful when merging topic branches because the branch will be shown in a graph log (otherwise, if it has merged master in the last commit, no commit will be created because Git will do a fast-forward).

p = push
pb = "!git push --set-upstream origin `git rev-parse --abbrev-ref HEAD`"

Pushing. pb pushes the current branch to the remote server and makes it tracking your local branch. Useful after creating a local branch.

rb = rebase --preserve-merges
rba = rebase --abort
rbc = rebase --continue
rbi = rebase --interactive
rbs = rebase --skip

Rebasing. The parameter names are mostly self-explaining. The --preserve-merges parameter ensures that local merges are preserved during a rebase. Otherwise, Git would perform a rebase instead of each merge, so you would loose the merges.

s = status --short --branch

Shows the status. --short makes the status more readable. --branch shows also the name of the current branch.

This is how the output of g s looks like:

Example of git s

sh = stash
sha = stash apply
shd = stash drop
shl = stash list
shp = stash pop
shs = stash show -p

Stashing. shs shows the topmost stash as a diff.

sw = show --format=fuller

Shows the given commit and displays more information.

tags = tag --list -n1

Lists all tags.

bl = blame
cp = cherry-pick
ei = edit-index
u = up

Just to save some typing.

Git Settings

The following settings also go to your ~/.gitconfig.

[color]
	ui = true

Enable colors in the output of Git commands. This makes the output more readable.

[color "grep"]
	filename = magenta
	match = yellow bold
	separator = cyan

Make the git grep colors match the colors I use for grep in Bash (see my .bashrc).

[core]
	whitespace = trailing-space,space-before-tab
	pager = less -iFRXS -x4
	editor = vim

Make git notice whitespace-related problems (e.g. in diffs). The used less parameters are explained here. Use vim as the editor for e.g. git commit and git rebase -i.

[merge]
	tool = vimdiff

As I use Vim as my editor, vimdiff is the natural merge tool to use.

[advice]
	pushNonFastForward = false
	statusHints = false
	commitBeforeMerge = false
	resolveConflict = false
	detachedHead = false

Make Git a little less verbose. See this post for a description and illustrations of the effect of these settings.

[include]
	path = .gitconfig.local

This allows me to have a ~/.gitconfig.local file that may override the settings in my ~/.gitconfig. For example, at work, I use a different user.name and user.email.

[git-up "rebase"]
	arguments = --preserve-merges
	log-hook = "echo \"* changes on $1:\"; git log --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s' $1..$2"

Settings for git up. The first one causes git-up to preserve local merges during rebasing (see the description of the --preserve-merges parameter to git rebase above). The second one makes git up use the same log format that I use in my log-related aliases.

My Configuration Files

My configuration files are available on Github. More specifically, configuration files for Git and Bash are here and here, respectively.

1 Comments

Leave a Reply to Kilimanjaro Cancel reply