Minimal dotfiles

Some of the companies I work at block GitHub (and many other sites). This page lays out some essential configs that I can quickly grab and copy-paste into a terminal to get a usable shell environment up and running. My full dotfiles are available here.

The two rules I tried to stick to:

~/.bashrc

# If not running interactively, don't do anything.
case $- in
  *i*) ;;
  *) return ;;
esac

##############################################################################
### history ###
##############################################################################
HISTCONTROL=ignoreboth
HISTSIZE=4000
HISTFILESIZE=8000
shopt -s histappend

##############################################################################
### misc ###
##############################################################################
# Resize LINES/COLUMNS after each command.
shopt -s checkwinsize
# Make autocompletion case-insensitive.
bind 'set completion-ignore-case on' 2>/dev/null
# Vi-style command-line editing.
set -o vi
# Do not exit shell with Ctrl-D.
set -o ignoreeof

##############################################################################
### exports ###
##############################################################################
# Editor: prefer vim, fall back to plain vi if vim is not installed.
if command -v vim >/dev/null 2>&1; then
  export EDITOR=vim
else
  export EDITOR=vi
fi
export VISUAL="$EDITOR"
export PAGER=less
export LESS='-R --mouse'

##############################################################################
### sources ###
##############################################################################
# Git completion, when available.
[ -f /usr/share/git/completion/git-completion.bash ] && . /usr/share/git/completion/git-completion.bash
[ -f /etc/bash_completion ] && . /etc/bash_completion

# Aliases.
[ -f ~/.bash_aliases ] && . ~/.bash_aliases

##############################################################################
### prompt ###
##############################################################################
# Minimal fallback prompt with git branch — overwritten by starship if installed later.
parse_git_branch() {
  git branch 2>/dev/null | sed -n 's/^\* \(.*\)/ (\1)/p'
}
PS1='\[\e[32m\]\u@\h\[\e[0m\] \[\e[34m\]\w\[\e[0m\]\[\e[33m\]$(parse_git_branch)\[\e[0m\] \$ '

~/.zshrc

# Editor: prefer vim, fall back to plain vi if vim is not installed.
if command -v vim >/dev/null 2>&1; then
  export EDITOR=vim
else
  export EDITOR=vi
fi
export VISUAL="$EDITOR"
export PAGER=less
export LESS='-R --mouse'

###############################################
### History ###
###############################################
HISTFILE="$HOME/.zsh_history"
HISTSIZE=50000
SAVEHIST=10000
setopt EXTENDED_HISTORY
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_VERIFY
setopt INC_APPEND_HISTORY
# Do not share history between shells.
unsetopt SHARE_HISTORY

###############################################
### Completion ###
###############################################
autoload -Uz compinit && compinit
zstyle ':completion:*' menu select
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'

# Tool-generated completions (guarded so the rc stays portable).
command -v kubectl >/dev/null && source <(kubectl completion zsh)
command -v helm    >/dev/null && source <(helm completion zsh)
command -v chezmoi >/dev/null && source <(chezmoi completion zsh)

###############################################
### Key bindings ###
###############################################
bindkey -v
# Do not exit shell with Ctrl-D.
setopt IGNORE_EOF

###############################################
### Aliases ###
###############################################
[ -f ~/.bash_aliases ] && source ~/.bash_aliases

###############################################
### Prompt — fallback if starship not installed ###
###############################################
autoload -Uz vcs_info
precmd() { vcs_info }
zstyle ':vcs_info:git:*' formats ' (%b)'
setopt PROMPT_SUBST
PROMPT='%F{green}%n@%m%f %F{blue}%~%f%F{yellow}${vcs_info_msg_0_}%f %# '

# Replace prompt with starship if it's available.
command -v starship >/dev/null && eval "$(starship init zsh)"

# Per-machine private overrides — never committed.
[ -f ~/.zshrc_private ] && source ~/.zshrc_private

~/.bash_aliases

# Sourced by both bash and zsh — keep it POSIX-friendly.

# --- ls ----------------------------------------------------------------------
if command -v lsd >/dev/null 2>&1; then
  alias ls='lsd'
else
  alias ls='ls --color=auto -F'
fi
alias l='ls -lF'
alias la='ls -hAlF'

# --- safety nets -------------------------------------------------------------
if command -v trash >/dev/null 2>&1; then
  alias rm='trash'
fi

# --- grep --------------------------------------------------------------------
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'

# --- editor ------------------------------------------------------------------
# Prefer nvim, then vim, then plain vi.
if command -v nvim >/dev/null 2>&1; then
  alias v='nvim'
  alias vi='nvim'
  alias vim='nvim'
elif command -v vim >/dev/null 2>&1; then
  alias v='vim'
else
  alias v='vi'
  alias vim='vi'
fi

# --- python ------------------------------------------------------------------
alias p='python3'
alias p3='python3'
alias ip3='ipython3'

# --- git ---------------------------------------------------------------------
# Most git shortcuts live in ~/.gitconfig (so `git st` works without aliases).
alias g='git'

# --- common tools (only aliased if installed) --------------------------------
command -v tmux      >/dev/null 2>&1 && alias t='tmux'
command -v kubectl   >/dev/null 2>&1 && alias k='kubectl'
command -v terraform >/dev/null 2>&1 && alias tf='terraform'
command -v yazi      >/dev/null 2>&1 && alias y='yazi'

# --- navigation --------------------------------------------------------------
alias cd..='cd ..'
alias cdd='cd ~/Desktop'
alias cdw='cd ~/workspace'

~/.gitconfig

[alias]
    st   = status
    hist = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
    a    = add -A :/
    ls   = log --oneline
    ca   = commit --amend
    cm   = commit -m
    cam  = commit -am
    co   = checkout
    cob  = checkout -b

[init]
    defaultBranch = main
[branch]
    sort = -committerdate
[tag]
    sort = version:refname

[core]
    editor       = vi
    excludesfile = ~/.gitignore_global
    autocrlf     = false

[color]
    ui = true
[column]
    ui = auto

[commit]
    verbose = true

[log]
    date         = iso
    decorate     = short
    graph        = true
    abbrevCommit = true
    pretty       = format:%C(auto)%h %C(auto)%ad | %C(auto)%s%d [%C(auto)%an]

[merge]
    tool          = vimdiff
    conflictstyle = zdiff3
[diff]
    tool           = vimdiff
    algorithm      = histogram
    colorMoved     = plain
    mnemonicPrefix = true
    renames        = true

[push]
    default = simple
[pull]
    ff = only
[rerere]
    enabled = true

[filter "lfs"]
    smudge   = git-lfs smudge -- %f
    process  = git-lfs filter-process
    required = true
    clean    = git-lfs clean -- %f

[protocol "file"]
    allow = always

~/.gitignore_global

# Editor / OS clutter that should never be committed anywhere.
*~
.*.swp
.*.swo
.~*
.\#*
.DS_Store

# Local-only env files.
.env
.venv

~/.inputrc

Readline config. Affects bash, psql, python REPL, gdb, and anything else that reads through GNU readline.

$include /etc/inputrc

# Case-insensitive Tab completion.
set completion-ignore-case on
set completion-map-case on

# Show all matches immediately, no second-Tab prompt.
set show-all-if-ambiguous on
set show-all-if-unmodified on

# Colorize completion listings and mark directories with /.
set colored-stats on
set visible-stats on
set mark-symlinked-directories on
set colored-completion-prefix on
set menu-complete-display-prefix on

# Up / Down arrow: search history matching what is already typed.
"\e[A": history-search-backward
"\e[B": history-search-forward

# Better word movement on the command line.
"\e[1;5C": forward-word    # Ctrl-Right
"\e[1;5D": backward-word   # Ctrl-Left

~/.tmux.conf

# Prefix: F12 (single keystroke) and Ctrl-Enter (chord).
set -g prefix F12
set -g prefix2 C-Enter
bind F12 send-prefix

# Required for tmux to receive Ctrl-Enter on modern terminals.
set -s extended-keys on
set -as terminal-features ',*:extkeys'

##### History, timing ##########################################################
set -g history-limit 100000
set -g display-time 5000
set -g escape-time 0          # instant key handling for Vim/TUI apps
set -g focus-events on

##### Indexing, naming #########################################################
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
set -g allow-rename off       # apps cannot rename windows

##### Mouse ####################################################################
set -g mouse on

##### Keys: vi everywhere ######################################################
set -g status-keys vi
setw -g mode-keys vi

# Splits keep the current path.
bind "|" split-window -h -c "#{pane_current_path}"
bind "-" split-window -v -c "#{pane_current_path}"

# Use Alt+n / Alt+p to switch windows.
bind -n M-n next-window
bind -n M-p previous-window

# Fast resizing with Alt+arrows.
bind -n M-h resize-pane -L 5
bind -n M-j resize-pane -D 5
bind -n M-k resize-pane -U 5
bind -n M-l resize-pane -R 5

##### Copy-mode yanks to system clipboard ######################################
# Falls back to xclip if wl-copy is missing; harmless if neither is installed.
bind -T copy-mode-vi y send -X copy-pipe-and-cancel \
  'sh -c "command -v wl-copy >/dev/null && wl-copy || xclip -i -sel clip"'

##### Reload ###################################################################
bind r source-file ~/.tmux.conf \; display "Reloaded."

##### Truecolor ################################################################
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",*:RGB"

~/.vimrc

set nocompatible
filetype plugin indent on
syntax enable

" Behaviour.
set encoding=utf-8
set hidden
set autoread
set backspace=indent,eol,start
set clipboard^=unnamed,unnamedplus
set mouse=n
set ttyfast
set lazyredraw
set history=500
set undolevels=500

" Display.
set number
set ruler
set showcmd
set cursorline
set cursorcolumn
set wildmenu
set wildmode=full
set laststatus=2
set scrolloff=10
set sidescrolloff=10
set sidescroll=1
set breakindent
set showbreak=\\\\\\\

" Search.
set ignorecase
set hlsearch
set incsearch

" Tabs / spaces — 4-space indent, expandtab.
set tabstop=4
set shiftwidth=4
set expandtab
set autoindent
set smartindent
set list listchars=tab:--

" Stop creating dotfile clutter in working directories.
set nobackup
set nowritebackup
set noswapfile
set undofile
set undodir=~/.vim/undo//
silent! call mkdir(expand('~/.vim/undo'), 'p')

" Performance: don't choke on extremely long lines.
set synmaxcol=300

" Quality-of-life mappings.
let mapleader = ' '
nnoremap ; :
" Unset 'last search pattern' register by hitting return.
nnoremap <CR> :noh<CR><CR>
" Reselect visual block after indent/outdent.
vnoremap < <gv
vnoremap > >gv
" Move by visual line, not by file line.
nnoremap j gj
nnoremap k gk
" System-clipboard copy/paste.
vmap <Leader>y "+y
nmap <Leader>p "+p
vmap <Leader>p "+p

" Highlight lines longer than 120 chars.
match ErrorMsg '\%>120v.\+'

" Better tmux integration when launched inside tmux.
if exists('$TMUX')
  set term=screen-256color
endif

" Auto-wrap at 80 chars for prose.
au BufRead,BufNewFile *.md  setlocal textwidth=80
au BufRead,BufNewFile *.tex setlocal textwidth=80

" A readable colorscheme that ships everywhere.
silent! colorscheme habamax