DEV Community

Cover image for Persisting Config Files Across Computers
Chiemezuo
Chiemezuo

Posted on

Persisting Config Files Across Computers

Introduction

Isaac Newton's famous third law of motion says: "For every action, there's an equal (in size) and opposite (in direction) reaction." A classic case of this is how the thrill of getting a new machine is often matched by the dread of setting up the said machine. With developers, for instance, the list of things to migrate can go on endlessly. From SSH keys to tools (or their equivalents in a different operating system), account details, program files, environment setups, and configurations. These can take a chunk of someone's time. Even worse, some of them (e.g. configurations) are only possible to the extent of the previous machine still being available. I imagine configurations being a nightmare to remember if something crashes unless there is a previous backup available on demand. I'll talk about a nifty way of keeping configurations.

Backstory

Decorative GIF for the word

I recently switched devices and found myself using the zsh terminal. It seemed very compatible with the bash commands that I was more familiar with, but I had a big gripe with it right away: "tab completions were not case-sensitive". This was a big deal because I like the idea of my directory names being capitalized, and having to account for this caused a lot of friction. I decided to switch to bash in the hopes of that being resolved, but I had no such luck. I figured I would have to play around with my terminal configurations and found some commands that did this. I created the required .zshrc file, copied the commands, saved them, and tested them. It worked, but I encountered another problem shortly after: My active GitHub branches weren't showing in the terminal.

I use branches a lot, and having the one I'm in show on my terminal is a big relief, and saves me the stress of manually checking every time. This is something I cannot live without, and I got some code from the internet to add to my .zshrc. Things worked fine, but three questions came to my mind:

  1. Would I always have to do this while setting up a new machine?
  2. What if I (or someone else) accidentally deleted the .zshrc file?
  3. What if I made a change and wanted to undo it later on?

The third question had the easiest solution: write comments for every new addition. And while having a trash folder felt like an answer to the second question, it wasn't guaranteed that it would always be retrievable.

As for the answer to all the questions? Well, that's what I'm here to talk about.

The Approach

Decorative GIF of a star wars character walking

I shared some of my annoyances with the new setup process with a friend of mine and we talked about possible ways of solving these problems. He mentioned a solution he developed for himself after several years of switching machines because he had very precise settings he liked to keep. Hint: it involved Version Control.

Version Control allows you to track and store different states of a file, with an option to store these versions in a remote repository. This answers the 3 questions from earlier, but brings with it, its own question: "How?"

There are two ways of doing this with git:

  1. Make the location of the .zshrc a git repo.
  2. Have the content of the .zshrc file in a different location (which will be a git repo), and then point to that location.

The first approach seems good at first glance. However, the usual location for the .zshrc file is in the home directory, which also has lots of files. To achieve the desired result, you would need a .gitignore file in place to ignore everything else except the pertinent config file. The drawback with this is that you could somehow end up committing something new (and sensitive) or even damage something in your home directory while setting up. It's a high-risk low-reward process.

The second approach, on the other hand, might seem a bit confusing to do at first, but is safer. The trick to achieving this is knowing how to point files to other files, similar to how variables work in programming languages. This is where Symbolic links (symlinks) come in. A symlink is a file that points to another file. Beneath the hood, it's simply a file that contains a text string file path, in a format that the operating system understands to follow up with. Essentially, we could write the configs in a safe (or even public) location, and have their counterparts in the home directory point to them instead. This way, you could make a change in the new location, and everything would reflect as expected. Best of all, you could commit changes without fear of damaging anything, and replicate the process for as many different machines as you want.

The Process

The first step would be knowing how to create a symlink. For POSIX, the shell command to do this is:

ln -s <target-path> <link-path>
Enter fullscreen mode Exit fullscreen mode

Where the <target-path> is what you want to point to, and the <link-path> is the copy that points to it. Let's say you have a file a in the documents directory and you want to make it read-only and accessible from the desktop directory, the command would look like this:

ln -s path/to/documents/a path/to/desktop/a
Enter fullscreen mode Exit fullscreen mode

The path/to/desktop/a will be created if no such file exists, but the path/to/documents/a should ideally exist, else there would be nothing to be linked to.

For my symlink, I created my new .zshrc file in the following path:

Documents/Code/Scripts/dotfiles/.zshrc
Enter fullscreen mode Exit fullscreen mode

Afterward, I initialized the Scripts folder into a git repo and pushed it to my GitHub remote. Having done this, I edited the .zshrc and filled it with the copied-over commands from my findings.

By default, shell terminals look for configuration files in the home directory (~/). My next step was to link one to the target I created in the git repo. To do this, I ran:

ln -s Documents/Code/Scripts/dotfiles/.zshrc ~/.zshrc
Enter fullscreen mode Exit fullscreen mode

I reloaded my terminal afterward, and all my new terminal configurations worked. To be sure changes would reflect, I appended some random characters to my target file and ran cat ~/.zshrc to see if the characters would reflect, and that worked. Essentially, problem solved.

Takeaways

With this technique, I can persist not only shell configs, but also other text file settings I would like to carry along to other machines, and it would take me only one terminal command to get everything working as intended.

Going even further, I could have this for multiple types of files, and then have a script.sh that I could run to set up everything automatically. For example, the following:

ln -s path/to/target/.zshrc ~./zshrc
ln -s path/to/target/.zshrc_profile ~./zshrc_profile
ln -s path/to/target/.zshrc_completion ~./zshrc_completion
Enter fullscreen mode Exit fullscreen mode

would make ./script.sh a convenient script to run, especially on a new machine.

A Few Things to Note

  • The target file and link file do not need to have the same name. It just helps for recognition.
  • The .zshrc file would work similarly to .bashrc, depending on the shell terminal you're using. The principles still hold.
  • These methods are not limited to just configurations and will work in pretty much any situation where you need to have something in a location you would rather not turn into a repo, but would like to keep for future usage.
  • There are different types of config files. I used the one I was most familiar with.

Credit

Special thanks to my friend Tom for pointers on how to solve the problem.

Finally, thank you for reading.

Cheers. 🥂

Top comments (0)