Advertisement

Setting Up a Mac Dev Machine From Zero to Hero With Dotfiles

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

Setting up a new machine can often be an exciting prospect. However, as developers, there are a lot of tools we need that don't come as standard.

In this post, I'd like to go through some of the techniques I use to help set up my machine quickly, efficiently and with added super powers.


Introduction

After reading this article, you should be able to do the following:

  1. Quickly set up a new machine
  2. Enhance SSH'ing into a Linux box
  3. Easily absorb smart configs from other developers on GitHub
  4. Optionally share your setup with other developers and participate
  5. This is how all professional developers maintain their configurations

Before we begin, you'll need some understanding of Git and using the command line. If you're not sure what these are, I'd recommend looking over the following first:


Superhero Dotfiles

What if you could style the Terminal, make the speed of Mission Control faster, run g instead of git, have tab autocomplete regardless of filename case, check for software updates daily, not just once per week? What if you could automate setting up all these features with a single script? Sound good? Then this post is for you.

In many respects setting up a new machine is very much down to personal preference. I'm always refactoring and reevaluating and I'd advise you to do the same. Find out what works best for you and share your knowledge.

TL;DR: Invest time learning to configure your machine and automate processes, you'll get that time back ten fold.

Dotfiles, so called because the filename begins with a . are found in the user's home directory. These files are created as you install and configure your machine. I think of each dotfile as a superhero each containing its own super powers. I'm going to go over each superhero dotfile and the powers that lie within. But first...

There's a lot to be said for the awesomeness of dotfiles, setting up configurations automatically and speeding up processes. It may be tempting to clone a repository and run dotfiles straight away, but I'd advise against this as the outcome may have undesired results.

Baby Steps

First of all, I'd recommend cloning some existing dotfiles repositories. Doing so will allow you to start to understand the file structure and get an overview of the code. The following are GitHub repos from some top developers who have shared their dotfiles:

It may seem daunting at first glance, but don't panic, I'll be going over each dotfile that I use when I setup a new machine. After reading this post, when you've got a better understanding of each file and what they can do, I'd recommend creating your own repository and taking advantage of existing dotfiles to build it up. You can then add the files and code in that's best going to suit your requirements.

As people generally name their dotfiles repo dotfiles I set the folder structure up like so:

└── dotfiles
    ├── mathias
    │   └── dotfiles
    │       ├── LICENSE-MIT.txt
    │       ├── README.md
    │       ├── bin
    │       │   ├── bash -> /usr/local/Cellar/bash/4.2.45/bin/bash
    │       │   ├── httpcompression
    │       │   └── subl -> /Applications/Sublime\ Text\ 3.app/Contents/SharedSupport/bin/subl
    │       ├── bootstrap.sh
    │       └── init
    │           └── Mathias.terminal
    ├── paulirish
    │   └── dotfiles
    │       ├── README.md
    │       ├── bin
    │       │   ├── github-email
    │       │   └── spot
    │       ├── install-deps.sh
    │       └── sync.sh
    └── simonowendesign
        └── dotfiles
            ├── bootstrap.sh
            ├── init
            │   ├── Mathias.terminal
            │   └── SolarizedDark.terminal
            ├── install-deps.sh
            └── readme.md

Here, I'm setting up a main folder called dotfiles, then a folder with the username and then the repo. The reason I recommend setting it up like this is to avoid confusion. Some of the code is fairly similar, so I find it useful to easily see whose code I'm looking at. For example, if I had four or more repos all named 'dotfiles' this process would be much more difficult.

Want to know how I output the folder structure like that? I used this awesome thing called tree, installed in the .brew file.

Let's break each file down and look at what's going on.


Superhero Dotfiles and Their Super Powers

Dotfiles are split into two main types. Those that contain a set of commands and only run once, .osx for example runs a list of commands and gives OS X super powers. Other files such as .bash_profile and .bashrc run each time you open a new Terminal session and gives your Terminal super powers.

Here's a run down of the dotfiles in my repo and a description of what they can do.

.brew

It's best to run this first. Once it checks that Homebrew is up to date, it will be used to install useful tools such as tree.

brew install tree

Instead of having to go to a site and download an app, it's also possible to automate the installation of some apps using brew-cask, such as:

brew cask install dropbox
brew cask install google-chrome

bootstrap.sh

This file is like turning the key in a car to start the engine.

When ran, it will sync the local repo and the one on GitHub, then copy those files to your home folder, overriding any existing files if they exist.

Therefore, before running bootstrap.sh it's a good idea to backup your existing dotfiles and save them somewhere else. A handy shortcut to get to your dotfiles in the Finder is:

Finder > Cmd + Shift + g > ~

I use an app called TotalFinder, this adds some nice features to the Finder. Tabbed windows and a shortcut to show and hide hidden files for example I find very useful.

In bootstrap.sh you'll notice source ~/.bash_profile. This means that if you run bootstrap.sh and have any Terminal windows open, your new settings will be applied without the need of a restart.

.bash_profile / .bashrc

When you open a new Terminal session, this file is loaded by Bash. It loads in the other dotfiles path,bash_prompt,exports,aliases,functions,extra and configures some useful settings such as auto correcting typos when using cd completion.

In some instances .bashrc can be loaded, so this file makes sure that .bash_profile is called.

I like my Terminal clean and clutter free, so I opt not to display the username / computer name at the top by default with this file.

Clean Terminal

.path

This file speeds up the process of running executable files. Rather than having to cd back and forth across various paths to executable files, you can set the file paths in your .path dotilfe and then run executable files directly.

Generally, this file isn't held in the public repo as it can contain sensitive information.

Here’s an example ~/.path file that adds ~/utils to the $PATH:
export PATH="$HOME/utils:$PATH"

.bash_prompt

Using this file you can customise and set the various colors of your Bash prompt.

.exports

Sets environment variables, such as setting Vim as the default editor using export EDITOR="vim". It also increases the amount of history saved, useful for backtracking over previous commands you've used.

.aliases

This file contains useful aliases to help you write less. For example, instead of typing 'cd ..' you can set it here to be '..'. Starting to like these files yet? :)

.functions

Similar to aliases, except functions can take arguments.

Before when I mentioned I was looking over different dotfile repos, I did mkdir to create a directory. After that, I'd then need to cd into that directory.

One example of a function that I find useful is:

# Create a new directory and enter it
function mkd() {
    mkdir -p "$@" && cd "$@"
}

Now you can simply do mkd. Now, not only have you made the directory, you're in the directory as well.

.extra

This file is used for adding your personal information and isn't added to your repository in order to make sure someone doesn't accidentally fork your project and then start committing using your details. Something nice to add in here would be your Git credentials.

.gitconfig

This file is only used by Git, for example, when a git command is invoked. So although there's an .aliases file, those aliases are run directly.

In .aliases I have g set to git and in .gitconfig, s set to status -s.

Now instead of running:

git status -s

I can simply run:

g s

.gitignore

Set files that you'd like Git to ignore on the entire system. Yay, no more .DS_Store being accidentally committed!

.gvimrc

A small file that improves readability for gvim.

.hgignore

Simliar to .gitignore for Mercurial.

.hushlogin

In some instances, for example, when you ssh into a machine, you may be presented with a message. It might look something like this:

                                    _
                                   | |
  _ __ ___  _   _    ___ ___   ___ | |  ___  ___ _ ____   _____ _ __
 | '_ ` _ \| | | |  / __/ _ \ / _ \| | / __|/ _ \ '__\ \ / / _ \ '__|
 | | | | | | |_| | | (_| (_) | (_) | | \__ \  __/ |   \ V /  __/ |
 |_| |_| |_|\__, |  \___\___/ \___/|_| |___/\___|_|    \_/ \___|_|
             __/ |
            |___/
 Welcome to my cool server.
 Any malicious and/or unauthorized activity is strictly forbidden.
 All activity may be logged.

This file prevents this from being shown.

.inputrc

Configures the 'Readline environment'. This controls the way keys work when you're entering a command into your shell.

An example of how I find this useful is to make tab autocomplete regardless of filename case:

set completion-ignore-case on

.osx

This is my favorite of all the dotfiles. It is run once, manually, for the commands to run and take effect. Depending on what you've added to this file, you may need to restart your machine.

Some of the awesome things I love are:

  • Disable the “Are you sure you want to open this application?” dialog
  • Check for software updates daily, not just once per week
  • Disable Notification Center and remove the menu bar icon
  • Enable access for assistive devices
  • Set a blazingly fast keyboard repeat rate
  • Finder: allow quitting via ⌘ + Q; doing so will also hide desktop icons
  • When performing a search, search the current folder by default
  • Speed up Mission Control animations

.screenrc

If you use screen, this removes the startup message.

.vimrc

I'm not that familiar with vim. However some of the things you can do with this file include enabling line numbers and adding syntax highlighting.

Sounds like a good idea to me :)

.wgetrc

If you use wget, this adds additional settings such as changing the timeout to 60 seconds rather than the default 15 minutes. It also sets the retry to three, rather than the default 20!


Dotfiles Are Go!

At this point, I've gone over all the files and I'm at a stage where I'm happy with everything in my repo. Anything I wasn't sure about has been commented out.

Now the exciting part! As it stands we have the dotfiles in a repo but we need to put them in the correct place so they can be found and used.

Think of it like this, we have Thor's Hammer, Batman's Utility Belt, Captain America's Shield, and Iron Man's Suit. All of our heroes know how to use these, but without them they're lost! We need to give our superheros their weapons so they can use them.

To do this (with my existing dotfiles backed up and my repo all up to date), open your Terminal, cd to the repo and run

source bootstrap.sh

Next, cd to ~ and run:

source .osx

Quick restart and... Awesome, super powers are now available!!!


Additional Super Powers

Rupa Z

Do you spend lots of time doing things like this?

cd this/is/the/path/that/i/want/so/i/type/it/all/out/to/get/whereiwant

What if instead, you could just do this:

z whereiwant

Yes please. Thank you https://github.com/rupa/z.

To add this, in .bash_profile I made the following change:

# init z https://github.com/rupa/z
. ~/z/z.sh

And also in install-deps.sh:

cd
git clone https://github.com/rupa/z.git
chmod +x ~/z/z.sh

Reverting Things

When you run your dotfiles for the first time, you may find that you don't like a piece of code that has been ran. For example, in the .osx file, I wasn't too keen with what the following code did:

defaults write com.apple.dock showhidden -bool true

This code changed the opacity on hidden apps in the dock.

To simply revert this behavior to its default state, I simply ran the command again, this time changing true to false, as so:

defaults write com.apple.dock showhidden -bool false

This set it back to default.

With most commands it's quite obvious to revert the command by simply changing true to false or vice versa. With others, it's possible to set it back to default using defaults delete, for example, defaults delete NSGlobalDomain AppleHighlightColor. In some instances you may also need to restart the machine.

Custom .osx Commands

Now this is for the more advanced dotfile master. As you gain more knowledge and confidence using dotfiles, you may want to include your own code.

On a new machine if you find you're manually changing settings, these would be best automated.

Adding your own .osx commands can get a bit tricky!

But generally, this is a good place to start:

  • defaults read > a
  • Change the setting
  • defaults read > b
  • diff a b

Doing this creates a file called a and b then displays the difference between them, with this knowledge you can then open up the file b in Sublime Text 2, search for the bit that changed and try and work out the command to change it. If you try out this method, good luck!


Conclusion

So, there you have it! Go forth, have fun with dotfiles, look forward to giving your machine super powers and the next time you need to set up a machine from scratch, you can smile to yourself as the whole process is automated.

Thanks very much for stopping by, please comment below if you have any questions or suggestions.

I'm especially interested to see your own .dotfiles repos and any new additions you make, so feel free to add a link to your dotfiles repo in the comments below.

Special Thanks

This blog post wouldn't have been possible without the wonderful help from the community, special thanks to @mathias, @paul_irish, @reybango and @AndrewPerkins.

Advertisement