Table of Contents
Open Table of Contents
There are a few command-line tools I use so heavily that I’m genuinely not sure how I would be productive without them.
Well, duh. Where would we even be as software engineers without
That said, I like to set a lot of aliases in my
git bd: branch delete, searching for branches with
git c: checkout branch, searching for branches with
git cam: commit all with message
git camp: commit all with message and push
git ci: checkout interactively; pick-and-choose files to
git d: diff with better behavior (showing staged and unstaged changes)
git df: diff with another branch by finding with
git dfn: diff with another branch by finding with
fzf, showing name-only
git l: show the log with one-line format
git lf: show the log and find a commit with
git lfc: show the log, find a commit with
fzf, and copy to pasteboard
git m: merge branch, finding branches with
git p: push
git s: show status
git unstage: unstage the listed files
git oops: squash changes with the last commit, because I committed too early
fzf is up there with
git as one of the miracles of command-line productivity. You throw it lines of text - usually piped in from somewhere else - and it presents a fancy, and highly customizable, fuzzy-find interface. As you can see above, that’s extremely useful when writing little shell scripts.
However, what I use it for most often is actually its Ctrl-R / Ctrl-T functionality. By default, Ctrl-R replaces the shell’s built-in search, using
fzf to fuzzy-find previous commands, even from days or weeks ago. Ctrl-T, meanwhile, performs a recursive fuzzy-find of filenames in the current directory and subdirectories, which is perfect to quickly pull up files by name regardless of the exact path.
rg is my all-purpose, cross-repo search tool. Throw a regex at
rg and it’ll chew through files looking for it, even respecting
I end up using it instead of my IDE’s search tool almost always - it’s just much more effective at actually finding what I’m looking for, and even works in plaintext situations, like if I need to search an Obsidian vault.
One of these days I’ll get around to writing up why I adopted tmux, but suffice to say I found my ~week of investment in learning tmux worthwhile, not least because I can operate a terminal without lifting my hands from the keyboard at all. When I’m running a terminal these days, I’m almost always running tmux. Among the benefits it offers:
- tmux can split the window with a simple hotkey, regardless of where it’s being run.
- Since tmux works on a client-server model, the shell keeps running even if you close the window.
- There’s a lot of utility just in having a pretty large scrollback buffer that you can save and search.
I also use a few plugins:
tmux-continuum: Together, these plugins will automatically save the state of the tmux session and automatically restore it when you restart.
tmux-open: Just press “o” while a file or URL is highlighted in tmux to open it. That combines particulary well with the built-in regex searches; I have a few particular searches (e.g. for URLs) bound to various keys.
tmux-yank: This makes the copying behavior work a little better, notably while opening tmux via a VS Code terminal.
vim-tmux-navigator: This lets me use Ctrl-h/Ctrl-j/Ctrl-k/Ctrl-l to navigate around tmux splits and Neovim sessions.
These are command-line tools I’ve been using a lot later that I would find inconvenient to switch away from.
fish: I’m not convinced that fish, the “friendly interactive shell”, is radically better than, say, zsh with oh-my-zsh, but it does start up much faster, has nicer autocompletions by default, and has a much less confusing shell scripting language.
neovim: These days I use VS Code for most code editing - making Neovim work like an IDE is just too painful - but when I just need to quickly open and edit a file, I still fall back on it. I use a handful of plugins - notably
vim-tmux-navigatorto make it play nicer with tmux - but otherwise I try to keep its configuration pretty minimal.
delta: This little utility makes git diff output much prettier, with word-level highlighting, line numbers, and an optional side-by-side mode. It can even be used outside a git context as a replacement for
zoxide: This is one of a couple different tools that remembers which directories you’ve previously visited, so you can
cdto them without typing out the full path. For instance, I can just go
z dotand I’ll jump to
~/Developer/dotfiles. I actually have this aliased directly to
cd- going back to
cdwould be really annoying.
just: I used to write little Makefiles encapsulating various useful commands for a project. Unfortunately, thanks to its history as a build tool,
makehas many well-known rough edges, like the requirement for
justis a tool that basically provides Makefiles without the build system. That may not sound useful, and Hacker News types mock it every time it’s posted, but I still like to make one for almost every repo. A great example where it’s useful is with
hledger, a plain-text accounting system with a, uh, convoluted CLI - I can turn a command like
hledger is -D -p "from 7 days ago" -f 2023.journalinto
just daily, and it’s helpfully documented directly in the
tldr: These are similar tools for sharing command-line cheatsheets.
cheatallows you to manage your own cheatsheets, while I’ve found
tldr’s community-contributed cheatsheets to be high quality. I use both.
Modernized Unix Tools
I use a few standard Unix utilies that I’ve aliased to more modern versions.
cat): A few of the other tools like to send output through
cat, and every so often it’s useful to splat a file to the command line. In those instances I use
cat, because its output is a bit nicer and it automatically pipes to a pager like
lessif the output is too long.
lswith pretty colors and icons! Frankly I don’t have a strong reason to prefer this over bog-standard
ls, but the colors are nice.
sed): I often do search-and-replace through an IDE, but sometimes it’s nice to do it from the command line and just check
git difffor changes. Unfortunately
sedmakes absolutely no sense to me.
sdis a simple alternative with a better interface for the common case.
fdworks almost identically to
find, but it’s a bit faster and, like
.gitignorefiles by default. In particular, I have
fzf’s Ctrl-T hotkey set up to use
- HTTPie: This is a straightforward replacement for good ol’ curl or wget for making basic HTTP requests, but I prefer it to curl because the command-line interface makes a lot more sense.
du): Every so often I need to check why a directory is so big, and in those instances I turn to
dust, a modern replacement for
duwith prettier output.
I don’t use this often, but they’re helpful when I do need them.
gh: Did you know GitHub has a fully-featured CLI that can access basically any GitHub API? That said, in practice, I rarely need many of the features
ghprovides, but it does do a couple cool things:
gh repo create --source .will create a new repo on GitHub from the current directory, assuming it’s a git repository. That’s especially useful if I create a new project locally and then decide I want to push it to GitHub.
gh pr view -wopens the PR for the current branch, if any, in the web browser.
tig:This is a pretty git viewer, but I mainly use it for
tig stash, which lets me interactively explore my git stash.
jq: I know a lot of folks love
jqfor working with JSON, but frankly I find it a pain to work with - its filter syntax is so idiosyncratic that I feel lost every time I pull it up. That said, when I do need to work with JSON,
jqis the obvious place to go; even just piping JSON output through
jqfor pretty printing is useful.
terminal-notifier: I don’t often need to trigger desktop push notifications from a shell script, but when I do,
terminal-notifieris the place to go.
watchexec: This is a cute little Rust tool that watches a file and reruns a command any time the watched file changes. I don’t realistically have a use for that, but if I ever do,
watchexecis where I’ll turn first.