Unofficial guide to dotfiles on GitHub
dotfiles.github.io
dotfiles.github.io
What I didn’t need at all, after all, was anything that installed different things on different hosts or classes of hosts.
Luckily, every tool I want to configure has a config file option to include another file, so I have a working copy of my version controlled defaults here:
~/.config/defaults
…and a one time installation script that makes various tool’s config files look like this: # begin defaults
source ~/.config/defaults/tool.conf
# end defaults
local specific config here
I am quite happy managing the local bits by editing files on local machines. All my configuration stuff splits into either “used everywhere” or “used just on this one host”, so that makes it easier.As soon as I figured this out I had to pinch myself as to why it had taken so long to come up with this idea.
I do this by having ~/.config/tool/blah.conf as you'd expect; but also ~/.config/by-host/$hostname/tool/blah.conf
I agree 'classes of hosts' is way overkill for probably anyone's personal machines though. Only thing close to that I do is with aconfmgr for more system-oriented stuff - but that's all simply on the basis 'if SSD enable TRIM' type 'classes', no manual specification.
# .dotfiles/.bashrc
# shared baseline config...
if [ -f ~/.bashrc.local ]; then
. ~/.bashrc.local
fi1: https://www.gnu.org/software/stow/ 2: https://wiki.archlinux.org/title/XDG_Base_Directory
I use it in combination with a make to automate the setup of a new install.
One thing, I didn't split things by apps per se. I split them based on task. In some machines, I do Python work, so I created a 'python' package. In some I do PHP, so I created a 'php' one. I have a 'base' one where it has my .bashrc, .profile, .bash_profile, fish configs and other things.
Everything in the .bashrc. .profile, etc is loaded around conditionals. So, while the files are long, the section only activates if the other package is available. I thought about splitting it onto files, but most editors have a way of collapsing sections, so I decided to keep it on one so it's easy to edit in one place.
[1]: https://github.com/nix-community/home-manager [2]: https://code.visualstudio.com/docs/remote/containers#_person...
I use this script (which I modified a bit from the Atlassian one) to bootstrap it on a new $HOME dir (replace "***YOUR_GIT_REPO_ADDRESS***" with your address; also, you need to copy the function ,cfg into your .*rc file for command-line use):
#!/bin/bash
set -euo pipefail # the usual stuff
# TODO: copy the below function into your .*rc file
function ,cfg {
/usr/bin/git --git-dir="$HOME/.cfg/" --work-tree="$HOME" "$@"
}
# TODO: replace '***YOUR_GIT_REPO_ADDRESS***' below
git clone --bare git@***YOUR_GIT_REPO_ADDRESS***/.cfg "$HOME/.cfg"
,cfg config status.showUntrackedFiles no
if ,cfg checkout; then
# worked fine, we're done
echo "Checked out config."
else
# it failed, so assume we need to move some files out of the way
echo "Backing up pre-existing dot files."
mkdir -p "$HOME/.config-backup"
,cfg checkout 2>&1 | grep -e "\s+\." | awk "{'print $1'}" | xargs -I{} mv {} "$HOME/.config-backup"/{}
,cfg checkout || (echo "Still cannot checkout configs; see messages and fix." && exit 1)
echo "Checked out config."
fi
I also have a git alias to commit files that are tracked with a message: ctm = commit -a -u -m #commit all tracked files with message
So you can do like this to commit changes and push them: ,cfg ctm "I modified my .zshrc"
,cfg push*Also, pretty sure they even say at the start of the post they got the original alias from a HN commenter.
Not everyone has the time to create their own custom dotfiles.
Some just want sane and beautiful terminal defaults.
It's somewhat involved to set up but now across windows/linux/macos my entire setup is literally just a one-liner.
I find the problem with "set and forget" kind of jobs is that you forget how to do something because someone else already did it for you, so you don't learn anything. It's similar to joining a complicated project where everything has been set up for you and all problems were solved and if you were to join a new project from day 1 you would have to learn everything again. (See setting up CI/CD, the structure of a java project, a gradle file, a maven POM, Dockerfiles, git, Kubernetes manifests and other devops tasks)
You still need to learn how to do things. I want to be fluent in the tools I use, so I would rather do things from memory.
I keep a second copy repo on a thumb drive so I can start my home directory on an offline computer.
https://docs.github.com/en/codespaces/customizing-your-codes...
e.g. the package management. vim-plug seems fine, it seems odd to me to mention the others. (Pathogen's readme now mentions that it recommends vim's built-in package management. Vundle and neoplug haven't had a commit in years).
In terms of vim distributions, https://github.com/SpaceVim/SpaceVim probably deserves a mention, as inspired by the popular Spacemacs.
It'd probably be worth mentioning NeoVim.
Glad they've come a long way since then.
In the home directory (~) run:
git init
git remote add origin https://github.com/username/dotfiles
echo '/**' >> .gitignore;
git add -f .gitignore
git add -f .gitconfig
git add -f .bash_profile
# etc and push
On the second machine: git clone https://github.com/username/dotfiles tmp --no-checkout
mv tmp/.git .
rmdir tmp
git reset --mixedTo avoid that, one can rename the `.git` folder, effectively disabling auto-discovery, and run git with the option `--git-dir=<newname>`.
At any rate, I didn't know renaming the .git directory was possible. Do you have to add the --git-dir option to every subsequent git command? Sounds like a pain but my dotfiles change rarely enough that I guess I could live with it if I had to.
[status]
showUntrackedFiles = no
That solves most of those problems, as git will only consider files already in the repository and ignore everything else in your home directory.The only issue I've had with this approach is that new files which I'd like to commit to the repository are ignored by default. One could use the .gitignore negation strategy like OP mentions to first unignore the file and then add it to the repository. I just end up using git add -f foo to force the addition even though foo is ignored.
What I do with RasPi servers is I make a pull and a push playbook that live in a repo, which let me deploy what I have onto a new server, and pull any changes made in server web GUIs into the repo where I can commit them.
Then of course any other random periodic task also becomes an Ansible task.
If I had a use case for lots of random little scripts on my main machine, I think I'd choose Ansible over bash where practical, you get so many tools premade, and you can run local or remote all the same.
The big benefit is that it can be organized in a modular way with roles and tags, and sensitives files (like my gpg keys...) can be encrypted with the vault.