Git Integration
fzf transforms git from a memory-heavy command system into an interactive, visual workflow. These patterns cover everything from single-repo workflows to multi-repo management.
git log Browser
# fzf git log with full diff preview
fgl() {
local commit
git log --oneline --color=always --decorate | fzf \
--ansi \
--no-sort \
--preview 'git show --stat --color=always {1}' \
--bind 'ctrl-d:change-preview(git diff --color=always {1}~1..{1})' \
--bind 'ctrl-s:change-preview(git show --color=always {1})' \
--bind 'ctrl-n:change-preview(git show --name-only {1})' \
--bind 'ctrl-/:toggle-preview' \
--preview-window 'right:60%' \
--prompt '📋 Log> ' \
--header $'Ctrl+D: diff Ctrl+S: show Ctrl+N: files CTRL-/: preview' \
| awk '{print $1}'
}
git add — Interactive Staging
# Stage files interactively with diff preview
git_fadd() {
local files
IFS=$'\n' files=($(
git status --short | fzf \
-m \
--ansi \
--preview 'git diff --color=always $(echo {} | awk "{print \$2}")' \
--preview-window 'right:60%' \
--bind 'ctrl-/:toggle-preview' \
--prompt '✅ Stage> ' \
--header 'Tab: mark Enter: git add CTRL-/: diff preview' \
| awk '{print $2}'
))
[[ ${#files[@]} -gt 0 ]] && git add "${files[@]}" && git status --short
}
git branch — Full Branch Manager
# Complete branch manager: checkout, delete, copy name
fbranch() {
local out key branch
out=$(git branch --all | grep -v HEAD | sed 's/^[* ]*//' | sort -u | fzf \
--ansi \
--expect=ctrl-d,ctrl-c \
--preview 'git log --oneline --graph --color=always {} | head -20' \
--preview-window 'right:50%' \
--prompt '🌿 Branch> ' \
--header $'Enter: checkout Ctrl+D: delete Ctrl+C: copy name')
key=$(head -1 <<< "$out")
branch=$(tail -1 <<< "$out" | sed 's#remotes/origin/##')
[[ -z "$branch" ]] && return
case "$key" in
ctrl-d)
echo "Delete branch: $branch?"
read -rp "[y/N] " confirm
[[ "$confirm" == "y" ]] && git branch -d "$branch"
;;
ctrl-c)
echo -n "$branch" | xclip -selection clipboard
echo "Copied: $branch"
;;
*)
git checkout "$branch"
;;
esac
}
git stash Manager
fstash() {
local stash action
stash=$(git stash list | fzf \
--preview 'git stash show -p $(echo {} | cut -d: -f1) | delta --paging=never' \
--preview-window 'right:60%' \
--bind 'ctrl-/:toggle-preview' \
--expect=ctrl-d \
--prompt '📦 Stash> ' \
--header 'Enter: pop Ctrl+D: drop' \
| cut -d: -f1)
[[ -z "$stash" ]] && return
local key
key=$(head -1 <<< "$stash")
if [[ "$key" == "ctrl-d" ]]; then
git stash drop "$stash"
echo "Dropped: $stash"
else
git stash pop "$stash"
fi
}
git reflog — Browse and Restore
freflog() {
local commit
commit=$(git reflog --color=always | fzf \
--ansi \
--no-sort \
--preview 'git show --stat --color=always {1}' \
--preview-window 'right:50%' \
--prompt '⏮ Reflog> ' \
--header 'Enter: checkout (recovers lost commits)' \
| awk '{print $1}')
[[ -n "$commit" ]] && git checkout "$commit"
}
git worktree Manager
# Switch between git worktrees
fworktree() {
local wt
wt=$(git worktree list | fzf \
--preview 'ls $(echo {} | awk "{print \$1}")' \
--preview-window 'right:40%' \
--prompt '🌳 Worktree> ' \
| awk '{print $1}')
[[ -n "$wt" ]] && cd "$wt"
}
Complete git Aliases
~/.gitconfig
[alias]
# fzf-powered git (requires fzf)
flog = "!f() { git log --oneline --color=always | fzf --ansi \
--preview 'git show --color=always {1}' \
--preview-window right:60% | awk '{print $1}'; }; f"
fadd = "!f() { git status -s | fzf -m \
--preview 'git diff --color=always {2}' | awk '{print $2}' \
| xargs git add; }; f"
fbr = "!f() { git branch | fzf | xargs git checkout; }; f"
ftag = "!f() { git tag | fzf | xargs git checkout; }; f"