Skip to content

10 Terminal Productivity Hacks That Save Me 2 Hours Daily

Stephan Birkeland 13 min read Updated Feb 21, 2026
10 Terminal Productivity Hacks That Save Me 2 Hours Daily

I used to type git checkout like it owed me money. Full command, every time, dozens of times a day, like some kind of terminal masochist. Then one afternoon I did the math on how many keystrokes I was wasting and nearly fell out of my chair. These 10 tricks have clawed back roughly two hours of my day, time I now spend on things that matter, like arguing about tabs vs. spaces.

1. Git Aliases That Actually Matter

Typing git checkout in full is the keyboard equivalent of taking the scenic route to work every single morning. Life’s too short.

Add these to your ~/.gitconfig (I go deeper on git aliases and commit hygiene in my solo git workflow post):

Typing git checkout every single time is like saying “I would like to order one large pepperoni pizza with extra cheese please” instead of just “the usual.” Aliases are nicknames for long commands. git co instead of git checkout, git st instead of git status. I type these dozens of times a day, so saving a few letters each time adds up to not wanting to throw my keyboard out the window. More git stuff in my solo git workflow post.

[alias]
  co = checkout
  br = branch
  ci = commit
  st = status
  unstage = reset HEAD --
  last = log -1 HEAD
  visual = !gitk
  # The real time-savers
  wip = !git add -A && git commit -m "WIP"
  undo = reset --soft HEAD~1
  amend = commit --amend --no-edit
[alias]
  co = checkout       # "co" instead of "checkout". Four letters saved, sanity preserved.
  br = branch         # See your branches. Two letters. You're welcome.
  ci = commit         # Save your work. Shortcut for lazy typists (me).
  st = status         # "What did I break?" in two letters.
  unstage = reset HEAD --  # "Actually, don't save that file yet." The undo for staging.
  last = log -1 HEAD  # Show the last thing I saved. Mostly to check I didn't do something dumb.
  visual = !gitk      # Open a visual history. For when text isn't cutting it.
  # The real time-savers
  wip = !git add -A && git commit -m "WIP"  # Grab EVERYTHING and save it as "work in progress". The panic button.
  undo = reset --soft HEAD~1  # Oops. Undo that last save but keep the work. Daily use. Daily.
  amend = commit --amend --no-edit  # "Actually, I forgot a file." Tack it onto the last save.

2. Fuzzy Finding Everything

Before fzf (a command-line fuzzy finder that lets you search through files, history, and basically anything from your terminal), finding a file in a large project felt like rummaging through a garage with the lights off. After fzf, it’s like the garage reorganized itself and installed motion-sensor lighting.

Imagine you lost a toy in a room with 10,000 toys. You sort of remember it was red and had wheels. fzf lets you type “red wheels” and instantly shows you every match. Except instead of toys, it’s files and commands. Need to find a file? Type a few letters of the name. Need that command you ran last Tuesday? Type a keyword and fzf digs it out. Before fzf, finding things in my terminal felt like playing hide and seek in the dark. After fzf, somebody turned the lights on and the toys started waving at me.

# Install on macOS
brew install fzf

# Install key bindings
$(brew --prefix)/opt/fzf/install
# Download the toy finder
brew install fzf

# Set up the keyboard shortcuts so you can actually use it
$(brew --prefix)/opt/fzf/install

Ctrl+R gives you fuzzy history search, Ctrl+T finds files. Pair it with bat for previews and you’ll wonder how you ever lived without it:

# Add to ~/.zshrc
export FZF_DEFAULT_OPTS="--preview 'bat --color=always {}'"
# Add to ~/.zshrc
# This makes fzf show you a colorful preview of each file before you pick it.
# Like peeking inside a toy box before you grab one.
export FZF_DEFAULT_OPTS="--preview 'bat --color=always {}'"

3. Directory Jumping with Zoxide

I refuse to type cd ../../../some/nested/path anymore. I’ve done my time. Zoxide (a smarter cd replacement that learns your most-used directories) remembers where you’ve been and teleports you there with a couple of keystrokes:

brew install zoxide
echo 'eval "$(zoxide init zsh)"' >> ~/.zshrc

Now z project jumps to whatever directory you visit most containing “project”. It learns your habits, which is either convenient or unsettling depending on how you feel about your tools knowing you better than you know yourself.

Moving between folders in the terminal normally means typing loooong paths like cd ../../../some/nested/project. It’s like walking through 15 rooms to get to the kitchen every single time. Zoxide remembers every folder you visit and lets you teleport there. Type z project and you’re there. No path, no dots, no thinking. It’s like having a magic door that knows your favorite rooms. The more you use it, the smarter it gets. Slightly creepy, incredibly useful.

