Configure Local Environment Using Dotfiles
Tags: dotfiles, shell, local, homebrew
Published: 2021-02-19 08:32:26

<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o0fpzhsdf0jbapv4beki.png" />

<sup><b>Credits:</b> [Logo](https://github.com/jglovier/dotfiles-logo) created by [Joel Glovier](https://github.com/jglovier)</sup>

Automate your local dev configuration in style on a personal, work or any other machine using a [dedicated CLI utility](https://zachinachshon.com/dotfiles-cli/).

<h2 id="tl-dr">TL;DR</h2>

Using a dotfiles repository has never been so easy. Interact with any dotfiles repository using a well defined CLI utility rather than executing random scripts.

Control the following items from a Git backed repository:

- .dotfiles (aliases, exports, functions, shell RC files and others...)
- Settings and configurations (`.gitconfig`, `.vimrc` and others...)
- Homebrew (packages, casks, services, drivers)
- macOS/Linux settings and preferences

<h2 id="long">LONG</h2>

- [Incentive](#incentive)
- [Solution](#solution)
- [What's included?](#whats-included)
- [Homebrew](#homebrew)
- [dotfiles](#dotfiles)
  - [Session Folder](#session-folder)
  - [Custom Folder](#custom-folder)
  - [Home Folder](#home-folder)
  - [Transient Folder](#transient-folder)
  - [Shell Folder](#shell-folder)
- [macOS/Linux settings override](#macos-linux-settings)
- [Demo](#demo)
- [Summary](#summary)

<p>&nbsp;</p>

**What is a .dotfile?**

It is a standard text file usually located within the `$HOME` folder. It contains a dot prefix in its name and is a hidden file which you can list with `ls -a` on a *nix system.

**What is a Homebrew package / cask?**

Homebrew is a package manager for macOS, it allows you to install CLI utilities (packages) & GUI applications (casks).

**Why override macOS settings?**

It is relevant if you have custom macOS settings. These are usually the settings that you change from the macOS GUI (Graphical User Interface) or from the terminal. You should back these custom settings so you'll be able to restore them on every new/formatted machine.

---

<h3 id="incentive">Incentive</h3>

We have all been there, being lost in the sea of information on our constant learning experience on a daily basis. When we identify a command / script / keybinding  that it is useful to us, we'll add it to a note taking application hoping to remember where it is stored for the next time.

The same goes for local applications and CLI utilities. When receiving a new machine or going through an OS re-install, we start a manual installation process of all the applications and CLI utilities we are used to, hopefully not to miss a few.

And what about run command files (`*rc`) such as `zshrc` and `bashrc` for example. They usually contain custom content such as terminal colors, plugins etc.. which you'll want to restore so you'll feel right at home within your comfortable shell.

It's not a simple task trying to keep our magic scripts that are scattered all over the place, either if its changing a system setting we've got used to or the repetitive command we're constantly searching for in Google since we cannot find the time to add a snippet for it since we cannot seem to find the appropriate note-taking-application-to-rule-them-all.

---

<h3 id="solution">Solution</h3>

Automate your local development environment installations/updates with just a few terminal commands. Manage everything under a Git backed repository so you'll keep your setting in a centralized location, detached from any machine and enjoy all the benefits a version control has to offer.<br>

**How does keeping dotfiles under a GitHub repo helpful?**

Even though the dotfiles are located under the folder you have cloned the Git repository into, by using symlinks (symbolic link / soft link) we're able to link them to `$HOME` or any other folder and every change within the repository is reflected on every new terminal shell session since these files get sourced with their latest content.

> **Tip:** Additionally, you can call `dotfiles reload` on the existing session without the need to create a new session.

**How do we start?**

There are a lot of dotfiles repositories publicly available in GitHub. People share their own managed dotfiles, either if it's a single script you'll have to add to the `.bash_profile` or other more complex alternatives that require a different setup.

In this blog post I'll share an [example dotfiles solution](https://github.com/ZachiNachshon/dotfiles-example) similar to the one I'm using which is managed by a [dotfiles-cli](https://zachinachshon.com/dotfiles-cli/) utility that allows its users some ease of mind when it comes to local environment setup.<br>

Please feel free to fork my [dotfiles GitHub repository](https://github.com/ZachiNachshon/dotfiles-example) and add your own content on top of it !

In case you wish to check the repository out before forking, you are welcome to clone and change it to suite your needs:

```bash
$ git clone https://github.com/ZachiNachshon/dotfiles-example.git ~/<my-codebase-folder>
```

<p>&nbsp;</p>

**Why using a dotfiles CLI utility?**

1. Simplify the complex dotfiles repository wiring by separating the files from the management layer
1. Use a dedicated CLI utility to control all aspects of the dotfiles repository with ease
1. Having a coherent dotfiles structure that is easy to get familiar with
1. Allow a generic CLI to control multiple dotfiles repositories (private and public)
1. Avoid from running arbitrary scripts

**How to install the dotfiles CLI?**

Install dotfiles-cli via Homebrew, pre-built release or from sources. Please head over to the [download section](https://zachinachshon.com/dotfiles-cli/docs/latest/getting-started/download/) for further installation information.

---

<h3 id="whats-included">What's included?</h3>

A well organized folder layout containing categorized scripts with minimum overhead to glue them all together using the dotfiles-cli utility.

An example of an expected repository structure:

   ```bash
   .
   ├── ...
   ├── brew   
   │   ├── casks.txt
   │   ├── drivers.txt
   │   ├── packages.txt
   │   ├── services.txt
   │   └── taps.txt
   │
   ├── dotfiles               
   │   ├── custom  
   │   │   ├── .my-company  
   │   │   └── ...
   │   ├── home
   │   │   ├── .gitconfig       
   │   │   ├── .vimrc
   │   │   └── ...
   │   ├── session 
   │   │   ├── .aliases
   │   │   └── ...
   │   ├── shell
   │   │   ├── .zshrc
   │   │   └── ...
   │   └── transient
   │       └── .secrets
   │
   ├── os
   │   ├── linux
   │   │   ├── key_bindings.sh
   │   │   └── ...
   │   └── mac
   │       ├── finder_settings.sh  
   │       └── ...
   │
   ├── plugins
   │   ├── zsh
   │   │   ├── oh_my_zsh.sh  
   │   │   └── ...
   │   └── bash 
   │       ├── dummy.sh
   │       └── ...
   └── ...
   ```

> **Tip:** Run `dotfiles structure` to get a reminder on the expected dotfiles repo structure.

---

<h3 id="homebrew">Homebrew</h3>

Automate the installation process of favorite CLI utilities & GUI applications by using Homebrew macOS package manager. All you will have to do is to update simple text files with the package, cask, driver or service you wish to install. Installation and updates takes place whenever `dotfiles brew <option>` command is being called.

To add a CLI utility (a.k.a Homebrew package):

1. Search for a desired package in [here](https://formulae.brew.sh/cask/)
1. Add the package name to the [packages.txt](https://github.com/ZachiNachshon/dotfiles-example/blob/master/brew/packages.txt) file
1. Run `dotfiles brew packages` to install/update


To add a GUI application (a.k.a Homebrew cask):

1. Search for a desired cask in [here](https://formulae.brew.sh/formula/)
1. Add the cask name to the [casks.txt](https://github.com/ZachiNachshon/dotfiles-example/blob/master/brew/casks.txt) file
1. Run `dotfiles brew casks` to install/update

> **Tip:** Similar flow for installing drivers and services via Homebrew.

---

<h3 id="dotfiles">dotfiles</h3>

<h4 id="session-folder">Session Folder</h4>

A folder containing dotfiles which are relevant across all machines (work, personal etc..) that get sourced along on every new shell session or upon `dotfiles reload` command.

Example of such session files I use (you can add your own):

- `.aliases` - define shortcuts for commonly used *nix commands

  Example:

   ```bash
   # -=-= Custom =-=-
   alias l="ls -lah" 
   alias dl="cd ~/Downloads"
   alias gop="cd ${GOPATH}/src/github.com"
   
   # -=-= ZSH =-=-
   alias zshconfig="vim ~/.zshrc"
   ```

<p>&nbsp;</p>

- `.functions` - add new utility scrips to the functions collection so they'll be available right away

   Example:

   ```bash
   # Create a new directory and cd into it
   mkd() {
     mkdir -p "$@"
     cd "$@" || exit
   }
   ```

<p>&nbsp;</p>

- `.paths` - add new environment variables you wish to make available on new shell sessions

  Example:

   ```bash
   # -=-= Kubernetes =-=-
   export KUBECONFIG=$HOME/.kube/k3s/config
   
   # -=-= Path =-=-
   export PATH=/usr/local/bin:/usr/bin:${JAVA_HOME}/bin:${GOROOT}/bin:${GOPATH}/bin:${PATH}
   ```

<p>&nbsp;</p>

<h4 id="custom-folder">Custom Folder</h4>

A folder containing custom files to symlink, usually relevant to specific machines e.g. work related or personal etc..

I have added an example file to the repository (you can and should add your own):

- `.my-company` - a work related content that should get sourced on every new shell session

  Example:

   ```bash
   alias work-repos="cd codebase/my-company-repos" 
   
   work() {
      echo "I work at ACME Corporation."
   }
   ```

<p>&nbsp;</p>

<h4 id="home-folder">Home Folder</h4>

A folder containing files that should get symlinked from the dotfiles GitHub repository to the `$HOME` folder for the same reasons [we have described in here](#solution). A few examples are `.gitignore_global, .gitconfig, .vimrc` and others...

To add such file as described:

1. Place it within `<repo-root>/dotfiles/home/` 
1. Run `dotfiles sync home`

<p>&nbsp;</p>

<h4 id="transient-folder">Transient Folder</h4>

A folder containing transient files, meaning, files that shouldn't get checked-in into source control or symlinked anywhere but should get sourced along on every new shell session.

You can use this to export ENV vars with sensitive information such as secrets to become available on newly opened shells. Files under `transient` folder are git ignored by default to prevent from committing to a source control.

<p>&nbsp;</p>

<h4 id="shell-folder">Shell Folder</h4>

A folder containing run command files (`*rc`) such as `zshrc` and `bashrc` for example. They usually contain custom content such as terminal colours, plugins etc.. which you'll probably want to backup and restore once needed.

To add such file as described:

1. Place it within `<repo-root>/dotfiles/shell/` 
1. Run `dotfiles sync shell`

   > **Note:** Only the relevant shell `*.rc` file is being symlinked to `$HOME` folder, depends on the shell you are using. Currently supported shells are: `bash`, `zsh`.

---

<h3 id="macos-linux-settings">macOS/Linux Settings Override</h3>

These are usually settings you have changed from the macOS/Linux GUI (Graphical User Interface) or from the terminal. In case you do have custom macOS/Linux settings, you'll probably want to back them via GitHub repository to be able to restore on-demand. 

Restoring these settings could take place either on new machine, after OS re-install or in case you have tweaked some knobs and forgot how to revert.

To override macOS/Linux settings and preferences:

1. Find the terminal command corresponding to the setting you wish to backup
1. Add the command to a script files under:
   - macOS - `<repo-root>/dotfiles/os/mac`
   - Linux - `<repo-root>/dotfiles/os/linux`
1. Run `dotfiles os <mac/linux>` to override settings and preferences

   > **Note:** Check out macOS settings [examples in here](https://github.com/ZachiNachshon/dotfiles-example/tree/master/os/mac).

---

<h4 id="demo">Demo</h4>

[Click here](https://zachinachshon.com/dotfiles-cli/docs/latest/assets/gif/dotfiles-cli.gif) for a running demo.

---

<h4 id="summary">Summary</h4>

I hope this post helped to shed some light on how dotfiles could be useful for your local environment and you have found the way I'm automating dotfiles with Homebrew & macOS overrides insightful and helpful.

Please leave your comment, suggestion or any other input you think is relevant to this post in the discussion below.

---

Like this post?
You can find more by:

Checking out my blog: https://blog.zachinachshon.com
Following me on twitter: @ZachiNachshon

Thanks for reading! :heart: