Ask HN: How do you sync your computer’s development configurations/environment?

105 points by baalimago ↗ HN
I have two personal computers and one work laptop, all of which have similar development environment but not the same. One personal computer runs windows, the other two Ubuntu.

Since I knew that I will be using different IDEs and environments, I decided to learn vim and use vim bindings in all my IDEs to ensure some sort of similarity across all my development environments, but it doesn't cover it all. I've also tried manually migrating my home directory between different computers, but that comes with several issues, primarily that I'd have to try to share it between professional and personal computers. So what I'm left with is basically remembering what I'm using, and then tediously spend a day or more re-configuring newly installed computers with the software and configurations I know I'm using. It feels like I have to throw away my perfectly configured hammer which I know by heart and get a new one every time I work at a different workplace instead of bringing it along and perfecting it further. Surely there's a better way.

How do you keep your development environments/ways of working synced and backed up?

152 comments

[ 4.7 ms ] story [ 198 ms ] thread
Yeah, mixed environments are really tough. Though (most) of my machines are Linux, they often have _some_ stuff that should be the same and _some_ stuff that should not. My solution has been to use the fine-grained GNU Stow approach, which allows me to apply only the bits I need for a particular machine.

The files you're managing don't even need to be text, though, of course, it makes versioning, etc. a lot easier.

I also check the host name in some of the scripts to modify behavior depending on the machine.

I did a write-up about my whole setup (emphasis on GNU Stow + Git) here:

https://ratfactor.com/setup2

I also use GNU Stow + Git and has worked well for me. For files I want to sync that I don't need versioning for and it is important that I have them available even in cases where I may have forgotten to commit my changes on some individual machine, I use Syncthing[1], which is really great for the more Dropbox-y kind of cross-machine sync that I also have a need for.

[1]: https://syncthing.net/

I just have a dotfiles repository and in it an installation script, one for Mac and one for Linux.

Might be bad of me, but I definitely share it between professional and personal - it's just dotfiles after all.

The biggest difficulty is making sure that the installation script actually matches what you want to happen because it is difficult to test on already finished system. so every so often I spin up a Digitalocean droplet and try to configure my system from scratch using the dotfiles.

There’s a neat tool - stow - which handles dotfiles style installs with soft links quite handily. Absolutely worth investigating.
yes, stow + a git repo is really useful when replicating a conf on many environments. Its a nice alternative to ansible which is sometimes overkill for some easy copy-and-paste
I wrote a utility for this problem. I had 3 computers -- Linux with HiDPI, Linux with a normal DPI, and Mac. They all used the same dotfiles with slight differences. It was impossible to keep them in sync. I created a super simple template utility designed for working with dotfiles.

https://github.com/kesslern/dot-templater

Sounds like a good opportunity for building a tool that syncs dotfiles in a smart way across different environments. Bonus points for managing what gets synced at a granular level, i.e. including/excluding certain files/configurations.
Not just with development environments, but all computer configuration, I stick with the defaults as much as possible. Instead of changing the configuration of the computer, I change myself.

For example, let's say an app has a default keyboard shortcut I don't like. I won't change it. Instead, I'll just get used to it until it becomes muscle memory.

Now the default configurations are my preferred configurations. Of course, there are still a few things I change from the defaults. But since there are so few I can just configure them by hand, because how often am I setting up a new computer? Not very often. And there are so few config changes, it only takes a minute.

The only thing I have to actually sync is my vim config. It's a very small config, but it's still more than nothing. I just store it in a Git repository.

This is where I’ve come to over the years as well. Generally defaults are best unless it’s something you really care about and that makes a big difference to your workflow.

Most configuration stuff doesn’t fit that category - or if it does, it’s best to first work on just caring about it less if possible.

I'm doing the same. In some companies you can't just get ssh to outside world, or download some stuff from github... So I stick to defaults and I try to do development on single machine.
Yes, this is one of the best decision I made quite a while back. I'm usually asked for ideas and advices on how to setup computers, both technical and non-technical friends and families. I have always suggested putting a little more effort in learning the defaults and getting used to it.

I have even written a short essay, as I found myself repeating the same suggestions many a times. https://notes.oinam.com/digital/apple/

