Files
MovePatchesFromToMahle/sync-pull.sh
2026-02-21 16:44:57 +01:00

214 lines
8.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# sync-pull.sh — Import a git bundle from the shared folder into the current repo.
#
# Usage: ./sync-pull.sh [<share-dir>]
# Default share dir: $SYNC_SHARE or ~/fifiletrans
#
# The script lists available bundles for this repo, lets you choose one,
# fetches all branches from it into refs/sync/incoming/<branch>, shows
# what's new, and offers to merge or rebase each branch.
set -euo pipefail
# ── Config ────────────────────────────────────────────────────────────────────
SHARE_DIR="${1:-${SYNC_SHARE:-$HOME/fifiletrans}}"
# ── Sanity checks ─────────────────────────────────────────────────────────────
if ! git rev-parse --git-dir &>/dev/null; then
echo "ERROR: Not inside a git repository." >&2
exit 1
fi
if [ ! -d "$SHARE_DIR" ]; then
echo "ERROR: Share directory not found: $SHARE_DIR" >&2
exit 1
fi
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
# ── Find bundles for this repo ────────────────────────────────────────────────
BUNDLES=()
while IFS= read -r f; do
BUNDLES+=("$f")
done < <(find "$SHARE_DIR" -maxdepth 1 -name "${REPO_NAME}-from-*.bundle" | sort)
if [ ${#BUNDLES[@]} -eq 0 ]; then
echo "No bundles found for repo '$REPO_NAME' in $SHARE_DIR"
echo " (looking for: ${REPO_NAME}-from-*.bundle)"
exit 0
fi
# ── Let user pick a bundle ─────────────────────────────────────────────────────
echo "Available bundles for '$REPO_NAME':"
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: newest bundle (last in sorted list)
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")
echo ""
echo "Using: $BUNDLE_NAME"
# ── Verify the bundle ──────────────────────────────────────────────────────────
echo ""
echo "Verifying bundle..."
if ! git bundle verify "$BUNDLE_PATH"; then
echo ""
echo "ERROR: Bundle verification failed." >&2
echo "This usually means the bundle is incremental and your repo is missing" >&2
echo "the prerequisite commits. Make sure you have applied earlier bundles first." >&2
exit 1
fi
# ── List refs in bundle ────────────────────────────────────────────────────────
echo ""
echo "Branches in bundle:"
BUNDLE_REFS=()
while IFS= read -r line; do
ref=$(echo "$line" | awk '{print $2}')
BUNDLE_REFS+=("$ref")
branch="${ref#refs/heads/}"
echo " $branch"
done < <(git bundle list-heads "$BUNDLE_PATH" | grep 'refs/heads/')
if [ ${#BUNDLE_REFS[@]} -eq 0 ]; then
echo "No branch refs found in bundle." >&2
exit 1
fi
# ── Fetch each branch into refs/sync/incoming/<branch> ────────────────────────
echo ""
echo "Fetching..."
INCOMING_BRANCHES=()
for ref in "${BUNDLE_REFS[@]}"; do
branch="${ref#refs/heads/}"
incoming_ref="refs/sync/incoming/${branch}"
git fetch "$BUNDLE_PATH" "${ref}:${incoming_ref}"
INCOMING_BRANCHES+=("$branch")
echo " Fetched: $branch -> $incoming_ref"
done
# ── Show what's new per branch ────────────────────────────────────────────────
echo ""
echo "── New commits ──────────────────────────────────────────────────────────"
for branch in "${INCOMING_BRANCHES[@]}"; do
incoming_ref="refs/sync/incoming/${branch}"
if git rev-parse --verify "$branch" &>/dev/null; then
# Branch exists locally
ahead=$(git log --oneline "${branch}..${incoming_ref}" | wc -l)
behind=$(git log --oneline "${incoming_ref}..${branch}" | wc -l)
if [ "$ahead" -eq 0 ]; then
echo " $branch: already up to date"
continue
fi
echo " $branch: $ahead new commit(s) incoming, $behind local-only commit(s)"
git log --oneline "${branch}..${incoming_ref}" | sed 's/^/ + /'
if [ "$behind" -gt 0 ]; then
echo " (your local commits not in bundle:)"
git log --oneline "${incoming_ref}..${branch}" | sed 's/^/ * /'
fi
else
n=$(git log --oneline "${incoming_ref}" | wc -l)
echo " $branch: new branch with $n commit(s)"
git log --oneline "${incoming_ref}" | head -10 | sed 's/^/ + /'
fi
done
echo ""
# ── Integrate each branch ─────────────────────────────────────────────────────
CURRENT_BRANCH=$(git branch --show-current)
for branch in "${INCOMING_BRANCHES[@]}"; do
incoming_ref="refs/sync/incoming/${branch}"
if ! git rev-parse --verify "$branch" &>/dev/null; then
# New branch — just create it
read -rp "Create new local branch '$branch' from bundle? [Y/n] " ans
ans="${ans:-Y}"
if [[ "$ans" =~ ^[Yy] ]]; then
git branch "$branch" "$incoming_ref"
echo " Created branch '$branch'"
fi
continue
fi
ahead=$(git log --oneline "${branch}..${incoming_ref}" | wc -l)
if [ "$ahead" -eq 0 ]; then
continue # Nothing to do
fi
behind=$(git log --oneline "${incoming_ref}..${branch}" | wc -l)
echo "── Integrating: $branch ─────────────────────────────────────────────"
if [ "$behind" -eq 0 ]; then
# Fast-forward possible
echo " Fast-forward possible."
read -rp " Fast-forward '$branch'? [Y/n] " ans
ans="${ans:-Y}"
if [[ "$ans" =~ ^[Yy] ]]; then
# Switch to branch if needed
if [ "$CURRENT_BRANCH" != "$branch" ]; then
git checkout "$branch"
CURRENT_BRANCH="$branch"
fi
git merge --ff-only "$incoming_ref"
echo " Done."
fi
else
# Diverged — offer merge or rebase
echo " Branches have diverged (you have $behind local commit(s))."
echo " Options:"
echo " [m] merge — creates a merge commit"
echo " [r] rebase — replays your commits on top of incoming"
echo " [s] skip — leave for manual handling"
read -rp " Choice [m/r/s, default s]: " ans
ans="${ans:-s}"
case "$ans" in
m|M)
if [ "$CURRENT_BRANCH" != "$branch" ]; then
git checkout "$branch"
CURRENT_BRANCH="$branch"
fi
git merge "$incoming_ref" --no-edit
echo " Merged."
;;
r|R)
if [ "$CURRENT_BRANCH" != "$branch" ]; then
git checkout "$branch"
CURRENT_BRANCH="$branch"
fi
git rebase "$incoming_ref"
echo " Rebased."
;;
*)
echo " Skipped. Run manually:"
echo " git checkout $branch && git merge refs/sync/incoming/$branch"
;;
esac
fi
done
echo ""
echo "Import complete."
echo ""
echo "Tip: The fetched commits remain in refs/sync/incoming/<branch> until"
echo "the next sync-pull run. You can inspect them anytime with:"
echo " git log refs/sync/incoming/<branch>"