4. Modern CLI Replacements

The default Unix tools were written when bell-bottoms were fashionable. They work, but these drop-in replacements for standard commands are like upgrading from a horse-drawn cart to, well, a regular car. Nothing flashy, just faster and less likely to kick you.

OldNewWhy
lsezaIcons, git status, tree view
catbatSyntax highlighting, line numbers
findfdFaster, simpler syntax
grepripgrepBlazingly fast
topbtopBeautiful, interactive

Your terminal comes with commands from the 1970s. They work, but they’re like drawing with one of those stubby broken crayons from a restaurant. These replacements are the brand new 64-pack with the built-in sharpener. eza replaces ls and shows icons and colors. bat replaces cat and adds syntax highlighting (fancy colors for code). ripgrep replaces grep and finds stuff so fast it feels like cheating. Same jobs, way better crayons.

brew install eza bat fd ripgrep btop
# Get all five shiny new crayons in one go
brew install eza bat fd ripgrep btop

5. Shell History on Steroids

Your shell history is a personal archaeology site of every brilliant and terrible command you’ve ever run. Treat it with respect:

# Add to ~/.zshrc
HISTSIZE=50000
SAVEHIST=50000
setopt SHARE_HISTORY          # Share history between sessions
setopt HIST_IGNORE_ALL_DUPS   # Don't save duplicates
setopt HIST_REDUCE_BLANKS     # Remove blank lines

50,000 entries sounds excessive until the day you need to find that exact curl command you ran three months ago. Then it feels like foresight.

By default, your terminal has the memory of a goldfish. It forgets commands when you close the window and only remembers a handful. These settings give it elephant-level memory: 50,000 commands, shared across all your terminal windows, no duplicates. 50,000 sounds ridiculous until the day you need to find that exact weird command you ran three months ago and it’s right there waiting for you. Future-you will want to hug past-you for this one.

6. Tmux for Session Persistence

Closing a terminal tab and losing six carefully arranged panes is the developer equivalent of accidentally saving over your game file. Tmux (a terminal multiplexer that lets you manage persistent sessions with multiple panes and windows) fixes this. I use tmux so heavily that I built an entire remote workflow around it for running Claude Code from anywhere.

You know when you’re building something awesome with LEGOs and someone says “time for dinner” and you have to leave? Imagine if you could freeze the whole table exactly as it is, eat dinner, come back, and unfreeze it. That’s tmux. Close the terminal, go eat lunch, come back, reattach, and everything is exactly where you left it. Every LEGO brick, right where you put it. I liked it so much I built my entire remote workflow around it. It’s that good.

brew install tmux

# Create ~/.tmux.conf
set -g mouse on
set -g history-limit 50000
set -g base-index 1
setw -g pane-base-index 1

# Better prefix
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# Install the save-your-LEGOs tool
brew install tmux

# Create ~/.tmux.conf (the settings file)
set -g mouse on               # Let me click stuff. I know, a mouse, how primitive.
set -g history-limit 50000    # Remember 50,000 lines of output. Your terminal is now an elephant.
set -g base-index 1           # Start counting windows at 1, not 0. Because we're humans.
setw -g pane-base-index 1     # Same for panes. Humans don't start counting at zero. Fight me.

# Better prefix (the magic key combo to control tmux)
unbind C-b                    # The default shortcut is Ctrl+B, which is awkward.
set -g prefix C-a             # Ctrl+A is way easier to reach. Trust me on this.
bind C-a send-prefix          # If you actually need to send Ctrl+A, double-tap it.

7. Smart Completion

Tab completion without autosuggestions is like autocorrect that only fixes the words you already spelled right. zsh-autosuggestions (a plugin that suggests commands from your history as you type) gives you fish-style autosuggestions, and accepting them is just a right-arrow key away:

You know predictive text on your phone? This is that, but for your terminal. You start typing and it ghosts in a suggestion from your history in gray. Right arrow to accept, keep typing to ignore it. It’s like your terminal watched what you did yesterday and goes “hey, you’re about to type this again, right? Let me just fill it in for you.” After a week with this, going back to a terminal without it feels like writing with a crayon that’s been snapped in half. You can do it, but why would you?

# Install zsh completions
brew install zsh-completions zsh-autosuggestions

# Add to ~/.zshrc
source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh
# Get the mind-reading plugins
brew install zsh-completions zsh-autosuggestions

# Tell your terminal to actually use them (add to ~/.zshrc)
source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh

8. Quick Note Taking

My brain leaks ideas like a colander holds water. This tiny function lets me capture thoughts without leaving the terminal:

# Add to ~/.zshrc
note() {
  echo "$(date '+%Y-%m-%d %H:%M'): $*" >> ~/notes.md
}

