Skip to content

Instantly share code, notes, and snippets.

@InTEGr8or
Last active April 1, 2026 06:48
Show Gist options
  • Select an option

  • Save InTEGr8or/4d836249324738e904d279614dd2905b to your computer and use it in GitHub Desktop.

Select an option

Save InTEGr8or/4d836249324738e904d279614dd2905b to your computer and use it in GitHub Desktop.
Migrate important folders and files from one WSL instance to another.
#!/usr/bin/env bash
# --- CONFIGURATION ---
BRIDGE="/mnt/wsl/migrate_source"
CORE_ITEMS=(".ssh" ".gitconfig" ".config" ".bashrc" ".zshrc")
SCAN_DIRS=("repos")
REQUIRED_GROUPS=("docker" "mysql" "ollama" "onepassword" "onepassword-cli" "tomcat" "lxd")
MARKER=".migration_complete"
# --- ICONS & COLORS ---
ICON_PENDING=""
ICON_PARTIAL="🟡"
ICON_SYNCED="🟢"
ICON_PURGED="🔵"
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
BOLD='\033[1m'
# --- STATE ---
items=("${CORE_ITEMS[@]}")
for sd in "${SCAN_DIRS[@]}"; do
if [[ -d "$BRIDGE/$sd" ]]; then
for item in $(ls "$BRIDGE/$sd" 2>/dev/null); do
items+=("$sd/$item")
done
fi
done
current_idx=0
item_count=${#items[@]}
TARGET_HOME="$HOME"
move_cursor() { printf "\033[%d;%dH" "$1" "$2"; }
hide_cursor() { printf "\033[?25l"; }
show_cursor() { printf "\033[?25h"; }
draw_header() {
move_cursor 1 1
printf "\033[J"
echo -e "${BLUE}${BOLD}=== WSL Mirror Migration Dashboard ===${NC}"
echo -e "Source: ${YELLOW}$BRIDGE${NC} -> Target: ${GREEN}$TARGET_HOME${NC}"
echo -ne "${BOLD}System Groups: ${NC}"
local missing=()
for g in "${REQUIRED_GROUPS[@]}"; do
if ! getent group "$g" > /dev/null; then missing+=("$g"); fi
done
if [ ${#missing[@]} -eq 0 ]; then echo -e "${GREEN}All Migrated ✓${NC}"; else echo -e "${RED}MISSING: ${missing[*]}${NC} (Press 'g')"; fi
echo "----------------------------------------------------------------"
echo -ne "${BLUE}Disk Space (Target): ${NC}"
df -h / | tail -n 1 | awk '{print $3" used / "$4" avail ("$5")"}'
echo -e "${BOLD}Controls:${NC} [j/k] Up/Down | [s/r] Sync/Resync | [v] Verify | [g] Fix Groups | [q] Quit"
echo "----------------------------------------------------------------"
}
draw_items() {
for i in "${!items[@]}"; do
local item="${items[$i]}"
local prefix=" "
[[ $i -eq $current_idx ]] && prefix="${YELLOW}> ${NC}"
local status_icon="$ICON_PENDING"
local status_text="${RED}Pending${NC}"
if [[ -e "$TARGET_HOME/$item" ]]; then
if [[ -d "$TARGET_HOME/$item" ]]; then
if [[ -f "$TARGET_HOME/$item/$MARKER" ]]; then
local last_sync=$(date -r "$TARGET_HOME/$item/$MARKER" "+%H:%M")
status_icon="$ICON_SYNCED"
status_text="${GREEN}Synced ($last_sync)${NC}"
else
status_icon="$ICON_PARTIAL"
status_text="${YELLOW}Partial/Existing${NC}"
fi
else
status_icon="$ICON_SYNCED"
status_text="${GREEN}File Synced${NC}"
fi
if [[ ! -e "$BRIDGE/$item" ]]; then
status_icon="$ICON_PURGED"
status_text="${BLUE}Fully Migrated${NC}"
fi
fi
printf "%b%-35s | %b %-15b\n" "$prefix" "$item" "$status_icon" "$status_text"
done
}
sync_item() {
local item="${items[$current_idx]}"
local src="$BRIDGE/$item"
local dest="$TARGET_HOME/$item"
echo -e "\n\n${YELLOW}Mirroring $item (Source -> Target)...${NC}"
if [[ -d "$src" ]]; then
mkdir -p "$dest"
src_path="$src/"
dest_path="$dest/"
else
src_path="$src"
dest_path="$dest"
fi
if sudo rsync -a --info=progress2 --delete --numeric-ids --exclude='*:Zone.Identifier' "$src_path" "$dest_path"; then
sudo chown -R $USER:$USER "$dest"
[[ -d "$dest" ]] && touch "$dest/$MARKER"
echo -e "\n${GREEN}Sync Complete.${NC}"
else
echo -e "\n${RED}Sync failed.${NC}"
fi
read -n 1 -s
}
verify_item() {
local item="${items[$current_idx]}"
local src="$BRIDGE/$item"
local dest="$TARGET_HOME/$item"
if [[ ! -e "$dest" ]]; then
echo -e "\n\n${RED}Cannot verify. Folder does not exist in target.${NC}"
read -n 1 -s
return
fi
if [[ -d "$src" ]]; then src_path="$src/"; dest_path="$dest/"; else src_path="$src"; dest_path="$dest"; fi
echo -e "\n\n${BLUE}Verifying $item (Dry Run)...${NC}"
local diffs=$(sudo rsync -nrlpt --delete --numeric-ids --exclude='*:Zone.Identifier' "$src_path" "$dest_path" | grep -E '^deleting|[^/]$')
if [[ -z "$diffs" ]]; then
echo -e "${GREEN}PERFECT MATCH.${NC}"
[[ -d "$dest" ]] && touch "$dest/$MARKER"
else
echo -e "${YELLOW}DIFFERENCES FOUND:${NC}"
echo "$diffs" | head -n 10
fi
read -n 1 -s
}
purge_item() {
local item="${items[$current_idx]}"
echo -e "\n\n${RED}${BOLD}DANGER: Delete $item from OLD WSL?${NC}"
read -p "Type 'yes' to confirm: " confirm
if [[ "$confirm" == "yes" ]]; then
sudo rm -rf "$BRIDGE/$item"
echo -e "${GREEN}Purged.${NC}"
read -n 1 -s
fi
}
fix_groups() {
echo -e "\n\n${BLUE}Fixing system groups...${NC}"
for g in "${REQUIRED_GROUPS[@]}"; do
if ! getent group "$g" > /dev/null; then sudo groupadd "$g"; fi
done
echo -e "${GREEN}Done.${NC}"
read -n 1 -s
}
if [[ ! -d "$BRIDGE" ]]; then
echo -e "${RED}Error: Bridge not found at $BRIDGE${NC}"
echo "Please run this command in your OLD WSL distro:"
echo -e " ${YELLOW}mkdir -p $BRIDGE && sudo mount --bind \$HOME $BRIDGE${NC}"
exit 1
fi
hide_cursor
trap show_cursor EXIT
printf "\033[H\033[J"
while true; do
draw_header
draw_items
read -rsn1 key
case "$key" in
k) ((current_idx--)); [[ $current_idx -lt 0 ]] && current_idx=$((item_count - 1)) ;;
j) ((current_idx++)); [[ $current_idx -ge $item_count ]] && current_idx=0 ;;
s|r) sync_item ;;
v) verify_item ;;
g) fix_groups ;;
p) purge_item ;;
q) exit 0 ;;
esac
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment