Configuring Git

Git is a pretty amazing tool. It doesn't force you to use it in a particular way. If you want to start with a simple workflow, where you write some code and add it to the master branch - that's fine. You learn a handful of commands: commit, checkout, push, pull, status, and diff, and you're ready to go. Later, you may decide to start collaborating with someone on the code, so you introduce the concept of branches and pull requests. Then a day comes when you release the first official version of your software on GitHub, so you learn about tags. The more you use git, the more advanced topics you discover: blaming, bisecting, rewriting history (a.k.a. "how to make your colleagues hate you"), reflog, submodules, hooks and more.

One of the first things that you will encounter as you begin to delve deeper into git is the .gitconfig file - the configuration file of git. Before you can create your first commit, git will ask you to configure your name and email. It will even show you how to do this:

  git config --global user.email "[email protected]"
git config --global user.name "Your Name"

Once you run those two commands, they will end up in the .gitconfig file in your home directory.

As with every tool, it's worth spending some time to figure out how you can configure it. You will learn about some features that you probably didn't know existed, and you will be able to configure that tool to work in a way you like the most.

So, let's take a look at what you might find in a .gitconfig file. And if you like something, feel free to copy the code (you can find my .gitconfig file here).

[alias]

Aliases are probably the biggest part of .gitconfig. On your journey to mastering git, you will be adding more and more of them. Git aliases are exactly what they sound - they let you call a specific function through a different name. It's quite a common practice to alias many of git's commands to a 1- or 2-letter shortcut, for example:

[alias]
amend = commit --amend
amendf = commit --amend --no-edit
br = branch
ci = commit
co = checkout
cp = cherry-pick
d = diff
ds = diff --staged
l = log
lg = log --graph --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)' --abbrev-commit --date=relative
lp = log --pretty=oneline
sa = stash apply
sh = show
ss = stash save
st = status

I like to keep my aliases sorted alphabetically. Otherwise, I've noticed that I was creating duplicates all over the file. Also, no, I did not write the formula for lg myself ;). I copy-pasted it from somewhere, but you should check it out - it gives you a nice, concise graph of how the repository has evolved over time.

[color]

[color]
ui = auto

[color "branch"]
current = yellow reverse
local = yellow
remote = green

[color "status"]
added = yellow
changed = green
untracked = cyan

[color "diff"]
meta = yellow
frag = magenta bold
commit = yellow bold
old = red bold
new = green bold
whitespace = red reverse

[color "diff-highlight"]
oldNormal = red bold
oldHighlight = red bold 52
newNormal = green bold
newHighlight = green bold 22

The ui = auto is the default setting for the UI - it colors the output when it's going straight to a terminal, but omits the color-control codes when the output is redirected to a pipe or a file.

The branch and status sections are changing the output colors of git branch and git status commands in the following way:

Git branch output

Git status output

The diff and diff-highlight sets the colors that will be used in the git diff commands. For diff-ing, I'm using the diff-so-fancy tool. It's very easy to set up and gives a new look to the git diff output, so make sure to check it out. Here is a screenshot of how it looks:

Git diff vs diff-so-fancy

[core]

[core]
editor = vim
excludesfile = ~/.gitignore
pager = diff-so-fancy | less --tabs=4 -RFX
# Configure Git on OS X to properly handle line endings
# autocrlf = input

The core section contains various different settings related to git. Here are some that I am using:

  • editor = vim sets which editor you want to use for editing commit messages (if this value is not set, git will first try to read what editor you are using from the environment variables VISUAL or EDITOR and if that fails, it will fall back to vi). I'm not using Vim for coding, but for quick edits like that, I prefer it over Sublime or VS Code.
  • excludesfile = ~/.gitignore lets you specify the global .gitignore file. Each git repository can contain a .gitignore file that specifies which files you want to exclude from version control. Quite often though, some of those files will be the same for each git repository (for example, the .DS_Store on macOS, or *.pyc when you are a Python developer), so instead of writing them over and over again, it's better to create a global .gitignore file.
  • pager = diff-so-fancy | less --tabs=4 -RFX specifies which tool you want to use to show the output of git log, git diff and git show commands. By default, git will use less. I'm using the diff-so-fancy.
  • UPDATE: As suggested by emn13 on reddit, using the autocrlf setting can corrupt your binary files - something that I wasn't aware of. I've decided to remove this setting from my .gitconfig file.
    autocrlf = input - since Windows is using different line endings than Unix and MacOS, if people from different operating systems are committing to the same repository, it can cause a bit of a mess. Since I'm working on MacOS, I'm setting this option to input. Here is a great explanation how to set it depending on which operating system you are using (TLDR: autocrlf = input on MacOS/Linux and autocrlf = true on Windows).

[credential]

[credential]
helper = cache --timeout=28800 # 8 hours

Some remote repositories that you will be working with are protected with passwords. The credential section of the configuration will specify how you want to store the credentials to those repositories. By default, git is not storing the credentials at all, so you will be prompted for the username and password each time you try to connect. If you want to store the credentials for further use, you can either save them in a file with the store option (it will create a plain-text file with your credentials) or store them in the memory using the cache option. There are additional options, depending on which operating system you are using (osxkeychain for MacOS or Git Credential Manager for Windows on Windows). I've decided to use the store in memory option. The default timeout for credentials is 15 minutes, but I've decided to increase it to 8 hours, so I type them once at the beginning of the day and when they expire, it's usually a sign that I should go home ;).

[push]

[push]
default = current

Every now and then, I forget to include the name of the branch in the git push command and that can result in unexpected behavior (e.g. I'm working on a dev branch, but by accident, I'm pushing the master branch). This can be especially problematic if you are using git push --force from time to time, as I do. To prevent this kind of mistake, I'm setting the default = current option of the push command. Now, if I forget to include the name of the branch, git will try to push to the branch with the same name. If it can't find a branch with the same name in the remote repository, it will create one.

Conclusion

That was a long list, but if you apply at least some of those settings in your .gitconfig file, you will be surprised at how much nicer git looks and how much more efficient you will become when using it. If you are looking for more information, I have two suggestions:

  • git-config documentation page that lists all the available settings.
  • search for gitconfig dotfiles and you will find plenty of existing .gitconfig files that other developers are using. The first item on that list - mathiasbynens/dotfiles is a repository with over 20,000 stars, so I'm sure you will find a lot of useful ideas.

Similar posts

Git Aliases Don't Have to Be Boring!

Git aliases can be far more advanced than just a simple "l = log". Check out those seven examples of what else you can do.

Managing Gigabytes of Images with git-annex

What is git-annex, how to set it up to store large files in Google Drive or NAS, and how I use it to seamlessly manage a git repository of 20GB (and counting)?