From d0958ecc33c91560c826ce83ab44959d0d19120d Mon Sep 17 00:00:00 2001 From: Darren 'Tadgy' Austin Date: Sun, 29 Oct 2023 19:52:50 +0000 Subject: [PATCH] Add git-auto-merge script. --- git-auto-merge | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 git-auto-merge diff --git a/git-auto-merge b/git-auto-merge new file mode 100755 index 0000000..b993bf9 --- /dev/null +++ b/git-auto-merge @@ -0,0 +1,69 @@ +#!/bin/bash +# Version: 0.1.0 +# Copyright (c) 2023: +# Darren 'Tadgy' Austin +# Licensed under the terms of the GNU General Public License version 3. +# +# Automatically fetch and merge (if possible) upstream changes into a local git repository. + +# What platform we're running on. +PLATFORM="$(uname -s)" + +# Only operate on repositories that are set for maintenance work in ~/.gitconfig. +while IFS= read -r REPO; do + # Get into the working directory. + pushd "$REPO" >/dev/null 2>&1 || { + printf "%s: %s\\n" "${0##*/}" "failed to change to working directory '$REPO'" >&2 + RET=1 + continue + } + + # Skip processing if auto-merging is disabled in this repository. + [[ "$(git config --local --get --type bool script.AutoMergeDisabled 2>/dev/null)" != "true" ]] && { + # Fetch the latest updates. + if git fetch --all --atomic --tags >/dev/null 2>&1; then + # Try to merge using fast-forward only, so no clobbering is done. + if MERGE="$(git merge --ff-only 2>/dev/null)"; then + [[ "$(printf "%s" "$MERGE" | awk '{ print $1; exit }')" == "Updating" ]] && { + if [[ "$PLATFORM" == "Linux" ]]; then + # Linux, how I love thee. + NOW="$(date +'%s%3N')" + elif [[ "$PLATFORM" == "Darwin" ]]; then + # This sucks... but so does Darwin. + NOW="$(perl -e 'use Time::HiRes; printf "%.3f", Time::HiRes::time();')" + NOW="${NOW/.}" + else + printf "%s: %s\\n" "${0##*/}" "unsupported platform: $PLATFORM" >&2 + RET=2 + break + fi + git config --local --replace-all --type int script.AutoMergeLast "$NOW" >/dev/null 2>&1 || { + printf "%s: %s\\n" "${0##*/}" "updating AutoMergeLast timestamp failed for '$REPO'" >&2 + RET=1 + } + git config --local --replace-all --type bool script.AutoMergeSuccess true >/dev/null 2>&1 || { + printf "%s: %s\\n" "${0##*/}" "updating AutoMergeSuccess marker failed for '$REPO'" >&2 + RET=1 + } + } + else + git config --local --replace-all --type bool script.AutoMergeSuccess false >/dev/null 2>&1 || { + printf "%s: %s\\n" "${0##*/}" "updating AutoMergeSuccess marker failed for '$REPO'" >&2 + RET=1 + } + fi + else + # Mark that the auto-merge failed. + printf "%s: %s\\n" "${0##*/}" "git fetch failed for '$REPO'" >&2 + git config --local --replace-all --type bool script.AutoMergeSuccess false >/dev/null 2>&1 || { + printf "%s: %s\\n" "${0##*/}" "updating AutoMergeSuccess marker failed for '$REPO'" >&2 + RET=1 + } + fi + } + + # Back to where we started... + popd >/dev/null 2>&1 || continue +done < <(git config --global --get-all maintenance.repo 2>/dev/null) + +exit "${RET:-0}"