A collection of custom scripts, aliases, and configuration tips for a better Git workflow.
Add these to your ~/.gitconfig:
[alias]
unadd = reset HEAD
amend = commit --amend
aa = add --allUse git grep instead of grep -r. It only searches tracked files, respects .gitignore, and works from any subdirectory.
# Instead of:
grep -r "TODO" --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist
# Just use:
git grep "TODO"Stage individual hunks interactively. Great for splitting changes across multiple logical commits.
git add -py— stage this hunkn— skip this hunks— split the hunk into smaller piecese— manually edit the hunk
Set up a global gitignore to keep throwaway files out of every repo:
git config --global core.excludesfile ~/.gitignore_globalThen in ~/.gitignore_global:
*.ignore
*.ignore.*
Now you can rename any file like scratch.ts to scratch.ignore.ts — git ignores it, but your editor still knows it's TypeScript.
For files that ARE tracked but you need to modify locally without committing (e.g., pointing API requests at a local proxy server):
# Tell git to ignore your local changes:
git update-index --skip-worktree <filename>
# Undo it:
git update-index --no-skip-worktree <filename>
# Check which files are hidden:
git ls-files -v | grep '^[a-z]'Add to your ~/.gitconfig:
[diff]
colorMoved = plainMoved code gets its own color instead of looking like a massive deletion + addition.
Also check out Git Delta for beautiful terminal diffs.
A tool for viewing and switching between branches, sorted by recency, with branch descriptions.
Did you know git supports branch descriptions? Set them with git branch --edit-description.
function recent-branches-list() {
{
printf "%s\n" "branch:modified:description"
printf "%s\n" "------:--------:-----------"
git for-each-ref --sort='-authordate:iso8601' \
--format='%(refname:short):%(authordate:relative)' refs/heads |
while IFS=: read -r branch modified; do
desc=$(git config --get "branch.$branch.description")
if [ -z "$desc" ] && [ -f ".git/branches/$branch" ]; then
desc=$(cat ".git/branches/$branch")
fi
desc=$(printf "%s" "$desc" | head -n1 | sed 's/^ *//; s/ *$//')
printf "%s:%s:%s\n" "$branch" "$modified" "$desc"
done
} | column -t -s:
}Keybindings:
space— checkout branch under cursorx— delete branch under cursorl— show git logcc— compare commits with main/mastere— edit branch description?— show help
function recent-branches {
base=$(git branch --list main master | head -1 | tr -d ' ')
remap1='nnoremap <silent> <space> :!git checkout <c-r><c-w><cr>:q!<cr>'
remap2='nnoremap <silent> x :!git branch -D <c-r><c-w><cr>dd'
remap3='nnoremap <silent> q :q!<cr>'
remap4='nnoremap <silent> l :!git log <c-r><c-w><cr>'
remap5="nnoremap <silent> cc :!git log --left-right --graph --cherry-pick --oneline ${base}...<c-r><c-w><cr>"
remap6='nnoremap <silent> e :terminal ++close git branch --edit-description <cfile><CR>'
remap7='nnoremap <silent> ? :echo "space: checkout; x: delete branch; l: git log; cc: compare commits; e: edit description; q: quit"<cr>h'
iskeyword='set iskeyword+=.'
nofile='setlocal buftype=nofile'
recent-branches-list | vi -c "$remap1 | $remap2 | $remap3 | $remap4 | $remap5 | $remap6 | $remap7 | $iskeyword | $nofile" -
}Git almost never truly deletes anything. git reflog tracks every HEAD movement for the past 90 days — it's your undo history.
Accidentally deleted a branch? Here's how to get it back:
# See your recent git actions:
git reflog
# Find the commit hash from before the deletion, then:
git checkout -b recovered-branch abc1234This works for recovering from bad resets, accidental deletes, rebases gone wrong, and more.
Find a search string only in lines YOU changed since a given branching point. Perfect for hunting down a console.log you introduced on a feature branch.
git-diff-grep master "console\.log"git-diff-grep() {
local commit="$1"
local pattern="$2"
if [[ -z "$commit" || -z "$pattern" ]]; then
echo "Usage: git-diff-grep <commit> <string>"
return 1
fi
git diff -U0 "$commit" --no-color | awk -v pat="$pattern" '
/^diff --git/ {file=""}
/^\+\+\+/ {file=substr($2,3)}
/^@@/ {
split($0,a," ")
split(a[3],b,",")
lineno=b[1]+0
}
/^\+/ && !/^\+\+\+/ {
if ($0 ~ pat) {
print file ":" lineno ":" $0
}
lineno++
}'
}To open results in vim interactively, pipe to vi:
git-diff-grep master "console\.log" | vi -c "set filetype=grep" -Navigate a file's entire git history, stepping forward and backward through time. Your cursor tracks the same line across revisions, and the gutter highlights what changed at each step.
Dependencies: vim-fugitive, vim-gitgutter, Taboo.vim
Usage (inside vim):
:TimeTravel— enter TimeTravel modeCtrl-D— go back in time (older commit)Ctrl-E— go forward in time (newer commit):TimeTravelEnd— exit
The full vimscript is extensive — reach out if you'd like the code or if you're interested in a standalone version of this concept.