Agreed, same thing with basic stuff like color schemes. I just pick one that's auto installed by default with an IDE and stick with it. I'm tired of futzing and installing stuff to get things juuuuust right. Most IDEs come with great defaults.
Additional benefit is that defaults are often such that they work well together, often in ways that you might not have foreseen beforehand and thus never would have set up yourself.
I think there's a healthy middle ground here. Endless tweaking of settings tends to be a waste of time, but if you spend hours a day on a computer, you might as well make it comfortable. Some people use no $EDITOR plugins and wear it like a badge of honor, this is pretty silly to me. The few minutes it takes to install and learn about a plugin might save you hundreds on hours in the future.

I guess my personal strategy is to run with the defaults until you find the pain points, and install/configure something to address them. And put them in git repo if possible.

> Some people use no $EDITOR plugins and wear it like a badge of honor, this is pretty silly to me.

I don't use any plugins for PyCharm or IntelliJ, but they're pretty full-featured right out of the box. I certainly don't do it as a badge of honor, that indeed is pretty silly.

But vim is useless without any plugins. Even VSCode is only marginally better than Notepad++ unless you give it the plugins necessary to turn it into an actual IDE and not just a code editor.

> vim is useless without any plugins

It’s not? I mean vim defaults are great, it supports a lot of formats out of the box (indentation, syntax highlighting), it’s ideal for quick edits. Surely if you need an IDE-like functional then it’s not enough (probably) but it is very far from being useless without plugins.

(comment deleted)
Yes, this. Custom configurations are a maintenance burden when you change systems. Living with defaults saves time in the long run, usually. Only when I spot an exception to that rule will I install something custom.
I have a friend who does this. But his reasoning goes one step further. He's usually mentoring people on his team, so he finds it very valuable to be able to not only function quickly on someone else's setup, which is usually the standard, but to give them hints that'll work directly for people unfamiliar with the tools.
Yeah, my macOS set-up is simple enough it's not worth scripting or otherwise saving.

Use the GUI settings panel to make CAPS LOCK an extra ctrl. Takes maybe 10 seconds.

Use same to make dock auto-hide. 10 seconds if I'm slow about it.

Install Homebrew. Maybe 15 seconds hands-on and a couple minutes in the background.

Use Homebrew to install spectacle. Less than 5 seconds hands-on time, done less than a minute later.

Start Spectacle and use its preferences panel to set it to start on boot. Maybe 15 seconds.

Remove all the pinned programs on the dock. 60-90 seconds.

The last one's the only part I've considered scripting, but since I only do it once every couple years at most, it's not really worth it.

Once I'm past a Mac's initial "welcome to Mac" flow and on the actual desktop, I'm only about 5 minutes (not all of it actively doing things) from having a comfortable environment set up and being all ready to install project-specific tools, as needed.

If I ever switch back to Linux (or FreeBSD, which is more likely at this point) I might go back to versioning and backing up a bunch of config and dot files. I need them, there.

> CAPS LOCK an extra ctrl

Another fine specimen, salute!

If it was ESC instead you'd get a +1. ;)
What if I told you that you can have both? For me it's ctrl when I hold it down and use it with another key and esc when I press it briefly. Can be set up on a Mac with Karabiner Elements.
Why not Command instead of Ctrl? Isn't that something that you use way more often?
I'm not that commenter but ctrl is my least favourite regularly used key to hit. It's not comfortable to reach with either my pinky or thumb. Command is basically where my thumb rests naturally, it's in prime position.
Yep, cmd is great where it is. If I compare cmd-shortcuts with identical ctrl-shortcuts, with normal key mapping, the ctrl ones strain my hand and pull my fingers away from the home row. The same cmd-based shortcuts do neither of those things. It's one thing Apple got very right, that everyone else is getting wrong.
Because I go used to use Emacs binding while on the terminal and VIM bindings for everything else. Ctrl + [ instead of ESC to change modes for me :D
> Use same to make dock auto-hide

Cmd-Opt-D to toggle auto-hiding – I use this one to check if the dock is frozen :)

