Tips for putting ~ under source control
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:
!/.gitignore
!/.profile
[...]
A trickier pattern I have is:
!/.ssh
/.ssh/*
!/.ssh/config
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 (don't 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.
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
.
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:
!/somedirname
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