My macOS Development Environment of 2018 — End of the Year Edition

Brian Schlining
7 min readDec 30, 2018

I just got a shiny, new, fully-loaded Mac Book Pro.

Woot!

As I set it up, I’m inspired to point out a few more tools and configuration tweaks that are important for my development set up. This list is an addendum to my original post at “My macOS Development Environment of 2018”.

Productivity Tools

  • Magnet — A window manger for macOS. With a keystroke you can position a window exactly where you want it on your desktop. For heavy computer users, any tool to help cut down on mouse usage is greatly appreciated and this Magnet does exactly that. There are free alternatives, like Spectacle, which is also very popular. Magnet is only $0.99 and I don’t mind paying developers to support and update tools that I use.
  • Charles — A web debugging proxy application. It allows me to see all HTTP/HTTPS traffic between my machine and the internet. It’s crazy useful for working on applications that consume microservices and web APIs. WARNING! If you’re the least bit into conspiracy theories definitely do not run this app. Modern computers are amazingly chatty and apps you’ve installed “phone home” with surprising frequency. The amount of ambient internet traffic your computer generates is astounding. Sometimes ignorance is bliss.

Command Line Tools

  • exa — A modern replacement for ls. It does everything that I need ls to do and it includes other features like git integration, tree views, sane display of file size, and colorized output. I alias exa in both my bash and fish shells: ~/.bashrc as alias ls='exa' and ~/.config/fish/config.fish as alias ls 'exa' then use it as a drop-in replacement for ls .
  • bat — I use this as a drop-in replacement for cat. In scripts and piping, it functions just like cat. But for interactive use, it displays the output with line numbers and colorized syntax. I alias cat to bat (e.g. alias cat-'bat').
  • dive — Docker is very heavily used where I work. Dive is a handy tool that lets you inspect the layers in your docker container and view changes between layers.
  • thefuck — An app that corrects errors in previous console commands. It’s both very handy and therapeutic. Here’s an example:
➜ git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

git push --set-upstream origin master


➜ fuck
git push --set-upstream origin master [enter/↑/↓/ctrl+c]
Counting objects: 9, done.
...

and another …

➜ puthon
No command 'puthon' found, did you mean:
Command 'python' from package 'python-minimal' (main)
Command 'python' from package 'python3' (main)
zsh: command not found: puthon

➜ fuck
python [enter/↑/↓/ctrl+c]
Python 3.4.2 (default, Oct 8 2014, 13:08:17)
...

Configuring Git

When setting up git I do the following in ~/.gitconfig :

  • Configure Kaleidoscope as my default diff and merge tool. You can use our preferred diff editor, but make sure you configure git to use it. It will make merging conflicts sooooo much easier.
  • Set up gpg signing for all my git commits. I like seeing the little verified badge next to my git commits :-).

Add some useful aliases to ~/.gitconfig:

  • st — Display a git status without all the usual git verbose-ness
  • sh and shr — Display a short history by date (sh) or by relative time (shr). This alias just displays tags and the HEAD.
  • fh and fhr — Display the full history by date (fh) or by relative time (fhr). This will show every commit for the current branch.
  • releasenotes — Display all commit messages since the last tag.
  • news — Display changes between HEAD and the last changeset.
  • alias — Display all the aliases you’ve configured for git.

.gitconfig

[commit]
gpgsign = true
[user]
signingkey = XXXXXXXXXX
name = Brian Schlining
email = XXXXXXXXXXX@gmail.com
[alias]
# Short History (tags, last 2 commits and related branches)
sh = log --graph --all --simplify-by-decoration --decorate --pretty=format:'%Cred%h%Creset - %C(yellow)%cd%Creset -%C(green)%d%Creset %s %C(bold blue)<%an>%Creset' --date=short
# Short History (tags, last 2 commits and related branches) using relative date
shr = log --graph --all --simplify-by-decoration --decorate --pretty=format:'%Cred%h%Creset - %C(yellow)%cd%Creset -%C(green)%d%Creset %s %C(bold blue)<%an>%Creset' --date=relative
# Full history graph
fh = log --graph --all --pretty=format:'%Cred%h%Creset - %C(yellow)%cd%Creset -%C(green)%d%Creset %s %C(bold blue)<%an>%Creset' --abbrev-commit --date=short
# Full History with relative date
fhr = log --graph --all --pretty=format:'%Cred%h%Creset - %C(yellow)%cd%Creset -%C(green)%d%Creset %s %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
# Show diffs of recent changes
news = log --word-diff=color -p HEAD@{1}..HEAD@{0}
st = status --short --branch # Show a release log
releasenotes = log --pretty=format:'- %s%n%b' --since='$(git show -s --format=%ad `git rev-list --tags --max-count=1`)'
# List all aliases
alias = ! git config --get-regexp ^alias\\. | sed -e s/^alias\\.// -e s/\\ /\\ =\\ /
[push]
default = matching
[difftool "Kaleidoscope"]
cmd = ksdiff --partial-changeset --relative-path \"$MERGED\" -- \"$LOCAL\" \"$REMOTE\"
[diff]
tool = Kaleidoscope
[difftool]
prompt = false
[mergetool "Kaleidoscope"]
cmd = ksdiff --merge --output \"$MERGED\" --base \"$BASE\" -- \"$LOCAL\" --snapshot \"$REMOTE\" --snapshot
trustExitCode = true
[mergetool]
prompt = false
[merge]
tool = Kaleidoscope
[core]
editor = code
excludesfile = /Users/brian/.gitignore_global
[color]
ui = true

Configuring Bash and Fish

Because of it’s excellent auto-completion, I use fish shell for interactive work. Because pretty much every modern computer has it, I use bash for my shell scripting language. For the most part, I configure both shells with the same environment variables and functions. For Macs, I put all my bash profile configuration details in .bashrc and my .bash_profile redirects to my .bashrc , both of which I’ve listed at the end of this article.

Prompt

A couple of notable details about my prompt:

  • Like many developers, my shell prompts show the current git branch. My fish prompt also shows other git details, like number of commits, adds, pulls, pushes, etc.)
  • I use a scp-friendly path in the prompt so that it’s easy for me to copy it an use if I need to transfer files between machines. This is a personal preference but it works well for me.

Functions

There are a few handy functions that I use:

  1. myip — Displays the IP address of my computer.
  2. usejava — I normally have several versions of Java installed and I switch between them for different projects. This function allows me to type usejava 11 or usejava 1.8 to switch between versions.
  3. useconda — Use conda as my default Python for a terminal session. See Python below for why I need this function.

Python

Setting up Python on a Mac is a pain-in-the-ass. If you’re not careful, you can easily have multiple incompatible pythons installed that are stomping all over each others dependencies with no hope of ever. sorting. it. out. EVER. My solution is to run exactly three versions of python:

  1. Python 2.7 that comes with the Mac
  2. Python 3 via Homebrew
  3. Miniconda

Python 2.7 and Python 3 are used to satisfy dependencies needed by the system and other applications (e.g. neovim). That’s it. In order to do that, these versions of python are the normal defaults when a terminal session is started. I rarely install any extra python modules into these versions of Python, but when I do I always install them as user packages. (e.g. pip install --user mypackage)

For analysis and real-work, I need miniconda to be my default python interpreter in a terminal. That’s the purpose of the useconda functions for my bash and fish shells. It configures the path to use miniconda by default for the current terminal session. Once miniconda is in use, I use conda’s version of virtualenv to isolate dependencies. Another (huge) perk is that if I ever screw up my miniconda environment beyond hope of recovery, I can just throw the miniconda directory in the trash and start from scratch. Conda is clean simple and nicely isolated.

neovim

I use neovim as my console editor along with Plug as my vim plugin manager. My setup is pretty basic but I’ve included my ~/.config/nvim/init.vim configuration file below for reference.

Config files

Below are my various configuration files for bash, fish and nvim:

--

--

Brian Schlining

Polyglot coder. Deep-sea Researcher. Zazen aficionado. I think squids are pretty cool.