DEV Community

loading...
Cover image for Using dotfiles and Git to manage your development environment across multiple computers

Using dotfiles and Git to manage your development environment across multiple computers

Adam DeHaven
Developer, designer, runner, & cyclist.
Originally published at adamdehaven.com Updated on ・6 min read

Your computer's dotfiles are a key piece of your development environment. Many of us work on multiple computers throughout the day (e.g. work laptop, desktop at home, etc.) and managing to keep settings consistent across machines is a pain. I'll walk you through one way to synchronize and back up your dotfiles utilizing a git repository.

Starting from scratch

Create a bare repository in your $HOME directory:

mkdir $HOME/dotfiles
git init --bare $HOME/dotfiles
Enter fullscreen mode Exit fullscreen mode

Add a .dotfiles-local-settings file in your $HOME directory. This file will be the home for any aliases, functions, values, etc. that you do not want to commit to the repository. I typically use this file for things like machine-specific values or aliases. For example:

# Create local settings file
touch $HOME/.dotfiles-local-settings

# The path to the development folder on this machine. This path may be different on my work computer
echo "alias dev=\"cd /d/adam/Development\"" >> $HOME/.dotfiles-local-settings
Enter fullscreen mode Exit fullscreen mode

After creating this file and populating it with anything you'd like, duplicate it, and rename the duplicate file .dotfiles-local-settings.example and clear out the values. This way, when you clone the repository to a new machine, you have a template to use to define your machine-specific settings.

One important entry to place into this file is the dotfiles alias we will use to manage version control for our dotfiles. Let's add that now (you will only need one of the aliases below, depending on your computer):

# Windows
alias dotfiles='/cmd/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME' >> $HOME/.dotfiles-local-settings
# --------------------------------------------------------------------------- #
# Mac (depends on location of git)
alias dotfiles='/usr/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME' >> $HOME/.dotfiles-local-settings
# or
alias dotfiles='/usr/local/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME' >> $HOME/.dotfiles-local-settings
Enter fullscreen mode Exit fullscreen mode

Add a .gitignore to your $HOME directory to ensure it will ignore the dotfiles folder where the bare repository lives, as well as your local settings file that you do not want in version control. You can also add any other files here you want to ensure do not get added:

echo -e "dotfiles/\n.dotfiles-local-settings" >> $HOME/.gitignore
Enter fullscreen mode Exit fullscreen mode

Also add a .gitignore to this new repository to ensure it will ignore the folder where you'll eventually clone it on another machine (prevents weird recursion problems):

echo "dotfiles/" >> $HOME/dotfiles/.gitignore
Enter fullscreen mode Exit fullscreen mode

Create an alias in your current environment for running git commands in the dotfiles repository we just created. Use the same alias we created earlier, as this one will only be used until we have everything up and running:

# Windows
alias dotfiles='/cmd/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'

# --------------------------------------------------------------------------- #

# Mac (depends on location of git)
alias dotfiles='/usr/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'
# or
alias dotfiles='/usr/local/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'
Enter fullscreen mode Exit fullscreen mode

Next, configure the repository status to hide files we have not chosen to track (i.e. files we have not added), and to suppress the instructions on how to add ignored files:

# Hide files we have decided not to track
dotfiles config --local status.showUntrackedFiles no

# Suppress the instructions on how to add ignored files
dotfiles config --local advice.addIgnoredFile false
Enter fullscreen mode Exit fullscreen mode

Add the remote to the repository (change to the remote URL of your repo on GitHub, or wherever):

dotfiles remote add origin git@github.com:username/dotfiles.git
Enter fullscreen mode Exit fullscreen mode

Add the .gitignore we created in our $HOME directory to the repository:

dotfiles add $HOME/.gitignore
dotfiles commit -m "Adding .gitignore"
Enter fullscreen mode Exit fullscreen mode

Now you can easily add other files to be tracked from where they are supposed to be.

For example, to add your .bashrc file:

dotfiles add $HOME/.bashrc
dotfiles commit -m "Adding .bashrc"
dotfiles push
Enter fullscreen mode Exit fullscreen mode

I like to add separate files for functions, aliases, etc. To add these files, I use a specific naming convention that makes it easy to add the files to the repository that looks like this: .dotfiles-functions and .dotfiles-aliases.

Then, to add these files to source control, you can simply do this:

