Skip to content

Instantly share code, notes, and snippets.

@lamngockhuong
Created February 24, 2026 08:59
Show Gist options
  • Select an option

  • Save lamngockhuong/198bb1ecd0b8e976455d7b4281307f3a to your computer and use it in GitHub Desktop.

Select an option

Save lamngockhuong/198bb1ecd0b8e976455d7b4281307f3a to your computer and use it in GitHub Desktop.
Git Worktree Manager - Manage worktrees in .worktrees/ directory
#!/bin/bash
# Git Worktree Manager - Manage worktrees in .worktrees/ directory
# Usage: ./scripts/worktree.sh <command> [args]
#
# Alias setup (add to ~/.bashrc or ~/.zshrc):
# alias wt='./scripts/worktree.sh'
#
# Then use: wt add feat/xyz, wt pr 123, wt remove feat/xyz, wt list, wt clean
set -e
WORKTREE_DIR=".worktrees"
REMOTE="origin"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_usage() {
echo -e "${BLUE}Git Worktree Manager${NC}"
echo ""
echo "Usage: $0 <command> [args]"
echo ""
echo "Commands:"
echo " add <branch> Create worktree from existing branch"
echo " pr <number> Create worktree from PR number"
echo " list List all worktrees"
echo " remove <name> Remove a worktree"
echo " clean Remove all worktrees"
echo " cd <name> Print path to worktree (use with: cd \$($0 cd <name>))"
echo ""
echo "Examples:"
echo " $0 add feature-auth"
echo " $0 pr 123"
echo " $0 remove pr-123"
echo " $0 clean"
}
ensure_worktree_dir() {
mkdir -p "$WORKTREE_DIR"
}
# Convert branch name to safe directory name (replace / with -)
sanitize_name() {
echo "$1" | tr '/' '-'
}
cmd_add() {
local branch="$1"
if [ -z "$branch" ]; then
echo -e "${RED}Error: Branch name required${NC}"
exit 1
fi
ensure_worktree_dir
local dir_name=$(sanitize_name "$branch")
local path="$WORKTREE_DIR/$dir_name"
if [ -d "$path" ]; then
echo -e "${YELLOW}Worktree already exists: $path${NC}"
exit 1
fi
echo -e "${BLUE}Creating worktree for branch: $branch${NC}"
git worktree add "$path" "$branch"
echo -e "${GREEN}Created: $path${NC}"
echo -e "Run: ${YELLOW}cd $path${NC}"
}
cmd_pr() {
local pr_number="$1"
if [ -z "$pr_number" ]; then
echo -e "${RED}Error: PR number required${NC}"
exit 1
fi
ensure_worktree_dir
local branch="pr-$pr_number"
local path="$WORKTREE_DIR/$branch"
if [ -d "$path" ]; then
echo -e "${YELLOW}Worktree already exists: $path${NC}"
exit 1
fi
echo -e "${BLUE}Fetching PR #$pr_number...${NC}"
git fetch "$REMOTE" "pull/$pr_number/head:$branch"
echo -e "${BLUE}Creating worktree...${NC}"
git worktree add "$path" "$branch"
echo -e "${GREEN}Created: $path${NC}"
echo -e "Run: ${YELLOW}cd $path${NC}"
}
cmd_list() {
echo -e "${BLUE}Worktrees:${NC}"
git worktree list
}
cmd_remove() {
local input="$1"
if [ -z "$input" ]; then
echo -e "${RED}Error: Worktree name required${NC}"
exit 1
fi
local name=$(sanitize_name "$input")
local path="$WORKTREE_DIR/$name"
if [ ! -d "$path" ]; then
echo -e "${RED}Worktree not found: $path${NC}"
exit 1
fi
echo -e "${BLUE}Removing worktree: $path${NC}"
git worktree remove "$path" --force 2>/dev/null || true
# Clean up local PR branch if exists
if [[ "$name" == pr-* ]]; then
git branch -D "$name" 2>/dev/null || true
fi
echo -e "${GREEN}Removed: $path${NC}"
}
cmd_clean() {
echo -e "${YELLOW}Removing all worktrees in $WORKTREE_DIR...${NC}"
if [ -d "$WORKTREE_DIR" ]; then
for dir in "$WORKTREE_DIR"/*; do
if [ -d "$dir" ]; then
local name=$(basename "$dir")
echo -e "${BLUE}Removing: $name${NC}"
git worktree remove "$dir" --force 2>/dev/null || true
# Clean up local PR branch
if [[ "$name" == pr-* ]]; then
git branch -D "$name" 2>/dev/null || true
fi
fi
done
fi
git worktree prune
echo -e "${GREEN}All worktrees cleaned${NC}"
}
cmd_cd() {
local input="$1"
if [ -z "$input" ]; then
echo -e "${RED}Error: Worktree name required${NC}" >&2
exit 1
fi
local name=$(sanitize_name "$input")
local path="$WORKTREE_DIR/$name"
if [ -d "$path" ]; then
echo "$path"
else
echo -e "${RED}Worktree not found: $path${NC}" >&2
exit 1
fi
}
# Main
case "${1:-}" in
add) cmd_add "$2" ;;
pr) cmd_pr "$2" ;;
list) cmd_list ;;
remove) cmd_remove "$2" ;;
clean) cmd_clean ;;
cd) cmd_cd "$2" ;;
*) print_usage ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment