Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to put my home directory (~) under source control (git, in this case), as I have many setting files (.gitconfig, .gitignore, .emacs, etc.) in there I would like to carry across machines, and having them in git would make it nice for retrieving them.

My main machine is my MacBook, and the way that OS X is set up, there are many folders i want to ignore (Documents, Downloads, .ssh). There are also folders which are already using git (.emacs.d).

My thought was to just add all these directories to my .gitignore file, but that seems kind of tiresome, and could potentially lead to some unforeseen consequences. My next thought was to periodically copy the files I want to store into some folder in home, then commit that folder. The problem with that will be that I have to remember to move them before committing.

Is there a clean way to do this?

share|improve this question
Out of curiosity, why GIT and not SVN? – Hugo Sep 13 '10 at 3:09
because GIT is cooler.... :P – Stefan Sep 13 '10 at 19:46
I've moved from SVN to git because it can actually merge, as well as its distrubuted. Its my go-to source control – Dan McClain Sep 14 '10 at 11:31
@Hugo also, with Git you don't need to worry about where to put your central repository (in case you want to use it on several machines), because there isn't one. The repository sits right in every "sandbox". – Daniel Hershcovich Nov 1 '11 at 20:14
@Hugo this is why: youtube.com/watch?v=4XpnKHJAok8 – ixtmixilix Apr 8 '12 at 13:10

10 Answers 10

up vote 56 down vote accepted

I have $HOME under git. The first line of my .gitignore file is


The rest are patterns to not ignore using the ! modifier. This first line means the default is to ignore all files in my home directory. Those files that I want to version control go into .gitignore like this:


A trickier pattern I have is:


That is, I only want to version .ssh/config - I don't want my keys and other files in .ssh to go into git. The above is how I achieve that.

Edit: Added slashes to start of all paths. This makes the ignore patterns match from the top of the repository ($HOME) instead of anywhere. For example, if !lib/ was a pattern (dont ignore everything in the lib directory) and you add a file .gitignore, previously the pattern (!.gitignore) was matching that. With the leading slash (!/.gitignore), it will only match .gitignore in my home directory and not in any subdirectories.

I haven't seen a case where this makes a practical difference with my ignore list, but it appears to me to be more technically accurate.

share|improve this answer
It seems to me that the same can be achieved in a much easier way. – Nick Volynkin Sep 15 '15 at 9:23

What I do (with the same objectives) is to put my configuration files in a subdirectory ~/lib and have symbolic links in my home directory, e.g., .emacs -> lib/emacs/dot.emacs. I only keep configuration files that I wrote explicitly under version control; my home directory contains plently of automatically-created dot files that are not under version control. Thus ~/lib is under version control, and my home directory is not.

I have a script that creates the symbolic links from the files under ~/lib. When I create an account on a new machine, I populate it by checking out ~/lib and running that script.

My experience is with CVS, not git, so it's not 100% transferable. One of the reasons I didn't put my home directory directly under CVS is that ~/.cvsignore would apply to all my CVS checkouts and not just my home directory; git doesn't have this problem. The downside of that approach compared with having the home directory under version control is that you can't use git status to distinguish between a file that you've explicitly decided to ignore (which would be listed in the ignore file, so not displayed) and a file that you have no opinion about (which would be displayed with a ?).

Some files need to be different on different machines. I put them in a directory called ~/Local/SITENAME/lib and either create symbolic links for them as well or (for file formats that support it) have an include directive in the file under ~/lib. I also have a symbolic link ~/Here -> ~/Local/SITENAME. Since git, unlike CVS, is designed to support mostly-similar-but-not-identical repositories, there may be a better way to manage machine-specific files. A few of my dot files are in fact not symbolic links, but automatically generated from content under ~/lib and ~/Here.

share|improve this answer
Maybe you have core.excludesfile = ~/.gitignore. Without such a configuration, the file is not applied to any repository except one stored in ~/.git (even then it would not apply to sub-repositories). I use core.excludesfile = ~/.git-user-excludes to avoid the conflict between the excludes I want applied to all my Git repositories (regardless of location) and the excludes I want applied to the repository that holds (parts of) my home directory. – Chris Johnsen Sep 11 '10 at 20:23
@Chris: I know extremely little about git. I may have misunderstood this sentence in the gitignore man page: “Patterns read from a .gitignore file in the same directory as the path, or in any parent directory (…)” Does it in fact stop at the root of the checkout (i.e. where the .git directory is)? – Gilles Sep 11 '10 at 20:57
Yes, the upwards search for .gitignore files is bounded by the root of the working tree. The sentence you quoted continues: “(up to the toplevel of the work tree)”. – Chris Johnsen Sep 11 '10 at 22:15
@Chris: my version of the man page doesn't have these words — it looks like the wording has been clarified. I've corrected my answer. Thanks! – Gilles Sep 12 '10 at 0:28
this was discussed in chat recently – strugee Dec 1 '13 at 22:22

We can use Git's ability to continue tracking files even if they're listed in .gitignore. So, this is enough for .gitignore:

$ cat .gitignore

For each file that you want to track, run add -f (the -f parameter overrides ignoring both in .gitignore and .git/info/exclude):

git add -f .gitignore
git add -f .profile
git add -f .zshrc
git add -f .ssh/config

Once having indexed a file, Git will track all changes despite the fact that the file is ignored. The same works for a directory, but only for the files that are actually present:

git add -f somedirname

If you want to track a whole directory with all new files that appear in it, it can be excluded from .gitignore in a way, described in the answer by camh:


If you ever want to stop tracking a file, this commands removes a file from Git's index but leaves it untouched on the hard drive:

git rm --cached .ssh/config
share|improve this answer
I'd give you my points if I could. If should be noted that this method can only be used to track files, not directories. If you want to have git track all files in a directory, you'll still need to un-ignore that directory in .gitignore. Otherwise new files in that directory will not appear as new files. – camh Sep 15 '15 at 11:31

I use the old rcs for that.

Have a look at manpages for ci, co, and rcs. Those sites should be helpful as well:

I use that for version controlling my dotfiles for instance:

ci -u .*vimrc

And if I want to edit them:

co -l .*vimrc

I recommend making a directory named RCS in your ~, you can then easily backup that directory somewhere.

share|improve this answer
rcs is pretty dated now, and git does everything rcs does and a lot more besides. I used to use rcs for anything local where I didn't want the overhead of setting up a repository on a server, but I've completely switched over to git now for that type of usage. I even wrote a script that wraps cvs2git to convert an existing directory hierarchy with rcs files in it to git. – Neil Mayhew Sep 11 '10 at 4:09
Yes, I know it is dated. The question was for a tip on how to do that. I've just told this guy how I've been doing it for many, many years ("dated", hint, hint). It wasn't meant in the way that it's the only reasonable way to do it. – polemon Jun 19 '13 at 3:18

I check out my config files to $HOME/.conf/ from a BitBucket Mercurial repository. A GitHub repo would work just as well.

The ~/.conf checkout contains config files and a shell script to populate symlinks in $HOME to each file in ~/.conf. For config formats that support inclusion (.bashrc, .inputrc, .vimrc, etc.) I include the ~/.conf file rather than link to it, so that I can do local overrides.

For some config files I symlink to a file in my Dropbox folder and share via dropbox.

For some months I tried keeping $HOME itself in version control, but I tired of managing the massive ignore lists, I tired of checking in config changes made by running apps, and the result was not even something I would want to check out on another computer. Can you imagine fixing conflicts over ~/.gconf or ~/.config/monitors.xml, or catering fro differing versions of desktop apps?

I find it easier to symlink to or include a limited list of config files that I have personally customised and want to share across machines as global defaults.

share|improve this answer

I think your second hunch to have non-related folder under source control is good.

Just add 2 shell scripts there. One to copy files under your control to ~ and the other to collect files from ~ and copy it back to the source-controlled folder and commit.

share|improve this answer

I've just started using the following Python Dotfiles script, which is a handy tool that auto-links the files for you: https://pypi.python.org/pypi/dotfiles

share|improve this answer

Here is a small ruby script which I use to setup a new machine

#!/usr/bin/env ruby
# setup.rb

#list of dirs which you don't want to symlink
ignored = %w(.gitignore .gitmodules misc setup.rb readme)

current_dir = File.expand_path(Dir.pwd)
home_dir = File.expand_path("~")

links = `git ls-tree --name-only HEAD`.lines.map(&:strip).select {|x| !ignored.include?(x)  }

links.each do |link|
  link = File.join(current_dir, link)
  symlink = File.join(home_dir, File.basename(link))
  `ln -ns #{link} #{symlink}`
share|improve this answer

You could try using dropbox


That's what I use. You could potentially mount /home to your dropbox folder. But I just have it in /home/dropbox and save all my settings and stuff to there. That way you don't have to svn pull or anything like that, the stuff is automatically synced

Source control means, amongst other things, that you have change logs, that you can commit individual files and see differences between commits, that the version history is kept forever

I just have to point that dropbox does everything on that list. It's not the BEST for all of those. But doing all of that is possible with dropbox

share|improve this answer
Dropbox provides backups, it doesn't provide source control. Source control means, amongst other things, that you have change logs, that you can commit individual files and see differences between commits, that the version history is kept forever... – Gilles Sep 12 '10 at 11:22
The other problem with this is that I am going to want to pull some of these configurations to production machines, and I would not want to install dropbox on a production server. – Dan McClain Sep 12 '10 at 17:09
Dropbox does do basic version control. It keeps records of all uploads and you can revert to previous versions or undelete deleted folders or files. The OP never said that he needed the features of version control, just that he'd like to share settings across machines. – Falmarri Sep 12 '10 at 22:14

You may also manage your home directory in Mac OS X using Chef and Homebrew.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.