Using Git and Github to Manage Your Dotfiles

If you use OS X or Linux on your desktop/servers, you may be at a point where you have configured a lot of your own settings, configurations, or themes within dotfiles. For the uninformed, dotfiles are files in your home directory that begin with a dot, or full-stop character. This indicates to the operating system that they are hidden files, used to set configuration settings for tools like vim, or shells such as bash and zsh to name a few.

GitHub’s very own Octocat

This tutorial does not go into the specifics of configuring your dotfiles. Instead, my goal is to provide you with a light introduction to Git version control, allowing you to maintain your dotfiles in a centralized repository on github.com

What’s The Point?

If you aren’t convinced it’s worth your time to put your dotfiles into Git version control, consider this:

By storing your dotfiles in a Git repository, you’ll be able to use them on any OS X or Linux machine with Internet access.

This means that in addition to gaining the ability to revert back to a known-working setup should you misconfigure your files, you will also be able to work in an environment you’ve customized yourself. On almost any workstation or server, you’re a simple git clone away from the familiarity of your customizations. More on git clone later. For now, we’ll begin with an example.

A Basic .vimrc

The following is an example of the type of file we would manage with git. This is actually an abridged version of my own .vimrc. The full version is available for view on my public Github:

set nocompatible          " get rid of Vi compatibility mode. SET FIRST!
filetype plugin indent on " filetype detection[ON] plugin[ON] indent[ON]
set t_Co=256              " enable 256-color mode.
syntax enable             " enable syntax highlighting (previously syntax on).
colorscheme desert        " set colorscheme
set number                " show line numbers
set laststatus=2          " last window always has a statusline
filetype indent on        " activates indenting for files
set nohlsearch            " Don't continue to highlight searched phrases.
set incsearch             " But do highlight as you type your search.
set ignorecase            " Make searches case-insensitive.
set ruler                 " Always show info along bottom.
set autoindent            " auto-indent
set tabstop=4             " tab spacing
set softtabstop=4         " unify
set shiftwidth=4          " indent/outdent by 4 columns
set shiftround            " always indent/outdent to the nearest tabstop
set expandtab             " use spaces instead of tabs
set smarttab              " use tabs at the start of a line, spaces elsewhere
set nowrap                " don't wrap text

If you don’t have your own .vimrc in your home directory, you’re welcome to use mine. It is intentionally minimal, as it works standalone (you don’t need to do anything other than drop it into your home directory for it to work). That said, we’re going to do things a little differently from here on, so pay attention (if you aren’t already).

Organization, Organization, Organization

The typical location for dotfiles on an OS X or Linux machine would be in a users home directory, e.g. /home/smalleycreative/.vimrc. We aren’t typical though, are we? We are trying to be crafty.

For starters, we’ll be putting all of our dotfiles into a folder called dotfiles, like so: /home/smalleycreative/dotfiles/vimrc. Then, we’ll simply symlink to them from our home directory. To programs like vim and bash these symlinks are transparent. As far as these programs are concerned, our dotfiles will still appear to exist at the top-level of our home directory, even though they’ll be tucked away in the dotfiles directory.

If you’re on your OS X or Linux workstation now, you can get started by creating the dotfiles directory in your home directory by running the following command:

mkdir ~/dotfiles

Place your .vimrc within ~/dotfiles (and/or any other dotfiles you want to manage with Git). For simplicity, I drop the dot from the filename (.vimrc becomes vimrc). I only prepend the dot when I create my symlink to vimrc in my home directory. What is important to keep in mind is we still haven’t used Git at all yet. We’re just preparing by organizing our dotfiles into one folder. For example, to copy an existing .vimrc, run the following command:

mv ~/.vimrc ~/dotfiles/vimrc

Once we have a bunch of dotfiles in this directory, a directory listing will likely look a lot like this:

ls ~/dotfiles
vimrc
zshrc
bashrc

The Install Script

Since we want portability (the ability to use our files on any machine with Internet access), we’re going to need an install script. This script goes in our ~/dotfiles directory. Here’s mine (The full version is available for view on my public Github):

#!/bin/bash
############################
# .make.sh
# This script creates symlinks from the home directory to any desired dotfiles in ~/dotfiles
############################

########## Variables

dir=~/dotfiles                    # dotfiles directory
olddir=~/dotfiles_old             # old dotfiles backup directory
files="bashrc vimrc vim zshrc oh-my-zsh"    # list of files/folders to symlink in homedir

##########

# create dotfiles_old in homedir
echo "Creating $olddir for backup of any existing dotfiles in ~"
mkdir -p $olddir
echo "...done"

