Skip to content

Instantly share code, notes, and snippets.

@willwillems
Created January 30, 2026 09:06
Show Gist options
  • Select an option

  • Save willwillems/a6baaec1814b3431e01163a6b0ca71d9 to your computer and use it in GitHub Desktop.

Select an option

Save willwillems/a6baaec1814b3431e01163a6b0ca71d9 to your computer and use it in GitHub Desktop.
wtpull - Set up a git worktree with ignored files and VS Code status bar color
#!/usr/bin/env bash
#
# wtpull - Set up a git worktree with ignored files and visual differentiation
#
# Copies .gitignore'd files from the main worktree to the current worktree,
# and sets a unique VS Code status bar color based on the branch name.
#
# Usage:
# wtpull Copy ignored files and set VS Code status bar color
# wtpull --no-vscode Copy ignored files only, skip VS Code customization
# wtpull --help Show this help message
#
# The status bar color is deterministic based on branch name, so the same
# branch always gets the same color. Colors are from the Flexoki palette.
#
# Requirements:
# - Must be run from within a git worktree (not the main repo)
# - jq (for JSON manipulation)
# - rsync
set -euo pipefail
# Flexoki 800/700 color pairs (background/hover)
COLORS=(
"#6C201C:#942822" # red
"#71320D:#9D4310" # orange
"#664D01:#8E6B01" # yellow
"#3D4C07:#536907" # green
"#164F4A:#1C6C66" # cyan
"#163B66:#1A4F8C" # blue
"#3C2A62:#4F3685" # purple
"#641F46:#87285E" # magenta
)
COLOR_NAMES=(red orange yellow green cyan blue purple magenta)
show_help() {
sed -n '2,16p' "$0" | sed 's/^# \?//'
exit 0
}
error() {
echo "error: $1" >&2
exit 1
}
warn() {
echo "warning: $1" >&2
}
# Parse arguments
NO_VSCODE=false
for arg in "$@"; do
case "$arg" in
--help|-h) show_help ;;
--no-vscode) NO_VSCODE=true ;;
*) error "unknown option: $arg" ;;
esac
done
# Validate: must be in a git repo
if ! git rev-parse --git-dir &>/dev/null; then
error "not in a git repository"
fi
# Get worktree list (first one is the main worktree)
mapfile -t worktrees < <(git worktree list --porcelain | sed -n 's/^worktree //p')
if [[ ${#worktrees[@]} -lt 2 ]]; then
error "no additional worktrees found — nothing to pull from"
fi
main_worktree="${worktrees[0]}"
current_dir="$(pwd)"
# Validate: must not be in the main worktree
if [[ "$current_dir" == "$main_worktree" ]]; then
error "you are in the main worktree — run this from a secondary worktree"
fi
# Validate: must be in a worktree (not just a subdirectory somewhere)
in_worktree=false
for wt in "${worktrees[@]:1}"; do
if [[ "$current_dir" == "$wt" || "$current_dir" == "$wt"/* ]]; then
in_worktree=true
break
fi
done
if [[ "$in_worktree" == false ]]; then
error "not in a git worktree"
fi
# --- Step 1: Rsync ignored files from main worktree ---
echo "Copying ignored files from main worktree..."
git -C "$main_worktree" ls-files -oi --exclude-standard -z \
| rsync -a0 --files-from=- "$main_worktree"/ ./
echo "Done copying ignored files."
# --- Step 2: VS Code status bar color ---
if [[ "$NO_VSCODE" == true ]]; then
exit 0
fi
# Check for jq
if ! command -v jq &>/dev/null; then
warn "jq not found — skipping VS Code customization"
exit 0
fi
# Get branch name
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "HEAD")
# Hash branch name to pick a color (deterministic)
hash=$(echo -n "$branch" | md5sum | cut -c1-8)
index=$((16#$hash % ${#COLORS[@]}))
color_pair="${COLORS[$index]}"
bg_color="${color_pair%%:*}"
hover_color="${color_pair##*:}"
color_name="${COLOR_NAMES[$index]}"
echo "Setting VS Code status bar to $color_name (based on branch '$branch')..."
# Create .vscode directory if needed
mkdir -p .vscode
settings_file=".vscode/settings.json"
# The color customizations to merge in
new_settings=$(cat <<EOF
{
"workbench.colorCustomizations": {
"statusBar.background": "$bg_color",
"statusBarItem.hoverBackground": "$hover_color"
}
}
EOF
)
if [[ -f "$settings_file" ]]; then
# Merge with existing settings (deep merge for colorCustomizations)
existing=$(cat "$settings_file")
merged=$(echo "$existing" | jq --argjson new "$new_settings" '
.["workbench.colorCustomizations"] = (
(.["workbench.colorCustomizations"] // {}) * $new["workbench.colorCustomizations"]
)
')
echo "$merged" > "$settings_file"
else
# Create new settings file
echo "$new_settings" > "$settings_file"
fi
# --- Step 3: Hide local changes from git using --skip-worktree ---
git update-index --skip-worktree "$settings_file" 2>/dev/null || true
echo "Done. VS Code status bar color set to $color_name."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment