Chances are, when you are reading this, that you are familiar with git. But if this word is not connected to any particular meaning — apart from the insult — for you, you should read up on it. To just introduce it shortly: git is a version control system for text-based files. Actually you can check in any kind of file, but it is really optimized towards text-files. If you want to learn more about git i suggest you take a look at the beautifully written ProGit-Book. It is freely available online and can be downloaded in multiple formats.

The commandline interface

But now let us get to the gist of this article: Configuring git. Usually git works quite well out-of-the-box. The only thing people pretty much always configure instantly is their name and e-mail-address.

Terminal

git config --global user.name "My actual Name"
git config --global user.email myusername@example.com
  

As we can see from the snippet, git actually comes with its own interface for configuring itself. And as you might've guessed the --global switch allows us to provide system-wide configurations. In this case system-wide actually is referring to the currently logged-in user, but more on that later. If one omits the --global switch git will store the provided configuration entry for the current repository only.

Git's configuration interface works like a setter-getter function system in object-oriented programming languages, where providing a value to the function will invoke the function as a setter and omitting that value will let the function behave like a getter-function, returning the currently stored value.

Terminal

git config --global user.name
My actual Name
git config --global user.email
myusername@example.com
  

Files are king, in Unix and in git

Reading and altering the git configuration through the commandline-interface is however not the only way to configure git. What the interface actually does is reading from and writing to configuration files that are written in the (quite standard) INI file format.

The git-config manpage states that there are four locations for such config-files supported:

  • $(prefix)/etc/gitconfig (usually: /etc/gitconfig)
    represents the system-wide configuration
  • $XDG_CONFIG_HOME/git/config
    added recently, for support of XDG-style.
  • ~/.gitconfig
    Your user-specific configuration (the usual equivalent of the --global switch)
  • $GIT_DIR/config
    Usually the .git/config file, but as you can change the location of the bare-repository, it will use the $GIT_DIR environment variable to find the file.

The most important ones for us are ~/.gitconfig and $GIT_DIR/config, which represent global and local configuration respectively. The other two files usually do not exist. Every existing configuration file contains a list of key-value pairs, which are separated by the equals-sign (=) and attributed to a section, which is placed in square brackets ([]).

; ~/.gitconfig
[user]
name = "My actual Name"
email = myusername@example.com

As we can see from the excerpt above, the section is the value before the dot (.) inside a commandline-interface call and the key is the value after the dot, e.g. user.name. And that is basically everything one needs to know about the syntax inside a configuration file for git.

So let's get to the sauce: garnishing our workflow with a useful git configuration.

Aliasing for elegance

Git supports something you might already know from configuring your shell: aliasing. Creating an alias allows you to call a git-command by a name you find most suitable. It also allows you to shorten more complex commands.

; ~/.gitconfig
[alias]
c = commit
ca = commit --amend
co = checkout
m = merge
mff = merge --ff-only
r = rebase
ri = rebase -i
rc = rebase --continue

The above snippet contains aliases for commonly used git commands. They are representative of a shortening alias, which is driven by the idea of writing as little as possible when executing commands you use constantly.

But like i indicated before, aliases are just as useful for crafting complex concatenations of switches for a certain command.

; ~/.gitconfig
[alias]
bunch = log --oneline --graph --decorate --all

The above one for example allows me to view a gitk-like view from my commandline. If i wanted something more complex i could install tig but i've found that the git bunch-alias is basically all i usually need.

You can even call external commands from a git alias by prefixing the first command with a bang (!).

[alias]
graph = !tig

But there are a few other nice ones which are especially suited for aliases. You know when you are using reset or even reset --hard to perform some action? Almost always i'm asking myself:

Is this right, or will i be using the reflog in a minute?

There are some common operation which could be much more safer if we were to make them available via aliases, as it is much less error prone with regard to typos.

; ~/.gitconfig
[alias]
to-origin = reset --hard HEAD@{upstream}
to-head = reset --hard HEAD
to-parent = reset --hard HEAD^

Now i can be a lot more expressive, and safe, relating to reset-style commands.

