A dotfile is a configuration file, in plain text, with a name that begins with a full stop (.), or a dot. On Unix systems, the full stop hides the file when executing ls or when browsing using a file manager like Finder. Dotfiles thus remain hidden during typical use but can be exploited by power users to extraordinary ends.


Because dotfiles are written in plain text, they’re easily transferable between different machines, even those running completely different operating systems. As long as your operating system has git, for example, you can configure it using .gitconfig.


Traditionally, dotfiles only work on Unix-based systems—that is, macOS, Linux, and *BSD variants, plus others—and that’s the focus of this guide. Windows users using Cygwin or the Windows Subsystem for Linux may have some luck, but setup will be for you to figure out.


Step 1. Establishing a dotfiles repository for the first time


Before you can start working with your own dotfiles repository, you need to create the directory and initialize it as a Git repository. You can name your folder anything you’d like, and put it wherever it’s convenient for you, but I think placing the .dotfiles directory in your home folder makes a lot of sense.

$ mkdir ~/.dotfiles
$ cd ~/.dotfiles
$ git init


You’re now set up with a local Git repository that will version control any changes.


For your repository to be shareable and accessible from multiple computers, you’ll want to connect this local repository to GitHub.

  • Log into GitHub.
  • Click on the plus sign + in the upper right-hand corner, and then New repository.
  • Choose a name, add a description. Skip initializing a README, adding a .gitignore file, and choosing a license for now.
  • Hit Create repository.


You should now have an empty repository on GitHub as well. Now to connect the two—look for the green Clone or download button on the right-hand side of the page and copy the text within the textarea—it should look something like git@github.com:joelhans/dotfiles.git. You want to add that to the git remote add origin command just below:

$ git remote add origin git@github.com:USER/NEW-REPOSITORY.git
$ git push -u origin master


If this doesn’t work, you may have to use HTTPS, or set up Git itself—check out GitHub’s handy documentation for more.


You should also initialize a README file with a single line of Markdown, and then add your changes and push them to GitHub.

$ echo "# Welcome to my dotfiles repository" > README.md
$ git add README.md
$ git commit -m "Added initial README."
$ git push -u origin master


At this point, your repository is ready to house some dotfiles! Let’s walk through a few fundamentals that you might be interested in.


Step 2. Creating a few dotfiles


Since we’re already working with Git, let’s create a few example Git-related dotfiles and add those to our repository.




This file offers some basic configurations on how your local git installation should connect to GitHub or any other remote provider. You can also create aliases in this file as well—check out this post for examples and inspiration.

  name = Joel Hans
  email = joel.g.hans@gmail.com

  user = joelhans

  excludesfile = ~/.gitignore_global
  editor = nano
  filemode = false
  trustctime = false
    autocrlf = input




As referenced in the .gitignore file, the .gitignore_global file forces Git to “forget” about a few file extensions and directories so that they don’t get included in version control.



Let’s assume for a second that you followed my previous Bash-to-Zsh migration post and are all set up with Zsh and oh-my-zsh. Even though that pair gives you a good deal of built-in flexibility, you can always push customization further. I’ve taken the default Oh My Zsh script and stripped it down, and made a few small tweaks.

# Setting $PATH
export PATH=$HOME/bin:/usr/local/bin:$PATH

# Path to the oh-my-zsh installation.
export ZSH=$HOME/.oh-my-zsh

# ZSH theme to display.

# Enable command auto-correction.

# Display red dots whilst waiting for completion.

# Disable marking untracked files as dirty.

# History time stamps

# Oh-my-zsh plugins
plugins=( git docker cp zsh-syntax-highlighting )

# Spaceship settings
SPACESHIP_PROMPT_ORDER=( time user host dir git )

# Sourcing oh-my-zsh and other shell helpers
source $ZSH/oh-my-zsh.sh
source $HOME/.zsh_exports
source $HOME/.zsh_aliases


See those last three lines, each beginning with source? Sourcing another file is like include() in PHP or #include in C—the file is gathered and executed as though it’s part of the original file. In this case, Zsh evaluates .zshrc and then seeks out any other sourced file, and evaluates those as well.


By separating different types of configuration into different files, we can keep our dotfiles small and easily navigable.




Both .zsh_exports and .zsh_aliases can be named anything you like—lots of other dotfile repositories name them simply .exports and .aliases—but I like this standard. Remember that when it comes to dotfiles, customization is key.


The .zsh_exports file establishes environment variables, which are used by scripts to open your preferred editor, for example.

# Set the shell
export SHELL=/bin/zsh

# Default editor
if [[ -n $SSH_CONNECTION ]]; then
  export EDITOR='nano'
  export EDITOR='nano'

# SSH key
export SSH_KEY_PATH="~/.ssh/rsa_id"

# Prefer US English and use UTF-8
export LC_ALL="en_US.UTF-8"
export LANG="en_US"




Once you get the hang of aliases, they can be addicting. They allow you to add arguments to common commands or create shortcuts to others, whether they’re a favourite of yours or a pain to type out.

