|
# ─── Git Worktree Helpers ────────────────────────────────────────── |
|
# Commands: |
|
# gwtr — list worktrees sorted by last modified |
|
# cdwt — fzf picker to cd into a worktree |
|
# cdwt <path> — cd directly with tab-completion |
|
# gwtb — jump back to previous worktree |
|
|
|
# ── 1. List worktrees sorted by date modified (most recent first) ── |
|
|
|
gwtr() { |
|
git worktree list --porcelain \ |
|
| awk '/^worktree /{path=$2} /^HEAD /{head=$2} /^branch /{branch=$2; print path, head, branch}' \ |
|
| while read -r wtdir head branch; do |
|
# Use wtdir, not path: zsh ties `path` to PATH; read into path breaks stat(1). |
|
modified=$(stat -f "%m" "$wtdir" 2>/dev/null || stat -c "%Y" "$wtdir" 2>/dev/null) |
|
date_fmt=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$wtdir" 2>/dev/null \ |
|
|| date -d "@$modified" "+%Y-%m-%d %H:%M" 2>/dev/null) |
|
branch_display="${branch:-detached@${head:0:7}}" |
|
# Strip refs/heads/ prefix for cleaner display |
|
branch_display="${branch_display#refs/heads/}" |
|
printf "%s\t%s\t%s\t%s\n" "$modified" "$date_fmt" "$branch_display" "$wtdir" |
|
done \ |
|
| sort -rn \ |
|
| awk -F'\t' ' |
|
BEGIN { printf "%-14s %-30s %s\n", "MODIFIED", "BRANCH", "PATH" |
|
printf "%-14s %-30s %s\n", "──────────────", "──────────────────────────────", "────────────────────────────────" } |
|
{ printf "%-14s %-30s %s\n", $2, $3, $4 }' |
|
} |
|
|
|
# ── 2. cd into a worktree — fzf picker or direct path w/ tab-complete ── |
|
|
|
_git_worktree_paths() { |
|
local worktrees |
|
worktrees=($(git worktree list --porcelain 2>/dev/null \ |
|
| awk '/^worktree /{print $2}')) |
|
_describe 'worktree' worktrees |
|
} |
|
|
|
cdwt() { |
|
local selected |
|
|
|
if [[ -n "$1" ]]; then |
|
# Direct path passed — tab-complete behaviour |
|
cd "$1" |
|
return |
|
fi |
|
|
|
# Interactive fzf picker |
|
selected=$(git worktree list --porcelain 2>/dev/null \ |
|
| awk '/^worktree /{path=$2} /^branch /{branch=$2; print branch"\t"path}' \ |
|
| column -t -s $'\t' \ |
|
| fzf --height=40% --reverse --border \ |
|
--preview 'git -C $(echo {} | awk "{print \$NF}") log --oneline -10' \ |
|
--prompt="worktree> ") |
|
|
|
[[ -z "$selected" ]] && return |
|
|
|
local target |
|
target=$(echo "$selected" | awk '{print $NF}') |
|
cd "$target" |
|
} |
|
|
|
compdef _git_worktree_paths cdwt |
|
|
|
# ── 3. Jump back to the previous worktree (toggle between last two) ── |
|
|
|
_GWT_PREV_PATH="" |
|
_GWT_CWD_PATH="" |
|
|
|
_gwt_track() { |
|
local current |
|
current="$(git rev-parse --show-toplevel 2>/dev/null)" |
|
[[ -z "$current" ]] && return |
|
if [[ "$current" != "$_GWT_CWD_PATH" ]]; then |
|
_GWT_PREV_PATH="$_GWT_CWD_PATH" |
|
_GWT_CWD_PATH="$current" |
|
fi |
|
} |
|
|
|
autoload -Uz add-zsh-hook |
|
add-zsh-hook chpwd _gwt_track |
|
|
|
gwtb() { |
|
if [[ -z "$_GWT_PREV_PATH" ]]; then |
|
echo "No previous worktree recorded." |
|
return 1 |
|
fi |
|
cd "$_GWT_PREV_PATH" |
|
} |