Here’s a small script to reflect a git repo from some source like GitHub to some destination like an internal gitea mirror. That’s my usecase. You could also use this to go the other direction, or whatever you like.
It’s designed to be run periodically with something like cron. If anything goes wrong during pull/push (for example, upstream rewrites history), that repo sync will fail but others will continue. Modify this to watch for errors if you like or run it manually on occasion to check for errors yourself.
Intermediary copies of repos are stored locally in
repos/ folder is created automatically. Run the script from whatever working directory you want to be the parent of
repos/, or change the script to put them somewhere else.
Repo list is in format:
local/repo/name source_url dest_url
repos= line for examples. Change this to set up your own repo list. You must use spaces as the delimiter, or change the script to use a different delimiter by changing
IFS=. For example, to use tabs, set
Here’s the script:
#!/usr/bin/env sh # FORMAT: # local/path source_url dest_url # # repos are cloned from source_url into folder <local/path> # local/path must not contain spaces because i dont want to deal with that. # If the folder doesn't exist, its a clone # If the folder exists, its an incremental pull # # after that, push the repo to dest_url. # If there's an error (like source overwrote history with --force) then this # doesn't happen. Resolve errors manually. repos='linux https://github.com/torvalds/linux.git email@example.com:mirrors/linux.git faithanalog/rtmouse https://github.com/faithanalog/rtmouse.git firstname.lastname@example.org:mirrors/faithanalog-rtmouse.git xf86-video-amdgpu https://gitlab.freedesktop.org/xorg/driver/xf86-video-amdgpu.git email@example.com:mirrors/xf86-video-amdgpu.git ' printf '%s' "$repos" | while IFS=' ' read -r path source_url dest_url; do # work in repos subdir so we can easily gitignore it path="./repos/$path" # make parent dir of repo mkdir -p "$(dirname "$path")" # clone if it doesnt exist already if ! [ -d "$path" ]; then echo "cloning $source_url into $path" git clone --mirror "$source_url" "$path" fi ( # enter repo cd "$path" # update all branches from source # docs for `git fetch -t` say it fetches tags in addition to a normal # fetch. in our testing this was not fully the case, and `git fetch -t` # did not fetch new branches. echo "pulling updates from $source_url" git fetch "$source_url" git fetch -t "$source_url" # push branches to dest echo "pushing updates to $dest_url" git push --all "$dest_url" git push --tags "$dest_url" ) done