24. 09. 2026 Gabriele Bocchi Automation, Development, DevOps

Why Your Dotfiles Deserve Version Control

If you spend enough time working on Linux, your home directory slowly becomes a reflection of how you like to work.

A few aliases are added to your shell. Git gets its own configuration. Your editor starts accumulating plugins and custom keybindings. The terminal gets some additional settings, and eventually even tools you barely remember configuring behave exactly the way you expect them to.

Most of these changes are small, and when you make them you rarely think about having to reproduce them in the future.

Then you get a new workstation.

Suddenly you have to remember which packages you installed, where that useful alias came from, how you configured Git, why your editor behaves differently, and which small settings made the old machine feel comfortable to use.

This is usually the point where dotfiles stop looking like a collection of hidden files and start looking like something worth managing properly.

What Are Dotfiles?

The name comes from a convention used by Unix-like operating systems. Files and directories whose names start with a dot are normally hidden from a regular directory listing and are often used to store application configurations.

Some familiar examples are .gitconfig, .zshrc, .ssh, or the many application directories living under .config.

The term “dotfiles” has become broader over time. A dotfiles repository can contain much more than files whose names literally start with a dot. Shell configuration, terminal settings, editor configuration, Git preferences, desktop settings, scripts and many other parts of a development environment can all be managed together.

At first, there’s nothing wrong with editing these files directly.

But problems gradually appear.

Your .zshrc depends on a plugin manager. Your editor configuration expects a particular tool to be installed. Git has aliases that call external commands. Some settings only make sense on a desktop machine, while others should be available everywhere.

The individual files are still simple, but the environment they describe is no longer simple to recreate.

That’s where version control starts to become useful.

Your Configuration Deserves Git, Too

We wouldn’t normally work on any application without Git.

Version control gives us a history of what changed, lets us compare versions, makes experimentation safer, and allows us to go back when a change turns out to be a bad idea.

The same advantages apply surprisingly well to our development environment.

Suppose you change part of your shell configuration and notice a few days later that something no longer behaves correctly. Without version control, finding the cause can mean trying to remember what you changed. With Git, it’s just another diff.

The same is true for larger changes. Maybe you replace one terminal emulator with another, switch shell plugin managers, reorganize your editor configuration, or test a new set of aliases. Committing those changes gives you a record of the evolution of your setup instead of leaving the current state as the only copy that exists.

This changes the way configuration feels.

Instead of a collection of files that happen to exist on one computer, the repository becomes the source of truth for how you want your environment to be configured.

It also makes experimenting much easier. Breaking a configuration is much less worrying when you know the last working version is still in Git.

The Real Goal Is Reproducibility

Using Git as a backup for configuration files is useful, but I think the more interesting benefit of dotfiles is reproducibility.

Consider what normally happens when setting up a new development machine manually.

You install Git, configure your username and preferences, install a shell, recreate aliases, install an editor, restore its configuration, add your usual command line utilities, configure the terminal, set up SSH and then spend the next few days discovering small things that are still missing.

None of these tasks is particularly difficult. The problem is that there are many of them, and most are performed from memory.

The process is also difficult to repeat. If you configure another machine six months later, you probably won’t perform exactly the same steps.

A managed dotfiles repository changes that.

The repository can become a description of the environment rather than just a backup of a few files. Setting up a new machine becomes a process you can repeat instead of a checklist you have to remember.

This isn’t very different from a principle we already apply to our infrastructure.

We don’t like manually configuring servers because manual changes are difficult to reproduce, difficult to audit and eventually lead to configuration drift. We use configuration management and Infrastructure as Code to make the desired state explicit.

A developer workstation obviously doesn’t need the same level of control as a production cluster, but the basic idea still works remarkably well.

If a piece of configuration matters enough that you would manually recreate it on the next machine, it’s probably worth considering whether it can be declared instead.

From a Git Repository to Configuration Management

The simplest dotfiles repository can be nothing more than a few files and symbolic links.

For many people, that’s enough.

A typical repository might start with something as small as:

.dotfiles/
├── git/
├── shell/
├── editor/
├── terminal/
└── install.sh

The installation script creates the necessary links or copies the configuration to the right locations.

There are also tools specifically designed for this job. GNU Stow is a popular approach based around symbolic links, while tools such as chezmoi provide additional features such as templates, machine-specific configuration and secret integration.

The specific tool you use isn’t particularly important. What matters is that there is one place describing the configuration and one predictable way of applying it.

Once this is in place, it’s natural for the setup to grow a little further.

If your shell configuration requires a particular plugin manager, the bootstrap process can install it. If your editor depends on command line tools, those dependencies can also be declared. The same process can install fonts, terminal utilities or other programs that are part of your normal environment.

This is where dotfiles become much more useful than a backup.

My own dotfiles followed roughly this path. They started as configuration files and gradually became a way to bootstrap most of the environment I expect on a machine. Today I use chezmoi to manage them, but the important part isn’t chezmoi itself. It’s having a reproducible process rather than relying on a machine that has been manually configured over several years.

There is a limit, of course.

Not every setting needs automation, and turning a dotfiles repository into a complicated configuration management framework can defeat the purpose. The useful question here is not “Can I automate this?” but “Will I need to reproduce this again?”

If the answer is yes, automation usually pays off.

Different Machines Should Still Be Different

There is another trap that becomes apparent once you start managing several machines: Trying to make all of them identical.

At first this sounds like the whole point of dotfiles, but it isn’t.

A personal workstation, a work laptop, a temporary VM and a headless server have different requirements. A desktop application may be useful on one and meaningless on another. Work-specific configuration may not belong on a personal machine. Some tools may only be available on certain operating systems or distributions.

A good setup should therefore provide a common baseline without pretending that every machine is the same.

This can be handled in several ways. Some dotfile managers support templates and conditional files. A simpler setup might just load an optional local configuration file when it exists.

For example, the shared repository can contain the general Git configuration, while a local file provides an identity or settings specific to a particular environment.

The same idea works for shell aliases, SSH hosts and application settings.

Keeping these differences explicit has another benefit: the shared configuration stays portable. Instead of slowly filling the repository with exceptions for individual machines, you can keep the common parts common and isolate what is genuinely local.

The objective is not to produce identical machines.

It’s to make each machine predictable.

Public Dotfiles Need a Security Boundary

Dotfiles are also a good example of why configuration and secrets should not be treated as the same thing.

It’s very easy for configuration files to accumulate sensitive information.

An API token temporarily added to an environment variable, an SSH private key, a credential embedded in an application configuration, an internal hostname or a forgotten .env file can all end up in the same directory as harmless settings.

That becomes particularly important when the dotfiles repository is public.

Publishing dotfiles can be useful. Other people can learn from the setup, configuration can be shared easily, and the repository itself becomes a useful reference. But a public repository should always be treated like any other public source repository.

Anything committed to it should be considered public information.

Secrets should live somewhere else.

Depending on the setup, that can mean a password manager, a dedicated secret manager, encrypted storage or simply local files excluded from Git. The repository can contain the logic necessary to use those secrets without containing the values themselves.

For example, it can describe where an SSH key should be placed without storing the private key in Git. It can configure an application to read a token from the environment without defining that token. It can include a local configuration file without tracking it.

That separation is useful even for private repositories. Credentials usually have a different lifecycle than configurations: They expire, rotate and may differ between machines. Keeping them separate makes both sides easier to manage.

And if a secret ever does accidentally make it into Git, deleting it in the next commit is not enough. At that point it should be considered exposed and rotated.

Reproducibility Also Means Being Able to Test the Setup

There’s another interesting consequence once a dotfiles repository starts doing more than copying files: it becomes possible to test it.

A broken alias is annoying. A bootstrap script that stops halfway through configuring a new machine is more annoying.

If the setup supports several environments, simple automated checks can quickly become worthwhile.

That doesn’t necessarily mean building a huge test suite. Even basic checks can answer useful questions:

Does the installation work on a clean system? Can it be executed twice without breaking anything? Are configuration files created with the expected permissions? Does a headless environment avoid installing desktop-only software?

This is the same reason idempotency matters in configuration management. Running the setup again should ideally converge on the desired state instead of producing a different result every time.

Testing also protects the repository from its own evolution. Once a dotfiles setup has accumulated enough automation, changing one part can unexpectedly affect another. A clean environment is often the best place to discover assumptions that are invisible on a workstation that has been configured for years.

You certainly don’t need CI for your first .zshrc, but it becomes surprisingly reasonable once the repository is responsible for rebuilding your working environment.

Keeping the Environment Maintainable

Versioning configuration also makes maintenance easier.

A manually configured workstation tends to accumulate things. Packages are installed and forgotten. Old aliases survive long after the tools they were written for disappear. Configuration from an application you stopped using two years ago remains in .config.

When the environment is represented in a repository, these changes become much more visible.

Removing a tool means removing its configuration. Replacing something produces a clear diff. Dependencies can even be kept up to date automatically in the same way as dependencies in a software project.

The repository becomes documentation as a side effect.

Months later, if you wonder why a particular setting exists, git blame and the commit history may actually have an answer. That’s much better than trying to remember why you added one obscure line to your shell configuration years ago.

It also encourages small improvements.

You don’t need to design the perfect dotfiles setup before starting. In fact, I would recommend the opposite.

Start by versioning the files you care about. Add an installation process when copying them manually becomes annoying.

Introduce conditional configuration when you actually have a second environment that needs it. Automate dependencies when the bootstrap process starts depending on them.

The setup can grow together with your needs instead of becoming a project of its own.

More Than a Backup

The biggest advantage of dotfiles is not that they save a copy of .zshrc somewhere.

It’s that they move your development environment from something implicit to something explicit.

Without them, your workstation is often the result of years of manual changes that exist only on that machine. With them, much of that state becomes versioned, understandable and reproducible.

That makes switching machines easier, but it also makes everyday changes safer. You can experiment, review what changed, share useful configuration and gradually automate repetitive setup work.

And, just like with infrastructure, the benefits tend to become more visible over time.

The first commit may contain only a few files. A few years later, that same repository may be the difference between spending a day configuring a new workstation and having a familiar environment available after a single setup process.

In Conclusion

Dotfiles may look like a very personal and relatively small part of a development setup, but they benefit from many of the same practices we apply to software and infrastructure.

Version control gives configuration history and traceability. Automation makes it reproducible. Separating local data and secrets keeps it portable and safe. Testing can make more advanced setups reliable instead of fragile.

None of this requires building the perfect setup or automating every preference on your machine.

The goal is much simpler: Stop relying on memory for configuration you know that you’ll need again.

Once setting up a new machine becomes something you can reproduce instead of something you have to remember, your dotfiles are doing much more than hiding in your home directory.

These Solutions are Engineered by Humans

Did you find this article interesting? Does it match your skill set? Programming is at the heart of how we develop customized solutions. In fact, we’re currently hiring for roles just like this and others here at Würth IT Italy.

Gabriele Bocchi

Gabriele Bocchi

Software Engineer - IT System & Service Management Solutions at Würth IT Italy

Author

Gabriele Bocchi

Software Engineer - IT System & Service Management Solutions at Würth IT Italy

Leave a Reply

Your email address will not be published. Required fields are marked *

Archive