Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:48:55 +08:00
commit f28999f19c
127 changed files with 62038 additions and 0 deletions

View File

@@ -0,0 +1,252 @@
#!/bin/bash
# Git Worktree Cleanup
# Interactive removal of old/merged worktrees
set -e
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m' # No Color
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${RED}✗ Error: Not in a git repository${NC}"
exit 1
fi
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
echo -e "${BLUE}╔════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Git Worktree Cleanup Tool ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════╝${NC}"
echo ""
# Get list of worktrees (excluding main)
WORKTREES=$(git worktree list --porcelain | grep -v "^$" | grep -v "^HEAD" | grep -v "^bare")
if [ -z "$WORKTREES" ]; then
echo -e "${YELLOW}No feature worktrees found${NC}"
echo "Only the main worktree exists."
exit 0
fi
# Arrays to store worktree info
declare -a PATHS
declare -a BRANCHES
declare -a STATUSES
declare -a MERGED_FLAGS
COUNT=0
# Parse worktrees
CURRENT_PATH=""
CURRENT_BRANCH=""
while IFS= read -r line; do
if [[ $line == worktree* ]]; then
CURRENT_PATH=$(echo "$line" | awk '{print $2}')
elif [[ $line == branch* ]]; then
CURRENT_BRANCH=$(echo "$line" | awk '{print $2}' | sed 's|refs/heads/||')
# Skip main worktree
if [ "$CURRENT_PATH" != "$REPO_ROOT" ] && [ -n "$CURRENT_BRANCH" ]; then
PATHS[$COUNT]="$CURRENT_PATH"
BRANCHES[$COUNT]="$CURRENT_BRANCH"
# Check if branch is merged into main
cd "$REPO_ROOT"
if git branch --merged main | grep -q "^[* ]*${CURRENT_BRANCH}$"; then
MERGED_FLAGS[$COUNT]="merged"
STATUSES[$COUNT]="${GREEN}✓ Merged to main${NC}"
else
MERGED_FLAGS[$COUNT]="not-merged"
# Check if worktree is clean
cd "$CURRENT_PATH"
if git diff-index --quiet HEAD -- 2>/dev/null; then
STATUSES[$COUNT]="${YELLOW}⚠ Not merged, clean${NC}"
else
CHANGE_COUNT=$(git status --short | wc -l | tr -d ' ')
STATUSES[$COUNT]="${RED}⚠ Not merged, $CHANGE_COUNT changes${NC}"
fi
fi
((COUNT++))
fi
CURRENT_PATH=""
CURRENT_BRANCH=""
fi
done <<< "$WORKTREES"
if [ $COUNT -eq 0 ]; then
echo -e "${YELLOW}No feature worktrees to clean up${NC}"
exit 0
fi
# Display worktrees
echo -e "${CYAN}Found $COUNT feature worktree(s):${NC}"
echo ""
for i in "${!PATHS[@]}"; do
echo -e "${CYAN}[$((i+1))]${NC} ${BRANCHES[$i]}"
echo -e " Path: ${GRAY}${PATHS[$i]}${NC}"
echo -e " Status: ${STATUSES[$i]}"
echo ""
done
# Prompt for selection
echo -e "${YELLOW}Which worktrees would you like to remove?${NC}"
echo -e " Enter numbers separated by spaces (e.g., '1 3 4')"
echo -e " Enter 'merged' to remove all merged worktrees"
echo -e " Enter 'all' to remove all worktrees"
echo -e " Press Enter to cancel"
echo ""
read -p "Selection: " SELECTION
# Parse selection
if [ -z "$SELECTION" ]; then
echo -e "${GRAY}Cancelled${NC}"
exit 0
fi
# Build list of indices to remove
declare -a TO_REMOVE
if [ "$SELECTION" = "all" ]; then
for i in "${!PATHS[@]}"; do
TO_REMOVE+=($i)
done
elif [ "$SELECTION" = "merged" ]; then
for i in "${!PATHS[@]}"; do
if [ "${MERGED_FLAGS[$i]}" = "merged" ]; then
TO_REMOVE+=($i)
fi
done
if [ ${#TO_REMOVE[@]} -eq 0 ]; then
echo -e "${YELLOW}No merged worktrees found${NC}"
exit 0
fi
else
# Parse space-separated numbers
for num in $SELECTION; do
# Validate number
if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le "$COUNT" ]; then
TO_REMOVE+=($((num - 1)))
else
echo -e "${RED}Invalid selection: $num${NC}"
exit 1
fi
done
fi
# Confirmation
echo ""
echo -e "${YELLOW}About to remove ${#TO_REMOVE[@]} worktree(s):${NC}"
echo ""
for idx in "${TO_REMOVE[@]}"; do
echo -e " ${RED}${NC} ${BRANCHES[$idx]}"
echo -e " ${GRAY}${PATHS[$idx]}${NC}"
done
echo ""
# Extra warning for non-merged branches
HAS_UNMERGED=false
for idx in "${TO_REMOVE[@]}"; do
if [ "${MERGED_FLAGS[$idx]}" != "merged" ]; then
HAS_UNMERGED=true
break
fi
done
if [ "$HAS_UNMERGED" = true ]; then
echo -e "${RED}⚠ WARNING: Some branches are NOT merged!${NC}"
echo -e "${RED} You may lose uncommitted work.${NC}"
echo ""
fi
read -p "Are you sure? (yes/no): " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
echo -e "${GRAY}Cancelled${NC}"
exit 0
fi
# Remove worktrees
echo ""
echo -e "${BLUE}Removing worktrees...${NC}"
echo ""
cd "$REPO_ROOT"
for idx in "${TO_REMOVE[@]}"; do
WORKTREE_PATH="${PATHS[$idx]}"
BRANCH_NAME="${BRANCHES[$idx]}"
echo -e "${CYAN}${NC} Removing worktree: ${BRANCH_NAME}"
# Remove worktree
if git worktree remove "$WORKTREE_PATH" --force 2>/dev/null; then
echo -e " ${GREEN}${NC} Worktree removed"
else
# Try manual removal if git worktree remove fails
if [ -d "$WORKTREE_PATH" ]; then
rm -rf "$WORKTREE_PATH"
git worktree prune
echo -e " ${GREEN}${NC} Worktree removed (manual cleanup)"
else
echo -e " ${YELLOW}${NC} Worktree already removed"
fi
fi
# Ask about deleting the branch
if [ "${MERGED_FLAGS[$idx]}" = "merged" ]; then
# Auto-delete merged branches
git branch -d "$BRANCH_NAME" 2>/dev/null && \
echo -e " ${GREEN}${NC} Branch deleted" || \
echo -e " ${GRAY}Branch already deleted or doesn't exist${NC}"
else
# Prompt for unmerged branches
echo -e " ${YELLOW}Branch '$BRANCH_NAME' is not merged.${NC}"
read -p " Delete branch anyway? (y/n): " DELETE_BRANCH
if [[ "$DELETE_BRANCH" =~ ^[Yy]$ ]]; then
git branch -D "$BRANCH_NAME" 2>/dev/null && \
echo -e " ${GREEN}${NC} Branch force-deleted" || \
echo -e " ${GRAY}Could not delete branch${NC}"
else
echo -e " ${GRAY}Branch kept${NC}"
fi
fi
echo ""
done
# Prune any stale references
echo -e "${CYAN}${NC} Cleaning up stale references..."
git worktree prune
echo -e "${GREEN}${NC} Done"
echo ""
# Summary
echo -e "${GREEN}✓ Cleanup complete!${NC}"
echo ""
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo -e "Removed: ${CYAN}${#TO_REMOVE[@]}${NC} worktree(s)"
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo ""
# Show remaining worktrees
REMAINING=$(git worktree list | wc -l)
if [ $REMAINING -gt 1 ]; then
echo -e "${CYAN}Remaining worktrees: $((REMAINING - 1))${NC}"
echo -e "${GRAY}Run 'scripts/list_worktrees.sh' to see them${NC}"
else
echo -e "${CYAN}No feature worktrees remaining${NC}"
fi
echo ""

View File

@@ -0,0 +1,211 @@
#!/bin/bash
# Git Worktree Creator for Claude Code
# Makes creating worktrees super simple with interactive prompts
set -e
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Default values
BASE_BRANCH="main"
CUSTOM_DIR=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--base)
BASE_BRANCH="$2"
shift 2
;;
--dir)
CUSTOM_DIR="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --base <branch> Base branch to branch from (default: main)"
echo " --dir <path> Custom directory for worktree"
echo " -h, --help Show this help"
echo ""
echo "Example:"
echo " $0"
echo " $0 --base develop"
echo " $0 --dir ~/worktrees/my-feature"
exit 0
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
echo "Use -h for help"
exit 1
;;
esac
done
echo -e "${BLUE}╔════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Git Worktree Creator for Claude Code ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════╝${NC}"
echo ""
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${RED}✗ Error: Not in a git repository${NC}"
echo " Please run this script from within a git repository."
exit 1
fi
# Get repository info
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
CURRENT_BRANCH=$(git branch --show-current)
echo -e "${GREEN}${NC} Found git repository: ${CYAN}$REPO_NAME${NC}"
echo -e "${GREEN}${NC} Current branch: ${CYAN}$CURRENT_BRANCH${NC}"
echo ""
# Prompt for feature name
echo -e "${YELLOW}What are you building?${NC}"
echo -e " Enter a feature name (e.g., feature-api, refactor-auth, hotfix-bug)"
echo ""
read -p "Feature name: " FEATURE_NAME
# Validate feature name
if [ -z "$FEATURE_NAME" ]; then
echo -e "${RED}✗ Feature name cannot be empty${NC}"
exit 1
fi
# Sanitize feature name (replace spaces with hyphens, lowercase)
FEATURE_NAME=$(echo "$FEATURE_NAME" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed 's/[^a-z0-9-]//g')
if [ -z "$FEATURE_NAME" ]; then
echo -e "${RED}✗ Invalid feature name${NC}"
echo " Use only letters, numbers, and hyphens"
exit 1
fi
echo -e "${GREEN}${NC} Using branch name: ${CYAN}$FEATURE_NAME${NC}"
echo ""
# Check if branch already exists
if git show-ref --verify --quiet "refs/heads/$FEATURE_NAME"; then
echo -e "${YELLOW}${NC} Branch ${CYAN}$FEATURE_NAME${NC} already exists"
echo ""
read -p "Use existing branch? (y/n): " USE_EXISTING
if [[ ! "$USE_EXISTING" =~ ^[Yy]$ ]]; then
echo -e "${RED}✗ Cancelled${NC}"
exit 1
fi
CREATE_BRANCH=false
else
# Prompt for base branch
echo -e "${YELLOW}Base branch${NC} (press Enter for default: $BASE_BRANCH)"
read -p "Base branch: " CUSTOM_BASE
if [ -n "$CUSTOM_BASE" ]; then
BASE_BRANCH="$CUSTOM_BASE"
fi
# Verify base branch exists
if ! git show-ref --verify --quiet "refs/heads/$BASE_BRANCH"; then
echo -e "${RED}✗ Base branch '$BASE_BRANCH' does not exist${NC}"
exit 1
fi
echo -e "${GREEN}${NC} Will create branch from: ${CYAN}$BASE_BRANCH${NC}"
CREATE_BRANCH=true
fi
echo ""
# Determine worktree directory
if [ -n "$CUSTOM_DIR" ]; then
WORKTREE_DIR="$CUSTOM_DIR"
else
# Default: create sibling directory
PARENT_DIR=$(dirname "$REPO_ROOT")
WORKTREE_DIR="$PARENT_DIR/${REPO_NAME}-${FEATURE_NAME}"
fi
# Check if directory already exists
if [ -d "$WORKTREE_DIR" ]; then
echo -e "${RED}✗ Directory already exists: $WORKTREE_DIR${NC}"
echo " Please remove it first or use --dir to specify a different location"
exit 1
fi
echo -e "${BLUE}Creating worktree...${NC}"
echo ""
echo -e " ${CYAN}Branch:${NC} $FEATURE_NAME"
echo -e " ${CYAN}Location:${NC} $WORKTREE_DIR"
echo ""
# Create the worktree
if [ "$CREATE_BRANCH" = true ]; then
echo -e "${CYAN}${NC} Creating branch from $BASE_BRANCH..."
git worktree add -b "$FEATURE_NAME" "$WORKTREE_DIR" "$BASE_BRANCH"
else
echo -e "${CYAN}${NC} Using existing branch $FEATURE_NAME..."
git worktree add "$WORKTREE_DIR" "$FEATURE_NAME"
fi
echo ""
echo -e "${GREEN}✓ Worktree created successfully!${NC}"
echo ""
# Success message with instructions
echo -e "${BLUE}╔════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Next Steps ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${CYAN}1. Open Claude Code in the new worktree:${NC}"
echo -e " ${YELLOW}cd $WORKTREE_DIR${NC}"
echo -e " ${YELLOW}code .${NC} (or your editor command)"
echo ""
echo -e "${CYAN}2. In Claude Code, run /init to orient Claude:${NC}"
echo -e " ${YELLOW}/init${NC}"
echo ""
echo -e "${CYAN}3. Give Claude your task:${NC}"
echo -e " ${YELLOW}\"Build the $FEATURE_NAME feature\"${NC}"
echo ""
echo -e "${CYAN}4. When done, merge back to main:${NC}"
echo -e " ${YELLOW}cd $REPO_ROOT${NC}"
echo -e " ${YELLOW}git checkout main${NC}"
echo -e " ${YELLOW}git merge $FEATURE_NAME${NC}"
echo ""
echo -e "${CYAN}5. Clean up the worktree:${NC}"
echo -e " ${YELLOW}scripts/cleanup_worktrees.sh${NC}"
echo ""
# Offer to open in editor
echo ""
read -p "Open in VS Code now? (y/n): " OPEN_NOW
if [[ "$OPEN_NOW" =~ ^[Yy]$ ]]; then
if command -v code &> /dev/null; then
echo -e "${CYAN}${NC} Opening in VS Code..."
code "$WORKTREE_DIR"
echo -e "${GREEN}${NC} VS Code opened!"
echo ""
echo -e "${YELLOW}Remember to run /init when Claude Code loads!${NC}"
else
echo -e "${YELLOW}${NC} VS Code command 'code' not found"
echo " Please open manually: $WORKTREE_DIR"
fi
fi
echo ""
echo -e "${GREEN}✓ Done!${NC}"
echo ""
# Summary
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo -e "Worktree: ${CYAN}$WORKTREE_DIR${NC}"
echo -e "Branch: ${CYAN}$FEATURE_NAME${NC}"
echo -e "Status: ${GREEN}Ready for Claude Code${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"

