If you find this post useful, please consider donating in the form of a Â
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.
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 —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.
60 comments: On Using Git and Github to Manage Your Dotfiles
Totally awesome article.
Thanks 🙂
Keep the good work.
I’m glad you enjoyed it. Thank you for the kind words!
Pingback: Setup a Django VM with Vagrant, VirtualBox, and Chef | smalley creative blog ()
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.
I’m glad you found it useful. You should now find managing your configurations across multiple machines a lot more convenient and quick!
Amazing stuff!
Thanks for getting me off the ground on this one!
I’m glad you found this informative and useful. Thanks for reading!
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.
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!
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.
Git is challenging for everyone who wants to do more than simple clone operations. I’m glad this helped!
Pingback: Managing Scripts and Configurations on Github with a script « Linux Tidbits ()
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.
Thanks for sharing. Really interesting stuff!
I’m glad you found it useful.
Thanks so much for publishing this! I’ve been telling myself I will get my dotfiles onto git forever and now I finally have.
I’m glad to hear I’ve helped you make the jump!
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.
Pingback: Sync dotfiles across multiple computers using Git & Github Pedram Navid ()
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.
Comments like yours are the reason I do what I do here. Thank you!
Great article! Exactly what I was looking for, thanks!
I’m glad it came in handy for you!
Thanks for this great and short introduction!!
This was exactly what I’ve been looking for.
You’re quite welcome. I’m glad I was able to help!
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?
I prefer zsh because I use
oh-my-zsh
, a framework that adds a lot of functionality to the standardbash
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
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 😉
Thanks a lot for sharing. Just pushed my dotfiles to github repo. 🙂
Pingback: One git repo to rule them all! | Sebastians Blog ()
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! 😉
Thank you for the kind words! I’m glad I was able to help!
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.
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!
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
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
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
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. 🙂
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!
I’m glad you’ve found this helpful in iterating toward a better way of wrangling those dotfiles. Thank you for your kind words.
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!
Adam, I’m happy to have helped you gain a better understanding of git and GitHub.
Pingback: Dotfiles (bashrc, vimrc,...) mit GitHub synchronisieren und aktuell halten | demaya.de ()
Pingback: braindump, playing around with flask / python / vim / bootstrap | orange narwhals ()
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!
I wasn’t able to get vim to follow the symlinks set up by your script to my vimrc. Please help.
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!
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.
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!
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?
Pingback: TDD (Test Driven Development) | aircrew.me ()
Thanks for the post! Very helpful in getting started with dotfile version control.
No problem Yosh. I’m happy you found it useful. Tell your friends about it!
Pingback: Meet the Dotfiles | Velz Dziu ()
Pingback: Dotfiles | Andrew Lee ()
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 🙂
Pingback: Managing Dotfiles – <ESPGH> ()
This is the exact setup I was looking for. Thanks for the article.
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.