# Common shortcuts
alias reload="source ~/.zshrc"
alias _="sudo -E"
alias dnf="sudo dnf"
alias rr="rm -rf"

# Directory traversal
alias ..="cd .."
alias ...="cd ../.."
alias ....="cd ../../.."
alias ~="cd ~"
alias -- -="cd -"

# Directory listing
# Colors courtesy https://github.com/mathiasbynens/dotfiles/blob/master/.aliases
if ls --color > /dev/null 2>&1; then # GNU `ls`
  export LS_COLORS='no=00:fi=00:di=01;31:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.ogg=01;35:*.mp3=01;35:*.wav=01;35:'
else # macOS `ls`
  export LSCOLORS='BxBxhxDxfxhxhxhxhxcxcx'
alias l="ls -lF ${colorflag}"
alias la="ls -laF ${colorflag}"
alias lsd="ls -lF ${co#lorflag} | grep --color=never '^d'"
alias ls="command ls ${colorflag}"

# IP addresses
alias ip="dig +short myip.opendns.com @resolver1.opendns.com"
alias ipl="hostname -I"
alias ips="ifconfig -a | grep -o 'inet6\? \(addr:\)\?\s\?\(\(\([0-9]\+\.\)\{3\}[0-9]\+\)\|[a-fA-F0-9:]\+\)' | awk '{ sub(/inet6? (addr:)? ?/, \"\"); print }'"

# Prevent ZSH from throwing autocorrect for weird-looking Sass commands
alias sass='nocorrect sass'



Other dotfiles and other “dotfiles”


Many Unix utilities, like vim, tmux, and screen, have dotfiles of their own. Start exploring to see what programs have dotfiles, and how you can configure/save them in your repository.


While not dotfiles in the traditional sense, many developer-centric programs store user preferences in plain text files in a variety of syntaxes. SublimeText and Atom, two widely-used code editors, both store user preferences files that you can store in your repository.


Step 3. Making and saving changes


Now that you have a few dotfiles in your repository, you want to start version controlling them. Every time you make a change to a dotfile, you should add it to the Git commit, write out a commit message that explains your change, and push it to your repository.

$ git add .     # for all changed files, or git add FILENAME to add a single file
$ git commit -m "Enter commit message here."
$ git push -u origin master


It’s that simple. Now that your repository contains a few unique dotfiles that are tracked and can be cloned to any new computer or server you boot up.


Step 4. Deploying dotfiles (with a Bash script)


Having a .dotfiles folder/repository with a handful of your unique configuration files does nothing without actually deploying them to your system. The basic, non-script version of deployment can be done on the command line in just a few steps, while the scripted version does everything in a batch using a single command.


Without a Bash script


In order for programs to pick up your dotfiles, you need to create symlinks between the expected location and your dotfile. In Linux/macOS, this is quite simple:

$ ln -sf "~/.dotfiles/.gitconfig" ~
$ ln -sf "~/.dotfiles/.gitignore_global" ~
$ ln -sf "~/.dotfiles/.zshrc" ~
$ ln -sf "~/.dotfiles/.zsh_exports" ~
$ ln -sf "~/.dotfiles/.zsh_aliases" ~


Rinse and repeat with any other dotfiles you might have.


The ln command, in conjunction with the -s argument, creates a symbolic link. The -f argument forces the creation of a symlink, overwriting any file that exists in the specified location. Here is where we start to enter the dangerous, overwriting-working-system-defaults part I mentioned before.


With ln -sf "~/.dotfiles/.gitconfig" ~, you’re basically saying to your computer, “If git wants to read ~/.gitconfig, please look at ~/.dotfiles/.gitconfig instead.” Once the symlink is in place, the program will begin reading its new configuration.


With a Bash script


A Bash script automates the installation process entirely, which is handly on for further deployments. Here’s a very simple example install.sh Bash script that would be placed in the .dotfiles folder.


# Get dotfiles installation directory
DOTFILES_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ln -sf "$DOTFILES_DIR/.gitconfig" ~
ln -sf "$DOTFILES_DIR/.gitignore_global" ~
ln -sf "$DOTFILES_DIR/.zshrc" ~
ln -sf "$DOTFILES_DIR/.zsh_exports" ~
ln -sf "$DOTFILES_DIR/.zsh_aliases" ~


You run the script by typing ./install.sh into your terminal, and it will create all the symlinks automatically.


But, once you bring Bash into the equation, you can do so much more than just creating symlinks. I have a somewhat-functional installation script in my own dotfiles repository that also installs Oh-my-Zsh, some plugins, and contains more dotfiles for other programs that I use frequently. It’s very much a work in progress, but that’s how all good projects are born.


It’s important to note here that once you’ve deployed symlinks, you don’t need to recreate them or re-run a bash script if you make changes to your .zshrc file, for example—the symlink will automatically connect to the newest version, which means your software will always have the latest and greatest setup.

Was this answer helpful? 0 Users Found This Useful (0 Votes)