Skip to content

Instantly share code, notes, and snippets.

@mrtysn
Last active December 5, 2025 09:29
Show Gist options
  • Select an option

  • Save mrtysn/04e0c8e1f29668203d7d23fbb05ab630 to your computer and use it in GitHub Desktop.

Select an option

Save mrtysn/04e0c8e1f29668203d7d23fbb05ab630 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Pull of Wonders - Unity project sync script
# Cleans local changes, pulls latest code, and updates the foundation submodule
#
# Usage: pull_of_wonders [OPTIONS]
#
# Interactive Mode (default):
# Run without arguments for a wizard-based interface:
# 1) Sync to development
# 2) Sync to a release branch (with branch picker)
# 3) Just clean local changes (no pull)
# 4) Cancel
#
# Options:
# --auto-discard Automatically discard all local changes without prompting
# --yes, -y Automatically answer yes to all prompts (uses defaults)
# --force-fetch Force fetch even if recent fetch detected
# --branch=NAME Target branch for main repository (default: development)
# --submodule-branch=NAME Target branch for submodule (default: main)
# --auto-release Skip wizard, go straight to release branch picker
# --release-variants Include variant branches (hotfix, debug, etc.) in release picker
# --help, -h Show help message
#
# Examples:
# pull_of_wonders # Interactive wizard
# pull_of_wonders --yes # Auto-sync to development with defaults
# pull_of_wonders --auto-release # Pick a release branch
# pull_of_wonders --auto-release -y # Auto-pick latest release branch
# Set project directory
PROJECT_DIR="/Users/mert/dev/merge-of-wonders" # Default path
# Set defaults for automatic operation
AUTO_DISCARD=false
AUTO_YES=false
FAST_MODE=true # Use cached data when possible (5 min threshold)
TARGET_BRANCH="development" # Default main repository branch
SUBMODULE_BRANCH="main" # Default submodule branch
AUTO_RELEASE=false # Automatically detect latest release branch
INCLUDE_RELEASE_VARIANTS=false # Include variant branches (hotfix, debug, etc.)
# Function to detect the latest release branch
detect_latest_release() {
local include_variants=$1
echo "πŸ” Detecting release branches..."
# Only fetch release branches that were updated recently (last 30 days)
# This is much faster than fetching all branches
# Note: With a 2-week release cycle, 30 days covers ~2 releases with buffer
echo "⚑ Fetching recently updated release branches (last 30 days)..."
# Fetch only release branches from remote (much faster than fetching everything)
git fetch origin 'refs/heads/release-*:refs/remotes/origin/release-*' --prune 2>/dev/null || {
echo "Warning: Could not fetch branches, using local branch information"
}
# Get release branches with their last commit date, sorted by commit date
local branches_with_dates=$(git for-each-ref \
--sort=-committerdate \
--format='%(refname:short)|%(committerdate:iso8601)' \
'refs/remotes/origin/release-*' 2>/dev/null)
if [ -z "$branches_with_dates" ]; then
echo "❌ No release branches found"
return 1
fi
# Month name to number mapping (bash 3.x compatible - no associative arrays)
month_to_num() {
case "$1" in
jan) echo 1 ;; feb) echo 2 ;; mar) echo 3 ;; apr) echo 4 ;;
may) echo 5 ;; jun) echo 6 ;; jul) echo 7 ;; aug) echo 8 ;;
sep|sept) echo 9 ;; oct) echo 10 ;; nov) echo 11 ;; dec) echo 12 ;;
*) echo "" ;;
esac
}
# Arrays to store branch info
local branch_names=()
local branch_times=()
local branch_dates=()
local current_year=$(date +%Y)
local current_month=$(date +%-m)
while IFS='|' read -r branch commit_date; do
# Remove 'origin/' prefix
branch=$(echo "$branch" | sed 's/^origin\///')
# Skip empty lines
[ -z "$branch" ] && continue
# Extract the commit timestamp for filtering
local commit_timestamp=$(date -j -f "%Y-%m-%d %H:%M:%S %z" "$commit_date" "+%s" 2>/dev/null || \
date -d "$commit_date" "+%s" 2>/dev/null)
local now_timestamp=$(date +%s)
local days_ago=$(( (now_timestamp - commit_timestamp) / 86400 ))
# Only show branches updated in last 30 days
if [ $days_ago -gt 30 ]; then
continue
fi
# Check if this is a variant branch
local is_variant=false
if echo "$branch" | grep -qE -- "-(hotfix|debug|levels|dev-test|VFX|soil-anim|tutorial|addressable)"; then
is_variant=true
fi
# Skip variants if not including them
if [ "$is_variant" = true ] && [ "$include_variants" = false ]; then
continue
fi
# Format the relative time
local time_str
if [ $days_ago -eq 0 ]; then
time_str="today"
elif [ $days_ago -eq 1 ]; then
time_str="yesterday"
elif [ $days_ago -lt 7 ]; then
time_str="${days_ago} days ago"
elif [ $days_ago -lt 30 ]; then
local weeks=$((days_ago / 7))
time_str="${weeks} week(s) ago"
else
local months=$((days_ago / 30))
time_str="${months} month(s) ago"
fi
# Extract base branch name for date parsing
local base_branch=$(echo "$branch" | grep -oE "release-[a-z]+[0-9]+" | head -1)
local branch_date=0
if [ -n "$base_branch" ]; then
if [[ "$base_branch" =~ release-([a-z]+)([0-9]+) ]]; then
local month_name="${BASH_REMATCH[1]}"
local day="${BASH_REMATCH[2]}"
local month_num=$(month_to_num "$month_name")
if [ -n "$month_num" ]; then
day=$(printf "%02d" $day)
local branch_year=$current_year
if [ $month_num -gt $current_month ] && [ $((month_num - current_month)) -gt 6 ]; then
branch_year=$((current_year - 1))
fi
branch_date=$(printf "%04d%02d%02d" $branch_year $month_num $day)
fi
fi
fi
branch_names+=("$branch")
branch_times+=("$time_str")
branch_dates+=("$branch_date")
done <<< "$branches_with_dates"
local count=${#branch_names[@]}
if [ $count -eq 0 ]; then
echo "❌ No recently active release branches found (last 30 days)"
return 1
fi
# Find the latest branch by date (for default selection)
local latest_idx=0
local latest_date=0
for i in "${!branch_dates[@]}"; do
if [ "${branch_dates[$i]}" -gt "$latest_date" ]; then
latest_date="${branch_dates[$i]}"
latest_idx=$i
fi
done
# Display menu
echo ""
echo "πŸ“‹ Select a release branch:"
echo ""
for i in "${!branch_names[@]}"; do
local num=$((i + 1))
local marker=""
if [ $i -eq $latest_idx ]; then
marker=" [latest]"
fi
# Format the date as ISO (YYYY-MM-DD) from YYYYMMDD
local raw_date="${branch_dates[$i]}"
local iso_date=""
if [ -n "$raw_date" ] && [ "$raw_date" != "0" ]; then
iso_date="${raw_date:0:4}-${raw_date:4:2}-${raw_date:6:2}"
fi
echo " $num) ${branch_names[$i]} ($iso_date, ${branch_times[$i]})$marker"
done
echo ""
local default_num=$((latest_idx + 1))
if [ "$AUTO_YES" = true ]; then
RELEASE_CHOICE="$default_num"
echo "Auto-selecting: ${branch_names[$latest_idx]} (--yes flag is set)"
else
read -p "Choice [$default_num]: " RELEASE_CHOICE
RELEASE_CHOICE=${RELEASE_CHOICE:-$default_num}
fi
# Validate choice
if ! [[ "$RELEASE_CHOICE" =~ ^[0-9]+$ ]] || [ "$RELEASE_CHOICE" -lt 1 ] || [ "$RELEASE_CHOICE" -gt $count ]; then
echo "❌ Invalid choice"
return 1
fi
local selected_idx=$((RELEASE_CHOICE - 1))
TARGET_BRANCH="${branch_names[$selected_idx]}"
echo ""
echo "βœ… Selected: $TARGET_BRANCH"
return 0
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--auto-discard)
AUTO_DISCARD=true
shift
;;
--yes|-y)
AUTO_YES=true
shift
;;
--force-fetch)
FAST_MODE=false
shift
;;
--branch=*)
TARGET_BRANCH="${1#*=}"
shift
;;
--submodule-branch=*)
SUBMODULE_BRANCH="${1#*=}"
shift
;;
--auto-release)
AUTO_RELEASE=true
shift
;;
--release-variants)
INCLUDE_RELEASE_VARIANTS=true
shift
;;
--help|-h)
echo "Pull of Wonders - Unity project sync script"
echo ""
echo "Usage: pull_of_wonders [OPTIONS]"
echo ""
echo "INTERACTIVE MODE (default):"
echo " Run without arguments for a wizard-based interface:"
echo " 1) Sync to development"
echo " 2) Sync to a release branch (with branch picker)"
echo " 3) Just clean local changes (no pull)"
echo " 4) Cancel"
echo ""
echo "OPTIONS:"
echo " --yes, -y Auto-confirm all prompts (uses defaults)"
echo " --auto-discard Auto-discard local changes without prompting"
echo " --auto-release Skip wizard, go straight to release branch picker"
echo " --release-variants Include variant branches (hotfix, debug, etc.)"
echo " --force-fetch Force fetch even if recent fetch detected"
echo " --branch=NAME Target branch for main repo (default: development)"
echo " --submodule-branch=NAME Target branch for submodule (default: main)"
echo " --help, -h Show this help message"
echo ""
echo "EXAMPLES:"
echo " pull_of_wonders # Interactive wizard"
echo " pull_of_wonders --yes # Auto-sync to development"
echo " pull_of_wonders --auto-release # Pick a release branch"
echo " pull_of_wonders --auto-release -y # Auto-pick latest release"
echo " pull_of_wonders --branch=feature/x # Sync to specific branch"
exit 0
;;
--fast)
echo "Warning: --fast is deprecated. Caching is enabled by default, use --force-fetch to disable."
shift
;;
-*)
echo "Unknown option $1"
echo "Available options: --auto-discard, --yes/-y, --force-fetch, --branch=NAME, --submodule-branch=NAME, --auto-release, --release-variants, --help/-h"
echo "Use --help for detailed usage information."
exit 1
;;
*)
# Positional argument - treat as project directory
PROJECT_DIR="$1"
shift
;;
esac
done
# Function to check if fetch is recent (less than 5 minutes ago)
# Works for both regular repos and submodules
is_fetch_recent() {
local fetch_head_file
# Check if we're in a submodule (has .git file instead of .git directory)
if [ -f ".git" ]; then
# Submodule: .git is a file pointing to the real git directory
local git_dir=$(cat .git | sed 's/gitdir: //')
fetch_head_file="$git_dir/FETCH_HEAD"
elif [ -d ".git" ]; then
# Regular repo: .git is a directory
fetch_head_file=".git/FETCH_HEAD"
else
# Not in a git repo
return 1
fi
if [ -f "$fetch_head_file" ]; then
# Use a more reliable method to get file modification time
# Try different approaches for macOS
local fetch_time
# Method 1: Try stat with -t flag (should work on most macOS versions)
fetch_time=$(stat -t "%s" -f "%m" "$fetch_head_file" 2>/dev/null)
# Method 2: If that fails, try using ls and date
if [ -z "$fetch_time" ] || ! [[ "$fetch_time" =~ ^[0-9]+$ ]]; then
# Get the modification time using ls and convert to epoch
local mod_time_str=$(ls -l "$fetch_head_file" | awk '{print $6" "$7" "$8}')
fetch_time=$(date -j -f "%b %d %H:%M" "$mod_time_str" "+%s" 2>/dev/null)
fi
# Method 3: If still failing, use Python as fallback
if [ -z "$fetch_time" ] || ! [[ "$fetch_time" =~ ^[0-9]+$ ]]; then
fetch_time=$(python3 -c "import os; print(int(os.path.getmtime('$fetch_head_file')))" 2>/dev/null)
fi
if [ -n "$fetch_time" ] && [[ "$fetch_time" =~ ^[0-9]+$ ]]; then
local current_time=$(date +%s)
local diff=$((current_time - fetch_time))
if [ $diff -lt 300 ]; then # 5 minutes = 300 seconds
return 0 # Recent
fi
fi
fi
return 1 # Not recent or doesn't exist
}
echo "===== Pull of Wonders ====="
echo "Project: $PROJECT_DIR"
echo ""
cd "$PROJECT_DIR" || { echo "Error: Could not change to directory $PROJECT_DIR"; exit 1; }
# Verify we're in a git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: Not in a git repository"
exit 1
fi
# Function to check for any local changes (staged, unstaged, or untracked that matter)
has_local_changes() {
# Check for staged changes
if ! git diff --cached --quiet; then
return 0 # Has changes
fi
# Check for unstaged changes
if ! git diff --quiet; then
return 0 # Has changes
fi
# Check for untracked files that aren't gitignored
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
return 0 # Has changes
fi
return 1 # No changes
}
# Function to handle local changes
handle_local_changes() {
local context="$1" # "main" or "submodule"
local return_to_dir="$2" # Directory to return to on error (for submodules)
echo "You have local changes in $context that need to be handled"
if [ "$AUTO_DISCARD" = true ]; then
CHANGE_OPTION=1
echo "Auto-discarding all local changes (--auto-discard flag is set)"
else
echo " 1) Discard all changes [default]"
echo " 2) Stash changes (save for later)"
echo " 3) Keep changes (may cause conflicts)"
echo ""
read -p "Choice [1]: " CHANGE_OPTION
CHANGE_OPTION=${CHANGE_OPTION:-1}
fi
case $CHANGE_OPTION in
1)
echo "Discarding all local changes in $context..."
git reset --hard HEAD || {
echo "Error: Could not reset changes in $context"
[ -n "$return_to_dir" ] && cd "$return_to_dir"
exit 1
}
git clean -fd || {
echo "Error: Could not clean untracked files in $context"
[ -n "$return_to_dir" ] && cd "$return_to_dir"
exit 1
}
echo "βœ“ All local changes discarded"
return 0
;;
2)
git stash push -m "Auto-stash from pull_of_wonders - $context" || {
echo "Error: Could not stash changes in $context"
[ -n "$return_to_dir" ] && cd "$return_to_dir"
exit 1
}
echo "βœ“ Changes stashed"
return 1 # Return 1 to indicate stash was created
;;
3)
echo "⚠ Proceeding with local changes (may cause conflicts)"
return 2 # Return 2 to indicate changes were kept
;;
*)
echo "Invalid option, discarding changes..."
git reset --hard HEAD || {
echo "Error: Could not reset changes in $context"
[ -n "$return_to_dir" ] && cd "$return_to_dir"
exit 1
}
git clean -fd || {
echo "Error: Could not clean untracked files in $context"
[ -n "$return_to_dir" ] && cd "$return_to_dir"
exit 1
}
echo "βœ“ All local changes discarded"
return 0
;;
esac
}
CURRENT_BRANCH=$(git branch --show-current)
echo "Current branch: $CURRENT_BRANCH"
echo ""
# Main mode selection (unless flags override)
if [ "$AUTO_RELEASE" = false ] && [ "$TARGET_BRANCH" = "development" ]; then
echo "What would you like to do?"
echo ""
echo " 1) Sync to development [default]"
echo " 2) Sync to a release branch"
echo " 3) Just clean local changes (no pull)"
echo " 4) Cancel"
echo ""
read -p "Choice [1]: " MODE_CHOICE
MODE_CHOICE=${MODE_CHOICE:-1}
case $MODE_CHOICE in
1)
TARGET_BRANCH="development"
;;
2)
detect_latest_release "$INCLUDE_RELEASE_VARIANTS" || {
echo "Failed to detect release branch, exiting"
exit 1
}
;;
3)
# Just clean mode - discard changes and exit
echo ""
echo "🧹 Cleaning local changes only (no pull)..."
if has_local_changes; then
handle_local_changes "main repository"
else
echo "βœ“ Main repository is already clean"
fi
# Also clean submodule
local sub_path=""
if [ -d "Assets/Foundation" ] && [ -e "Assets/Foundation/.git" -o -d "$PROJECT_DIR/.git/modules/Assets/Foundation" ]; then
sub_path="Assets/Foundation"
elif [ -d "foundation" ] && [ -e "foundation/.git" ]; then
sub_path="foundation"
elif [ -d "Foundation" ] && [ -e "Foundation/.git" ]; then
sub_path="Foundation"
fi
if [ -n "$sub_path" ]; then
echo ""
echo "🧹 Cleaning submodule at $sub_path..."
cd "$sub_path" || { echo "Error: Could not change to submodule directory"; exit 1; }
if has_local_changes; then
handle_local_changes "foundation submodule" "$PROJECT_DIR"
else
echo "βœ“ Submodule is already clean"
fi
cd "$PROJECT_DIR"
fi
echo ""
echo "===== Done ====="
exit 0
;;
4|*)
if [ "$MODE_CHOICE" != "4" ] && [ -n "$MODE_CHOICE" ]; then
echo "Invalid choice."
fi
echo "Operation canceled"
exit 0
;;
esac
elif [ "$AUTO_RELEASE" = true ]; then
detect_latest_release "$INCLUDE_RELEASE_VARIANTS" || {
echo "Failed to detect release branch, falling back to default branch"
}
fi
# Display git status before cleaning
echo "Current git status:"
STATUS_OUTPUT=$(git status --short)
if [ -z "$STATUS_OUTPUT" ]; then
echo "βœ“ Working directory is clean"
else
echo "$STATUS_OUTPUT"
fi
echo "------------------------"
# Check if branch switch is needed
NEEDS_BRANCH_SWITCH=false
if [ "$CURRENT_BRANCH" != "$TARGET_BRANCH" ]; then
NEEDS_BRANCH_SWITCH=true
else
echo "βœ“ Already on target branch ($TARGET_BRANCH)"
fi
# Handle local changes first if they exist
MAIN_STASH_CREATED=false
if has_local_changes; then
handle_local_changes "main repository"
case $? in
1) MAIN_STASH_CREATED=true ;;
2) NEEDS_BRANCH_SWITCH=false ;; # Can't switch branches with conflicting changes
esac
fi
# Handle branch switching if needed and safe
if [ "$NEEDS_BRANCH_SWITCH" = true ]; then
echo ""
echo "πŸ”€ Branch: $CURRENT_BRANCH β†’ $TARGET_BRANCH"
echo ""
if [ "$AUTO_YES" = true ]; then
BRANCH_CHOICE="1"
echo "Auto-switching to $TARGET_BRANCH branch (--yes flag is set)"
else
echo "What would you like to do?"
echo " 1) Switch to $TARGET_BRANCH and continue [default]"
echo " 2) Stay on $CURRENT_BRANCH and continue"
echo " 3) Cancel"
echo ""
read -p "Choice [1]: " BRANCH_CHOICE
BRANCH_CHOICE=${BRANCH_CHOICE:-1}
fi
case $BRANCH_CHOICE in
1)
git checkout "$TARGET_BRANCH" || { echo "Error: Could not switch to $TARGET_BRANCH branch"; exit 1; }
;;
2)
echo "Staying on $CURRENT_BRANCH (will pull from $CURRENT_BRANCH instead)..."
TARGET_BRANCH="$CURRENT_BRANCH"
;;
3|*)
if [ "$BRANCH_CHOICE" != "3" ] && [ -n "$BRANCH_CHOICE" ]; then
echo "Invalid choice. Canceling."
else
echo "Operation canceled"
fi
exit 0
;;
esac
fi
echo "Cleaning untracked meta files..."
# List of patterns to clean (add more as needed)
META_PATTERNS=(
"Assets/Packages/Microsoft.*.meta"
"Assets/Packages/System.*.meta"
)
# Create a temporary file for git clean command
TEMP_FILE=$(mktemp)
for pattern in "${META_PATTERNS[@]}"; do
git ls-files --others --exclude-standard | grep "$pattern" >> "$TEMP_FILE"
done
# If there are files to clean
if [ -s "$TEMP_FILE" ]; then
echo "The following files will be removed:"
cat "$TEMP_FILE"
# Confirm before deletion
if [ "$AUTO_YES" = true ]; then
CONFIRM="y"
echo "Auto-confirming removal (--yes flag is set)"
else
read -p "Continue with removal? (y/n): " CONFIRM
fi
if [ "$CONFIRM" = "y" ]; then
while IFS= read -r file; do
rm -f "$file"
echo "Removed: $file"
done < "$TEMP_FILE"
echo "Cleanup completed"
else
echo "Cleanup skipped"
fi
else
echo "No matching untracked files found"
fi
rm -f "$TEMP_FILE"
# Fetch optimization based on cache age
SHOULD_FETCH=true
if [ "$FAST_MODE" = true ]; then
if is_fetch_recent; then
echo "⚑ Using cached fetch data (< 5 min old, use --force-fetch for fresh data)"
SHOULD_FETCH=false
else
echo "πŸ”„ Cache expired, fetching latest changes..."
fi
else
echo "πŸ”„ Force fetch mode - always getting latest data"
fi
if [ "$SHOULD_FETCH" = true ]; then
echo "Fetching latest changes..."
git fetch origin || { echo "Error: Could not fetch from origin"; exit 1; }
else
echo "βœ“ Using cached fetch data"
fi
# Check if local and remote commits differ before pulling
LOCAL_COMMIT=$(git rev-parse HEAD)
REMOTE_COMMIT=$(git rev-parse "origin/$TARGET_BRANCH" 2>/dev/null || echo "unknown")
if [ "$LOCAL_COMMIT" = "$REMOTE_COMMIT" ] && [ "$SHOULD_FETCH" = false ]; then
echo "βœ“ Already up to date (skipping pull)"
else
echo "Pulling latest changes from origin/$TARGET_BRANCH..."
git pull origin "$TARGET_BRANCH" || { echo "Error: Could not pull from origin/$TARGET_BRANCH"; exit 1; }
fi
# Pop the stash if we stashed changes
if [ "$MAIN_STASH_CREATED" = true ]; then
echo "Reapplying stashed changes..."
git stash pop || { echo "Warning: Could not pop stash - you may need to resolve conflicts manually"; }
echo "Stashed changes reapplied"
fi
# Update the foundation submodule
echo "Checking for 'foundation' submodule..."
# Check for different possible locations of the Foundation submodule
if [ -d "foundation" ] && [ -e "foundation/.git" ]; then
SUBMODULE_PATH="foundation"
elif [ -d "Foundation" ] && [ -e "Foundation/.git" ]; then
SUBMODULE_PATH="Foundation"
elif [ -d "Assets/Foundation" ] && [ -e "Assets/Foundation/.git" -o -d "$PROJECT_DIR/.git/modules/Assets/Foundation" ]; then
SUBMODULE_PATH="Assets/Foundation"
else
# Try to find the submodule using git
SUBMODULE_PATH=$(git config --file .gitmodules --get-regexp path | grep -i foundation | sed 's/.*path = //')
fi
if [ -n "$SUBMODULE_PATH" ]; then
echo "===== Updating 'foundation' submodule at path: $SUBMODULE_PATH ====="
cd "$SUBMODULE_PATH" || { echo "Error: Could not change to foundation directory at $SUBMODULE_PATH"; exit 1; }
# Verify we're in a git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: foundation is not a valid git repository"
cd "$PROJECT_DIR"
exit 1
fi
# Get current branch of the submodule
SUB_CURRENT_BRANCH=$(git branch --show-current)
echo "Current foundation branch: $SUB_CURRENT_BRANCH"
# Submodule fetch optimization
SUB_SHOULD_FETCH=true
if [ "$FAST_MODE" = true ]; then
if is_fetch_recent; then
echo "⚑ Using cached submodule data (< 5 min old)"
SUB_SHOULD_FETCH=false
else
echo "πŸ”„ Submodule cache expired, fetching..."
fi
else
echo "πŸ”„ Force fetching submodule data"
fi
if [ "$SUB_SHOULD_FETCH" = true ]; then
echo "Fetching latest changes for the foundation submodule..."
git fetch origin || { echo "Error: Could not fetch from origin in submodule"; cd "$PROJECT_DIR"; exit 1; }
else
echo "βœ“ Using cached submodule fetch data"
fi
# Handle submodule changes
SUB_STASH_CREATED=false
if has_local_changes; then
handle_local_changes "foundation submodule" "$PROJECT_DIR"
case $? in
1) SUB_STASH_CREATED=true ;;
esac
fi
# Switch to target branch if not already on it
if [ "$SUB_CURRENT_BRANCH" != "$SUBMODULE_BRANCH" ]; then
echo "Switching to $SUBMODULE_BRANCH branch in foundation submodule..."
git checkout "$SUBMODULE_BRANCH" || { echo "Error: Could not switch to $SUBMODULE_BRANCH branch in submodule"; cd "$PROJECT_DIR"; exit 1; }
fi
# Optimize submodule pull based on commit comparison
SUB_LOCAL_COMMIT=$(git rev-parse HEAD)
SUB_REMOTE_COMMIT=$(git rev-parse "origin/$SUBMODULE_BRANCH" 2>/dev/null || echo "unknown")
if [ "$SUB_LOCAL_COMMIT" = "$SUB_REMOTE_COMMIT" ] && [ "$SUB_SHOULD_FETCH" = false ]; then
echo "βœ“ Submodule already up to date (skipping pull)"
else
echo "Pulling latest changes from origin/$SUBMODULE_BRANCH for foundation submodule..."
git pull origin "$SUBMODULE_BRANCH" || { echo "Error: Could not pull from origin/$SUBMODULE_BRANCH in submodule"; cd "$PROJECT_DIR"; exit 1; }
fi
# Pop the stash if we stashed changes
if [ "$SUB_STASH_CREATED" = true ]; then
echo "Reapplying stashed changes in submodule..."
git stash pop || { echo "Warning: Could not pop stash in submodule - you may need to resolve conflicts manually"; }
echo "Stashed changes reapplied in submodule"
fi
# Return to the main project directory
cd "$PROJECT_DIR" || { echo "Error: Could not return to main project directory"; exit 1; }
echo "Foundation submodule updated successfully"
elif [ -f ".gitmodules" ] && grep -qi "foundation" ".gitmodules"; then
echo "Foundation submodule exists but isn't initialized"
if [ "$AUTO_YES" = true ]; then
INIT_SUB="y"
echo "Auto-initializing submodule (--yes flag is set)"
else
read -p "Do you want to initialize and update the submodule? (y/n): " INIT_SUB
fi
if [ "$INIT_SUB" = "y" ]; then
# Extract the submodule path from .gitmodules
SUBMODULE_PATH=$(git config --file .gitmodules --get-regexp path | grep -i foundation | sed 's/.*path = //')
if [ -n "$SUBMODULE_PATH" ]; then
echo "Initializing submodule at path: $SUBMODULE_PATH"
git submodule update --init --recursive "$SUBMODULE_PATH" || { echo "Error: Could not initialize foundation submodule"; exit 1; }
echo "Foundation submodule initialized and updated"
else
echo "Could not determine submodule path from .gitmodules"
git submodule update --init --recursive || { echo "Error: Could not initialize all submodules"; exit 1; }
echo "All submodules initialized and updated"
fi
fi
else
echo "No 'foundation' submodule found in this project (.gitmodules check)"
# One final check - use git directly to list submodules
if git submodule status | grep -qi "foundation"; then
echo "Submodule detected through git submodule status"
if [ "$AUTO_YES" = true ]; then
INIT_SUB="y"
echo "Auto-initializing all submodules (--yes flag is set)"
else
read -p "Do you want to initialize and update all submodules? (y/n): " INIT_SUB
fi
if [ "$INIT_SUB" = "y" ]; then
git submodule update --init --recursive || { echo "Error: Could not initialize all submodules"; exit 1; }
echo "All submodules initialized and updated"
fi
else
echo "No 'foundation' submodule found in this project"
fi
fi
echo "===== Operation completed successfully ====="
echo "Your local branch is now up-to-date with origin/$TARGET_BRANCH"
if [ -n "$SUBMODULE_PATH" ]; then
echo "And foundation submodule at path '$SUBMODULE_PATH' is up-to-date with origin/$SUBMODULE_BRANCH"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment