| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- #!/usr/bin/env bash
- # svn_git_sync — sync current SVN working copy into a Git mirror
- # Usage:
- # svn_git_sync init [mirror_name]
- set -euo pipefail
- show_usage() {
- echo "Usage: $0 init [mirror_name]" >&2
- exit 1
- }
- subcommand="${1:-}"
- [[ -n "$subcommand" ]] || show_usage
- shift
- case "$subcommand" in
- init)
- ;;
- -h|--help|help)
- show_usage
- ;;
- *)
- echo "Unknown command: $subcommand" >&2
- show_usage
- ;;
- esac
- SRC_DIR="$(pwd)"
- MIRROR_ROOT="${GIT_SVN_MIRROR_ROOT:-$HOME/git_svn_mirror}"
- # Derive a collision-resistant mirror name from the full path (unless overridden).
- raw_name="${1:-$(pwd -P)}"
- BASE_NAME="$(printf "%s" "$raw_name" | sed 's#^[\\/]*##; s#[\\/]#_#g')"
- DEST="${MIRROR_ROOT}/${BASE_NAME}"
- echo "Exporting SVN working copy to $DEST (versioned files only)..."
- rm -rf -- "$DEST"
- mkdir -p "$MIRROR_ROOT"
- # Optionally compute total items upfront for a rough percentage
- total_items=""
- if total=$(svn list -R . 2>/dev/null | wc -l || true); then
- total_items="$total"
- fi
- start_ts="$(date +%s.%N)"
- elapsed() {
- local now
- now="${1:-$(date +%s.%N)}"
- awk -v s="$start_ts" -v n="$now" 'BEGIN{split(s,sa,".");split(n,na,".");printf "%.1f", (na[1]-sa[1]) + (na[2]-sa[2])/1e9}'
- }
- # Run export in background so we can emit our own progress based on files created.
- svn export --quiet . "$DEST" &
- export_pid=$!
- last_reported=-1
- while kill -0 "$export_pid" 2>/dev/null; do
- if [[ -d "$DEST" ]]; then
- current=$(find "$DEST" -mindepth 1 -print | wc -l)
- else
- current=0
- fi
- if [[ "$current" -ne "$last_reported" ]]; then
- elapsed_val="$(elapsed)"
- pct=""
- if [[ -n "$total_items" && "$total_items" -gt 0 ]]; then
- pct=$(awk -v c="$current" -v t="$total_items" 'BEGIN{printf(" (%.1f%%)", (c*100)/t)}')
- fi
- printf "[%ss] Exported %d items%s\n" "$elapsed_val" "$current" "$pct"
- last_reported="$current"
- fi
- sleep 1
- done
- wait "$export_pid"
- final_count=$(find "$DEST" -mindepth 1 -print | wc -l 2>/dev/null || echo 0)
- printf "[%ss] Exported %d items (done)\n" "$(elapsed)" "$final_count"
- cd "$DEST"
- echo "[$(elapsed) s] Initializing git repository..."
- GIT_QUIET=1 git init >/dev/null
- git config init.defaultBranch trunk || true
- git config core.fileMode false || true
- git config core.autocrlf true || true
- git config core.safecrlf false || true
- # Seed ignores for common noise (pyc/cache)
- if [[ ! -e .gitignore ]]; then
- echo "[$(elapsed) s] Adding default ignores (.pyc/__pycache__)..."
- printf "*.pyc\n__pycache__/\n" > .gitignore
- fi
- echo "[$(elapsed) s] Staging files..."
- git add -A
- echo "[$(elapsed) s] Creating initial commit..."
- GIT_QUIET=1 git commit -q -m "Import SVN snapshot" || true
- # Reuse the repo for the source working tree by linking .git back to the new repo.
- echo "[$(elapsed) s] Linking git metadata to source working tree..."
- DEST_ABS="$(pwd -P)"
- cd "$SRC_DIR"
- if [[ -e .git || -L .git ]]; then
- echo "[$(elapsed)s] Replacing existing .git in $SRC_DIR..."
- rm -rf -- .git
- fi
- printf "gitdir: %s/.git\n" "$DEST_ABS" > .git
- echo "[$(elapsed)s] Linked .git to $DEST_ABS/.git"
- # Normalize working tree to match repo filters (e.g., CRLF handling).
- echo "[$(elapsed) s] Syncing working tree to repo content..."
- GIT_QUIET=1 git checkout -q -- .
|