Created
February 24, 2026 08:59
-
-
Save lamngockhuong/198bb1ecd0b8e976455d7b4281307f3a to your computer and use it in GitHub Desktop.
Git Worktree Manager - Manage worktrees in .worktrees/ directory
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
| #!/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