Consistent modern shell tooling on MacOS and Windows WSL for developers
Tags: tools, productivity
Published: 2022-01-30 00:55:41

---
title: Consistent modern shell tooling on MacOS and Windows WSL for developers
published: true
date: 29/01/2022 17:12:33 UTC
tags: #tools #productivity
canonical_url: https://www.darraghoriordan.com/2022/01/28/developer-shell-modern-bat-fzf-antigen-zsh-wsl-mac/
---

I regularly code on both MacOS and Windows machines and I was always annoyed how different the experiences are on each.

Many of the terminal tools that come with unix environments are functionally similar to how they were 20 years ago. But other developer tooling has advanced quite a bit since then.

You can replace tools like `ls` or `cat` with modern equivalents that support full colour, unicode icons, git state and more. Terminal prompts can be made git aware and use colour to indicate state so you don't have to query git so often.

Installing and configuring these tools on a new MacOS or Windows machine is tedious and takes a few hours without scripts.

Keeping any shell changes you make on one machine up to date on all the machines you use is a nightmare without the right tooling.

This article explains all the tools I use and how I keep the same terminal setup consistent on MacOS and Windows!

<!-- end excerpt -->
## A look at modern terminal tools

Some examples

Old ls

[![old ls output](https://www.darraghoriordan.com/static/506a3b2290ac1771ea8f086cd63023eb/d9217/old-ls.png "old ls output")](/static/506a3b2290ac1771ea8f086cd63023eb/d9217/old-ls.png)
_old ls output_

New ls - git aware with icons and colour hints

[![new ls output](https://www.darraghoriordan.com/static/ce4e352709f930a17fe632edc4a2815d/1cfc2/new-ls.png "new ls output")](/static/ce4e352709f930a17fe632edc4a2815d/1cfc2/new-ls.png)
_new ls output_

Old cat on a json file

[![old cat output](https://www.darraghoriordan.com/static/8721326b4da0f25f6d07be9e83eda13c/59822/old-cat.png "old cat output")](/static/8721326b4da0f25f6d07be9e83eda13c/59822/old-cat.png)
_old cat output_

New cat on the same file - syntax highlighting and formatting

[![new cat output](https://www.darraghoriordan.com/static/5723e82d18c1bb7be7edbb5099274a81/078fe/new-cat.png "new cat output")](/static/5723e82d18c1bb7be7edbb5099274a81/078fe/new-cat.png)
_new cat output_

But tooling is just half the story. I’ll also show settings to change, aliases and scripts that will make the terminal more productive for you.

## Pre-written scripts to save time

It took me around **30 hours** to investigate and configure all of the tolls on MacOS and Windows WSL.

I’ve included everything I learned in this article, but if you want avoid manually configuring all of these tools please check out the [link](https://darraghoriordan.gumroad.com/l/devshell) at the end of the article.

My setup scripts will install and configure all of these tools for you on all your computers in one go!

## Use ITerm2 on MacOS

iTerm2 is a nice replacement for the MacOS terminal. You can have tabs, pane splitting, floating windows, transparency, image backgrounds and full colour.

It has a really nice autocomplete feature (`ctrl-;`), full search and history. You can store profiles for starting a set of terminals (BE + FE is very common!) just like tmux sessions. It also integrates with KeyChain.

Here is my setup for a typical node and react application running on the right-hand side and the left hand side is for working in.

[![showing iterm2 split panes](https://www.darraghoriordan.com/static/4f9ae432e6bdc2ef0201d529b45d3563/acf8f/iterm2.png "showing iterm2 split panes")](/static/4f9ae432e6bdc2ef0201d529b45d3563/ce0a7/iterm2.png)
_showing iterm2 split panes_

Full documentation for iterm2 is [on their site](https://iterm2.com/).

Install it with brew: `brew install --cask iterm2`.

Iterm2 isn’t available on WSL.

## Antigen for zsh management

Antigen is a plugin manager for zsh. You can install plugins from any repository and it caches them until you explicitly reload the configuration so it’s quite fast.

The antigen configuration keeps your zshrc very clean because it will go and clone any repos you need for you. It can automatically check for updates for all plugins with `antigen update`.

Here’s an example configuration. You can see that third party plugins are just listed in shorthand as a github organisation/repository. When you’ve loaded everything you call `antigen apply` and it will set the state to your configuration.

```
# Load the oh-my-zsh's library.
antigen use oh-my-zsh

# Bundles from the default repo (robbyrussell's oh-my-zsh).
antigen bundle node

# Load a theme.
antigen bundle sindresorhus/pure@main

# Tell Antigen that you're done.
antigen apply
```

At any time you can manually refresh everything with `antigen refresh`.

I use brew to install antigen on MacOS - `brew install antigen`.

On Windows I use the shell script - `curl -L git.io/antigen > antigen.zsh`.

If you install using the same methods you have to remember to source them from the different install locations!

Full documentation for antigen is [on their github](https://github.com/zsh-users/antigen)

## Use bat instead of cat

`bat` is a command line utility that is similar to `cat` but with a few extra features. Use `bat` instead of `cat` for reading text files to the terminal.

You get full colour syntax highlighting for code files. You get line numbers. It integrates with git and will show changes to files right in the terminal.

[![showing bat cat output for a json file](https://www.darraghoriordan.com/static/5723e82d18c1bb7be7edbb5099274a81/078fe/new-cat.png "showing bat cat output for a json file")](/static/5723e82d18c1bb7be7edbb5099274a81/078fe/new-cat.png)
_showing bat cat output for a json file_

Install with brew on Mac

```
brew install bat
```

or apt on Windows WSL

```
sudo apt install -y bat
```

On Windows wsl bat is installed as `batcat` so if you’re aliasing `cat` you can use `batcat` instead of `alias cat=bat --paging=never`!.

Full documentation for bat is [on their github](https://github.com/sharkdp/bat)

## Exa for ls

Exa is a replacement for `ls` that is well suited for developers. Exa integrates with git so you can easily see which files are ignored (I), modified (M), new (N) or untracked (?).

It also provides icons, colour coding of files, symlink destinations right in the list, ability to have folders sorted to the top and much more.

[![showing exa output with git state](https://www.darraghoriordan.com/static/80e9c698fbc8b1c79ec6761446100770/dea13/exa.png "showing exa output with git state")](/static/80e9c698fbc8b1c79ec6761446100770/dea13/exa.png)
_showing exa output with git state_

On a mac you install exa with brew and you can alias it to ls

```
brew install exa

alias ls='exa -l --group-directories-first --color=auto --git --icons --no-permissions --no-user'
alias ll='exa -lahF --group-directories-first --color=auto --git --icons'
```

On Windows you must upgrade Ubuntu to use exa via apt. Here is how to upgrade WSL Ubuntu from 20.04 LTS to 20.10.

```
# upgrading Ubuntu on Windows WSL

# change from lts only to normal updates for OS
sudo sed -i 's/prompt=lts/prompt=normal/g' /etc/update-manager/release-upgrades

# update all packages
sudo apt update && sudo apt upgrade

# this snapd package manager breaks the Ubuntu upgrade process on WSL so remove it first
sudo apt remove snapd

# check for an Ubuntu update
sudo do-release-upgrade
```

now you can use exa

```
sudo apt install -y exa
```

on Windows you can’t use the git integration so the alias is slightly different.

```
alias ls='exa -l --group-directories-first --color=auto --icons --no-permissions --no-user'
alias ll='exa -lahF --group-directories-first --color=auto --icons'
```

Full documentation for exa is [on their github](https://github.com/ogham/exa)

## Pure Terminal Prompt

The pure terminal prompt is a very clean zsh prompt. It isn’t an oh-my-zsh theme. It’s a stand alone prompt. It’s very fast and it’s git aware like the Agnoster prompt but much cleaner.

[![showing pure prompt](https://www.darraghoriordan.com/static/c80e45601aec82cddc1a025cb69f7a88/7762d/pure.png "showing pure prompt")](/static/c80e45601aec82cddc1a025cb69f7a88/7762d/pure.png)
_showing pure prompt_

You can see that the prompt shows state above the actual prompt. This gives a dedicated, consistent space for typing commands.

It also gives the information area an entire line to show state. You can see the `*` indicating that I have uncommitted changes. The prompt will also indicate if you have commits to push or pull.

I install this prompt with antigen

```
antigen bundle sindresorhus/pure@main
```

You must also remember to disable any oh-my-zsh prompts if you have one set in an env var.

```
# disable zsh theme for pure prompt
export ZSH_THEME=""
```

Full documentation for pure is [on their github](https://github.com/sindresorhus/pure)

## diff-so-fancy for git diff

Diff so fancy is a terminal based diff tool. It provides a nicer format and better contrasting to the built in diff tool.

This screenshot from the diff-so-fancy docs shows the differences.

[!["side by side showing normal diff and diff-so-fancy"](https://www.darraghoriordan.com/static/60a3a289440d8e92b068c5f852d752fa/acf8f/diffdofancy.png ""side by side showing normal diff and diff-so-fancy"")](/static/60a3a289440d8e92b068c5f852d752fa/3d405/diffdofancy.png)
_"side by side showing normal diff and diff-so-fancy"_

Install on mac with brew

```
brew install diff-so-fancy
```

and on Windows install with npm

```
npm i -g diff-so-fancy
```

You’ll have to add all the required git configuration so that git uses diff-so-fancy instead of the built in diff tool. This is all on their github page.

Full documentation for diff-so-fancy is [on their github](https://github.com/so-fancy/diff-so-fancy)

## RipGrep instead of grep

RipGrep is a fast grep tool for finding occurrences of strings in files. It’s perfect for developers because it’s git aware. It will respect your `.gitignore` file and ignore files in node\_modules for example.

The tool is written in Rust and it’s very quick!

[![showing a search for the term ripgrep with ripgrep](https://www.darraghoriordan.com/static/188abdeff5299040528503f62f879bec/f3c12/ripgrep.png "showing a search for the term ripgrep with ripgrep")](/static/188abdeff5299040528503f62f879bec/f3c12/ripgrep.png)
_showing a search for the term ripgrep with ripgrep_

Install with brew

```
brew install ripgrep
```

or on Windows WSL use apt

```
sudo apt install -y ripgrep
```

Full documentation for ripgrep is [on their github](https://github.com/BurntSushi/ripgrep)

## fx for json files

fx is a terminal viewer for json files. It supports syntax highlighting, understands the tree structure, supports the mouse, filtering and searching json files right in your terminal.

This gif from the tool’s github page shows all of the features.

![animation showing fx's features](https://www.darraghoriordan.com/ac79062c1bf549a380ddcb7529770178/fx.gif)

To install on mac use brew as usual

```
brew install fx
```

However for Windows wsl you should use npm for this one

```
npm install -g fx
```

You can find the full documentation on their [github page](https://github.com/antonmedv/fx).

## Use vscode as default terminal editor

As well as duti (see duti section) for setting MacOS defaults for vscode as text editor. You can also set the default editor for any file type in the terminal and git by setting env vars.

```
export EDITOR="code"
export GIT_EDITOR="code"
export VISUAL="code"
```

## fzf for searching

fzf is a command line fuzzy finder. You can pipe a list into it, search the list and pipe the found item to the next shell command.

To install, use homebrew on mac and apt on Windows WSL.

```
# mac
brew install fzf

# wsl
sudo apt install -y fzf
```

Now you can quickly search your files in the terminal with `ctrl-T`.

I combine fzf with ripgrep for searching files.

```
export FZF_CTRL_T_COMMAND='rg --files --no-ignore --hidden --follow --glob "!.git/*" --glob "!node_modules/*" --glob "!vendor/*" 2> /dev/null'
```

I change `z` so that it uses fzf for searching when no parameter is provided.

```
unalias z 2> /dev/null
z() {
  [$# -gt 0] && _z "$*" && return
  cd "$(_z -l 2>&1 | fzf-tmux +s --tac --query "$*" | sed 's/^[0-9,.]* *//')"
}
```

A nice usage of fzf is to search your chrome history. The paths below support chrome profiles. This is the mac version. The chrome history has a different location on Windows WSL - `/mnt/c/Users/$(whoami)/AppData/local/google/chrome/User Data/Default`.

```
function ch() {
  local cols sep google_history open
  cols=$(( COLUMNS / 3 ))
  sep='{::}'

  if [-d "$HOME/Library/Application Support/Google/Chrome/Default"]; then
    google_history="$HOME/Library/Application Support/Google/Chrome/Default/History"
 else
    google_history="$HOME/Library/Application Support/Google/Chrome/Profile 1/History"
 fi
    open=open

  cp -f "$google_history" /tmp/h
  sqlite3 -separator $sep /tmp/h \
    "select substr(title, 1, $cols), url
     from urls order by last_visit_time desc" |
  awk -F $sep '{printf "%-'$cols's \x1b[36m%s\x1b[m\n", $1, $2}' |
  fzf --ansi --multi | sed 's#.*\(https*://\)#\1#' | xargs $open > /dev/null 2> /dev/null
}
```

The full documentation for fzf is on their [GitHub page](https://github.com/junegunn/fzf) with lots of great examples.

## Duti for changing default text editor

On mac most text files will open in XCode by default. You can change these to open in your preferred text editor by using duti. I use vscode so these are the commands.

```
duti -s com.microsoft.VSCode public.json all
duti -s com.microsoft.VSCode public.plain-text all
duti -s com.microsoft.VSCode public.python-script all
duti -s com.microsoft.VSCode public.shell-script all
duti -s com.microsoft.VSCode public.source-code all
duti -s com.microsoft.VSCode public.text all
duti -s com.microsoft.VSCode public.unix-executable all
duti -s com.microsoft.VSCode .c all
duti -s com.microsoft.VSCode .cpp all
duti -s com.microsoft.VSCode .cs all
duti -s com.microsoft.VSCode .css all
duti -s com.microsoft.VSCode .go all
duti -s com.microsoft.VSCode .java all
duti -s com.microsoft.VSCode .js all
duti -s com.microsoft.VSCode .sass all
duti -s com.microsoft.VSCode .scss all
duti -s com.microsoft.VSCode .less all
duti -s com.microsoft.VSCode .vue all
duti -s com.microsoft.VSCode .cfg all
duti -s com.microsoft.VSCode .json all
duti -s com.microsoft.VSCode .jsx all
duti -s com.microsoft.VSCode .log all
duti -s com.microsoft.VSCode .lua all
duti -s com.microsoft.VSCode .md all
duti -s com.microsoft.VSCode .php all
duti -s com.microsoft.VSCode .pl all
duti -s com.microsoft.VSCode .py all
duti -s com.microsoft.VSCode .rb all
duti -s com.microsoft.VSCode .ts all
duti -s com.microsoft.VSCode .tsx all
duti -s com.microsoft.VSCode .txt all
duti -s com.microsoft.VSCode .conf all
duti -s com.microsoft.VSCode .yaml all
duti -s com.microsoft.VSCode .yml all
duti -s com.microsoft.VSCode .toml all
```

## Nerd fonts (Hack)

To use most of these modern terminal tools you’ll need a font that has been patched with icons. These are often called “Powerline” fonts. [Nerd Fonts](https://www.nerdfonts.com/) have a nice alternative collection of fonts that are property patched with icons.

I found some issues with the backtick character when using “Inconsolata” Nerd Font so I changed over to the “Hack” font now.

To install Hack font on mac use homebrew. You’ll have to tap a new repo to get the nerd fonts.

```
brew tap homebrew/cask-fonts
brew update
brew install --cask font-hack-nerd-font
```

On Windows WSL use apt-get to install nerd fonts.

```
sudo apt install -y fonts-hack-ttf
```

## Configure git defaults

Git has many configuration options where the defaults are not ideal. For example by default git pushes all changes on all branches to the remote.

This isn’t the way most developers work. We usually work on one branch at a time and only want to push that branch.

You can change what happens with a `git push` by setting

```
git config --global push.default current
```

Another recommended change is on the default pull behaviour. If you do trunk based dev with short-lived feature branches you shouldn’t have merges on your branches if you always pull first.

You might want to fast forward only and avoid git “auto” merges. Auto merges are usually due to operator error. Rebasing on pull has a similar effect where you might change the history unexpectedly.

Instead force fast forward only. Git will error if it cannot fast forward.

```
git config --global pull.ff only
```

You can override fast forward only when you need to with `git pull --no-ff`.

I use beyond compare for visual diffs so I configure that in my git config.

```
git config --global diff.tool bc3
git config --global difftool.bc3.trustExitCode true
git config --global merge.tool bc3
git config --global mergetool.bc3.trustExitCode true
```

It’s difficult to remember the log syntax so set some log aliases for yourself

```
git config --global alias.dlast 'diff HEAD^'
git config --global alias.l "log --graph -n 20 --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(green)- %an, %cr%Creset'"
git config --global alias.ll "log --stat --abbrev-commit"
git config --global alias.ln "log --graph -n 20 --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(green)- %an, %cr%Creset' --name-status"
git config --global alias.lp "log --oneline -n 20 -p"
git config --global alias.ls "log --stat --abbrev-commit -n 1" # display previous log
```

## Extra git aliases

There are some powerful git aliases available in a single package from `unixorn` github.

You can install these with antigen by adding the following bundle to your antigen configuration.

```
antigen bundle unixorn/git-extra-commands@main
```

Now you have access to handy aliases.

If you accidentally commit a couple of times to the wrong branch you can use `git-move-commits 2 feat/myFeatureBranch` to move them to the correct branch.

You can `git-checkout-pr 586` to check out a pull request by id from GitHub.

`git-what-the-hell-just-happened` will show you the result of your last command.

[![output of git-wthjh showing last command](https://www.darraghoriordan.com/static/2dfad0cdeca9e4ae0943176b9bf5aa2e/09e48/git-wthjh.png "output of git-wthjh showing last command")](/static/2dfad0cdeca9e4ae0943176b9bf5aa2e/09e48/git-wthjh.png)
_output of git-wthjh showing last command_

`git-churn` will show you which files change often in your repository. This is useful to identify merge contention hotspots. You might want to split these files up.

`git-incoming` will show you what you’re going to pull down. `git-outgoing` will show you what you’re going to push.

`git-thanks` will show you who has contributed to your repo.

`git-wtf` will show you the current state of your local branch.

[![output of git-wtf showing current state of files](https://www.darraghoriordan.com/static/da10a75dae1228cbaec4c3ee547dca7b/c1c45/git-wtf.png "output of git-wtf showing current state of files")](/static/da10a75dae1228cbaec4c3ee547dca7b/c1c45/git-wtf.png)
_output of git-wtf showing current state of files_

Because you installed fzf you can add some nice aliases to use fzf to search through your git repository.

```
gcoc() {
  local commits commit
  commits=$(git log --pretty=oneline --abbrev-commit --reverse) &&
  commit=$(echo "$commits" | fzf --tac +s +m -e) &&
  git checkout $(echo "$commit" | sed "s/ .*//")
}

gcob() {
  local tags branches target
  tags=$(
    git tag | awk '{print "\x1b[31;1mtag\x1b[m\t" $1}') || return
  branches=$(
    git branch --all | grep -v HEAD |
    sed "s/.* //" | sed "s#remotes/[^/]*/##" |
    sort -u | awk '{print "\x1b[34;1mbranch\x1b[m\t" $1}') || return
  target=$(
    (echo "$tags"; echo "$branches") |
    fzf-tmux -l30 -- --no-hscroll --ansi +m -d "\t" -n 2) || return
  git checkout $(echo "$target" | awk '{print $2}')
}
```

## Homeshick for dot files

Homeshick is a dot files manager using git as a shared store. It’s a great way to manage the dot files that live in your home directory.

You create a github repository with a `home` folder. You can then clone that repository with homeshick and it symlinks the files to your home folder. It asks before overwriting files.

This is my homeshick repo for example

[![Homeshick file list as example](https://www.darraghoriordan.com/static/b93c4cee074c35da62d239e28ddf5121/e3b18/homeshick-repo.png "Homeshick file list as example")](/static/b93c4cee074c35da62d239e28ddf5121/e3b18/homeshick-repo.png)
_Homeshick file list as example_

Now if I make a change to a file in the `home` folder I can push it to the repository and it will be updated in the shared store (git).

I can then do a simple `homeshick refresh` to update the files in my home folder on all other Mac or Windows machines and everything is synchronized. It’s very powerful.

Detailed instructions for homeshick can be found on the [homeshick github page](https://github.com/andsens/homeshick).

## Mac defaults

There are lots of “hidden” mac settings that you can change using `defaults write` and `defaults read`. It’s like the Windows registry but on MacOS.

There are awesome lists of these settings available on github, here are some that are useful for developers.

```
# Use plain text mode for new TextEdit documents
defaults write com.apple.TextEdit RichText -int 0

# Enable full keyboard access for all controls
# (e.g. enable Tab in modal dialogs)
defaults write NSGlobalDomain AppleKeyboardUIMode -int 3

# Use scroll gesture with the Ctrl (^) modifier key to zoom (this makes mac work like Windows for this :) )
defaults write com.apple.universalaccess closeViewScrollWheelToggle -bool true
defaults write com.apple.universalaccess HIDScrollZoomModifierMask -int 262144

# Disable smart quotes and smart dashes - annoying when coding imho
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false

# Disable auto-correct
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false

# Use list view in all Finder Windows by default
# Four-letter codes for the other view modes: `icnv`, `clmv`, `Flwv`
defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"

# Finder: show all filename extensions
defaults write NSGlobalDomain AppleShowAllExtensions -bool true

# Save to disk (not to iCloud) by default
defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false

# Display full POSIX path as Finder window title
defaults write com.apple.finder _FXShowPosixPathInTitle -bool true

```

## Unix tool aliases

You can add these small aliases for the built in unix tools to make them report what they just did. I like getting this verification.

```
alias mv="mv -v"
alias cp="cp -v"
alias rm="rm -v"
# ...etc
```

Alias sudo so that it passes your current environment into the elevated shell.

```
alias sudo="sudo -E"
```

## Configuring vscode

Tell vscode that you want to use the iTerm terminal on MacOS and use our Nerd Font on both.

Note that on Windows the font “Hack” and on MacOS the font is “Hack Nerd Font”.

```
{
  "terminal.explorerKind": "external",
  "terminal.external.osxExec": "iTerm.app",
  "terminal.integrated.fontSize": 14,
  "terminal.integrated.fontFamily": "Hack Nerd Font",
  "terminal.integrated.profiles.osx": {
    "zsh": {
      "path": "/bin/zsh",
      "args": ["-l"]
    }
  }
}
```

## Install zsh (Windows WSL)

In Windows WSL zsh is not the default shell like on MacOS so you need to install it.

To install zsh grab it from apt and then run the following command to set it as your default shell.

```
sudo apt install zsh && chsh -s $(which zsh)
```

## Open current folder in Explorer (Windows WSL)

You can use the following alias to open the current folder in Explorer from Windows WSL.

```
alias open="explorer.exe $1"
```

This mimics the mac finder open command.

## Automate ssh agent for ssl passwords (Windows WSL)

There is no keychain on WSL so you have to enter your password every time you ssh into a server.

You can limit this to entering the password just once on WSL by using ssh-agent.

```
SSH_ENV="$HOME/.ssh/agent-environment"

function start_agent {
    /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
}

if [-f "${SSH_ENV}"]; then
    . "${SSH_ENV}" > /dev/null
    #ps ${SSH_AGENT_PID} doesn't work under cywgin
    ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
        start_agent;
    }
else
    start_agent;
fi
```

## Detect MacOS or Windows in zshrc

In my custom scripts I have to detect the OS a few times. I thought it would be useful to show how I do that.

```
# detect the machine we're running on
# assume linux is wsl on Windows (although any Ubuntu should be ok)
unameOut="$(uname -s)"
case "${unameOut}" in
    Linux*) machine=Linux;;
    Darwin*) machine=Mac;;
    CYGWIN*) machine=Cygwin;;
    MINGW*) machine=MinGw;;
    *) machine="UNKNOWN:${unameOut}"
esac
```

## Summary

That's all the steps I perform on a new machine to have it work for my development workflow.

I hope some these tools and configuration suggestions help you get more out of your terminal on Windows and Mac!

Hit me up [on twitter](https://twitter.com/darraghor) if you have any questions.

## Save 30+ hours with my scripts

It took me around 30 hours to configure all of this.

If you want to save the time of setting all of this up manually you can get all the scripts I use to setup everything on a new Mac or Windows machine from [https://darraghoriordan.gumroad.com/l/devshell](https://darraghoriordan.gumroad.com/l/devshell).

You’ll get

- 14 well tested, re-runnable, shell scripts that install everything you need from scratch.
- Dot files with all of the aliases and configuration I use pre-configured.
- Run on Mac or Windows WSL Ubuntu.
- In the correct structure for immediate consumption by homeshick.
- Full source - you can place these in a git repo and edit to suit your needs.
- Lifetime access - I keep the scripts updated and you can get the latest version
- My developer vscode configuration which has many improvements but in particular it sets the built in terminal and fonts correctly.
- All of my aliases and functions.
- A developer focused git configuration.

[https://darraghoriordan.gumroad.com/l/devshell](https://darraghoriordan.gumroad.com/l/devshell) - AUD $ 29