Settings for streamlined ease of use

Now we'll talk about a few options you might want to adjust, or at least check if the default seems sensible to you.

First one on the list is probably colorizing output. While colors are not really necessary when working with git, they still make it more comfortable. So here are some options you might want to set in the [color] section of your gitconfig.

  • branch = auto will colorize output of the git branch command when working inside of a terminal.
  • ui = auto Basically sets colorization for git diff and git grep to auto. But explicitly setting it is only necessary if you are using a git-version prior to 1.8.4.
  • status = auto By now you might've guessed it. This will enable colorization of the git status command when inside of a terminal.
  • interactive = auto does the same as the above for interactive commands like git add -i.

All in all it would look like the configuration below:

[color]
branch = auto
ui = auto
status = auto
interactive = auto

The other settings that i personally find quite useful are scattered across the different configuration sections. But let's work our way forward lexicographically.

Ignoring on the global stage

If you're familar with git, chances are that you've had some contact with the .gitignore file inside of a repository. This file allows you to exclude certain files (or filetypes, as globbing is allowed) from consideration for version control. Git will not suggest those files as part of your working tree and if you want to add them anyway you'll need to provide the --force switch to git add. Usually there are some files we always want to ignore. Common ones among them would be .out files (default for c-style compiled file) or .aux, which is a generated file that is created when generating a pdf from a .tex file. Setting core.excludesfile allows you to provide a location to a file, that is also considered when determining ignored files. A global .gitignore if you will.

Gits partners

Git is a tool that does not stand alone. It heavily relies on editors and pagers. And as such, it allows us to configure which tool to use. core.editor and core.pager allow us to set our preferred editor and pager respectively. But when setting core.editor to a graphical one, you should remember that you'll need to switch it to synchronous mode. For Sublime this would be -n -w, for Textmate -w and for Atom --wait. And for MacVim or GVim you should use -f. By the way -w stands for waiting and -f for preventing to fork.

But there is another variable which can be set to the path of an editor: sequence.editor. This allows you to configure a different editor when calling git rebase -i, which starts an interactive rebase that fills your editor with the commits that are targeted for a rebase.

Diffing is hard enough

If you're someone who writes code but then wants to create multiple commits, or if you just want to look at the diff of something before you commit it, it might be useful to have as much information as possible. Per default git generates a context of 3 lines in a git-diff for you. But you can expect more from git if you want to. Just set diff.context to an appropriate number.

Additionally sometimes a diff can seem odd to you. This is because the diffing-algorithm chooses 'changes' in such a way that can seem odd to a human user. Maybe try out setting diff.algorithm to either patience or histogram to improve your result.

Deep in the history

When you're working with history your friends are most certainly git show and git log. The latter can be usefully customized via the config file. If you've really worked with git history before you might be familiar with the following:

I'm pretty sure that change was introduced about two weeks ago.

Wouldn't it be useful if git were to show you exactly what you were looking for? If you set log.date to relative it will display date in a relative manner like 5 days ago. And if you set log.decorate to full, you will get useful branch information next to the commit id.

it's a figurative tug-of-war

And to complete this list of configurations we'll get a little bit of information with regard to pulling and pushing. If you set pull.ff to only, a git pull will become a safe operation, in which neither a conventional merge or a rebase is tried. It will only check if the state can be fast-forwarded — more commonly known as the state where you have no new commits locally, but where the remote contains new commits — and will perform such a fast-forward merge if applicable. But if you set pull.rebase to true, git will try to perform a rebase instead of a conventional merge when appropriate.

Another really important setting is the push.default setting. But instead of providing a sensible default here, i urge you to read the manpage section (git-config) for this particular setting. It is quite important you match this setting with your workflow.

Conclusions

There might be more hidden gems in the git-config which specifically apply to your use-case. And it is quite probable that there are a lot of gems that will be added in the future, so keep a look-out for changes regarding the git-config and maybe read the manpage from time to time. If you get that feeling that you like my particular configuration you can get the whole .gitconfig file from this gist.