19 comments

[ 3.4 ms ] story [ 47.7 ms ] thread
This is very clever, but I'd have to relearn Make's subtleties each time I tried to debug it or add a feature (count me in the "prefer to avoid it" crowd).

I ended up writing a Go CLI to symlink my dotfiles. It's probably 10x more lines of code, but it uses a "plan, then execute" pattern, similar to Terraform that I find easier to test and clearer to use too. And it's a single binary so it's easy to install on Windows too.

I use a combination of stow and make to manage my dotfiles. I added a makefile well after using stow for a decade. The makefile is more for new system setup than day to day management. I might try out replacing stow with make based on this blog, more for fun than anything. I'm a bit reluctant to replace what has been working so well for a decade, but I'm very intrigued by this. Make has always interested me. It seems like it could be incredibly powerful in the right hands.
I've been using Chezmoi for a little while now. It simplifies what I want to do better than anything else I have tried.
Chezmoi is probably the best thing I've found. But I do have aome complaints about it. I don't love the filenames, and using symlinks often feels like a second class citizen.

It also has the downside that you have to install and set up chezmoi first, and it isn't included in the debian or ubuntu repos.

I do this and like it: https://github.com/staticshock/dotfiles/blob/main/Makefile

I also tend to put a Makefile into the root of any repo I work in (ignored via .git/info/exclude), so that shell commands relevant to my workflow can accumulate under that Makefile. I've been doing this for at least 10 years and love it. Most repos have some sort of a cli interface, but that doesn't mean that they're any good. Make is nice way to wrap all of them, and to standardize on at least the build/test/run commands across many disparate repos.

Here's an example of one of those from a long-abandoned project: https://gist.github.com/staticshock/0e88a3232038d14a2817e105...

Is there a reason to not include your makefile in the git repo? Is it not useful to anyone else?
Have you ever tried to submit a PR of your Makefile to the maintainers of, say, an open source npm package? If you have, what compelling story were you able to tell about that Makefile that got the maintainers to merge your PR? And after they successfully merged it, did you continue putting up PR after PR for each successive round of tweaks to that Makefile?

What an extraordinary amount of unnecessary effort that would be. My workflow does not belong to the repo, it belongs to me. The only thing that belongs in the repo is all the shared workflows (or the elements they comprise.)

Been using yadm for a long time and i love it. super simple and has the "bootstrap" concept as an escape hatch for when i want to get weeeird
What worked best for me is to turn my user's home dir into a Git repository. My .gitignore contains this:

*

And if I need to add something, I just "git add -f ...". Works surprisingly well. Combines well with git-secret for things like SSH keys, certificates and API keys.

Nothing beats nix + home manager. But it is fun to see how many different ways people go about solving this particular problem. All of them have their tradeoffs and annoyances.
I found Andrew Burgess's method approachable and ended up cribbing from his dotfiles concept [1] and making my own repository [2]. His method uses bash instead of make to create the symlinks defined in the links.prop file in each subdir of the repo.

I typically checkout the dotfiles repo to a personal project folder on every new OS build and then run the installer to get all my configs in place.

- [1] https://shaky.sh/simple-dotfiles/ - [2] https://gitlab.com/jgonyea/dotfiles

Articles like this one are more likely to drive people away from make(1) than teach them to appreciate it.

This Makefile is anything but simple. It uses advanced features that are meant for complicated situations, just to create a few symlinks. The same symlinks, every time. And if you introduce a new dotfile to the repo, you have to update the Makefile too.

It also makes no use of the main feature of make(1) - to track files for changes, and update them.

For demonstration, here is the same functionality, in sh(1):

  files=$(find files -type f | sed s=^files/==)
  echo "$files" | sed s=[^/]*\$== | sort -u | { cd; xargs mkdir -p; }
  echo "$files" | xargs -I{} -n1 ln -sf $PWD/files/{} ~/{}
Doesn't use advanced features, shorter, and you don't need to update the script for new dotfiles. And more "ubiquitous" than GNU make.
> And if you introduce a new dotfile to the repo, you have to update the Makefile too.

Not at all. The rules are generic. I can give make any path inside my home directory and it will try to match it against an equivalent file in the repository.

  $ make /home/matheus/.vimrc
  ln -snf /home/matheus/.files/~/.vimrc /home/matheus/.vimrc
I only need to update the makefile if I want easy to use phony targets. These phony targets in turn simply depend on the paths to the real files which activate the generic rules I described in the article.

It looks complicated because I used functions to compute all these paths from the items in the repository. Here's what the final result looks like:

  $ phony-targets GNUmakefile
  git
          /home/matheus/.config/git/config
  mpv
          /home/matheus/.config/mpv/mpv.conf
  vim
          /home/matheus/.vimrc
  # ...
I could have used any of those paths and it would have worked. The phony targets are nice but not strictly needed.

The bulk of the makefile is dealing with environment variables such as XDG_*_HOME and GNUPGHOME variables which affect where the links are supposed to end up.

I do like Make so quite an interesting article, but the author seems overly impressed with their idea of using a literal ~ for the name of the subdirectory. That adds an unnecessary WTF factor to the code in my opinion :)
Nice article, I love Make and your blog looks sharp. I would suggest to provide the beginner friendly version in which all the rules are hard coded, so that a beginner can profit and don't be freightened. And then, introduce the problem of needing to add rules by hand for each new dotfile, and then provide your solution using Make's builtins.

I also suggest putting the complete final version of the Makefile at then end, so I can copy it.

Regards,

I don't understand what "managing" this accomplishes?