# change to the dotfiles directory
echo "Changing to the $dir directory"
cd $dir
echo "...done"

# move any existing dotfiles in homedir to dotfiles_old directory, then create symlinks 
for file in $files; do
    echo "Moving any existing dotfiles from ~ to $olddir"
    mv ~/.$file ~/dotfiles_old/
    echo "Creating symlink to $file in home directory."
    ln -s $dir/$file ~/.$file
done

The commented sections in the above script explain it. First, the script cleans up any old symlinks that may exist in our home directory and puts them into a folder called dotfiles_old. It then iterates through any files in our ~/dotfiles directory and it creates symlinks from our home directory to these files. It handles naming these symlinks and prepending a dot to their filename.

If we’ve got this script in our dotfiles directory, and we’ve got our dotfiles in there too, we’re ready to start using Git to manage these files.

Gitting Started with GitHub (Git it?)

Before continuing, we’re going to want to create a GitHub account. GitHub allows us to set up a free public Git repository, accessible from any machine with Internet access. They also have a very well-written help section. You would be well advised to read through and follow the instructions pertaining to your particular operating system:

Seriously — Read or at least skim over this documentation. Once you’ve set up your account, and you’re comfortable with the basics, come back here, and we’ll continue with the steps required to get your dotfiles stored in your public Git repository at GitHub.com.

Creating Our Local Git Repo

On our workstation we are going to initialize a new Git repo. To make our ~/dotfiles directory a Git repo, we simply change to it, and run the git init command:

cd ~/dotfiles
git init

We then start to track any files that we want to be a part of our repo by using the git add command on them:

git add makesymlinks.sh
git add vimrc

Finally, once we’re happy with the state of our files, we can commit them.

Think of a commit as a snapshot of your project’s ”code, files, everything” at a particular point in time. More accurately, after your first commit, each subsequent commit is only a snapshot of your changes. For code files, this means it only takes a snapshot of the lines of code that have changed. For everything else like music or image files, it saves a new copy of the file.

git commit -m 'My first Git commit of my dotfiles'

What’s important to realize is that this commit is local — We still haven’t uploaded anything to GitHub. In fact, we cannot do this until we tell our local repository where our public GitHub repository actually resides. To do this, we use git remote add origin, like so:

git remote add origin git@github.com:mygithubusername/dotfiles.git

Finally, we can push our changes to GitHub:

git push origin master

Tracking Updates to Our Git Repo

If we decide to update our vimrc, we’re going to want to make sure these changes get tracked on GitHub.com, so what is the process? First, add the file:

git add vimrc

Then, commit locally, and write a commit message:

git commit -m 'Changed vim colorscheme!'

Then, push to GitHub:

git push origin master

Cloning Our Dotfiles to Another Machine

Ultimately, we’re going to come to a point where we want to use our customized dotfiles on another server or workstation. That is, after all, one of the primary benefits of using Git to manage our dotfiles. To do this, it’s as simple as running the following command from our home directory:

git clone git://github.com/<mygithubusername>/dotfiles.git

Once the repository has been cloned to our home directory, simply change to the dotfiles directory, make the makesymlinks.sh script executable, and run the script, like so:

cd ~/dotfiles
chmod +x makesymlinks.sh
./makesymlinks.sh

Warning: If you’re running Debian Linux, this will most likely install zsh on your system if it isn’t already installed. This is a feature I added to my script to automate things as much as possible. If for some reason you don’t want zsh to be installed on your computer (e.g. you’re on somebody else’s server), remove the install_zsh line from makesymlinks.sh. This will cause it to set up all of your dotfiles without attempting to install zsh.

That’s it! If the settings don’t take effect right away, we can just log out and log back in (this will re-source our dotfiles).

Updating a Local Git Repo

The best way to explain this is with a scenario. Say we’ve created a repository on our workstation (Machine A) and we’ve pushed our changes to GitHub, then we’ve cloned these changes down to our server (Machine B). We then go back onto our workstation (Machine A), make more changes, and push them to GitHub. How do we get these changes onto our server (Machine B)? To do this, we use the git pull command:

git pull origin master

After running this command, Machine B will be current with any changes that were pushed to GitHub from Machine A. It quite literally pulls any updates to the repo from GitHub.

Colophon

Whether you’re trying to wrangle a large collection of custom dotfiles or you’re just getting started and you weren’t sure where to begin, I hope this was an informative introduction to managing your configuration settings via the power of Git.


Posted

in

by

Comments