View File

@@ -0,0 +1,117 @@
#!/bin/bash
# List Git Worktrees
# Shows all active worktrees with clean formatting
set -e
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m' # No Color
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${RED}✗ Error: Not in a git repository${NC}"
exit 1
fi
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
echo -e "${BLUE}╔════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Git Worktrees - $REPO_NAME"
printf "${BLUE}${NC}"
printf "%*s${BLUE}${NC}\n" $((47 - ${#REPO_NAME})) ""
echo -e "${BLUE}╚════════════════════════════════════════════════╝${NC}"
echo ""
# Get worktree list
WORKTREES=$(git worktree list --porcelain)
if [ -z "$WORKTREES" ]; then
echo -e "${YELLOW}No worktrees found${NC}"
exit 0
fi
# Parse and display worktrees
MAIN_WORKTREE=""
FEATURE_WORKTREES=""
WORKTREE_COUNT=0
while IFS= read -r line; do
if [[ $line == worktree* ]]; then
CURRENT_PATH=$(echo "$line" | awk '{print $2}')
elif [[ $line == branch* ]]; then
CURRENT_BRANCH=$(echo "$line" | awk '{print $2}' | sed 's|refs/heads/||')
elif [[ $line == "" ]]; then
# End of worktree block
if [ -n "$CURRENT_PATH" ]; then
((WORKTREE_COUNT++))
# Get status
cd "$CURRENT_PATH"
if git diff-index --quiet HEAD -- 2>/dev/null; then
STATUS="${GREEN}clean${NC}"
else
CHANGE_COUNT=$(git status --short | wc -l | tr -d ' ')
STATUS="${YELLOW}$CHANGE_COUNT uncommitted changes${NC}"
fi
# Get last commit info
LAST_COMMIT=$(git log -1 --format="%cr" 2>/dev/null || echo "no commits")
# Check if it's the main worktree
if [ "$CURRENT_PATH" = "$REPO_ROOT" ]; then
MAIN_WORKTREE+="📁 ${CYAN}Main Worktree${NC}\n"
MAIN_WORKTREE+=" Path: ${GRAY}$CURRENT_PATH${NC}\n"
MAIN_WORKTREE+=" Branch: ${CYAN}$CURRENT_BRANCH${NC}\n"
MAIN_WORKTREE+=" Status: $STATUS\n"
MAIN_WORKTREE+=" Last: ${GRAY}$LAST_COMMIT${NC}\n"
else
FEATURE_WORKTREES+="📦 ${CYAN}$CURRENT_BRANCH${NC}\n"
FEATURE_WORKTREES+=" Path: ${GRAY}$CURRENT_PATH${NC}\n"
FEATURE_WORKTREES+=" Status: $STATUS\n"
FEATURE_WORKTREES+=" Last: ${GRAY}$LAST_COMMIT${NC}\n\n"
fi
fi
# Reset for next worktree
CURRENT_PATH=""
CURRENT_BRANCH=""
fi
done <<< "$WORKTREES"
# Display main worktree
if [ -n "$MAIN_WORKTREE" ]; then
echo -e "$MAIN_WORKTREE"
echo ""
fi
# Display feature worktrees
if [ -n "$FEATURE_WORKTREES" ]; then
echo -e "${BLUE}Feature Worktrees:${NC}"
echo ""
echo -e "$FEATURE_WORKTREES"
else
echo -e "${GRAY}No feature worktrees (only main)${NC}"
echo ""
fi
# Summary
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo -e "Total worktrees: ${CYAN}$WORKTREE_COUNT${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo ""
# Tips
if [ $WORKTREE_COUNT -gt 1 ]; then
echo -e "${GRAY}Tip: Run 'scripts/cleanup_worktrees.sh' to remove old worktrees${NC}"
else
echo -e "${GRAY}Tip: Run 'scripts/create_worktree.sh' to create a new worktree${NC}"
fi
echo ""

View File

@@ -0,0 +1,232 @@
#!/bin/bash
# Git Worktree Sync
# Keep worktree branch up-to-date with main branch
set -e
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m' # No Color
# Default values
TARGET_WORKTREE=""
BASE_BRANCH="main"
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--base)
BASE_BRANCH="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [WORKTREE_PATH] [OPTIONS]"
echo ""
echo "Syncs a worktree with the latest changes from main (or specified base branch)."
echo ""
echo "Arguments:"
echo " WORKTREE_PATH Path to worktree (optional if run from within worktree)"
echo ""
echo "Options:"
echo " --base <branch> Base branch to sync from (default: main)"
echo " -h, --help Show this help"
echo ""
echo "Examples:"
echo " # From within a worktree"
echo " $0"
echo ""
echo " # Specify worktree path"
echo " $0 ../repo-feature-api"
echo ""
echo " # Sync from develop instead of main"
echo " $0 --base develop"
exit 0
;;
*)
TARGET_WORKTREE="$1"
shift
;;
esac
done
echo -e "${BLUE}╔════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Git Worktree Sync Tool ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════╝${NC}"
echo ""
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${RED}✗ Error: Not in a git repository${NC}"
exit 1
fi
# Determine target worktree
if [ -z "$TARGET_WORKTREE" ]; then
# Use current directory
TARGET_WORKTREE=$(pwd)
echo -e "${CYAN}${NC} Using current directory"
else
# Use specified path
if [ ! -d "$TARGET_WORKTREE" ]; then
echo -e "${RED}✗ Error: Directory not found: $TARGET_WORKTREE${NC}"
exit 1
fi
cd "$TARGET_WORKTREE"
echo -e "${CYAN}${NC} Using specified worktree: $TARGET_WORKTREE"
fi
# Verify we're in a git worktree
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${RED}✗ Error: Not a git worktree: $TARGET_WORKTREE${NC}"
exit 1
fi
CURRENT_BRANCH=$(git branch --show-current)
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
echo -e "${GREEN}${NC} Repository: ${CYAN}$REPO_NAME${NC}"
echo -e "${GREEN}${NC} Current branch: ${CYAN}$CURRENT_BRANCH${NC}"
echo ""
# Check if current branch is the base branch
if [ "$CURRENT_BRANCH" = "$BASE_BRANCH" ]; then
echo -e "${YELLOW}${NC} You're on the base branch ($BASE_BRANCH)"
echo " Nothing to sync!"
exit 0
fi
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
echo -e "${YELLOW}⚠ Warning: You have uncommitted changes${NC}"
echo ""
git status --short
echo ""
read -p "Stash changes and continue? (y/n): " STASH_CHANGES
if [[ ! "$STASH_CHANGES" =~ ^[Yy]$ ]]; then
echo -e "${GRAY}Cancelled${NC}"
exit 1
fi
echo -e "${CYAN}${NC} Stashing changes..."
git stash push -m "Auto-stash before sync at $(date)"
STASHED=true
echo -e "${GREEN}${NC} Changes stashed"
echo ""
else
STASHED=false
fi
# Fetch latest
echo -e "${CYAN}${NC} Fetching latest from remote..."
git fetch origin
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Failed to fetch from remote${NC}"
if [ "$STASHED" = true ]; then
echo -e "${CYAN}${NC} Restoring stashed changes..."
git stash pop
fi
exit 1
fi
echo -e "${GREEN}${NC} Fetched latest"
echo ""
# Check if base branch exists locally
if ! git show-ref --verify --quiet "refs/heads/$BASE_BRANCH"; then
echo -e "${RED}✗ Base branch '$BASE_BRANCH' does not exist locally${NC}"
if [ "$STASHED" = true ]; then
echo -e "${CYAN}${NC} Restoring stashed changes..."
git stash pop
fi
exit 1
fi
# Show what we're about to do
BEHIND_COUNT=$(git rev-list --count HEAD..origin/$BASE_BRANCH 2>/dev/null || echo "0")
if [ "$BEHIND_COUNT" = "0" ]; then
echo -e "${GREEN}${NC} Already up-to-date with $BASE_BRANCH!"
if [ "$STASHED" = true ]; then
echo ""
echo -e "${CYAN}${NC} Restoring stashed changes..."
git stash pop
echo -e "${GREEN}${NC} Changes restored"
fi
exit 0
fi
echo -e "${YELLOW}Your branch is $BEHIND_COUNT commit(s) behind $BASE_BRANCH${NC}"
echo ""
echo -e "${CYAN}Recent commits in $BASE_BRANCH:${NC}"
git log --oneline HEAD..origin/$BASE_BRANCH | head -5
echo ""
read -p "Merge $BASE_BRANCH into $CURRENT_BRANCH? (y/n): " CONFIRM_MERGE
if [[ ! "$CONFIRM_MERGE" =~ ^[Yy]$ ]]; then
echo -e "${GRAY}Cancelled${NC}"
if [ "$STASHED" = true ]; then
echo -e "${CYAN}${NC} Restoring stashed changes..."
git stash pop
fi
exit 0
fi
# Perform the merge
echo ""
echo -e "${CYAN}${NC} Merging $BASE_BRANCH into $CURRENT_BRANCH..."
if git merge origin/$BASE_BRANCH -m "Merge $BASE_BRANCH into $CURRENT_BRANCH"; then
echo -e "${GREEN}${NC} Merge successful!"
# Show summary
echo ""
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo -e "Branch: ${CYAN}$CURRENT_BRANCH${NC}"
echo -e "Status: ${GREEN}Synced with $BASE_BRANCH${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
# Restore stashed changes if any
if [ "$STASHED" = true ]; then
echo ""
echo -e "${CYAN}${NC} Restoring stashed changes..."
if git stash pop; then
echo -e "${GREEN}${NC} Changes restored successfully"
else
echo -e "${RED}${NC} Conflicts while restoring stashed changes"
echo " Resolve conflicts manually, then run: git stash drop"
exit 1
fi
fi
echo ""
echo -e "${GREEN}✓ Sync complete!${NC}"
echo ""
else
# Merge failed (likely conflicts)
echo -e "${RED}✗ Merge conflicts detected${NC}"
echo ""
echo -e "${YELLOW}Conflicting files:${NC}"
git diff --name-only --diff-filter=U
echo ""
echo -e "${CYAN}To resolve:${NC}"
echo " 1. Fix conflicts in the files above"
echo " 2. Stage resolved files: ${YELLOW}git add <file>${NC}"
echo " 3. Complete the merge: ${YELLOW}git commit${NC}"
if [ "$STASHED" = true ]; then
echo ""
echo -e "${YELLOW}Note: Stashed changes will be restored after merge is complete${NC}"
echo " Run: ${YELLOW}git stash pop${NC}"
fi
exit 1
fi