Better Dotfiles
iamdan.me
iamdan.me
The main reason was because I discovered the power of templating. With Yadm it required an external dependency, envptl, then j2cli, and both of these became unmaintained, while chezmoi used the text/template standard library. After the task of converting my jinja2 templates to gotmpl I never looked back.
One of the other things I like about chezmoi is I significantly cut down any "scripts" to just a few as most of the logic became "deterministic", ie I would set conditions based on the host in chezmoi.toml.tmpl and then that would define how everything under that would run across multiple hosts, and devices.
If you make your dotfiles repo publicly accessible, you will leak your private keys unless you use other features in chezmoi to protect them.
Or how about when you want to symlink an entire directory? For example something like neovim, considering that you may want to split config into separate files for organization. My neovim configuration has an "autoload setup" so any lua files inside the config directory are automatically required.
Lastly, this approach does not appear to support running commands. My dotfile install script ensures that tmux plugins are installed, the terminal font I use is available, and some other stuff that you need to invoke a command or script to achieve.
I like that the approach is simple, but I do not think it can support even relatively common use cases very well.
Symlinking a directory - admittedly didn't come up for my dotfiles, maybe `.ln` files with a similar format in dir roots.
Commands - yes, I still keep a set of shell scripts alongside my config files.
# starship
export STARSHIP_CONFIG="$HOME/dotfiles/etc/starship/starship.toml"
# git
export GIT_CONFIG_GLOBAL="$HOME/dotfiles/etc/git/.gitconfig"
# vim
export MYVIMRC="$HOME/dotfiles/etc/vim/vimrc"
export VIMINIT='source $MYVIMRC'
# ...
So one symlink is enough :-) Something similar can be done for ssh config (this file can not be symlinked for security reasons, so be careful working around this "feature"): # contents of $HOME/.ssh/config
Include ~/dotfiles/etc/ssh/hosts.d/*https://www.chezmoi.io/user-guide/manage-machine-to-machine-...
1/ the defaults, either built in or read from /etc;
2/ my defaults, included in each file (or with ssh, at the bottom) with that particular config’s native version of #include; and
3/ local specifics that are rarely if ever used anywhere else, or trivially short as to be copy-paste-able.
Almost everything I want to customize goes into (2) so I wrote a single Python function that manages a block at the top (or with ssh, at the bottom) of each config file:
# BEGIN my foo stuff
include = /my/repo/foo/config
# END my foo stuff
That way foo starts out with (1) the system defaults; then adds (2) my personal foo defaults as defined in a working copy at /my/repo; (3) anything else I insert in the file after that which isn’t centrally managed and that’s ok.I haven’t ever needed anything more complicated. I do not have any work specific configs that I need to gate. I no longer have to manage different configs based on whether I am using Debian, Debian (old), Debian (very old), SunOS (very very old), or AIX (very very very old) because those days are behind me.
If you do still need to manage slightly different but ethereally different configs on different hosts then I’m sorry to hear that. Rationalising my computing life so that I use the latest version of some Linux distribution everywhere has been very helpful!
IMO you don't need a special tool to manage your home directory / dotfiles. Git is the tool. Your home directory is a repo with a .git directory like any other repo. No other tools; no symlinks; nothing else. Commit what you want and gitignore the rest. I've done this since 2008.
Never had a problem with it.
Also less need on any scripts to set things up, due to chezmoi being more "deterministic" which means applying everything was a lot faster too.
git config --local status.showUntrackedFiles noOn the off chance there's anyone else who sees this as worth exploring here's a <1min demo video - https://www.reddit.com/r/unixporn/comments/1f9u1xk/oc_better...
What secrets? I generally don’t copy them, but you could manually. For example I use the same ssh keypair on two machines, but I generally don’t.
https://github.com/twpayne/dotfiles/blob/master/home/dot_zsh...
This means that: 1. My secrets are safely stored in my password manager so I can share my dotfiles. 2. When I update the secret in my password manager it automatically gets updated in my dotfiles when I run `chezmoi apply`.
I store them in Bitwarden not in dotfiles
I… am not sure what that has to do with scripts?
Like consuming time. If there is a tool which does what you need like chezmoi then you should use it, so that you don't have to spend maintaining something bespoke which consumes your time that could be better spent on other things.
chezmoi was actually inspired by Puppet, not stow.
Source: me, I'm the author of chezmoi.
So my .gitignore looks like
/*
!.gitignore
!/dotfiles
!/install_dotfiles.sh
!/i3
!/git
...
I then have a directory under .config, .config/dotfiles, where I have all of my unfixable dotfiles without the leading ., so to install them I have a script that just does `ln -snf ./$x ~/.$x` instead of messing with sed scripts.This is both self-contained and allows me to manage both XDG-style config and traditional dotfiles.
For the holdouts that don’t yet support that config directory, I have a short Makefile that sets up the required symlinks. So running “make” makes the links I’ll most likely need on a new server, while e.g. “make ssh” makes only the links required for that specific program.
Now that tmux supports ~/.config, and vim just added support as well, that Makefile is shrinking.
This is so much easier and more full featured.
ok...
> The files can be scanned and symlinks can be created with some awk magic:
wut.
this is just bespoke file management scheme. we've all been there, but there are better tools for this, as other comments have mentioned.
Of course, (ab)using comment syntax for structured machine directives is something many programming languages end up doing too. Here's a recent example: https://peps.python.org/pep-0723/#example. Surrounded with a pair of "# ///"? It must be something to do with Adidas.
For this broader problem, there are other more complete solutions that are more robust and flexible. Personally I like dotbot (https://github.com/anishathalye/dotbot) as a balance between power and simplicity, particularly when managing files across multiple OS homedirs (e.g. linux server, macos laptop).
There's so many interesting edge-cases that affect UX even when distro-hopping between Debian-based distros... especially if you used it for several years and had plenty of custom scripts in your ~/.local/bin folder.
I may yet need to learn or (re)discover some best practices of how to get up to a working development environment faster. I'm thinking of using Guix for that... but I digress.
So far, my workflow goes like this (on a newly-installed distro):
1. Configure environment variables that affect package-specific file locations (/etc/security/pam_env.conf and a custom /etc/profile.d/xdg_std_home.sh script that creates and assigns correct permissions for required directories).
2. Provision packages
3. Deploy config files (using stow).
What I've yet to figure out (haven't really researched it yet), how do you handle app-specific configs (think Firefox add-ons, add-on configs, Thunderbird accounts, etc.)?
As to your last question, nix+home manager gets you there, but that's a whole other Thing.
I generally use a makefile + stow to handle my dotfiles and home-dir setup. Each program has an entry in this Makefile - most of them are very simple, I keep a list of programs who's dots need to be in ~, and another for ~/.config/ and using make's variable expansion they just get a stow target.
For things like the above example (nvim):
nvim: nvim_alert_install nvim_stow
$(shell echo "PackerSync\nqall" | nvim -es )
This also allows me to not just copy preference, but provision a bunch of stuff that's invariant across machines (e.g. what i have installed via rustup, go install, etc).Dotfiles are just a component, but not the whole story, of your personal compute environment. Your environment also includes things like:
* ~/bin scripts (etc)
* programming language stuff - e.g. go, rust, python, ruby etc have tooling for per-user package management, language version, etc.
* various forms of password/key/auth stuff like ssh allow lists, encrypted password stores, etc.
And the biggest one: Type of machine - work, daily driver, server, etc
The type of machine may require different dotfiles or different parts of dotfiles (e.g. what basrc includes from `. .config/bash/my_local_funcs`), and having some scripting around this makes life easier.
Similarly OS packages are great, and I use them heavily, but work and personal servers and personal desktop all use a different OS, so its useful to have provision scripts for the type of machine, and i keep all that together with my dotfiles (etc) in my "personal environment repo" (it's name is dots, and when i talk about dotfiles I really mean "personal environment". I suspect other share this view, which leads to this "pure dotfiles" vs "dotfiles+parts of provisioning" viewpoint difference even though they largely have the same set of problems and tooling.
A dot file management system is only part of the picture.
To spin up a new machine is a 30 minute job, and then it feels like “home”.
1. Cronjobs replaced with systemd user timers
2. User packages (i.e. brew install or $HOME/bin) with systemd user services and distrobox manifest files
3. I don't think there's a `defaults` equivalent on Linux or at least not one that isn't file based (and thus manageable through dotfiles)
So maybe that's just an OSX concern.
git -c status.showUntrackedFiles=no --git-dir=$HOME/.dotfiles --work-tree=$HOME "$@"Well, you can't have different configs for different hosts. Other than that, I can't quickly recall what other limitations are, I see none. I really like the simplicity of the "pure git" approach.
My dotfiles repo dates back to 2018, I'm happy user of this git one-liner for the past 6 years.
Though you can use git branches, but I prefer not to
You can? Git is a DVCS, that's kinda the point of the Distributed part (although most people use it as a centralized VCS.
I have not only host specific configs, but also (host specific) work configs. It's really easy to merge/cherry pick changes between them.
I rename .git directory to .dotfiles in my $HOME
When people ask me which tool I use to manage my dotfiles, I tell them about this little-known tool called `git`. ;)
Side note: I use an shell alias instead, but it's pretty much the same.
`alias home="git --work-tree=$HOME --git-dir=$HOME/.files.git"`
- Create repo in ~ with a few dot files, push
- Make a new system setup script, run on other machine:
# install git; cd ~
# I use a read-only token, optional:
git clone "https://x-token-auth:${TOKEN}@bitbucket.org/you/dot_repo.git" dot_repo
# move into $HOME
cp -afv dot_repo/. .
rm -rf dot_repo
git config --local status.showUntrackedFiles no
Later on, if I want to write to the repo on this machine I run ssh-keygen, copy the public key to the remote and remove the token from .git/config and use ssh access instead.I used to have everything excluded in .gitignore and force add files to the repo, but prefer status.showUntrackedFiles instead. There are still a few edge cases but they don't bother you everyday like having to force every operation.
Some of my scripts have things like, if dist fedora, do this, else debian, do this, else Mac, do that, when they differ.
if you're talking about symlinks, you ought to say "ln -s" shouldn't you?
(also, I think this is the tip of another iceberg: learn to say "link" when you mean "hardlink" because that's what a link is in unix filesystem. not saying "stamp out hardlink", I'm saying if you feel comfortable using it correctly yourself, it will help you help other people to disambiguate what they say and not get progressively sloppier. you may not like what these words mean, but that ship is well at sea)
you are overlooking the human factor I pointed out: you have no idea if the other person has removed the ambiguity from what they said. My point was to be comfortable with the correct language yourself so you'll more easily spot slip-ups, not to mention be able to read docs. I specifically said not trying to stamp out hardlink.
>Until we can get 100% of people to immediately think of the hard link concept
that's not the goal (being impossible). my goal is to get OP to be cleaner in his doc, and for anybody who cares to be cleaner in their usage.
You're suggesting "being comfortable with the correct language", but if it is not already the case that almost everyone means "hardlink" when they say "link", then it's not "the correct language". Your mental mappings should reflect actual language as actually used, so that you can understand and be understood. Those mappings should include knowledge of the ambiguity.
"hardlink" unambiguously means "hardlink" (modulo rare mistakes)
"symlink" unambiguously means "symlink" (modulo rare mistakes)
"link" means "probably hardlink, but possibly symlink being referred to sloppily, or possibly referring to the category that includes both; generally ambiguous without further contextual information".
In other words: I am advocating against deleting error-correcting bits from language, because language is a noisy channel and error-correcting bits help reduce errors.
Could you elaborate on what makes stow's concept more sound than chezmoi?
https://github.com/llimllib/personal_code/blob/6e86441d992ca...
source ~/dotfiles/.zshrc
This is how I manage different environments. There are work/home/remote specific things in each domain's `~/.zshrc` files!I just have a small shell script which symlinks everything into my home dir - also serves as a reference as to what actually gets put where.
just add a makefile, add your mappings. done!
example:
~/.gitignore: ./dotfiles/gitignore
ln -s $< $@
you can even add something like ~/.%: ./dotfiles/%:
ln -s $< $@
and just have 1:1 mapping...I just keep my dotfiles repo in the same tree structure as the home directory, and loop over the tree to create symlinks. Plus some miscellaneous commands to set some other things up.
Depending on the use case, the `/etc/skel` directory (and equivalents depending on the distro/OS) might be useful. When creating a user, the files in $HOME are copied from such "skeleton" directory, and there's usually a way to tell that command to use a different skeleton directory.
So a different way (not better, just different) would be to have a directory already setup with symlinks and all, and use that directory as the skeleton when creating the user, so its $HOME gets created all ready with symlinks and all.
In my dotfiles I have a couple folders which includes rcfiles and configs. rcfiles includes things like {bash,zsh}rc, .vim{,rc}, tmux.conf, and so on, as well as folders like zsh that include things I import like aliases I have for specific linux machines (e.g. ubuntu has batcat instead of bat...) or osx. Then in config I have folders that contains all the things I would have under ~/.config (starship.toml, ipython_config.py, wezterm/<only lunatics have a single config if you have more than 50 total lines>, and so on. Then I just
$ find "${DOTFILES_DIR%/}"/rc_files ! -name "README.md" ! -name "*root" -depth 1 -exec bash -c 'ln -sf "${0}" "${HOME%/}"/."${0##*/}"' {} \;
$ ln -sf "${DOTFILES_DIR5/}"/configs/* "${HOME%/}/.configs/"
I mean I have other folders too like scripts, skels, templates, systemd configs, notes (notes in dotfiles is underappreciated!), and so on. What are you all using these managers for? Are they replacements for bash scripting? And also, find is super powerful and I think under appreciated. It really is worth learning. If you jump into the deepend I think you can get good at it in an afternoon.The problem isn't you. It's the way Unix-inspired systems do things that are entirely wrong. It's an insane mess of all of the things you mentioned because all the programs could do whatever they wanted. Bad conventions emerged and were propagated throughout the ecosystem.
Here's a fun exercise: try to change your home directory's physical location on a *nix system and see if anything works afterwards. It won't because every config thinks your files are in /home/me while you've changed your user name/home directory to /home/new-me. Windows (eventually) actually got this (approximately) right with a 'virtual directory' for 'my home directory' regardless of where exactly it is on disk. Programs refer to that virtual location.
The current status quo on any *nix is absurd.
(Just FTR, I only use Linux systems, personally. My criticism is borne from a place of aspiration/hope.)
Besides, install scripts are the norm for me, so it's typically easy to fix when things do go wrong.
Pro tip: "${HOME%/}/" will always result in /home/godelski even if I include my last name and even if I accidentally modified it to have a / at the end. Some simply variable substitutions go a long way.