if type brew &>/dev/null; then FPATH=$(brew --prefix)/share/zsh-completions:$FPATH autoload -Uz compinit compinit fi #compdef gt ###-begin-gt-completions-### # # yargs command completion script # # Installation: gt completion >> ~/.zshrc # or gt completion >> ~/.zprofile on OSX. # _gt_yargs_completions() { local reply local si=$IFS IFS=$' ' reply=($(COMP_CWORD="$((CURRENT-1))" COMP_LINE="$BUFFER" COMP_POINT="$CURSOR" gt --get-yargs-completions "${words[@]}")) IFS=$si _describe 'values' reply } compdef _gt_yargs_completions gt ###-end-gt-completions-### # gh completions fpath=($HOME/.zsh/completions $fpath) autoload -Uz compinit compinit # Determine defaultBranch once per repo, store it if not set get_default_branch() { local branch branch=$(git config --get bakert.defaultBranch 2>/dev/null) if [[ -z "$branch" ]]; then branch=$(git remote show origin 2>/dev/null | awk '/HEAD branch/ {print $NF}') branch=${branch:-master} git config --local bakert.defaultBranch "$branch" echo "Set bakert.defaultBranch to '$branch' in local git config" >&2 fi echo "$branch" } # Perform an operation that might fail if the current branch is implicated in a way that won't fail # Leaves you on default branch after if your current branch ceased to exist. with_default_branch() { local current_branch=$(git rev-parse --abbrev-ref HEAD) local default_branch=$(get_default_branch) if [[ "$current_branch" != "$default_branch" ]]; then git switch "$default_branch" fi "$@" if [[ "$current_branch" != "$default_branch" ]] && git show-ref --verify --quiet "refs/heads/$current_branch"; then git switch "$current_branch" fi } ## Functions not aliases to allow completions ga() { git add "$@"; }; compdef _git ga=git-add gaa() { git add . "$@"; }; compdef _git gaa=git-add # Equivlent to `git add !$` gal() { emulate -L zsh setopt noglob local cmd last cmd=$(fc -ln -1) || return 1 local -a words words=(${(z)cmd}) (( ${#words} )) || { echo "No history."; return 1; } last=${words[-1]} last=${(Q)last} # remove surrounding quotes if any # Expand ~ / ~user without enabling globbing if [[ $last == "~"* ]]; then last=${~last} fi [[ -n $last ]] || { echo "No last arg."; return 1; } git add -- "$last" }; compdef _git gal=git-add gap() { git add -p "$@"; }; compdef _git gap=git-add gb() { git branch "$@"; }; compdef _git gb=git-branch gbd() { with_default_branch git branch -D "$@"; }; compdef _git gbd=git-branch gbl() { git blame "$@"; }; compdef _git gbl=git-blame gc() { git commit "$@"; }; compdef _git gc=git-commit gca() { git commit --amend "$@"; }; compdef _git gca=git-commit gcae() { git commit --amend --no-edit "$@"; }; compdef _git gcae=git-commit gcan() { git commit --amend -n "$@"; }; compdef _git gcan=git-commit gcane() { git commit --amend -n --no-edit "$@"; }; compdef _git gcane=git-commit gclb() { gpru && gded }; compdef _git gclb=git-branch gclfd() { git clean -fd "$@" }; compdef _git gclfd=git-clean gcp() { git cherry-pick "$@" }; compdef _git gcp=git-cherry-pick gcpa() { git cherry-pick --abort "$@" }; compdef _git gcpa=git-cherry-pick gcpc() { git cherry-pick --continue "$@" }; compdef _git gcpa=git-cherry-pick glc() { git clone "$@"; }; compdef _git glc=git-clone gcm() { git commit -m "$@"; }; compdef _git gcm=git-commit gcn() { git commit -n "$@"; }; compdef _git gcn=git-commit gco() { git checkout "$@"; }; compdef _git gco=git-checkout gd() { git diff "$@"; }; compdef _git gd=git-diff gdc() { git diff --cached "$@"; }; compdef _git gdc=git-diff gdd() { git diff $(get_default_branch) "$@"; }; compdef _git gdd=git-diff # Delete all local branches that don't have changes not already in default branch gded() { local default_branch=$(get_default_branch) for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/); do if [[ "$branch" != "$default_branch" ]]; then local count=$(git rev-list --count "$branch" --not "$default_branch") if [[ "$count" -eq 0 ]]; then echo "Deleting branch: $branch" git branch -D "$branch" fi fi done } gfo() { git fetch origin $(get_default_branch):$(get_default_branch) "$@"; }; compdef _git gfo=git-fetch # Make a gist, guessing exactly what you want a gist of based on state of repo gg() { local target=$1 local desc="" local filename="" local url="" if [[ -z $target ]]; then if [[ -n $(git status --porcelain) ]]; then desc="Working copy diff" filename="working.diff" url=$((git diff HEAD && git ls-files --others --exclude-standard | xargs -I {} git diff /dev/null {}) | gh gist create -f "$filename" -d "$desc" - | tail -n1) else desc="Top commit diff (HEAD)" filename="head.diff" url=$(git show HEAD | gh gist create -f "$filename" -d "$desc" - | tail -n1) fi elif [[ $target == "develop" ]]; then desc="Diff from develop" filename="develop.diff" url=$(git diff develop...HEAD | gh gist create -f "$filename" -d "$desc" - | tail -n1) else desc="Diff of $target" filename="$target.diff" url=$(git diff "$target...HEAD" | gh gist create -f "$filename" -d "$desc" - | tail -n1) fi echo "$url" open "$url" }; compdef _git gg=git-show # Make a gist of the difference between working copy and default branch ggd() { gg "$(get_default_branch)"; }; compdef _git ggd=git-show gl() { git log "$@"; }; compdef _git gl=git-log # Pretty one-liner log glp() { local git_args=() if [[ $1 =~ ^-[0-9]+$ ]] || [[ $1 =~ ^--max-count=[0-9]+$ ]] || [[ $1 =~ ^-n$ && $2 =~ ^[0-9]+$ ]]; then git_args=("$@") else git_args=("$@") fi git log --pretty="tformat:$FORMAT" "${git_args[@]}" | column -t -s '{' | less -XRS --quit-if-one-screen }; compdef _git glp=git-log gm() { git mv "$@"; }; compdef _git gm=git-mv gp() { git pull "$@"; }; compdef _git gp=git-pull gpf() { git push --force-with-lease "$@"; }; compdef _git gpf=git-push gpr() { gh pr create "$@"; }; compdef _gh gpr=gh-pr gprb() { gh pr create -B "$@"; }; compdef _gh gprb=gh-pr gprd() { gh pr create -d "$@"; }; compdef _gh gprd=gh-pr gprdb() { gh pr create -d -B "$@"; }; compdef _gh gprdb=gh-pr # Remove local branches that aren't on remote any more gpru() { cleanup_gone_branches() { git remote update origin --prune local gone_branches=$(git branch -vvv | grep gone | cut -d' ' -f3) if [[ -n "$gone_branches" ]]; then echo "$gone_branches" | xargs -I{} git branch -D '{}' fi } with_default_branch cleanup_gone_branches } gpso() { git push --set-upstream origin "${@:-$(git branch --show-current)}"; }; compdef _git gpso=git-push grb() { git rebase "$@"; }; compdef _git grb=git-rebase grba() { git rebase --abort "$@"; }; compdef _git grba=git-rebase grbc() { git rebase --continue "$@"; }; compdef _git grbc=git-rebase grbd() { git rebase $(get_default_branch) "$@"; }; compdef _git grbd=git-rebase grbdo() { gfo && git rebase $(get_default_branch) "$@"; }; compdef _git grbd=git-rebase grbi() { git rebase -i $(get_default_branch) "$@"; }; compdef _git grbi=git-rebase grl() { git reflog "$@"; }; compdef _git grl=git-reflog grs() { git reset "$@"; }; compdef _git grs=git-reset grsh1() { git reset HEAD~1 "$@"; }; compdef _git grsh1=git-reset grsh2() { git reset HEAD~2 "$@"; }; compdef _git grsh2=git-reset grsh3() { git reset HEAD~3 "$@"; }; compdef _git grsh3=git-reset grsh4() { git reset HEAD~4 "$@"; }; compdef _git grsh4=git-reset grsh5() { git reset HEAD~5 "$@"; }; compdef _git grsh5=git-reset grsh6() { git reset HEAD~6 "$@"; }; compdef _git grsh6=git-reset grsh7() { git reset HEAD~7 "$@"; }; compdef _git grsh7=git-reset grsh8() { git reset HEAD~8 "$@"; }; compdef _git grsh8=git-reset grsh9() { git reset HEAD~8 "$@"; }; compdef _git grsh9=git-reset grt() { git restore "$@"; }; compdef _git grt=git-restore grta() { git restore . "$@"; }; compdef _git grt=git-restore grts() { git restore --staged "$@"; }; compdef _git grt=git-restore grtsa() { git restore --staged . "$@"; }; compdef _git grt=git-restore grm() { git rm "$@"; }; compdef _git grm=git-rm gs() { git status "$@"; }; compdef _git gs=git-status gsh() { git show "$@"; }; compdef _git gsh=git-show gshn() { git show --name-only "$@"; }; compdef _git gsh=git-show gst() { git stash "$@"; }; compdef _git gst=git-stash gstd() { git stash drop "$@"; }; compdef _git gstd=git-stash gstl() { git stash list "$@"; }; compdef _git gstl=git-stash gstp() { git stash pop "$@"; }; compdef _git gstp=git-stash gsts() { git stash show -p "$@"; }; compdef _git gsts=git-stash gstu() { git stash -u "$@"; }; compdef _git gstu=git-stash gsw() { git switch "$@"; }; compdef _git gsw=git-switch gswc() { git switch -c "$@"; }; compdef _git gswc=git-switch gswcd() { git switch -c "$1" $(get_default_branch); }; compdef _git gswcd=git-switch gswd() { git switch $(get_default_branch); }; compdef _git gswd=git-switch gswp() { git switch - "$@"; }; compdef _git gswd=git-switch gtc() { gt create "$@"; } gtl() { gt log "$@"; } gtm() { gt move "$@"; } gtr() { gt restack "$@"; } gts() { gt submit "$@"; } gtsy() { gt sync "$@"; } gtt() { gt track "$@"; } alias gwip='git add . && git commit -m "WIP" -n'
Sort committers by average length of commit message
git log --no-merges --pretty=format:'COMMIT_START|%an|%B|COMMIT_END' | \ awk ' BEGIN { RS = "COMMIT_END\n"; FS = "|" } /COMMIT_START/ { author = $2 message = "" for (i = 3; i <= NF; i++) { if (i > 3) message = message "|" message = message $i } len = length(message) authors[author] += len counts[author]++ if (!min[author] || len < min[author]) min[author] = len if (len > max[author]) max[author] = len } END { for (author in authors) { avg = authors[author] / counts[author] printf "%6.1f|%-30s|(min: %d, max: %d, commits: %d)\n", avg, author, min[author], max[author], counts[author] } }' | sort -t'|' -k1 -nr | awk -F'|' '{printf "%-30s %s chars %s\n", $2, $1, $3}'
Gradient Borders with Transparent Background

