Skip to content

Instantly share code, notes, and snippets.

@wdhowe
Last active September 2, 2026 16:14
Show Gist options
  • Select an option

  • Save wdhowe/726bc72ce086ffeb041f08b4d5964eb6 to your computer and use it in GitHub Desktop.

Select an option

Save wdhowe/726bc72ce086ffeb041f08b4d5964eb6 to your computer and use it in GitHub Desktop.
bashrc/profile
##-- Aliases --##
alias ll='ls -l'
alias k='kubectl'
alias ke='kubectl exec -it'
alias kc='kubectx'
alias kn='kubens'
##-- Completions and Prompt --##
# bash-completion@2 (installed via brew install bash-completion@2)
[[ -r "/opt/homebrew/etc/profile.d/bash_completion.sh" ]] && . "/opt/homebrew/etc/profile.d/bash_completion.sh"
# task completion (go-task / taskfile)
command -v task &>/dev/null && eval "$(task --completion bash)"
# direnv load/unload environments automatically (installed via brew install direnv)
eval "$(direnv hook bash)"
# bash-git-prompt (installed via brew install bash-git-prompt)
if [ -f "/opt/homebrew/opt/bash-git-prompt/share/gitprompt.sh" ]; then
__GIT_PROMPT_DIR="/opt/homebrew/opt/bash-git-prompt/share"
source "/opt/homebrew/opt/bash-git-prompt/share/gitprompt.sh"
fi
##-- Utility Functions --##
function nth() {
# Print the nth line of stdin.
# Usage: <command> | nth <line-number>
sed -n "${1}p"
}
##-- Shared Helpers --##
function _confirm() {
# Ask before a step that could destroy work existing nowhere else. True when
# the answer is yes. Declines when there is no terminal to answer on.
# Usage: _confirm <prompt>
# Env: CONFIRM_ASSUME_YES=1 answer yes without asking
local prompt="$1"
local reply
if [ "${CONFIRM_ASSUME_YES:-}" = 1 ]; then
echo " ${prompt} y (CONFIRM_ASSUME_YES=1)"
return 0
fi
if [ ! -t 0 ]; then
return 1
fi
read -r -p " ${prompt} [y/N] " reply
case "$reply" in
[yY]*) return 0 ;;
*) return 1 ;;
esac
}
function _gh() {
# Run gh under its own keyring login.
# Usage: _gh <gh-arguments...>
(
# .envrc exports a PAT in some repositories, and it shadows that login.
unset GH_TOKEN GITHUB_TOKEN
command gh "$@"
)
}
function _gh-pr() {
# Print the newest pull request for a head branch as jq output. Empty when
# there is none, or when gh cannot answer.
# Usage: _gh-pr <branch> <state> <json-fields> <jq-expression>
_gh pr list --head "$1" --state "$2" --limit 1 --json "$3" --jq "$4" 2>/dev/null
}
##-- Git Functions --##
function _git-branch-exists() {
# True when a local branch of this name exists.
# Usage: _git-branch-exists <branch>
git show-ref --verify --quiet "refs/heads/$1"
}
function _git-primary-worktree() {
# Print the absolute path of the repository's primary worktree, or nothing
# outside a repository.
# `git worktree list` always prints the primary first, so a linked worktree
# can find its way home.
git worktree list --porcelain 2>/dev/null | sed -n '1s/^worktree //p'
}
function _git-linked-worktrees() {
# Print every worktree except the primary, in `git worktree list` form.
git worktree list | tail -n +2
}
function _git-integration-branch() {
# Print the branch that sweeps measure against: main, master, or HEAD when
# neither exists.
local branch
# Named explicitly rather than left as HEAD, so a sweep run from a
# topic-branch worktree does not widen to "merged into whatever is checked out".
for branch in main master; do
if _git-branch-exists "$branch"; then
echo "$branch"
return 0
fi
done
echo HEAD
}
function _git-require-clean-tree() {
# True when a worktree has no uncommitted changes, staged or unstaged. Warns
# when it does.
# Usage: _git-require-clean-tree [worktree-path] (default the current directory)
local dir="${1:-.}"
if ! git -C "$dir" diff --quiet 2>/dev/null ||
! git -C "$dir" diff --cached --quiet 2>/dev/null; then
echo "Warning: Uncommitted changes in ${dir}. Stash or commit them first."
return 1
fi
}
function _git-sync-main() {
# Fast-forward main in the primary worktree. Callers that need the path ask
# _git-primary-worktree.
local primary
# main can only be checked out in the primary worktree, so doing this by path
# is what lets a caller run from a linked worktree, where a plain
# `git checkout main` fails with "already used by worktree".
primary=$(_git-primary-worktree)
if [ -z "$primary" ]; then
echo "Error: Not in a git repository"
return 1
fi
_git-require-clean-tree "$primary" || return 1
git -C "$primary" checkout main && git -C "$primary" pull
}
##-- Git Worktree Release --##
function _git-scan-cwds() {
# Snapshot every process's current directory into _GIT_CWD_SCAN, once per
# sweep. Callers starting a sweep unset _GIT_CWD_SCAN first to force a refresh.
[ -n "${_GIT_CWD_SCAN+set}" ] && return 0
# `lsof -d cwd` reads the process table rather than walking any tree, so one
# pass costs a fraction of a second. One pass per branch would not.
if command -v lsof >/dev/null 2>&1; then
_GIT_CWD_SCAN=$(lsof -d cwd -Fn 2>/dev/null | sed -n 's|^n/|/|p')
else
_GIT_CWD_SCAN=""
fi
}
function _git-worktree-in-use() {
# True when a process sits in the worktree: another shell, an editor, an agent
# session, a dev server. Reads the snapshot _git-scan-cwds took.
# Usage: _git-worktree-in-use <worktree-path>
local worktree="$1"
[ -n "$_GIT_CWD_SCAN" ] || return 1
printf '%s\n' "$_GIT_CWD_SCAN" |
awk -v w="$worktree" '
index($0, w) == 1 &&
(length($0) == length(w) || substr($0, length(w) + 1, 1) == "/") { found = 1 }
END { exit !found }'
}
function _git-worktree-block-reason() {
# Print why a linked worktree must not be released, or nothing when it may be.
# Changes nothing.
# Usage: _git-worktree-block-reason <worktree-path>
local worktree="$1"
local here
# `pwd -P`, not $PWD: git records the physical path, and on macOS /tmp and
# /var are symlinks, so a logical cwd would never match and the caller would
# delete the directory it is standing in.
here=$(pwd -P 2>/dev/null)
if [ "$worktree" = "$(_git-primary-worktree)" ]; then
echo "checked out in the primary worktree"
return 0
fi
case "${here}/" in
"${worktree}"/*)
echo "you are standing in worktree ${worktree}"
return 0
;;
esac
if [ -n "$(git -C "$worktree" status --porcelain 2>/dev/null)" ]; then
echo "uncommitted work in worktree ${worktree}"
return 0
fi
if _git-worktree-in-use "$worktree"; then
echo "a running process is working in ${worktree}"
return 0
fi
}
function _git-worktree-ignored-ok() {
# True when a worktree's ignored files may be destroyed along with it. Lists
# them and asks first when it has any.
# Usage: _git-worktree-ignored-ok <worktree-path>
# Env: CONFIRM_ASSUME_YES=1 answer yes without asking
local worktree="$1"
local count
# `status --porcelain` hides ignored paths and `git worktree remove` deletes
# them without comment, so an untracked .env.dev or a populated .terraform
# would vanish silently. Regenerating node_modules is cheap, a secret is not.
count=$(git -C "$worktree" status --porcelain --ignored 2>/dev/null | grep -c '^!!')
[ "$count" -gt 0 ] || return 0
echo " Removing ${worktree} would also delete ${count} ignored path(s):"
git -C "$worktree" status --porcelain --ignored 2>/dev/null |
sed -n 's/^!! / /p' | head -5
if [ "$count" -gt 5 ]; then
echo " ... and $((count - 5)) more"
fi
_confirm "Delete worktree ${worktree} and those files?"
}
function _git-release-worktree() {
# Remove the worktree holding a branch, so the branch itself can be deleted.
# True when the branch had no worktree or its worktree was removed; prints the
# reason and returns false when the worktree must stay.
# Usage: _git-release-worktree <branch>
local branch="$1"
local worktree
local reason
worktree=$(git for-each-ref --format='%(worktreepath)' "refs/heads/${branch}")
[ -n "$worktree" ] || return 0
_git-scan-cwds
reason=$(_git-worktree-block-reason "$worktree")
if [ -n "$reason" ]; then
echo " Skipped ${branch}: ${reason}"
return 1
fi
if ! _git-worktree-ignored-ok "$worktree"; then
echo " Skipped ${branch}: kept worktree holding ignored files"
return 1
fi
if ! git worktree remove "$worktree"; then
echo " Skipped ${branch}: could not remove worktree ${worktree}"
return 1
fi
echo " Removed worktree ${worktree}"
}
##-- Git Branch Sweeps --##
function _git-branch-pr-state() {
# Print what GitHub says became of a branch, as "STATE|number". STATE is
# MERGED, CLOSED, OPEN, NONE when no pull request was ever opened, or UNKNOWN
# when gh cannot answer.
# Usage: _git-branch-pr-state <branch>
# Env: GIT_CLEAN_NO_GH=1 skip the lookup and report UNKNOWN
local answer
if [ "${GIT_CLEAN_NO_GH:-}" = 1 ] || ! command -v gh >/dev/null 2>&1; then
echo "UNKNOWN|"
return 0
fi
# Authoritative where `git cherry` is not: a squash-merge of a multi-commit
# branch rewrites every patch-id, so cherry calls a merged branch unmerged.
answer=$(_gh-pr "$1" all 'state,number' '"\(.[0].state // "NONE")|\(.[0].number // "")"')
echo "${answer:-UNKNOWN|}"
}
function _git-vet-forced-delete() {
# True when a branch whose upstream vanished is safe to force-delete. Asks
# first, and prints the reason and returns false, when it is not.
# Usage: _git-vet-forced-delete <branch>
# Env: CONFIRM_ASSUME_YES=1 answer yes without asking
local branch="$1"
local base
local pr
local state
local number
local unmerged
# A gone upstream normally means "PR merged, remote branch deleted", and the
# branch is then safe to discard even though ancestry cannot vouch for it
# after a squash-merge. Everything here checks that story holds.
pr=$(_git-branch-pr-state "$branch")
state=${pr%%|*}
number=${pr#*|}
case "$state" in
MERGED) return 0 ;;
OPEN)
echo " Skipped ${branch}: PR #${number} is open but its remote head is gone"
return 1
;;
esac
# CLOSED, no PR at all, or gh could not answer. Fall back to patch
# containment, which over-reports on squash-merges but never under-reports.
base=$(_git-integration-branch)
unmerged=$(git cherry "$base" "refs/heads/${branch}" | grep -c '^+')
[ "$unmerged" -gt 0 ] || return 0
echo " ${branch}: upstream gone, ${state} on GitHub, ${unmerged} commit(s) not in ${base}:"
git cherry -v "$base" "refs/heads/${branch}" | sed -n 's/^+ / /p' | head -5
if ! _confirm "Force-delete ${branch} anyway?"; then
echo " Skipped ${branch}: unmerged commits, upstream gone"
return 1
fi
}
function _git-remove-branch() {
# Delete one local branch, releasing its worktree first when it has one.
# Usage: _git-remove-branch <branch> [--force]
local branch="$1"
local force="$2"
# Every check runs before anything is destroyed, so a branch is never left
# behind with its worktree already gone. Only the forced path needs vetting:
# without --force the branch is an ancestor of the integration branch, so its
# commits are already there.
if [ "$force" = "--force" ]; then
_git-vet-forced-delete "$branch" || return 0
_git-release-worktree "$branch" || return 0
git branch --delete --force "$branch"
else
_git-release-worktree "$branch" || return 0
git branch --delete "$branch"
fi
}
function _git-branches-with-gone-upstream() {
# Print the local branches whose remote head has been deleted.
# Read from for-each-ref, not `git branch`: the latter marks a branch checked
# out in a worktree with a `+` and swaps the upstream column for the worktree
# path, so column-parsing it yields "+" as the branch name.
git for-each-ref --format='%(refname:short)%09%(upstream:track)' refs/heads |
awk -F'\t' '$2 == "[gone]" { print $1 }'
}
function _git-branches-merged-into() {
# Print the local branches already contained in <base>, main and master aside.
# Usage: _git-branches-merged-into <base>
# Matched with -x so a name like topic/domain-main is not mistaken for main.
git for-each-ref --merged "$1" --format='%(refname:short)' refs/heads |
grep -vx -e main -e master
}
function _git-sweep-branches() {
# Remove every branch in a newline-separated list, or report there were none.
# Usage: _git-sweep-branches <none-message> <branches> [--force]
local none="$1"
local branches="$2"
local force="$3"
local branch
if [ -z "$branches" ]; then
echo " ${none}"
return 0
fi
while IFS= read -r branch; do
[ -n "$branch" ] || continue
_git-remove-branch "$branch" "$force"
done <<<"$branches"
}
function _git-report-worktrees() {
# Print the linked worktrees that survived a sweep, so a skipped branch is
# easy to go and finish.
local linked
linked=$(_git-linked-worktrees)
if [ -n "$linked" ]; then
echo "Remaining worktrees:"
echo "$linked" | sed 's/^/ /'
fi
}
function git-rm-local-merged-branches() {
# Delete the local branches whose upstream is gone, then those already merged
# into the integration branch, releasing their worktrees first. Anything
# unsafe to touch is skipped with a printed reason.
# Env: CONFIRM_ASSUME_YES=1 answer every prompt yes
# GIT_CLEAN_NO_GH=1 skip the pull-request lookups
local base
# Force one fresh process-cwd snapshot for this sweep.
unset _GIT_CWD_SCAN
base=$(_git-integration-branch)
echo "Removing branches with deleted upstreams..."
_git-sweep-branches "No branches with deleted upstreams" \
"$(_git-branches-with-gone-upstream)" --force
echo "Removing branches merged into ${base} (exclude main,master)..."
_git-sweep-branches "No merged branches to remove" \
"$(_git-branches-merged-into "$base")"
}
function git-clean() {
# Fetch with pruning, then sweep the local branches and worktrees the remote
# no longer has.
# Env: CONFIRM_ASSUME_YES=1 answer every prompt yes
# GIT_CLEAN_NO_GH=1 skip the pull-request lookups
echo "Fetching latest changes and pruning deleted branches..."
git fetch --prune
git worktree prune
git-rm-local-merged-branches
_git-report-worktrees
}
##-- Git Workflow --##
function git-fresh-main() {
# Update main in the primary worktree, then sweep merged branches and their
# worktrees. Runs from a linked worktree too, and leaves you where you were.
# Env: CONFIRM_ASSUME_YES=1 answer every prompt yes
# GIT_CLEAN_NO_GH=1 skip the pull-request lookups
local primary
primary=$(_git-primary-worktree)
echo "Checking out a fresh main branch${primary:+ in ${primary}}..."
_git-sync-main && git-clean
}
function _git-allow-branch-write() {
# True when a destructive branch command may touch this branch. Refuses main
# and master.
# Usage: _git-allow-branch-write <branch> <what-would-happen>
local branch="$1"
local action="$2"
# The mk/rm names read as general-purpose tools, unlike the create-dev and
# delete-dev they replaced, so the shared branch needs an explicit refusal
# rather than relying on nobody typing it.
case "$branch" in
main | master)
echo "Error: Refusing to ${action} ${branch}, the integration branch"
return 1
;;
esac
return 0
}
function git-mk-branch() {
# Create a branch from an up-to-date main and push it upstream. Checks the
# branch out instead when it already exists.
# Usage: git-mk-branch [branch] (default topic/bill-dev)
local branch="${1:-topic/bill-dev}"
local primary
if _git-branch-exists "$branch"; then
echo "Local branch ${branch} already exists, checking it out..."
git checkout "$branch"
return
fi
echo "Creating ${branch} from main..."
_git-sync-main || return 1
# Created in the primary worktree, where _git-sync-main just left main, so the
# new branch starts from main rather than from a linked worktree's HEAD.
primary=$(_git-primary-worktree)
git -C "$primary" checkout -b "$branch" &&
git -C "$primary" push -u origin "$branch"
}
function git-rm-branch() {
# Delete a branch locally and on origin, releasing its worktree first. Refuses
# main and master.
# Usage: git-rm-branch [branch] (default topic/bill-dev)
# Env: CONFIRM_ASSUME_YES=1 answer every prompt yes
local branch="${1:-topic/bill-dev}"
_git-allow-branch-write "$branch" "delete" || return 1
echo "Deleting ${branch} locally and on origin..."
_git-sync-main || return 1
if _git-branch-exists "$branch"; then
# Both halves or neither. Deleting only the remote would leave the local
# branch with a gone upstream, which the next git-clean reads as "PR merged,
# safe to force-delete" -- the exact work this just declined to touch.
if ! _git-release-worktree "$branch"; then
echo " Keeping the remote branch too, so ${branch} keeps its upstream"
return 1
fi
git branch --delete --force "$branch" || return 1
else
echo " Local branch not found, skipping"
fi
if git ls-remote --exit-code --heads origin "$branch" &>/dev/null; then
git push origin --delete "$branch"
else
echo " Remote branch not found, skipping"
fi
}
function git-undo-last-commit() {
# Undo the last commit, keeping its changes staged.
if ! git rev-parse HEAD~1 &>/dev/null; then
echo "Error: No commit to undo (initial commit or empty repo)"
return 1
fi
echo "Undoing last commit, keeping changes staged..."
git reset HEAD~1
}
function gh-pr-create-retry() {
# Open a pull request, retrying so a GitHub write outage does not need
# babysitting. Exits early when a PR for the branch already exists.
# Usage: gh-pr-create-retry <title> <body-file> [branch] [base]
# branch defaults to the current one, base to main
# Env: PR_ATTEMPTS how many tries (default 12)
# PR_INTERVAL seconds between tries (default 180)
local title="$1"
local body_file="$2"
local branch="${3:-$(git rev-parse --abbrev-ref HEAD 2>/dev/null)}"
local base="${4:-main}"
local attempts="${PR_ATTEMPTS:-12}"
local interval="${PR_INTERVAL:-180}"
local ls_status
if [ -z "$title" ] || [ -z "$body_file" ]; then
echo "Usage: gh-pr-create-retry \"Title of the PR\" /path/to/body.md [branch] [base]"
return 1
fi
if ! command -v gh &>/dev/null; then
echo "Error: gh CLI not found on PATH"
return 1
fi
if [ ! -r "$body_file" ]; then
echo "Error: Body file not found or unreadable: ${body_file}"
return 1
fi
if [ -z "$branch" ]; then
echo "Error: Not in a git repository, pass the branch explicitly"
return 1
fi
if [ "$branch" = "$base" ]; then
echo "Error: Head branch and base are both ${base}"
return 1
fi
# Exit 2 means the branch is genuinely absent from origin; any other failure is
# treated as "network is unhappy", which is exactly what the retry loop is for.
git ls-remote --exit-code --heads origin "$branch" &>/dev/null
ls_status=$?
if [ "$ls_status" -eq 2 ]; then
echo "Error: Branch ${branch} is not on origin. Push it first: git push -u origin ${branch}"
return 1
fi
(
err_file="$(mktemp -t gh-pr-create-err)"
trap 'rm -f "$err_file"' EXIT
for ((i = 1; i <= attempts; i++)); do
existing=$(_gh-pr "$branch" open url '.[0].url // empty')
if [ -n "$existing" ]; then
echo "PR already exists: ${existing}"
exit 0
fi
echo "Attempt ${i}/${attempts} at $(date -u +%H:%M:%SZ): opening PR (${title})..."
if url=$(_gh pr create --base "$base" --head "$branch" --assignee @me \
--title "$title" --body-file "$body_file" 2>"$err_file"); then
echo "PR created: ${url}"
exit 0
fi
echo " Failed: $(tr -d '\n' <"$err_file" | tail -c 200)"
if [ "$i" -lt "$attempts" ]; then
sleep "$interval"
fi
done
echo "Error: Gave up after ${attempts} attempts ${interval}s apart, GitHub writes still failing"
exit 1
)
}
##-- K8s Functions --##
function k8s-cached-images() {
# Print every container image cached on any node, digest references included.
kubectl get nodes -o jsonpath="{.items[*].status.images[*].names}" |
tr -s '[[:space:]],' '\n' |
tr -d '"' |
sort -u
}
function k8s-cached-images-tags() {
# Print the cached images without digest references, which comm cannot line up
# against a tag.
k8s-cached-images | grep -v '@sha256:'
}
function k8s-pod-images() {
# Print every container image a running pod uses, in any namespace.
kubectl get pods --all-namespaces -o jsonpath="{..image}" | tr -s '[[:space:]]' '\n' | sort -u
}
function k8s-unused-images() {
# Print the images cached on nodes that no running pod uses.
comm -23 <(k8s-cached-images-tags) <(k8s-pod-images)
}
function _k8s-node-names() {
# Print the name of every node in the current cluster.
kubectl get nodes -o jsonpath='{.items[*].metadata.name}'
}
function _k8s-prune-node-images() {
# Drop every unused image from one kind node, whichever runtime CLI it ships.
# Usage: _k8s-prune-node-images <node>
local node="$1"
docker exec "$node" crictl rmi --prune 2>/dev/null ||
docker exec "$node" ctr -n k8s.io images prune 2>/dev/null ||
echo " Could not prune images on ${node} (unsupported runtime or not a kind cluster)"
}
function k8s-clear-cached-images() {
# Delete every cached image no running pod uses, from every node. Asks first.
# Intended for kind clusters, whose nodes are docker containers.
# Env: CONFIRM_ASSUME_YES=1 answer yes without asking
local node
echo "Clearing unused container images from all nodes (for kind clusters)..."
echo "Warning: This will delete ALL images not currently used by pods"
echo "Sample of unused images (tag references only):"
k8s-unused-images
echo ""
echo "Note: The cleanup will remove all unused images, including digest references."
echo ""
if ! _confirm "Continue with deletion?"; then
echo "Cancelled."
return 1
fi
for node in $(_k8s-node-names); do
echo "Cleaning images on node: ${node}"
_k8s-prune-node-images "$node"
done
echo "Done!"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment