Last active
December 16, 2025 17:11
-
-
Save eskil/2629551a9d02f1ea9427e23a0cceb83d to your computer and use it in GitHub Desktop.
Some git aliases I use
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| echo "Pruning..." | |
| git fetch --prune --quiet | |
| # Collect branches whose upstream is gone | |
| branches=$(git for-each-ref \ | |
| --format='%(refname:short) %(upstream:track)' refs/heads \ | |
| | awk '$2 == "[gone]" {print $1}') | |
| if [[ -z "$branches" ]]; then | |
| echo "No gone branches." | |
| exit 0 | |
| fi | |
| # fzf selection with preview: last commit | |
| selected=$(echo "$branches" | fzf \ | |
| --multi \ | |
| --prompt="Select gone branches to delete: " \ | |
| --ansi \ | |
| --reverse \ | |
| --marker="x " \ | |
| --pointer="- " \ | |
| --preview='git log -n 3 --color=always --decorate --oneline --graph --pretty=medium {1}' \ | |
| --color='pointer:161,marker:168' \ | |
| --preview-window=right:50%) | |
| if [[ -z "$selected" ]]; then | |
| echo "No branches selected." | |
| exit 0 | |
| fi | |
| current_branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "") | |
| needs_checkout=false | |
| # If current branch is among the branches to delete → auto-checkout safe branch | |
| if echo "$selected" | grep -qx "$current_branch"; then | |
| needs_checkout=true | |
| fi | |
| if $needs_checkout; then | |
| echo "Current branch '$current_branch' is selected for deletion." | |
| echo "Checking out a safe branch..." | |
| safe="" | |
| # Priority 1: main | |
| if git rev-parse --verify main >/dev/null 2>&1; then | |
| safe="main" | |
| # Priority 2: master | |
| elif git rev-parse --verify master >/dev/null 2>&1; then | |
| safe="master" | |
| # Priority 3: upstream default branch (if available) | |
| elif upstream_default=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null); then | |
| safe="${upstream_default#refs/remotes/origin/}" | |
| fi | |
| if [[ -n "$safe" ]]; then | |
| git checkout "$safe" | |
| else | |
| echo "No safe branch found. Detaching HEAD." | |
| git checkout --detach | |
| fi | |
| fi | |
| # Proceed with deletions | |
| echo "$selected" | while read -r br; do | |
| echo "Deleting branch: $br" | |
| git branch -D "$br" | |
| done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # Usage: git recent [compare_branch] [count] | |
| refbranch="${1:-origin/master}" | |
| count="${2:-20}" | |
| # Collect branch metadata | |
| rawlist=$( | |
| git for-each-ref \ | |
| --sort=-committerdate \ | |
| --format='%(refname:short)|%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)' \ | |
| --color=always \ | |
| --count="$count" \ | |
| refs/heads \ | |
| | while IFS='|' read -r branch colored_branch date msg author; do | |
| # Remove possible leading '*' from current branch indicator | |
| clean_branch=$(echo "$branch" | tr -d '*') | |
| # Ahead/behind counts | |
| ahead=$( git rev-list --count "$refbranch..$clean_branch" 2>/dev/null || echo 0 ) | |
| behind=$( git rev-list --count "$clean_branch..$refbranch" 2>/dev/null || echo 0 ) | |
| # Output format for further processing | |
| printf "%s|%s|%s|%s|%.70s|%s\n" \ | |
| "$ahead" "$behind" "$colored_branch" "$date" "$msg" "$author" | |
| done | |
| ) | |
| # Nicely aligned table for fzf display | |
| displaylist=$(printf "%s\n" "$rawlist" | column -ts '|') | |
| # Launch fzf | |
| selected=$(printf "%b" "$displaylist" | fzf \ | |
| --ansi \ | |
| --with-nth=1.. \ | |
| --delimiter='|' \ | |
| --prompt='Recent Branches › ' \ | |
| --reverse \ | |
| --color='pointer:161,marker:168' | |
| ) | |
| # If user cancelled | |
| if [[ -z "$selected" ]]; then | |
| exit 0 | |
| fi | |
| # Extract the branch name (3rd column) | |
| branch=$(echo "$selected" | awk '{print $3}') | |
| echo "Switching to $branch" | |
| git switch "$branch" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # ------------------------------ | |
| # CONFIGURATION | |
| # ------------------------------ | |
| PROTECTED_PATTERNS=( | |
| "*.env" | |
| "*.pem" | |
| "*.key" | |
| "*.crt" | |
| "*.p12" | |
| "*secrets*" | |
| ) | |
| EDITOR="${EDITOR:-vim}" | |
| # ------------------------------ | |
| # HELPERS | |
| # ------------------------------ | |
| is_protected() { | |
| local f="$1" | |
| for pat in "${PROTECTED_PATTERNS[@]}"; do | |
| [[ "$f" == $pat ]] && return 0 | |
| done | |
| return 1 | |
| } | |
| # Portable move-to-trash: | |
| move_to_trash() { | |
| local f="$1" | |
| # Try trash-put (trash-cli) | |
| if command -v trash-put >/dev/null 2>&1; then | |
| trash-put "$f" && return 0 | |
| fi | |
| # Try gio (GNOME) | |
| if command -v gio >/dev/null 2>&1; then | |
| gio trash "$f" && return 0 | |
| fi | |
| # Try gvfs-trash (older systems) | |
| if command -v gvfs-trash >/dev/null 2>&1; then | |
| gvfs-trash "$f" && return 0 | |
| fi | |
| # macOS: use AppleScript to move to Trash | |
| # macOS Finder | |
| if [[ "$(uname -s)" == "Darwin" ]]; then | |
| for f in "$@"; do | |
| # Resolve absolute path | |
| if command -v realpath >/dev/null 2>&1; then | |
| absf=$(realpath "$f") | |
| else | |
| absf="$PWD/$f" | |
| fi | |
| /usr/bin/osascript -e "tell application \"Finder\" to move (POSIX file \"$absf\") to trash" | |
| done | |
| return | |
| fi | |
| # # Fallback: move into $XDG_DATA_HOME/Trash/files or ~/.local/share/Trash/files | |
| # echo "\t try fallback" | |
| # local trash_dir="${XDG_DATA_HOME:-$HOME/.local/share}/Trash/files" | |
| # mkdir -p "$trash_dir" | |
| # # If file name collision, append timestamp | |
| # local base | |
| # base=$(basename -- "$f") | |
| # if [[ -e "$trash_dir/$base" ]]; then | |
| # mv -- "$f" "$trash_dir/${base}.$(date +%s)" && return 0 | |
| # else | |
| # mv -- "$f" "$trash_dir/" && return 0 | |
| # fi | |
| return 1 | |
| } | |
| # Permanent delete | |
| permanent_delete() { | |
| local f="$1" | |
| rm -f -- "$f" | |
| } | |
| # ------------------------------ | |
| # BUILD A TEMP PREVIEW SCRIPT (robust) | |
| # ------------------------------ | |
| PREVIEW_SCRIPT=$(mktemp) | |
| chmod +x "$PREVIEW_SCRIPT" | |
| cat > "$PREVIEW_SCRIPT" <<'PREVIEW_EOF' | |
| #!/usr/bin/env bash | |
| # arg1 -> path to file to preview | |
| f="$1" | |
| # If not a regular file, show message | |
| if [[ ! -f "$f" ]]; then | |
| echo "Not a regular file" | |
| exit 0 | |
| fi | |
| # Protected check: we can't access PROTECTED_PATTERNS array from parent here, so | |
| # replicate a small subset of patterns or read them from env var if exported. | |
| # We'll accept PROTECTED list in PROTECT_PATTERNS env if present. | |
| if [[ -n "${PROTECT_PATTERNS:-}" ]]; then | |
| IFS=$'\n' read -r -d '' -a pats <<< "$PROTECT_PATTERNS" || true | |
| for pat in "${pats[@]}"; do | |
| if [[ "$f" == $pat ]]; then | |
| echo "[ PROTECTED FILE ]" | |
| echo "Matches protected pattern: $pat" | |
| echo | |
| break | |
| fi | |
| done | |
| fi | |
| # Show text preview if file command says text | |
| if file "$f" | grep -qi text; then | |
| if command -v bat >/dev/null 2>&1; then | |
| bat --style=plain --color=always --line-range=1:200 "$f" | |
| else | |
| head -n 200 "$f" | |
| fi | |
| else | |
| echo "[binary file]" | |
| fi | |
| PREVIEW_EOF | |
| # Ensure temp preview script is removed on exit | |
| cleanup() { | |
| rm -f "$PREVIEW_SCRIPT" | |
| } | |
| trap cleanup EXIT | |
| # Export protected patterns into a single-line env var for preview script | |
| # Use null-separated to be safe | |
| PROTECT_PATTERNS=$(printf "%s\n" "${PROTECTED_PATTERNS[@]}") | |
| export PROTECT_PATTERNS | |
| # ------------------------------ | |
| # MAIN | |
| # ------------------------------ | |
| files=$(git ls-files --others --exclude-standard) | |
| if [[ -z "$files" ]]; then | |
| echo "No untracked files." | |
| exit 0 | |
| fi | |
| # keep original fzf options the user requested | |
| selected=$(printf "%s\n" "$files" | fzf \ | |
| --multi \ | |
| --prompt="Untracked Files › " \ | |
| --border \ | |
| --ansi \ | |
| --reverse \ | |
| --marker="x " \ | |
| --pointer="- " \ | |
| --preview="$PREVIEW_SCRIPT {}" \ | |
| --color='pointer:161,marker:168' \ | |
| --preview-window=right:50% \ | |
| --bind="ctrl-o:execute($EDITOR {+})" \ | |
| --bind="ctrl-e:execute($EDITOR {+})" | |
| # --bind="ctrl-d:execute( | |
| # echo 'Force deleting:' {+}; | |
| # for f in {+}; do rm -f \"\$f\"; done; | |
| # echo 'Done'; | |
| # sleep 1 | |
| # )+abort" | |
| ) | |
| # If user aborted / nothing selected | |
| if [[ -z "${selected:-}" ]]; then | |
| exit 0 | |
| fi | |
| # ------------------------------ | |
| # NORMAL DELETE (Enter key): move to trash unless protected | |
| # ------------------------------ | |
| # iterate selected lines (could be multiple) | |
| printf "%s\n" "$selected" | while IFS= read -r f; do | |
| if is_protected "$f"; then | |
| echo "Skipping PROTECTED file: $f" | |
| continue | |
| fi | |
| echo "Moving to trash: $f" | |
| if move_to_trash "$f"; then | |
| echo " → Moved to trash" | |
| else | |
| echo " → Failed to move to trash, attempting permanent delete" | |
| permanent_delete "$f" | |
| fi | |
| done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [alias] | |
| recent = "!git-recent.sh" | |
| gone = "!git-gone.sh" | |
| what = "!git-what.sh" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment