git_infra

Git infra scripts for git.bracken.jp
git clone https://git.bracken.jp/git_infra.git
Log | Files | Refs | LICENSE

backup_git.bracken.jp.sh (2532B)


      1 #!/bin/sh
      2 # Backup script for git repos, invoked from Synology Task Scheduler.
      3 #
      4 # Invoke with a backup tag, typically "daily", "weekly", "monthly" and the
      5 # number of previous backups to be retained. Older backups that fall out of
      6 # retention are deleted.
      7 #
      8 #   backup_git.bracken.jp.sh daily 10
      9 #   backup_git.bracken.jp.sh weekly 100
     10 
     11 # Fail if any step fails, so we don't collect half-baked backups.
     12 set -e
     13 
     14 TAG=$1
     15 RETAIN_COUNT=$2
     16 
     17 # Check script arguments.
     18 if [ -z "$TAG" -o -z "$RETAIN_COUNT" ]; then
     19   echo "usage: $0 BACKUP_TAG RETAIN_COUNT"
     20   exit 1
     21 fi
     22 
     23 USER=chris
     24 HOST=git.bracken.jp
     25 PORT=1022
     26 
     27 # NOTE: the remote side runs a FORCED COMMAND configured in the server's
     28 # ~/.ssh/authorized_keys:
     29 #
     30 #   restrict,command="tar Jcf - -C /zroot/data git-repos" ssh-ed25519 ...
     31 #
     32 # Whatever command this script sends is ignored. The archive contains
     33 # git-repos/ at the top level (previously '*.git' and 'git_infra'), so restore
     34 # paths differ from archives taken before 2026-08.
     35 #
     36 # To change WHAT is backed up, edit authorized_keys on the server, not here.
     37 
     38 BACKUP_OUT_DIR="/volume1/Backups/git.bracken.jp/$TAG"
     39 BACKUP_OUT_FILE="$(date +"%Y-%m-%d_%H.%M").txz"
     40 # Deliberately on /volume1 rather than /tmp to ensure we have enough space.
     41 # Deliberately OUTSIDE $BACKUP_OUT_DIR, so a leftover .part file can never be
     42 # counted by the retention find below.
     43 BACKUP_TMP_FILE="/volume1/Backups/.git-backup-$TAG.$$.part"
     44 
     45 echo "[git backup] Backup of $HOST ($TAG) starting"
     46 mkdir -p "$BACKUP_OUT_DIR"
     47 
     48 # Write to a temp file outside the backup directory, and only move it into
     49 # place on success.
     50 if ssh "$USER@$HOST" -p "$PORT" > "$BACKUP_TMP_FILE"; then
     51   mv "$BACKUP_TMP_FILE" "$BACKUP_OUT_DIR/$BACKUP_OUT_FILE"
     52   echo "[git backup] Wrote archive $BACKUP_OUT_DIR/$BACKUP_OUT_FILE"
     53 else
     54   echo "[git backup] ERROR: transfer failed, no archive written" >&2
     55   rm -f "$BACKUP_TMP_FILE"
     56   exit 1
     57 fi
     58 
     59 # Sanity check: a valid xz archive is never this small. Catches the case where
     60 # the transfer "succeeded" but produced nothing useful.
     61 if [ "$(stat -c %s "$BACKUP_OUT_DIR/$BACKUP_OUT_FILE")" -lt 1000000 ]; then
     62   echo "[git backup] ERROR: archive suspiciously small, keeping it but not pruning" >&2
     63   exit 1
     64 fi
     65 
     66 # Delete archives past the retain count.
     67 EXPIRED_ARCHIVES="$(find "$BACKUP_OUT_DIR" -maxdepth 1 -type f  \
     68                     | sort -r | tail -n +$(($RETAIN_COUNT + 1)))"
     69 for f in $EXPIRED_ARCHIVES; do
     70   echo "[git backup] Deleting expired archive: $f"
     71   rm -f "$f"
     72 done
     73 
     74 echo "[git backup] Backup of $HOST ($TAG) complete"