gitpages-mirror-git.sh (2259B)
1 #!/bin/sh 2 # 3 # Copyright (c) 2026 Fred Großkopf 4 # 5 # Permission to use, copy, modify, and/or distribute this software for any 6 # purpose with or without fee is hereby granted, provided that the above 7 # copyright notice and this permission notice appear in all copies. 8 # 9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17 set -eu 18 19 usage() { 20 cat << EOF 21 usage: $(basename "$0") SRC DST_DIR 22 23 Mirror bare git repositories to destination. 24 25 SRC Bare repo OR directory of *.git repos 26 DST_DIR Output directory 27 28 Examples: 29 $(basename "$0") /src/repo.git /srv/git 30 $(basename "$0") /src/repos /srv/git 31 EOF 32 } 33 34 error() { 35 printf 'error: %s\n' "$1" >&2 36 exit 1 37 } 38 warning() { printf 'warning: %s\n' "$1" >&2; } 39 info() { printf 'info: %s\n' "$1"; } 40 41 check_args() { [ $# -eq 2 ] || { 42 usage >&2 43 error "usage: $0 SRC DST_DIR" 44 }; } 45 46 is_bare_repo() { git --git-dir="$1" rev-parse --is-bare-repository > /dev/null 2>&1; } 47 has_repos() { [ -d "$1" ] && ls "$1"/*.git > /dev/null 2>&1 2> /dev/null; } 48 49 sync_repo() { 50 src="$1" dst_dir="$2" name=$(basename "$src") 51 dst="$dst_dir/$name" 52 53 is_bare_repo "$src" || { 54 warning "skipping $name (not bare)" 55 return 0 56 } 57 58 rm -rf "$dst" 59 cp -R "$src" "$dst" 60 git --git-dir="$dst" update-server-info > /dev/null 2>&1 61 } 62 63 main() { 64 check_args "$@" 65 SRC="$1" DST_DIR="$2" 66 67 [ -d "$DST_DIR" ] && [ -w "$DST_DIR" ] || error "DST_DIR '$DST_DIR' not writable" 68 69 if is_bare_repo "$SRC"; then 70 sync_repo "$SRC" "$DST_DIR" 71 info "synced: $SRC → $DST_DIR" 72 elif has_repos "$SRC"; then 73 [ "$DST_DIR" != "/" ] && rm -rf "$DST_DIR"/* 74 for repo in "$SRC"/*.git; do 75 [ -d "$repo" ] || break 76 sync_repo "$repo" "$DST_DIR" 77 done 78 info "synced all: $SRC → $DST_DIR" 79 else 80 error "$SRC: neither bare repo nor *.git directory" 81 fi 82 } 83 84 main "$@"