[0] https://github.com/podiki/dot.me
[1] https://www.gnu.org/software/stow/
[2] https://github.com/podiki/dot.me/blob/master/x11/README.org
(I use GNU Stow too, though have not thought to create a literate version of my scripts and hacks.)
The first is that I have a habit of running `git add .` when I'm working on source code, and as a result I have accidentally added my entire home directory to the bare repo more than once... Easy enough to undo but a bit inconvenient. `dotfiles add -u` is the safe option, or just be explicit about which files you are staging.
The second issue is the 'branch per machine' approach, which I do use. I have two machines I use regularly, and a third occasionally. There are some bits of config (e.g. for vim) that are shared across all the machines, while other bits are not. If I use one machine for a while, then I end up with lots commits that I need to cherry pick when I next use another machine. Depending on how long it has been, this can be a bit of a faff.
Finally, because there is no clear mainline branch, you have to pick commits to/from any of the branches. If you are undisciplined like me, then this will leave you with a 'three way ahead and behind' scenario at some point.
Anyway, I like the approach overall. If anyone has a suggestion to ease those pain points I'm all ears.
I combined the bare repo approach with a per-machine custom branch approach described in https://www.anishathalye.com/2014/08/03/managing-your-dotfil...
The idea is that you have the shared configuration in one repo, and at the end of each config file, you include a local version. The local versions live in a separate repository and use a separate branch for each machine.
For example, at the end of .bashrc, you'd have
if [[ -r $HOME/.bashrc_local ]]; then
. "$HOME/.bashrc_local"
fi
and so on, for each config file. My general dotfiles repo is public here, if you want to take a look how I did it for the tools I use: https://github.com/bewuethr/dotfilesThis still isn't ideal. For example, I use Git submodules for Vim plugins in the shared repo – but maybe I don't need all of that on my Raspberry pi. I feel like at some point, a config file based solution could be better; or using a tool such as https://yadm.io/, which is using bare repos under the hood.
cat ~/dotfiles/local/profile
SETUP=goes.here
load-global-config "$BASH_SOURCE"
after: cat ~/dotfiles/local/profile
load-global-config "$BASH_SOURCE"
MODIFY=${EXISTING:settings}
OVERWRITE=options
OTHER=things.too
and "around": cat ~/dotfiles/local/profile
echo "BEFORE"
load-global-config "$BASH_SOURCE"
echo "AND AFTER"
The nice thing about keeping local dotfiles in a separate directory is that you can `.gitignore` it for your "public" dotfiles repository, but still keep the local dotfiles under source control easily.[1]: https://github.com/svieira/dotfiles/blob/4b7e948b698b623a498...
Thanks for those pointers and the link to your dotfiles too. I will check that out and maybe steal a couple of ideas!!
install() {
SRC=$DOTFILES/$1
if [ -e "$SRC-$HOSTNAME" ]; then
SRC="$SRC-$HOSTNAME"
fi
echo "installing $SRC -> $2"
mkdir -p $(dirname "$2")
ln -sf "$SRC" "$2"
}
install vim ~/.vim
install bashrc ~/.bashrc
install gitconfig ~/.gitconfig
# etc.
This is much simpler than messing around with branches since 99% of files are the same on different machines. Just add e.g. gitconfig-workpc to use a different git identity at work.For some files I also support a +$HOSTNAME suffix that will append instead of override. In this case it assembles the destination file rather than creating a symlink. This is a bit annoying because you can't edit the destination file; you have to edit the originals and re-run the install script. But it's worth it in a few cases (e.g. i3 config) to reduce duplication.
Maintained for 8 years now, 1.7k stars, only needs git >=1.5, bash >=3, and no root access to install.
It's well tested, stable, and super hackable to fit your needs.
Thanks for all your work on homeshick. It's a wonderful replacement for the old ruby version.
I've found that the bare repo approach has too many rough edges, and that the various dotfile management frameworks are overkill.
https://github.com/cbarrick/dotfiles/blob/master/home/instal...
#!/bin/sh
mkdir -p ~/.config
ln -sf ~/.dotfiles/vim ~/.vim
ln -sf ~/.dotfiles/bashrc ~/.bashrc
ln -sf ~/.dotfiles/gitconfig ~/.gitconfig
ln -sf ~/.dotfiles/i3 ~/.config/i3
This is two steps instead of three. You can manage ~/.dotfiles like a normal git repository instead of the "dotfiles" command in the article. It isn't full of hidden files, you can put other scripts and stuff in it, you don't have to turn off showUntrackedFiles or add your whole home directory to gitignore, etc. It's so much simpler and easier to keep clean and organized. The only real downside is that to add a file you have to move it to ~/dotfiles and add a line for it to the script.Side note, I get the benefit of publishing dotfiles for others to learn from, but why go through so much trouble to document how to install your dotfiles? Does anyone actually use the dotfiles of strangers? One time upon joining a company it was strongly recommended to me to just install another developer's dotfiles on my computer to get started. I had such a strong feeling of revulsion from this. Using someone else's dotfiles is like using someone else's toothbrush. I have my own, thanks.
It's good to look at others for ideas but for anyone new to versioning your dotfiles I would strongly recommend starting from scratch and doing the simplest thing that could possibly work. Hence a script like above.
E.g. I have created [0] the simplest of scripts for managing updates for manually-installed / source-compiled applications (something I've dubbed "misc", very proud of this backronym :p).
The script itself is extremely simple (just a list of greps over latest release announcement urls), but it has solved a big problem for me, of helping me keep such "misc" items seamlessly up-to-date.
A comparison of popular dotfile managers:
https://github.com/twpayne/chezmoi/blob/master/docs/COMPARIS...
for FN in ~/.paths/sneak-sync/bashrc.d/*.sh ; do
source $FN
done
Then updates (by adding or removing files to these directories) propagate to all my workstations. I have machine-specific ones, too, that also sync but aren't included due to differing hostnames.That's why I created my own solution, which maintains a state file in the repo, so doing something like deleting a config file or switching a git branch doesn't result in a bunch of broken symlinks lying in your system.
The trick is to use the combination of --git-dir and --work-tree git options. An alias can be defined to simplify the process: `alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'`.
`dotfiles` can be used as you would use `git`, e.g.:
- `dotfiles add <file>`
- `dotfiles commit [options]`
If you do that stuff, great, but here's what I do if you don't want to use any specialized tools:
My home directory is just a git repo. There's a regular old ~/.git directory. All of the management I do is regular git stuff, like any other repo. Everything I don't want to commit is listed in .gitignore, like any repo.
The only wrinkle is setting up a new machine. You can't clone into an existing directory (AFAIK), and your home directory already exists, so you need a workaround. An easy solution: clone the remote repo to ~/dotfiles, then `mv ~/dotfiles/.git ~`, then `rm -r ~/dotfiles`. Now your home directory is a git repo where the working copy is exactly as the home directory was before, and HEAD points to your repo's default branch. It will be dirty because all of your config files are missing. Use regular `git status` to take a look. It's always looked fine to me, so I `git checkout .`, which effectively installs the dotfiles. Then I'm done until I need to do that copy trick again when I buy my next computer. In the meantime I just commit and push as normal, and occasionally add a new file to .gitignore.
It might not work for every program out there, but it does for the small number that I use.
I have my own dotfiles mechanism which splits out paths and configs by operating system, portable runtimes (e.g. Mono - may work on different OSes) and environments (enabling home and work configs to be stored in a separate repo and avoiding data leakage). Things like .bashrc and .bash_profile are assembled piecewise from fragments in each component.
Modifications to generated files by installers (notoriously, things like rvm, nvm etc. all want their stuff to be last in the config file, first in the path and all that) are detected so they can be integrated and not accidentally overwritten.
It's somewhat complex - I'm deliberately not linking it because I wouldn't recommend other people use mine, I have no time to support it - but to my mind these features are critical for any dotfile management system.
if [ $(uname) = "Darwin" ]; then ... # macos
if [ "$TERM" != "cygwin" ] ; then ... # cygwin
I'm sure there are other ways to determine WSL and others you mentioned.