<html lang="en">
<head>
<title>Gradient borders with transparent background</title>
<meta charset="utf-8">
<style>
* {
box-sizing: border-box;
}
body {
background-color: black;
color: white;
}
.card {
background-color: gray;
color: black;
}
.gradient-border-mask {
display: flow-root;
position: relative;
padding: 1.3rem;
}
.gradient-border-mask::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 5px;
border: 5px solid transparent;
background: linear-gradient(45deg, purple, orange) border-box;
-webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: destination-out;
mask-composite: exclude;
}
</style>
</head>
<body>
<div class="gradient-border-mask">
<p>Lorem ipsum dolor sit amet consectetur</p>
</div>
<div class="card">
<p>Lorem ipsum dolor sit amet consectetur</p>
<div class="gradient-border-mask">
<p>Lorem ipsum dolor sit amet consectetur</p>
</div>
</div>
</body>
</html>
How to keep your input and dismiss/cancel atuin
The normal behavior of atuin is to put either the command you matched onto your commandline, or nothing. So if you Ctrl-r and type something with no good match and exit, you “lose” what you have typed. You can Ctrl-g to get back what you had when you pressed Ctrl-r but anything you typed after that is lost.
To get what I think is superior behavior set exit_mode = "return_query"
in ~/.config/atuin/config.toml
. Now whatever is in the atuin buffer is now on your commandline if you hit Esc. You can still Ctrl-g to get what you had before Ctrl-r or Ctrl-c to exit to an empty commandline.
Starting more than one dev webserver each in its own terminal window (Mac)
#!/usr/bin/env zsh # Script to start monorepo development processes in separate terminals open_position_run() { local dir=$1 local cmd=$2 # Start the server osascript -e 'tell application "Terminal" do script "cd '"$dir"' && nvm use 20 && '"$cmd"' &" in window 1 end tell' } open_position_run "/Users/bakert/monorepo/apps/app1 "pnpm dev" open_position_run "/Users/bakert/monorepo/apps/app2 "pnpm dev"
History (Fourth Time)
I did this in 2008, 2011 and 2015 but forgot to do it for ten years.
[zarniwoop ~] history 0 | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head 34675 git 5294 composer 4376 cd 3761 vi 3076 pnpm 2914 python 2188 m 1917 ls 1822 python3 1717 ssh
Compared to 2015. New: composer, pnpm, python/python3, m (run scripts for an app I work on). Climbers: git, cd. Fallers: ssh, ls. Old: c, php, pass, sudo, ruby.
COUNT(*) OVER () in Drizzle
In general I like to use COUNT(*) OVER ()
to get the total count for a query when retrieving a slice with OFFSET and LIMIT (very useful for pagination) rather than issuing a separate query for the total count. This is not super well supported in Drizzle but you can do it like this:
const data = await db.query.tableName.findMany({ … extras: { // Weird cast here because COUNT(*) is a bigint which is handled as a string in js // https://orm.drizzle.team/docs/guides/count-rows total: sql<number>`CAST(COUNT(*) OVER() AS INTEGER)`.as("total"), }, …
Set Up a New Mac (May 2025 Edition)
Previously: July 2019, July 2022, August 2023
- Upgrade to latest MacOS
- Restore from Blackblaze backup: u directory, dotfiles, .atuin dir, .config dir, .cursor dir, .nvm-zsh dir, .ssh dir, .vim dir, any other dot dirs that look useful, ~/Library/Application Support/Alfred
- Set perms on .ssh
$ cd ~ && chmod 600 ~/.ssh/* && chmod 700 ~/.ssh && chmod 644 ~/.ssh/*.pub
- Set perms on ~/u/bin
$ chmod u+x ~/u/bin/*
- Hide Desktop icons
$ defaults write com.apple.finder CreateDesktop false $ killall Finder
- Show hidden files in Finder with Cmd-Shift-.
- 1Password
- Dock: remove everything, hiding on, magnification on
- Alfred (and give it Accessibility access, add license key)
- System Settings, Mouse, set Trackpad speed to max and enable right-click
- Sublime Text 4 (add license key, set
"trim_trailing_white_space_on_save": "all"
in sublime prefs, install Package Control, install Nord Theme via Package Control) - subl commandline sublime.
$ ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" ~/u/bin/subl
- sublime git-ignorer. (1) add Package Control repo https://github.com/apc999/sublime-text-gitignore (2)
install package sublime-text-gitignore (3) use menu item : File->Exclude Git-ignored (4) Give this a keyboard shortcut in Sublime, Preferences, Key Bindings with{ "keys": ["super+shift+i"], "command": "exclude_ignored" }
- Keyboard shortcut to toggle word wrap in Sublime Text. Preferences, Key Bindings
{ "keys": ["super+shift+w"], "command": "toggle_setting", "args": { "setting": "word_wrap" } }
- Install FiraCode and add it to Sublime Text prefs with
"font_face": "Fira Code"
. - Nord theme for Terminal and make default in preferences.
- Polar theme for terminal when ssh’ing to remotes
- For both Nord and Polar themes: “Use Option as Meta Key” in Terminal to make left Alt work as Esc. And Terminal, Settings, Advanced, un-check “Audible bell” and “Only when sound is muted”. And Shell, (When the shell exits) “Close the window”.
- System Preferences, Sound, turn “Alert volume” all the way down
- Use Ctrl-f7 to enable keyboard navigation of dialogs
- Homebrew. (Installs OSX commandline tools)
- Discord
- Change all .txt to open with Sublime Text
- Chrome. Sign in to Chrome to get extensions, then tell it you really do want uBlock Origin via “Keep for Now” under Extensions in Settings. Uninstall Chrome if they’ve finally locked it down entirely
- Firefox. Sign in to sync extensions. Set as default browser. Settings, search for “Autoplay”, Settings, Allow Audio and Video. Visit each extension you want in Private Browsing and select Run in Prviate Windows
- Skitch
- Backblaze. Choose to inherit the previous backup (it won’t copy anything down). Give System Settings, Privacy & Security, Full Disk Access
- Parallels Desktop + Windows + MTGO
- Disable Ask Siri in System Preferences, Siri
- Turn on “tap to click” in System Preferences, Trackpad
- Disable long-press (it’s annoying when selecting text in Chrome):
defaults write -g ApplePressAndHoldEnabled -bool false
- Spotify
- Slack
- Rectangle Pro
- DaisyDisk
- ChatGPT
- Claude
- Linear
- Zed
- Notion
brew install nvim
brew install mariadb
brew install npm
brew install pnpm@9
brew install apache2
.brew install php
. Enable in Apache with LoadModule, FilesMatch and DirectoryIndex directives as per homebrew output andbrew services restart apache2
.brew install gh
brew install composer
brew install bat
brew install atuin && atuin import auto
brew install delta
brew install vercel-cli
npm install -g rtm-cli
git clone
important repos (ff, pd, monorepo)- Restore any local databases for dev (ff, decksite, logsite)
ln -s ~/ff/src/www /opt/homebrew/var/www/ff
GRANT ALL ON ff.* TO ff@localhost IDENTIFIED BY *REDACTED*
- pd setup
- Check open but unsaved files in Sublime Text in case there’s anything you need to preserve
git status
in any recent repos and check for uncommitted work.
zsh “shortcuts”
$ cat ~/.config/zsh/nav.zsh ───────┬───────────────────────────────────────────────────────────────────── │ File: /Users/bakert/.config/zsh/nav.zsh ───────┼───────────────────────────────────────────────────────────────────── 1 │ export MONOREPO_ROOT="/Users/bakert/cardeio-monorepo-v2" 2 │ export ORGANIZED_PLAY="$MONOREPO_ROOT/apps/organized-play" 3 │ export PLAY_NEXT="$MONOREPO_ROOT/apps/play-next" 4 │ export LUDWIG="$MONOREPO_ROOT/apps/ludwig" 5 │ export CARD_SEARCH_DEMO="$MONOREPO_ROOT/apps/card-search-demo" 6 │ export DECK_BUILDER="$MONOREPO_ROOT/packages/deck-builder" 7 │ 8 │ hash -d mr="$MONOREPO_ROOT" 9 │ hash -d op="$ORGANIZED_PLAY" 10 │ hash -d pn="$PLAY_NEXT" 11 │ hash -d lw="$LUDWIG" 12 │ hash -d cs="$CARD_SEARCH_DEMO" 13 │ hash -d db="$DECK_BUILDER" ───────┴──────────────────────────────────────────────────────────────────────
Use prefixed with ~ anywhere you need a path:
$ cd ~mr $ vi ~lw/src/index.ts
Git – You’re Doing It Wrong
Instead of | Do this |
git checkout {file} | git restore {file} |
git checkout {branch} | git switch {branch} |
git checkout -b {newbranch} | git switch -c {newbranch} |
git push --force | git push --force-with-lease |
git rebase | git rebase --update-refs |