66 responses to “Using Git and Github to Manage Your Dotfiles”

  1. amar Avatar
    amar

    Totally awesome article.

    Thanks 🙂
    Keep the good work.

    1. Michael Smalley Avatar

      I’m glad you enjoyed it. Thank you for the kind words!

  2. […] we’ll use git (for more information on git, check out Using Git and GitHub to Manage Your Dotfiles) to clone the Chef cookbooks repository from GitHub. We will not need all of the cookbooks […]

  3. Saiyasodharan Avatar

    I have been saving all my config files in gmail drafts since now and its been a mess. Thanks to you for this article. I now moved all those files to github.

    1. Michael Smalley Avatar

      I’m glad you found it useful. You should now find managing your configurations across multiple machines a lot more convenient and quick!

  4. lwm Avatar

    Amazing stuff!
    Thanks for getting me off the ground on this one!

    1. Michael Smalley Avatar

      I’m glad you found this informative and useful. Thanks for reading!

  5. nathaniel Avatar
    nathaniel

    Good article & well written. Shame you neglected to mention anywhere in the article that if someone used your install script it would install zsh at the same time. I guess it’s a good thing I read the code.

    1. Michael Smalley Avatar

      I’m glad you enjoyed the article. You’ll be pleased to know that I’ve added a warning for anyone who would dare run any script from the Internet without reading the actual code contained within. To anyone reading this, running scripts without taking a glance at them to see what they do does you a disservice on two fronts. Firstly, you’re skipping an opportunity to learn from somebody else’s code. Secondly, you’re putting your system/network in jeopardy by running something on it that you don’t fully understand. The point is, take a note from Nathaniel. If you download a script from the Internet, read it before you run it!

  6. Todd Partridge (Gen2ly) Avatar

    Want to add too that this is a great article. Git’s always been one of those 100 pound gorillas to me, so very much appreciate it.

    1. Michael Smalley Avatar

      Git is challenging for everyone who wants to do more than simple clone operations. I’m glad this helped!

  7. […] post is a follow-up to Michael Smalley’s excellent post on how to Use Git and Github to Manage Your Dotfiles. I wanted a way to regularly have my configurations and scripts updated on Github that didn’t […]

    1. Michael Smalley Avatar

      One of the biggest rewards I get from effective knowledge-sharing is seeing people build on what they’ve learned. For anyone interested, this is a great extension of my tutorial.

  8. Granze Avatar

    Thanks for sharing. Really interesting stuff!

    1. Michael Smalley Avatar

      I’m glad you found it useful.

  9. Pedram Avatar

    Thanks so much for publishing this! I’ve been telling myself I will get my dotfiles onto git forever and now I finally have.

    1. Michael Smalley Avatar

      I’m glad to hear I’ve helped you make the jump!

  10. jm Avatar
    jm

    Solid. For a while I’d been thinking of doing the same thing, and you’ve gone and done it!

    Currently my home directory itself is a git repo where everything is ignored and files have to be force-added to track them. Having the root of one’s home tree be a git repository is problematic, however.

  11. […] Click on the Fork and my repo will be cloned into yours: (Full disclosure, my repo is a fork of Michael Smalley’s dotfiles, where I found this wonderful […]

  12. Patrick Avatar

    Thank you so much. This post was phenomenal, I sat down today thinking “Man, how am I going to get my .vimrc into gitHub.. maybe symlinks?”.
    Then on my first goole your post comes up and blows me away. Thank you so much for taking the time to make this script and to share it with such a well laid out post.

    1. Michael Smalley Avatar

      Comments like yours are the reason I do what I do here. Thank you!

  13. Ara Avatar

    Great article! Exactly what I was looking for, thanks!

    1. Michael Smalley Avatar

      I’m glad it came in handy for you!

  14. Marcus Avatar
    Marcus

    Thanks for this great and short introduction!!
    This was exactly what I’ve been looking for.

    1. Michael Smalley Avatar

      You’re quite welcome. I’m glad I was able to help!

  15. Hans Avatar

    Thx for this great article. I saw a lot people sharing their dotfiles at github and I always was thinking how they do it. Because they won’t use a large .gitignore file to exclude all their stuff in ~/

    Your article really helps and later I will have a look at your files 😉

    But one question: I use the bash an my mac und like it. Why do you prefer zsh?

    1. Michael Smalley Avatar

      I prefer zsh because I use oh-my-zsh, a framework that adds a lot of functionality to the standard bash you may be used to. Give it a look here, I’m sure you’ll be convinced after reading the feature-set:
      https://github.com/robbyrussell/oh-my-zsh

      1. Hans Avatar

        Oh-my-zsh has some nice features. I’ll give it a try but I’m not fully convinced. Maybe I’m not this hardcore user and I don’t see the real advantages 😉

  16. Abdullah Al Mamun Avatar

    Thanks a lot for sharing. Just pushed my dotfiles to github repo. 🙂

  17. […] Ein sehr guter (englischer) Artikel zur Einrichtung eines solchen Repositories ist der folgende: http://blog.smalleycreative.com/tutorials/using-git-and-github-to-manage-your-dotfiles/ […]

  18. David Weinraub Avatar

    Another “Me, too” post thanking you for this excellent tutorial.

    For a long while now, I’ve been wanting to push my dotfiles down into a single folder and get them under source control, but somehow just mentally missed that symlinking them up into the home directory would keep everything working fine. Your automated symlink script is the cherry on top.

    Thanks again! 😉

    1. Michael Smalley Avatar

      Thank you for the kind words! I’m glad I was able to help!

  19. Vidit Avatar
    Vidit

    I’m setting up my own dotfile git repo, and this post was a great help.

    I have a small question though, does it matter whether the file and directory names in the repo have ‘.’ in them? I have seen many github dotfiles repo which have them, but all the blogs suggest otherwise.

    I understand the ‘make_symlinks’ scripts will need modification, but I’m not worried about that. I’m confused about the naming.

    1. Michael Smalley Avatar

      It does matter. As long as the symlinks begin with a dot, the files they point to can be called anything. You’ll notice this is how my implementation works. For example, I have the ~/.bashrc symlink pointing to a file called ~/dotfiles/bashrc. Technically, ~/dotfiles/bashrc could be called anything — as long as when the symlink gets created (in the setup script) it points to the correct file within the ~/dotfiles directory.

      Thank you for your question!

  20. Richard "RichiH" Hartmann Avatar

    Hi Michael,

    this post has been referenced in a discussion about managing dotfiles with Git in freenode’s #git channel just now. I have to say it’s quite a concise and to the point howto; kudos for that.

    I was wondering if you ever tried vcsh[1]? This would allow you to ditch the dotfiles directory and maintain your dotfiles directly in $HOME. No need for symlinks or other hacks; just clean Git repositories happily sharing $HOME and not interfering with each other.

    Even if you don’t get around to try it or if you don’t like it I’d like to thank you for pushing the use of Git for non-code purposes. It’s a bit of a passion of mine and it’s nice to see that others Care as well.

    Richard

    [1] https://github.com/RichiH/vcsh

    1. Michael Smalley Avatar

      Richard,

      Thank you for the compliment. This is the first I’ve ever heard of vcsh. I’ll definitely give it a fair shot at some point this week. It seems quite interesting!

      If you have a thing for using Git for non-code purposes, you’ll probably enjoy this book (which I reviewed): http://www.amazon.com/Git-Version-everyone-Ravishankar-Somasundaram/dp/1849517525

  21. Brett Batie Avatar

    Michael,

    Thanks for this post! It inspired me to organize my dot files and look over the other dot files shared on git hub, there are a ton.

    I started with the script you provided and then made a few customizations and a few more and a few more. Well, now I have an application that I’m calling dotm that has quite a long list of features. You or others might find it useful as well. It is on github at https://github.com/brettbatie/dotfiles

    1. Michael Smalley Avatar

      Brett,

      I’m honored! Now you’ve got my gears turning and I’m thinking I’d love to see something like this developed in Python as a more full-featured application. I might have to get on that. 🙂

  22. Steve Avatar
    Steve

    Very clever! Thanks for some inspiration. I’ve been keeping my dotfiles in Dropbox and copying them manually but I love the advantages of your method. I’ve been looking for an excuse to learn git; I think this is it!

    1. Michael Smalley Avatar

      I’m glad you’ve found this helpful in iterating toward a better way of wrangling those dotfiles. Thank you for your kind words.

  23. Adam Avatar
    Adam

    I have wanted to get my dotfiles on github for a while, but I’m a noob to the whole github thing, but this guide just taught me how to use github and how to get my dotfiles up there. Bravo!

    1. Michael Smalley Avatar

      Adam, I’m happy to have helped you gain a better understanding of git and GitHub.

  24. […] Glück fand ich einen Blogeintrag von Michael Smalley, der sehr übersichtlich und verständlich erklärt, wie man sein eigenes […]

  25. Melch Avatar
    Melch

    I was going to just shove my dotfiles into a github repo for backup and sharing, but had a sneaky suspicion there was a better way. One lucky google hit later, those suspicions were confirmed. The setup script idea is a fantastic way of recovering, copying to other machines, and supporting a single directory for dotfiles to make git usage simpler. Thanks for sharing!

  26. Chris Avatar
    Chris

    I wasn’t able to get vim to follow the symlinks set up by your script to my vimrc. Please help.

    1. Chris Avatar
      Chris

      Got it fixed! Your script dumped my .vim files into ‘dotfiles_old’. This file housed my bundle file where bundle controlled my plugins. The symlink pointed to ‘~/user/me/dotfiles/vim’. I moved the ‘vim’ folder from dotfiles_old to dotfiles and it worked great. Thanks again for the article!

  27. chan Avatar
    chan

    There’s one gotcha in the script. If your run the script twice. You’ll end up backing up the “already symlinked dotfiles” in $HOME directory to $dotfiles_old.
    So in the end the files on $dotfiles_old will also be soft links.

    This is dangerous, because you’ll end up erasing your original dotfiles before running the script.

    1. Michael Smalley Avatar

      I am aware of this lack of idempotence. One solution would be to create a file in the dotfiles_old directory that if present, would cause the script to skip this step. If you want to submit a pull request that does that I’ll review it and merge it if it looks good. Otherwise I’ll get to it when I have a few minutes to test functionality. Thanks for your feedback!

      1. chan Avatar
        chan

        what i did was to check if the file that i am about to move to $dotfile_old w/c is a dotfile in the $HOME directory is not a symlink then it should be no-op.

        If the dotfile in the $HOME directory is already a symlink, then there’s no point in backing it up. I don’t know if this will work in all cases.

        I wonder, is this still the script you use for managing your dotfiles?

  28. […] they are really attached, so really soon I’ll do some personalization on my own, I found this tutorial that I think it is a good point to start with my dotfiles sync at […]

  29. Yosh Avatar

    Thanks for the post! Very helpful in getting started with dotfile version control.

    1. Michael Smalley Avatar

      No problem Yosh. I’m happy you found it useful. Tell your friends about it!

  30. […] Here I also found an example of basic installation script, which backups old dotfiles and creates symlinks to the files in the dotfile/ directory. This looks like super helpful thingy after for configuring freshly-installed systems. […]

  31. […] for this weekend was to get my dotfiles symlink’d and uploaded to GitHub for version control. This article was excellent at helping me get it […]

  32. Alf Avatar

    Well, thanks indeed. I always wanted to do this as I usually work on multiple machines and so far had to manually keep my dotfiles sync’d.
    Thanks to your article, I just set-up my first GitHub repo with my dotfiles 🙂

  33. jonny Avatar
    jonny

    I’m getting an error when trying to push the origin master:

    Warning: Permanently added ‘github.com,192.30.252.129’ (RSA) to the list of known hosts.
    Permission denied (publickey).
    fatal: Could not read from remote repository.

    Please make sure you have the correct access rights
    and the repository exists.

    1. Michael Smalley Avatar

      This is indicative of a connectivity error to your GitHub repository, namely around your SSH key configuration. I would suggest re-configuring your SSH access keys and trying again.

  34. […] dotfiles repo uses this method for an out of tree directory structure with a bootstrapping shell script to symlink the files into […]

  35. EdmundsEcho Avatar
    EdmundsEcho

    Thank you for this post. I concur with the positive feedback. How would I think through using this for my dot files not in my home directory, /.config/.vimrc.local and files such as .bash_profile?

    1. Michael Smalley Avatar

      With some modifications, this is certainly possible too. It’s been a decade since I’ve written this tooling and it still gets a lot of attention, so consider submitting a pull request on GitHub if you want to integrate functionality to operate beyond the home directory.

  36. Amit Avatar

    This is the exact setup I was looking for. Thanks for the article.

  37. Daniel Macuare Avatar
    Daniel Macuare

    Great article Michael. Can’t thank you enough for the information provided, it has been pretty useful for me as I’m starting to learn GIT from scratch. Great work!

  38. Denis Avatar
    Denis

    Thanks. More than five years later and this post is still helping people 🙂

  39. Luke Davis Avatar

    Excellent guide, thanks so much! Great excuse to start using .git, just finished setting up my dotfiles folder. One alteration I did was in your “.make.sh” folder I changed the “files=” line to “files=($(git ls-tree –name-only master))”, then changed the loop to “for files in ${files[@]}”. This will add all the first-level files/folders currently committed to a bash array, and make symlinks for them by looping over that array. That way you don’t have to specify the names manually.

Leave a Reply

Your email address will not be published. Required fields are marked *