# Controlled by chezmoi # System alias sctl='systemctl' alias sctlu='systemctl --user' alias jctl='journalctl' alias sup='sudo apt update' alias sug='sudo apt upgrade' alias supg='sudo apt update && sudo apt upgrade' alias supgy='sudo apt update && sudo apt upgrade -y' alias sai='sudo apt install' alias saa='sudo apt autoremove' alias sdr='sudo systemctl daemon-reload' alias sn='sudo micro' alias sv='sudo nvim' # Core aliases alias ll='ls -AlFh' alias la='ls -Ah' alias l='ls -CF' alias nano='micro' alias lg='lazygit' alias vim='nvim' alias chlg='lazygit --path ~/.local/share/chezmoi' alias es='exec $SHELL' # Chezmoi alias cha='chezmoi apply' alias chai='chezmoi apply --interactive' alias ch='chezmoi' alias cdc='chezmoi cd' # Remote Management alias romanlog="ssh roman 'tail -F /var/log/syslog' --lines 100" # Other aliases alias oc='opencode' alias ocs='opencode --model anthropic/claude-sonnet-4-5' alias oco='opencode --model anthropic/claude-opus-4-5' alias och='opencode --model anthropic/claude-haiku-4-5' alias cl='claude' alias cope='claude --model opus' alias copes='claude --model sonnet' alias copeh='claude --model haiku' alias hcope='claude --model haiku' alias gpt='chatgpt' alias copilot='copilot' alias suggest='copilot -p "suggest:" --allow-all-tools' alias spt='spotify_player' alias gitalias='alias | grep "git "' alias mousefix='sudo udevadm trigger' # helped with mouse issues on laptop alias rt='riptree' alias tree='rt --compat' # Clipboard aliases {{ if not .wsl -}} alias copy='xsel -ib' alias paste='xsel -b' alias cdp='cd $(xsel -b)' {{- else -}} alias copy='clip.exe' alias paste='powershell.exe -noprofile Get-Clipboard' alias cdp='cd $(xsel -b)' {{- end }} # fast chmod execute alias function chfix() { last_command=$(history | tail -n 1 | awk '{$1=""; sub(/^ /, ""); print $0}') if [[ -f $last_command ]]; then chmod +x $last_command else echo "Error: $last_command is not a valid file" fi } # https://docs.gitignore.io/install/command-line function gi() { curl -sL https://www.toptal.com/developers/gitignore/api/$@; } function chcode() { EDITOR="code --wait" # If no arguments are provided, the chezmoi directory is opened if [[ "$@" == *"--watch"* ]]; then for arg in "$@"; do if [[ ! $arg == -* ]]; then chezmoi edit $@ return fi done echo "--watch requires a file to be provided, directories aren't supported with watch mode" fi chezmoi edit $@ } # Creates a temporary file with the given function tempCode() { if [ -z "$1" ]; then echo "Must provide filetype argument (ex: py, .xml, html)" else # Remove preceding dot, then re-add to support both '.py' and 'py' as arguments EXTENSION=$(echo $1 | sed 's/^\.//') TEMP_FILE=$(mktemp "/tmp/XXXXXXXXXXXX_$(uuidgen).$EXTENSION") echo "Temporary $1 file created at $TEMP_FILE" code --file-uri "file://$TEMP_FILE" fi } # Alias to disable/enable bluetooth connection to Galaxy Buds budsAddress="60:3A:AF:75:61:80" alias budsOff="bluetoothctl block $budsAddress" alias budsOn="bluetoothctl unblock $budsAddress && bluetoothctl connect $budsAddress" # Alias to disable/enable bluetooth connection to Bose QC45s maestroAddress="AC:BF:71:66:FE:B2" alias maestroOff="bluetoothctl block $maestroAddress" alias maestroOn="bluetoothctl unblock $maestroAddress && bluetoothctl connect $maestroAddress" function lastRuns() { if [ -z "$1" ]; then RUNS=10; else RUNS=$1; fi gh run list -L $RUNS --json name,url | jq -c '.[] | [.name, .url] | join(" ")' -r } # Touches a file while also creating the parent directory (and any other necessary directories) in order to do so. mktouch() { mkdir -p $(dirname $1) && touch $1; } # When in the appropriate KiTTy terminal, use the SSH kitten [ "$TERM" = "xterm-kitty" ] && alias ssh="kitty +kitten ssh" # Git aliases alias ga='git add' alias gaa='git add .' alias gaaa='git add --all' alias gau='git add --update' alias gb='git branch' alias gbd='git branch --delete ' alias gc='git commit' alias gcm='git commit --message' alias gcf='git commit --fixup' alias gco='git checkout' alias gcob='git checkout -b' alias gcom='git checkout master' alias gcos='git checkout staging' alias gcod='git checkout develop' alias gd='git diff' alias gda='git diff HEAD' # alias gi='git init' alias glg='git log --graph --oneline --decorate --all' alias gld='git log --pretty=format:"%h %ad %s" --date=short --all' alias gm='git merge --no-ff' alias gma='git merge --abort' alias gmc='git merge --continue' alias gp='git pull' alias gpr='git pull --rebase' alias gr='git rebase' alias gs='git status' alias gss='git status --short' alias gst='git stash' alias gsta='git stash apply' alias gstd='git stash drop' alias gstl='git stash list' alias gstp='git stash pop' alias gsts='git stash save' # Git log find by commit message function glf() { git log --all --grep="$1"; } # ============================================================================= # Git Worktree Functions # ============================================================================= # Helper: Sanitize branch name for directory (feature/foo -> feature-foo) _wt_sanitize() { echo "$1" | tr '/' '-' } # Helper: Get the current branch's tip (not HEAD if detached) _wt_get_base() { local branch branch=$(git symbolic-ref --short HEAD 2>/dev/null) if [[ -n "$branch" ]]; then echo "$branch" else # Detached HEAD - try to find which branch we're on git rev-parse HEAD fi } # Helper: Get git repo root _wt_root() { git rev-parse --show-toplevel 2>/dev/null } # Helper: Clone gitignored files from source to destination worktree _wt_clone_ignored() { local src_path="$1" local dst_path="$2" # Find gitignored files (excluding .git and .worktrees) local ignored_files ignored_files=$(git -C "$src_path" ls-files --others --ignored --exclude-standard 2>/dev/null | \ grep -v "^\.git" | grep -v "^\.worktrees") if [[ -z "$ignored_files" ]]; then return 0 fi echo "" echo "Found gitignored files to copy..." # Measure size with timeout local size_output local size_bytes=0 local size_human="unknown" if size_output=$(timeout 10s du -sb "$src_path" --exclude='.git' --exclude='.worktrees' 2>/dev/null | head -n1); then size_bytes=$(echo "$size_output" | awk '{print $1}') size_human=$(numfmt --to=iec --suffix=B "$size_bytes" 2>/dev/null || echo "$size_bytes bytes") fi local threshold=$((100 * 1024 * 1024)) # 100MB if [[ "$size_bytes" -gt "$threshold" ]] || [[ "$size_human" == "unknown" ]]; then echo "Gitignored files size: $size_human" read -p "Copy these files to new worktree? [y/N] " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Skipping gitignored file copy" return 0 fi fi echo "Copying gitignored files..." echo "$ignored_files" | while read -r file; do local src="$src_path/$file" local dst="$dst_path/$file" if [[ -e "$src" ]]; then mkdir -p "$(dirname "$dst")" cp -r "$src" "$dst" 2>/dev/null fi done echo "Done copying gitignored files" } # wtl - List all worktrees function wtl() { git worktree list "$@" } # wts - Show git status for all worktrees function wts() { local root root=$(_wt_root) if [[ -z "$root" ]]; then echo "Not in a git repository" >&2 return 1 fi git worktree list --porcelain | grep '^worktree ' | cut -d' ' -f2- | while read -r wt_path; do local branch branch=$(git -C "$wt_path" symbolic-ref --short HEAD 2>/dev/null || echo "detached") # Print header echo -e "\033[1;34m╭─────────────────────────────────────────────────────────────╮\033[0m" echo -e "\033[1;34m│\033[0m \033[1;33m$wt_path\033[0m" echo -e "\033[1;34m│\033[0m \033[0;36m[$branch]\033[0m" echo -e "\033[1;34m╰─────────────────────────────────────────────────────────────╯\033[0m" # Run git status git -C "$wt_path" status --short echo "" done } # wtr - FZF-based worktree remover (multi-select) function wtr() { local root root=$(_wt_root) if [[ -z "$root" ]]; then echo "Not in a git repository" >&2 return 1 fi # Get worktrees excluding the main one local main_wt main_wt=$(git worktree list --porcelain | grep '^worktree ' | head -n1 | cut -d' ' -f2-) local selected selected=$(git worktree list | grep -v "^$main_wt " | fzf --multi --height=40% --reverse \ --header="Select worktrees to remove (Tab to multi-select)" \ --preview="git -C {1} log --oneline -5 2>/dev/null || echo 'No commits'") if [[ -z "$selected" ]]; then echo "No worktrees selected" return 0 fi echo "Will remove the following worktrees:" echo "$selected" | awk '{print " - " $1}' echo "" read -p "Confirm removal? [y/N] " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then echo "$selected" | while read -r line; do local wt_path wt_path=$(echo "$line" | awk '{print $1}') echo "Removing $wt_path..." git worktree remove "$wt_path" done else echo "Cancelled" fi } # wtb - Add worktree with new branch # Usage: wtb [base-ref] function wtb() { if [[ -z "$1" ]]; then echo "Usage: wtb [base-ref]" >&2 return 1 fi local root root=$(_wt_root) if [[ -z "$root" ]]; then echo "Not in a git repository" >&2 return 1 fi local branch="$1" local base="${2:-$(_wt_get_base)}" local dir_name dir_name=$(_wt_sanitize "$branch") local wt_path="$root/.worktrees/$dir_name" # Create .worktrees directory if needed mkdir -p "$root/.worktrees" # Add to .gitignore if not already there if ! grep -q "^\.worktrees/?$" "$root/.gitignore" 2>/dev/null; then echo ".worktrees/" >> "$root/.gitignore" echo "Added .worktrees/ to .gitignore" fi echo "Creating worktree at $wt_path" echo " Branch: $branch" echo " Base: $base" if git worktree add -b "$branch" "$wt_path" "$base"; then echo "" echo "Worktree created: $wt_path" # Clone gitignored files from current worktree local current_wt current_wt=$(pwd) _wt_clone_ignored "$current_wt" "$wt_path" cd "$wt_path" fi } # wtf / wtfeature - Create feature branch worktree # Usage: wtf [base-ref] function wtf() { if [[ -z "$1" ]]; then echo "Usage: wtf [base-ref]" >&2 return 1 fi wtb "feature/$1" "${2:-}" } function wtfeature() { wtf "$@"; } # wth / wtfix - Create hotfix branch worktree # Usage: wth [base-ref] function wth() { if [[ -z "$1" ]]; then echo "Usage: wth [base-ref]" >&2 return 1 fi wtb "hotfix/$1" "${2:-}" } function wtfix() { wth "$@"; } # wtcd - FZF-based worktree picker - cd into selected function wtcd() { local root root=$(_wt_root) if [[ -z "$root" ]]; then echo "Not in a git repository" >&2 return 1 fi local selected selected=$(git worktree list | fzf --height=40% --reverse \ --header="Select worktree" \ --preview="git -C {1} log --oneline -5 2>/dev/null; echo ''; git -C {1} status --short 2>/dev/null") if [[ -n "$selected" ]]; then local wt_path wt_path=$(echo "$selected" | awk '{print $1}') cd "$wt_path" fi } # fzf abbreviation/alias search if command -v fzf-abbr-search.ts &> /dev/null && command -v fzf &> /dev/null; then fzf_search_abbr() { local result key selected result=$(fzf-abbr-search.ts | fzf \ --ansi \ --height=50% \ --reverse \ --delimiter=$'\t' \ --with-nth=4 \ --nth=1,2 \ --prompt='Aliases > ' \ --preview='echo {2}' \ --preview-window=up:3:wrap \ --expect='tab' \ --header='Enter: insert name | Tab: insert expansion') if [ -n "$result" ]; then # First line is key, second line is selected key=$(echo "$result" | head -n1) selected=$(echo "$result" | tail -n1) if [ -n "$selected" ]; then if [ "$key" = "tab" ]; then # Insert expansion (field 2) READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$(echo "$selected" | cut -f2)${READLINE_LINE:$READLINE_POINT}" else # Insert name (field 1) READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$(echo "$selected" | cut -f1)${READLINE_LINE:$READLINE_POINT}" fi fi fi } # Bind to Alt+A bind -x '"\ea": fzf_search_abbr' fi