#!/bin/sh self=watch-git-tags # List sorted local tags lt() { git tag -l | LC_COLLATE=C sort } # List sorted remote tags rt() { git ls-remote -qt | awk '!/\^\{\}$/{print substr($2,11)}' | LC_COLLATE=C sort } # Create a temporary directory with name in $td, and handle POSIX-ish traps to # remove it when the script exits; requires mktemp(1) (not POSIX) td=$(mktemp -d) || exit cleanup() { [ -n "$td" ] || return rm -fr -- "$td" } for sig in EXIT HUP INT TERM ; do # shellcheck disable=SC2064 trap "cleanup $sig" "$sig" done # Use current directory if no other arguments [ "$#" -gt 0 ] || set -- . # Iterate through each repo in a subshell in parallel for repo ; do ( # Make a temporary directory with a hash in its name for uniqueness df=$(printf %s "$repo" | sed s:/:_:g) cs=$(printf %s "$repo" | cksum) sd=$td/$df.${cs%% *} mkdir -- "$sd" || exit # Step in and write repo path to file cd -- "$sd" || exit printf '%s\n' "$repo" > path || exit # Write local and remote tags to files ( cd -- "$repo" || exit lt "$repo" > "$sd"/a || exit rt "$repo" > "$sd"/b ) || exit # Write new tags to file LC_COLLATE=C comm -13 -- [ab] > new ) & done # Wait for each of those to finish wait # Iterate through the temp dirs in order for dir in "$td"/* ; do ( cd -- "$dir" || exit 0 # Look for non-zero "new" files (at least one new tag) [ -s new ] || exit 0 # Print repository path and new tags sed '1!s/^/\t/' -- path new exit 1 ) ; done