181 lines
7.2 KiB
Bash
Executable File
181 lines
7.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# sync-init-import.sh — Bootstrap a repository from scratch using an INIT bundle
|
|
# placed in the shared folder by sync-init-export.sh.
|
|
#
|
|
# Usage: ./sync-init-import.sh [<share-dir>] [<target-dir>]
|
|
#
|
|
# <share-dir> Shared folder containing the bundle (default: $SYNC_SHARE or ~/fifiletrans)
|
|
# <target-dir> Where to create the new repo (default: prompted interactively)
|
|
#
|
|
# After completion:
|
|
# - A fully functional git repo exists at <target-dir>
|
|
# - All branches and tags from the bundle are present
|
|
# - sync-push.sh and sync-pull.sh are copied into <target-dir>
|
|
# - Export checkpoints are set so the first sync-push is incremental
|
|
# - Both machines are now in sync
|
|
|
|
set -euo pipefail
|
|
|
|
# ── Config ────────────────────────────────────────────────────────────────────
|
|
SHARE_DIR="${1:-${SYNC_SHARE:-$HOME/fifiletrans}}"
|
|
TARGET_DIR="${2:-}"
|
|
|
|
# ── Sanity checks ─────────────────────────────────────────────────────────────
|
|
if [ ! -d "$SHARE_DIR" ]; then
|
|
echo "ERROR: Share directory not found: $SHARE_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── Find INIT bundles ─────────────────────────────────────────────────────────
|
|
BUNDLES=()
|
|
while IFS= read -r f; do
|
|
BUNDLES+=("$f")
|
|
done < <(find "$SHARE_DIR" -maxdepth 1 -name "*-INIT-from-*.bundle" | sort)
|
|
|
|
if [ ${#BUNDLES[@]} -eq 0 ]; then
|
|
echo "ERROR: No INIT bundle found in $SHARE_DIR" >&2
|
|
echo " (looking for: *-INIT-from-*.bundle)" >&2
|
|
echo " Run sync-init-export.sh on the source machine first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── Let user pick a bundle ─────────────────────────────────────────────────────
|
|
echo "Available INIT bundles:"
|
|
echo ""
|
|
for i in "${!BUNDLES[@]}"; do
|
|
b="${BUNDLES[$i]}"
|
|
size=$(du -sh "$b" | cut -f1)
|
|
name=$(basename "$b")
|
|
echo " [$((i+1))] $name ($size)"
|
|
done
|
|
echo ""
|
|
|
|
DEFAULT=${#BUNDLES[@]}
|
|
read -rp "Pick bundle [1-${#BUNDLES[@]}, default $DEFAULT]: " CHOICE
|
|
CHOICE="${CHOICE:-$DEFAULT}"
|
|
|
|
if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || [ "$CHOICE" -lt 1 ] || [ "$CHOICE" -gt "${#BUNDLES[@]}" ]; then
|
|
echo "Invalid choice." >&2
|
|
exit 1
|
|
fi
|
|
|
|
BUNDLE_PATH="${BUNDLES[$((CHOICE-1))]}"
|
|
BUNDLE_NAME=$(basename "$BUNDLE_PATH")
|
|
|
|
# Derive a default target dir name from bundle name: <repo>-INIT-from-...
|
|
REPO_NAME=$(echo "$BUNDLE_NAME" | sed 's/-INIT-from-.*//')
|
|
|
|
echo ""
|
|
echo "Using bundle : $BUNDLE_NAME"
|
|
|
|
# ── Determine target directory ─────────────────────────────────────────────────
|
|
if [ -z "$TARGET_DIR" ]; then
|
|
read -rp "Target directory [$HOME/$REPO_NAME]: " TARGET_DIR
|
|
TARGET_DIR="${TARGET_DIR:-$HOME/$REPO_NAME}"
|
|
fi
|
|
|
|
TARGET_DIR="$(realpath -m "$TARGET_DIR")"
|
|
echo "Target dir : $TARGET_DIR"
|
|
echo ""
|
|
|
|
if [ -e "$TARGET_DIR" ]; then
|
|
echo "ERROR: Target already exists: $TARGET_DIR" >&2
|
|
echo " Remove it first or choose a different path." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── Verify the bundle ──────────────────────────────────────────────────────────
|
|
echo "Verifying bundle..."
|
|
# INIT bundles are full — they have no prerequisites, so verify should always pass
|
|
git bundle verify "$BUNDLE_PATH"
|
|
echo ""
|
|
|
|
# ── List branches in bundle ────────────────────────────────────────────────────
|
|
echo "Branches in bundle:"
|
|
BUNDLE_BRANCHES=()
|
|
DEFAULT_BRANCH=""
|
|
while IFS= read -r line; do
|
|
ref=$(echo "$line" | awk '{print $2}')
|
|
if [[ "$ref" == refs/heads/* ]]; then
|
|
branch="${ref#refs/heads/}"
|
|
BUNDLE_BRANCHES+=("$branch")
|
|
echo " $branch"
|
|
# Prefer 'main', then 'master' as default checkout
|
|
if [ -z "$DEFAULT_BRANCH" ] || [ "$branch" = "main" ] || \
|
|
{ [ "$DEFAULT_BRANCH" != "main" ] && [ "$branch" = "master" ]; }; then
|
|
DEFAULT_BRANCH="$branch"
|
|
fi
|
|
fi
|
|
done < <(git bundle list-heads "$BUNDLE_PATH")
|
|
|
|
if [ ${#BUNDLE_BRANCHES[@]} -eq 0 ]; then
|
|
echo "ERROR: No branches found in bundle." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo "Will check out: $DEFAULT_BRANCH"
|
|
echo ""
|
|
|
|
# ── Create and populate the repository ───────────────────────────────────────
|
|
echo "[1/4] Initializing repository at $TARGET_DIR..."
|
|
mkdir -p "$TARGET_DIR"
|
|
cd "$TARGET_DIR"
|
|
git init
|
|
git checkout -b "$DEFAULT_BRANCH" 2>/dev/null || true
|
|
|
|
echo ""
|
|
echo "[2/4] Fetching all branches and tags from bundle..."
|
|
git fetch "$BUNDLE_PATH" 'refs/heads/*:refs/heads/*' 'refs/tags/*:refs/tags/*'
|
|
|
|
# Check out the default branch (fetch leaves us detached or on empty branch)
|
|
git checkout "$DEFAULT_BRANCH"
|
|
|
|
# Report what we got
|
|
echo ""
|
|
echo " Branches:"
|
|
git branch | sed 's/^/ /'
|
|
echo " Tags:"
|
|
git tag | sed 's/^/ /' || echo " (none)"
|
|
|
|
# ── Copy sync scripts into the new repo ───────────────────────────────────────
|
|
echo ""
|
|
echo "[3/4] Installing sync scripts..."
|
|
|
|
SCRIPTS=("sync-push.sh" "sync-pull.sh")
|
|
for script in "${SCRIPTS[@]}"; do
|
|
src="${SHARE_DIR}/${script}"
|
|
if [ -f "$src" ]; then
|
|
cp "$src" "${TARGET_DIR}/${script}"
|
|
chmod +x "${TARGET_DIR}/${script}"
|
|
echo " Installed : $script"
|
|
else
|
|
echo " WARNING: $script not found in $SHARE_DIR — copy it manually." >&2
|
|
fi
|
|
done
|
|
|
|
# ── Set export checkpoints so first sync-push is incremental ──────────────────
|
|
echo ""
|
|
echo "[4/4] Setting sync checkpoints..."
|
|
for branch in "${BUNDLE_BRANCHES[@]}"; do
|
|
tip=$(git rev-parse "$branch")
|
|
git config "sync.exported.${branch}" "$tip"
|
|
echo " sync.exported.$branch = ${tip:0:8}..."
|
|
done
|
|
|
|
# ── Done ───────────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "══════════════════════════════════════════════════════"
|
|
echo " Repository ready at: $TARGET_DIR"
|
|
echo "══════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "Both machines are now in sync."
|
|
echo ""
|
|
echo "Ongoing workflow:"
|
|
echo " cd $TARGET_DIR"
|
|
echo " ./sync-push.sh # after committing — export changes"
|
|
echo " ./sync-pull.sh # to receive changes from the other machine"
|
|
echo ""
|
|
echo "Tip: verify everything looks correct:"
|
|
echo " cd $TARGET_DIR && git log --oneline --graph --all"
|