Versioning Your Home Directory
martinovic.blog
martinovic.blog
<quote> I use:
git init --bare $HOME/.myconf
alias config='/usr/bin/git --git-dir=$HOME/.myconf/ --work-tree=$HOME'
config config status.showUntrackedFiles no
where my ~/.myconf directory is a git bare repository. Then any file within the home folder can be versioned with normal commands like: config status
config add .vimrc
config commit -m "Add vimrc"
config add .config/redshift.conf
config commit -m "Add redshift config"
config push
And so one…No extra tooling, no symlinks, files are tracked on a version control system, you can use different branches for different computers, you can replicate you configuration easily on new installation. </quote>
I will probably have to use this approach at some point as my config continues growing.
* I split everything into topical modules, which were immediate subdirectories of the home directory, partly so the little laptop didn't have to install everything.
* There was a "config" directory that included most of the typical home directory dotfiles, as well as things like fonts. It had a small shell script in it, for keeping symlinks from the home dir up to date (e.g., "~/.bashrc" was a symlink to "config/bashrc".
* Not everything was in CVS. Photos, for example, were backed up separately.
* It was good to have my server Internet-accessible, since a few times I'd walk for an hour to work from my laptop, and realize I didn't have the latest version of my code.
* Nowadays I would probably use Git, only for the sake of standardizing, but the simple model of CVS was nice for this purpose. (I also knew many other fancier SCM systems, but intentionally went with a simple one.) Also, the repository was just in RCS format (files with reverse deltas of diffs), so, on rare occasions that I made an oops (like accidentally committed a huge file I didn't intend to), I could just SSH in and fix it manually.
* I had various servers for this over time, starting with my desktop, and then a PC in the closet, then a colo server, and then (my favorite) a small home RAID server I made from a fanless Atom board and Debian (which was effectively silent, running years 24/7 before I finally took it out of service, still working; one drive had to be replaced during that time, but was RAID mirrored).
Just use a snapshot-enabled filesystem. ZFS works awesomely, BTRFS too (but it's not released as stable and production ready AFAIK) and LVM can have snapshots too (take a look at the snapper project by Red Hat).
Just use ZFS and snapshot the whole filesystem.
I use the same setup (with a similar get of ignores) of my home being the root of a git repo for my dotfiles, but it's dotfiles alone that get added to git.
That being said, if you want to "version your home directory", I think that zfs is the best approach.
Also, transient files and browser temp files should reside on /tmp AFAIK... So that's less of an issue. If you application is writing temporary files outside of /tmp, then it's probably a bug.
http://www.mikerubel.org/computers/rsync_snapshots/
The idea is, you rsync to a snapshot directory (just like .zfs/snapshot/name_of_snapshot would be) but since you are hardlinking everything, almost all of the files take up zero space. Only files that change get their hardlinks broken and take up any space.
You can put the dir names in rotation and make them work exactly like zfs snapshots.
This is how people did snapshots before zfs.
One feature of this pair (unique to them?) that I find useful is the ability to apply different subsets of my repos to any given account's home directory.
Dropbox deals with syncing across machines on in instantaneous basis so that all machines have the same thing at every instant, allowing me to change location or machine and keep working. Git deals with versioning.
The scripts also do a periodic “git fetch origin” in a broader set of local git repositories, so I usually have up-to-date code locally even if I haven’t been keeping things synced manually.
find .git/ -name '*conflict*'
There ya go.Too many things come and go to justify a git workflow to me. And git ignoring wide swaths of private data seems haphazard at best.
It's like discovering that there's a special type of hammer just for the task you're doing. You know hammers. You hit lots of things with hammers. The new hammer is a little different, and to be honest you could make do with the old hammer in a pinch, but once you've spent a little time pounding away with the right hammer, you may suspect the world needs more types of hammer.
You can mount your whole backup using FUSE and browse around, or restore to some other directory. Multiple computers? Multiple folders to backup? All handled. It's got ignore/include for your binaries and bundled dependencies and whatnot.
Edit: encrypted by default.
1. maintaining .gitignore is kind of annoying.
2. I don't need all my configuration files on some machines, say a remote sever, you can just stow what you need instead of adding many files to your home.
3. it's not convenient setting up an environment when you already have many files in home, for git clone to a directory not empty is not allowed.
First of all for most files manual versioning is overkill; you probably only need to share them and for that something like for Dropbox or Syncthing; this together with a file system that supports snapshots gives you most if not all that you need with much less work (no commits).
There are also some things that I don't want to share between computers for a reason or another (for example, some of my ssh keys). I know I can use .gitignore, but I prefer the opposite approach (state what I want to include, not exclude).
I do version my configuration scripts, but I keep them in a subfolder and symlink them to their proper place. This also allows me to selectively decide what should be shared on a given machine and what not.
What I found, is that while these systems all worked reasonably well, I ended up writing out several manual steps in README files (e.g. install packages xyz, create user/group, create directory, enable systemd unit, replace {some_template_var} in fileX before copying, etc).
Ansible seemed like a reasonable solution so I switched to that and it's worked out very well for me.
Pros: - all steps can be encoded as config (config-only updates can still be run using tags) - a fresh install can be ready to use in minutes
Cons: - overhead encoding copy operations - slower then alternatives if just updating config (e.g. stow or rcm)
Dotfiles are stored in git, and run a script that creates symlinks to those dotfiles
My ~ directory tree, early on in setting up a new system, might look like:
~/
.config/
dotfiles/
i3/
.config/
i3/
config
zsh/
.config/
zshenv.d/
README.txt
.zshenv
.zshrc
When I want to use a package, I cd to ~/dotfiles and run: stow zsh
Running that sets up symlinks rooted one directory above, ~. Now ~ looks like: ~/
.config/
zshenv.d/ -> ../dotfiles/zsh/.config/zshenv.d/
dotfiles/
(as earlier)
.zshenv -> ../dotfiles/zsh/.zshenv
.zshrc -> ../dotfiles/zsh/.zshrc
Because ~/.config already existed, stow made the zsh symlink inside it. If ~/.config hadn't existed, stow would have symlinked it from ~/dotfiles/zsh.To remove the symlinks stow set up:
stow -D zsh
I did eventually set up a wrapper script to pass a few default arguments to stow, to ignore certain files I use for documentation. But stow does all of the work of managing the symlinks.[1]: https://www.gnu.org/software/stow/manual/stow.html#Introduct...
It also supports automatic backups to an external storage.
http://brandon.invergo.net/news/2012-05-26-using-gnu-stow-to...