(Also a great option to rebind: it's a global hotkey so no other app should be using it)

Ha, I hit this by accident a couple times a year, then have to fix it in settings because I can never remember what the combo is.
Just as a sidenote, because I was using Spectacle as well. JFYI: As it is no longer maintained, I switched to Rectangle (https://github.com/rxhanson/Rectangle) and can highly recommend it.
Yeah, I'm just putting off switching because Spectacle still works, and has never broken or even behaved in a way that seemed weird or less than ideal, even across multiple monitors, with changing screen situations (hiding/un-hiding the dock), et c. It is one of the very few pieces of software I run that has given me precisely zero problems of any kind. Ain't broke, don't fix it, and all that.
You can take it even further: stick to the defaults and mainly use command line tools.

Almost every linux box has bash, vim, and the GNU command line tools. If you can become proficient with default config cli tools, you can become proficient on almost any linux box.

If i have to deal with ancient osx gnu gplv2 utilities, i think I'd go bananas. You have to modify the default settings at some point or your productivity will surely wane in comparison to others. I see your point with some defaults but the purest approach doesn't seem practical either.
This is a great answer if, like you said, you don't set up computers very often. I use mostly defaults in part because I set up computers a couple times a month. Often just for a day does that physical or virtual device live, consuming my configs, but having to manually do it every time would be a pain.
> I stick with the defaults as much as possible. Instead of changing the configuration of the computer, I change myself.

This is the worst advice you could give. There are plenty of shitty defaults and default tastes vary from app to app and there's a reason things are customizable.

Customize to your taste throughout your tools and don't let a new tool eat your time.

It's probably awful but I sorta really just rely on system backups for my configs. Download and restore anything I'm missing from the latest backup when I reinstall the system.

I do keep my ~/scripts/ directory in a git repo (also this directory is in my $PATH) because they're all very hack and slash "I need to do a thing repeatedly, quickly" scripts. Sometimes I might want to go back a step or two when I really break everything. This repo auto pulls/commitpushes every now and then as this one is more useful to be up to date on all machines than to have useful commit messages

As for live syncing devices I do have unison running on my laptop frequently to sync (when its on) a few directories I might need offline. Mostly everything I need as a dev is in git repos though, so I use manual git push/pulls to sync everything else

I did previously use mackup (https://github.com/lra/mackup) to sync configs but if I'm honest I forgot I had it set up the last time I reinstalled so it got removed from the process unintentionally

It isn't what you asked, but we use Gitpod to have identical environments across our team and between different laptops. I used to avoid writing code on my Macbook (using it only for administrative stuff I can do in Chrome), but now that it's identical to my main Ubuntu driver it's actually pretty nice. I also used to hate Windows/Mac developers complaining that scripts don't work for them because bash/coreutils are different on their machines.
Basically I use git for .local/dotfiles/ which are then symlinked to the relevant files like .zshrc or .emacs.d/init.el. Then I just keep that repo up to date with git pulls. Works across 2 macbooks, a Fedora workstation, and a Fedora headless server.

Couple of bits from a guide I wrote recently: https://gist.github.com/aclarknexient/0ffcb98aa262c585c49d4b...

    # store stuff here that you don't want in github
    [[ -f $HOME/.zshenv-local ]] && source $HOME/.zshenv-local

    # depends on 'brew install grep'
    [[ $OSTYPE =~ ^darwin.* ]] && alias grep='ggrep --colour=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn,.idea,.tox}'
That OSTYPE is great for all those little bits that are unique to each operating system. The zshenv-local is in .gitignore, so you can keep tokens, api keys, etc etc in there. OSTYPE could even be used to import specific files like .zshenv-darwin or .zshenv-linux-gnu

If you're ssh'ing between your hosts, you can use something like this:

    if [[ -n $SSH_CONNECTION ]]; then
      ZSH_THEME="afowler"
    else
      ZSH_THEME="powerlevel10k/powerlevel10k"
    fi
It's not fancy and doesn't use cool tools, but my setup works for me just fine.
I do something similar, but even simpler. I have my entire home dir as a git repo, but my .gitignore contains a single "*". I git add files I want with a -f.

I'm gonna go though your guide later though-- I like quite a bit of what I've skimmed so far. Thanks for posting that.

Any feedback on the guide will be gratefully received. I'm trying to write better docs to give a little back to the open source community - it's not much but it's what I can manage :)

EDIT: and that "*" for gitignore is intriguing, I'll have to take a better look at that whitelist vs blacklist setup, thank you!

I've been doing "home dir is a repo" for a while now too and I'm always surprised when people think it's weird/dangerous. I wrote a few guides with tricks on how to do it on my blog that all started with "This is probably a horrible idea but here's how to do it anyway!"
I did the same plus just a little bit of Ansible makes deployment a little nicer.
I looked into Ansible after reading your comment - I've only ever used it and Puppet for larger-scale stuff so hadn't even thought of using it as a localhost-only playbook. This looks like it could manage my symlinks for me very nicely :) Thank you!
This is what I've done for a long time. You get the benefits of keeping things synced and having a full history.
I keep a .dotfiles git-repo similarly. The configs/custom scripts/etc are organized into separate folders by what they do (shell config/work tools/...) and I use GNU Stow to symlink them into my home directory. Makes setting up super easy:

    git clone <repo> .dotfiles && cd .dotfiles
    stow --target=$HOME --dir=packages shell-config
    stow --target=$HOME --dir=packages work-stuff
I've found this to be much more manageable than tools like yadm since I can pick-and-choose sets of configs/scripts based on the machine I'm using them on.
I've been using Ansible for years now to do this.

Right now all my computers run fedora so there's not much difference between them but for some time I used Ansible on macOS too. It worked but was a pain to make my roles compatible for both linux and macOS.

In my experience Ansible is good when dealing with text files or if there's already a module for what you're trying to do (for example managing postgresql users). If what you're trying to do is complex enough that you need to write a custom module or plugin, it is a pain in the ass: we had to do that at work and it was terrible.

Ansible works on Windows but I have no experience with it.

I’ve used a git repo with ansible on ubuntu, win10, WSL2 and macos. Works close-enough-ish and I mainly use it to copy dotfiles into place. I’ve used symlinks in the past to avoid reliance on a tool, but symlinks are no good on windows.
(comment deleted)
I just use Goodsync personally. I used to have it sync to a WebDAV server in my house, but these days I just use a cloud provider.
I use Nix: https://bou.ke/blog/nix/

I'm able to have the same shell with all my Vim plugins across macOS and Linux with changes committed to git. It's been so good, setting up all my command-line tooling now takes about 15 minutes from scratch.

Nice writeup, just wanted to comment in case you hadn't thought of it, that you can achieve a nix-shebang with flakes by adding a wrapper script. e.g. foo_wrapper.sh:

    #!/usr/bin/env bash

    readonly gitsha="..."
    nix shell nixpkgs/${gitsha}#bash nixpkgs/${gitsha}#{foo-pkg} nixpkgs/${gitsha}#{bar-pkg} -c bash foo.sh $@
- Dotfile repo hoested on GitHub

- `git clone` said repository to my machines

- `ln` from repository folder to `~/` (can be done in an install script or piecemeal)

- `git pull` to update

I also purposely try and use as many default configurations as possible. I use a lot of remote machines that do not have my configs on them, so I do not want to become too reliant on custom setups.

Dotfiles in my home directory go in a repo that gets cloned and "installed" (I use a shell script that I wrote to make all the symlinks, but GNU Stow is probably better better). System level configuration and package installation is handled by ansible, with a certain amount of stuff controlled by conditional statements based on the distro and host name of the machine to allow arbitrarily local overrides.

All that said, if I was starting today I would strongly consider just putting everything into nix with home manager and carry that config around in a git repo that installed my packages and their configuration and encapsulated my entire environment.

You could use a dotfiles manager like https://yadm.io/

It's more or less a wrapper of git, but it comes with a bunch of features that allow you to do the things you describe.

This is what I have set up. Admittedly I keep forgetting to use it.
It slows my shell start-up a few hundred milliseconds, but I keep a nag in my bashrc to list changed files.

    yadm_diff=$(yadm --no-pager diff --name-only --exit-code)
    if [ $? -ne 0 ]; then
        echo -e "\e[1m\e[91m[yadm] \e[0m\e[92mThese config files have been modified:\e[39m"
        echo "$yadm_diff"
    fi
I used to use a git repo of dotfiles which used a script to symlink into $HOME: https://github.com/RyanGibb/dotfiles

But there were a few problems with it: - installed packages needed to be managed separately (the mechanisms for which varied by platform) - managing differing configs for different machines (e.g. headless servers, hardware quirks) was done by managing different branches of this repo and rebasing, which was a pain - it was generally brittle and hard to change

I've started to use https://nixos.org/ and it's been like night and day: https://github.com/RyanGibb/nixos/

My config is version controlled, reproducible, manages packages, and is very composable.

Using the nix package manager and https://github.com/nix-community/home-manager this should work on other Linux distributions, MacOS, and even Windows Subsystem for Linux. Although I haven't tried this for myself yet.

Personally I'm in Emacs for almost anything so different environments are just different set of org-mode files with things to tangle, different org attach and roam directories etc, common staff sync-ed with unison.

That's work VERY well, but might not fit your needs depending on what you need to use for work...

the main question here is, do you really need to change the settings once you have a baseline?

I'm another one using a private GitHub repo for this. But I don't need to pull, update, sync or whatsoever. I've been using the same config for years, and in the eventual case that I would change / add something, I can do that quickly in a few computers, no need to have any sort of sync.

For VSCode settings I just use the built-in service.