How can I tell git (or some other dvcs) to track a file privately?
My use case starts from something a lot like this; a team uses a central repository (in my case it is subversion, but I believe if it were git the issue would be the same), and some of the files are member-private (Django local settings files, IDE private project preferences etc). While the private file should remain private — that is, I don’t want changes I make to it to be pushed or dcommitted — I do want the file tracked and version controlled.
The best option would be a way to keep the file private by default; a workaround would be a way to keep private commits — having to remember to commit the private file separately would be a nuisance, but still better than not being able to track it at all.
In comparison to suggested solutions:
this and this aren’t good because they prevent the file from being committed at all; this is not what I want. I want it committed locally; I just don’t want it published.
BTW — while I love DVCSs, and git has been a sort-of default, I don’t feel particularly committed to it (pun unintended); if only hg or bzr can do this, it may be reason enough for me to switch.
7 Solutions collect form web for “How can I tell git (or some other dvcs) to track a file privately?”
the way I have managed this, and I don’t know if this would be agreeable in your situation, is to create a template file, eg
settings.txt.template which resided in the committed repo. and then setup your personal file locally (settings.txt added to the .gitignore file).
Otherwise you might look at git submodules http://book.git-scm.com/5_submodules.html
How about having an ignored subfolder with user preferences? Similar to schoetbi suggests, but just a single folder, not one for each user.
/Project /Foo /Bar /Preferences
in /Project/.gitignore, the line
/Preferences to ignore /Project/Preferences. And initialize a ‘secret’ repo in /Project/Preferences. (I’m calling it secret because the outer repo doesn’t know about it.) If other software expects its preference files in a certain in the part of the main repo, you can create a symlink to something in the /Project/Preferences folder. The symlink could be tracked or not; it should be mostly stable over time, so you wouldn’t care about its history, and its history would anyway be independent of the main project, so I would probably ignore it.
You don’t need /Preferences underneath /Project, but it does have to be in one location relative to /Project for the symlink idea to work, so I would keep it underneath. It’s perfectly fine to initialize a repository underneath another repository, as long as the outer repository is ignoring the inner one. I do this with my ~ folder and projects underneath my ~ folder.
Even though you might logically want your user preferences to be linked to certain commits that you’ve made in the main repo, this is fundamentally impossible with git, so you’re definitely going to have to do manual synchronization between commits in your main repo and the preferences that go with those commits in your secret repo. Git fundamentally cares about the state of entire repo (which means everything it’s tracking) and it can never submit a partial commit. (Because the SHA-1 hash identity of the commit is completely different if you take out even a single file).
I would recommend to have a settings folder and underneath it a folder for each user. If you have a decent OS then there is a environment variable with the name of the logged in user.
Your directory structure will then be:
Project / Settings / User1 / User2 / User3
Now everything is checked in and every user has its directory. The next step is to use the userspecific part in your buildscript, projectfiles, and scripts or whatever using the environment variable.
A dirty hackish way to do this would be to keep the private file under a different version control system than the main project content. For example, ignore the preferences file in
.gitignore but make a Mercurial repository in the directory that ignores everything but the preferences file. This will at least let you track changes in each set of files, but it won’t allow associating one with the other.
Maybe you could store your files in a separate git folder and use a symbolic link which is .gitignored?
Or, maybe, tell git to ignore changes in this file :
git update-index --assume-unchanged <file name>
mine does this for git, and if you add a global svn ignore rule for
*_mine_* it should work just fine for svn.
Disclaimer: it doesn’t version by default, but will let you backup and restore anything that matches the
*_mine_* ignore rule