dotfiles add $HOME/.dotfiles-*
dotfiles commit -m "Adding custom files"
dotfiles push
Enter fullscreen mode Exit fullscreen mode

Install on a new system

Clone your dotfiles into a bare repository in your other computer's $HOME (change to the remote URL of your repo on GitHub, or wherever):

git clone --bare git@github.com:username/dotfiles.git $HOME/dotfiles
Enter fullscreen mode Exit fullscreen mode

Add the alias to the .bashrc or .zshrc on the new machine (this will only be used until we have everything up and running):

# Windows
alias dotfiles='/cmd/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'

# --------------------------------------------------------------------------- #

# Mac (depends on location of git)
alias dotfiles='/usr/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'
# or
alias dotfiles='/usr/local/bin/git --git-dir=$HOME/dotfiles/ --work-tree=$HOME'
Enter fullscreen mode Exit fullscreen mode

Checkout the actual content from the bare repository to your $HOME:

dotfiles checkout
Enter fullscreen mode Exit fullscreen mode

You may receive an error message similar to the following:

error: The following untracked working tree files would be overwritten by checkout:
   .bashrc
   .bash_profile
Please move or remove them before you can switch branches.
Aborting
Enter fullscreen mode Exit fullscreen mode

This is because your $HOME folder may already contain some of the configuration files which would be overwritten by the checkout. To resolve, copy or back up the existing file(s) to another location if you care about them, otherwise, simply remove them.

If you'd like to back up the current settings, here's a shortcut to move the matching files to a new folder:

mkdir -p $HOME/dotfiles-originals-backup && \
dotfiles checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | \
xargs -I{} mv {} $HOME/dotfiles-originals-backup/{}
Enter fullscreen mode Exit fullscreen mode

Then, re-run the checkout:

dotfiles checkout
Enter fullscreen mode Exit fullscreen mode

Set the showUntrackedFiles flag to no for this local copy of your dotfiles repository:

dotfiles config --local status.showUntrackedFiles no
Enter fullscreen mode Exit fullscreen mode

Duplicate the .dotfiles-local-settings.example file, and rename it to .dotfiles-local-settings (removing .example). Now, update the contents of the file to store the machine-specific values for this new computer. These settings will not be tracked in source control.

Be sure to include the dotfiles alias we created in this file so you can access the dotfiles command globally.

Making updates

So you're up and running with your new way of managing dotfiles. Great! 🎉 Now you want to make some updates, so let's walk through the update process.

Editing a tracked file

Let's say you want to add a new function to your custom .dotfiles-functions file to search for files in your current directory.

Open the .dotfiles-functions file, and add the following lines:

# Case insensitive file search, excluding node_modules and AppData directories
function ff() {
  find . -type d \( -iname node_modules -o -iname AppData \) -prune -false -o -type f -iname "*$1*"
}
Enter fullscreen mode Exit fullscreen mode

With our new function in place, adding this change to our tracked version is simple. First, we'll add the file, write a commit message, and push it to our remote repository:

# Remember to use your dotfiles alias!
dotfiles add -u
dotfiles commit -m "Adding find file function"
dotfiles push
Enter fullscreen mode Exit fullscreen mode

Now that the function lives in the repository, we can easily pull down the changes on another computer:

dotfiles pull
# Don't forget to source your .bashrc (or .zshrc, etc.) file to pull in the new function
source $HOME/.bashrc
Enter fullscreen mode Exit fullscreen mode

Adding a new file

To add a new file to be tracked with our dotfiles setup, simply create and edit the file, ensure it doesn't have any personal information that shouldn't live in source control, and add it to version control.

Remember, if the file contains any personal information or machine-specific information, it's better to place the information in your .dotfiles-local-settings file.

For this example, maybe we want to force Vim to use a specific theme. Create a new file .vimrc, and paste this content into the file:

set background=dark
colorscheme solarized
let g:solarized_termtrans=1
Enter fullscreen mode Exit fullscreen mode

Now, let's add the new file to our dotfiles repository:

dotfiles add $HOME/.vimrc
dotfiles commit -m "Adding Vim config"
dotfiles push
Enter fullscreen mode Exit fullscreen mode

Now that the new config file lives in our repository, we can easily pull down the new file to another computer:

dotfiles pull
Enter fullscreen mode Exit fullscreen mode

Discussion (1)

Collapse
nicolaerario profile image
Nicola Erario

Thank you for the article!
github.com/twpayne/chezmoi
is a good tool