# Usage: note Fix the login bug tomorrow

Not glamorous. Doesn’t sync to the cloud or have a subscription tier. Just works.

My brain leaks ideas like a bucket with holes in it. This tiny function lets me scribble a note without leaving the terminal. Type note fix the login bug tomorrow and it saves it with a timestamp to a file. That’s the whole thing. No fancy app, no subscription, no syncing. Four lines of code. A digital sticky note that I actually use, unlike the 47 note apps I’ve downloaded and abandoned.

9. Project-Specific Environments

Hardcoding environment variables in your shell profile is fine until you work on two projects with different database URLs and spend 20 minutes debugging why your app is talking to the wrong Postgres instance. Ask me how I know.

Direnv (a tool that automatically loads and unloads environment variables per project directory) handles this by swapping env vars when you cd in and out:

Apps need secret settings like passwords and special keys. The problem is when Project A needs one password and Project B needs a different one. Without direnv, you set them for your whole computer and pray you don’t accidentally connect the wrong project to the wrong database. (I have done this. It was not fun.) Direnv automatically loads the right settings when you walk into a project folder and hides them when you leave. Each project gets its own toy box with its own toys. No more accidentally putting the wrong toy in the wrong box.

brew install direnv
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
# Install the "right settings for the right project" tool
brew install direnv
# Tell your terminal to check for project settings every time you change folders
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc

Create a .envrc in any project directory:

export DATABASE_URL="postgres://localhost/myapp"
export API_KEY="dev-key-here"
# These are the secret settings for THIS project only.
# Direnv loads them when you enter the folder and hides them when you leave.
export DATABASE_URL="postgres://localhost/myapp"  # Where the database lives
export API_KEY="dev-key-here"                     # The secret key for the API

10. Custom Functions for Repetitive Tasks

If you type the same sequence of commands more than twice, you’re volunteering for unpaid labor. Wrap it in a function:

If you catch yourself typing the same three commands over and over, you’re doing free labor. Bundle them into one shortcut. Type one word, all three commands run. It’s like teaching your terminal a new trick: “when I say ‘mkproject’, build me a new LEGO base, put it on the table, and write my name on it.” My favorite is killport 3000, which boots whatever process is hogging a port. I use it approximately every day because Node processes apparently don’t believe in going home when the lights go off.

# Quick project scaffolding
mkproject() {
  mkdir -p "$1" && cd "$1" && git init
  echo "# $1" > README.md
  git add . && git commit -m "Initial commit"
}

# Kill process on port
killport() {
  lsof -ti:$1 | xargs kill -9
}

# Quick HTTP server
serve() {
  python3 -m http.server ${1:-8000}
}
# Build a new project from scratch. One word does five things.
mkproject() {
  mkdir -p "$1" && cd "$1" && git init  # Make a folder, go into it, set up git
  echo "# $1" > README.md               # Write a little title page
  git add . && git commit -m "Initial commit"  # Save everything as the first snapshot
}

# Kill whatever is hogging this port. No mercy, no trial.
killport() {
  lsof -ti:$1 | xargs kill -9  # Find the process on the port and end it immediately
}

# Start a tiny web server in the current folder. Great for testing.
serve() {
  python3 -m http.server ${1:-8000}  # Defaults to port 8000 if you don't pick one
}

killport 3000 alone has saved me from mass-producing orphaned Node processes that silently hog my ports.

The Compound Effect

None of these individually feel revolutionary. A few seconds here, a smoother workflow there. But stack 50+ uses a day over a year and you’ve reclaimed entire weeks. It’s like putting spare change in a jar, embarrassingly small per deposit, surprisingly heavy when you finally pick it up.

I’d start with fzf and zoxide. Those two changed my terminal life more than anything else. The rest you can layer on whenever something starts to feel tedious. If you want to see how all these tools fit into a full development environment, I walk through my complete setup in my developer workflow post.

None of these individually feel like a big deal. A few seconds saved here, a tiny bit less annoyance there. But you use the terminal hundreds of times a day. Those seconds add up. It’s like putting coins in a piggy bank. Feels pointless per coin, but crack it open a year later and suddenly you can buy a bike. Start with fzf and zoxide (hacks 2 and 3). Those two alone changed my terminal life more than everything else combined. Add the rest whenever something starts to annoy you. My full tool setup lives in my developer workflow post.


What terminal tricks have I been sleeping on? I’m always one alias away from peak laziness.

Share:
Stephan Birkeland

Stephan Birkeland

Consultant and developer based in Norway. Runs on coffee, curiosity, and a questionable number of side projects.

Keep reading

Phone controlling a terminal session on a remote computer
Up nextproductivity

Claude Code Remote Control Killed My Phone Workflow