Tuesday, December 8, 2009

Managing dotfiles with git

I've never managed dotfiles before, but now that I'm a serious vim user I thought it was time to get on with it. Naturally, I googled around to see what other fellows had done. I found a few different schemes. They all seemed more complicated than they should be. Some had scripts to run and symlinks everywhere. Others appeared to require a lot of manual bit pushing to maintain.

all of this because dotfiles are in your home directory along with a lot of other stuff you want to ignore. There is a very simple way to take care of this, let's get started.

First, you'll need a git repository. So cd into your home directory and type
git init

Now run the following command
git status

you should see a gigantic list of files. Some we want to version with git, most we do not.

Now here's the first trick. We want git to ignore everything by default, so we type:
echo "*" > .gitignore

Now run 'git status' again and git will tell you there's nothing to add to the repository. Excellent!

At this point you have a choice. You can manually add the dotfiles you want to version by prefixing their name with a '!' like this:
echo "!.vim" >> .gitignore

This makes for a short .gitignore file, but git won't tell you when new dotfiles are added - they'll be globally ignored along with everything else. That may be fine for some, but I like to know when new dot files are created.

To do this, I told git not to ignore anything that was prefixed with a '.'. My .gitignore file now looks like this:

Now when you run 'git status' you get a big list of all the dotfiles that have not been versioned, most of these we want to ignore. So we capture the output in a file:
git status > unversioned

Open 'unversioned' and '.gitignore' in your favorite editor, copy the file list from 'unversioned' to the bottom of '.gitignore'. Now remove everything that you *DO* want to version. Be careful not to ignore your '.gitignore' file! That'd be silly.

Finally, add and commit your changes normally:
git commit -a -m "hey dotfiles! woohoo!"

That's it! If you want to store your dotfiles on github create a repo and follow their instructions for setting up github with an existing git repository.

You can see my dotfiles repo here



Sudhindra Rao said...

Good idea Tyler. I was using the one with an install script which lets you have your dotfiles anywhere and just symlinked them to your home. That way you can swap your git repositories of stuff. But this is native and better I guess.


Tyler Jennings said...

I don't know if it is better. It is simple to maintain, I like that.

Not sure what you mean by 'swap git repositories' why would I want to do that?

ctank said...

Hi Tyler,
I've been looking for a straightforward way to do just this, and was really pleased to come across your site the other day. But I've got a question for you about this: once I put this .gitignore file in my home directory, I have my dotfile git repository ignoring all my other files and directories, which I want. But now git thinks this .gitignore applies to all my git repositories that track all my other projects. Not so much what I want.

Any clue what's going wrong here? Thanks in advance for your help.

ctank said...

Hi Tyler,
I solved my own problem! Apparently git treats a .gitignore file as a global directive, so any files you include in a .gitignore in your home directory will be ignored by any git repo.

But if you put your .gitignore file at .git/info/exclude (of the right repo, of course), it will apply just to that directory. Hope that made sense.

Thanks for this great post.

blog said...

I also recommend storing your dotfiles on github. After doing git init and git commit, create a project "dotfiles" on github and do:

git remote add origin git@github.com:/dotfiles.git
git push -u origin master

From then on, do "git push" everytime you commit, to push your changes to github.

zrajm said...

This is a nice idea, however some of my config files (notably the Irssi config) contains passwords, and other sensetive information.

Anybody have any good ideas on how to handle these outside of the git repo is a similarly simple way? (I'm thinking that these should be stored on my home machine, and have a small tool to only insert the passwords as needed, after fetching them via SSH.. Or something like that.)

docker said...

Maybe you interested in these tips:

Antonio Argote Bertely said...

I had an issue echoing `!` into my .gitignore file. Got "event not found" back. It turned out the shell was confused by the bang. Fixed it using single quotes instead of double quotes.
Thanks for this entry, it's exactly what I was looking for.