Skip to content

Instantly share code, notes, and snippets.

@nrclark
Last active October 31, 2018 23:41
Show Gist options
  • Save nrclark/e315e0439d9b04fc017594262e1a8956 to your computer and use it in GitHub Desktop.
Save nrclark/e315e0439d9b04fc017594262e1a8956 to your computer and use it in GitHub Desktop.
Git Diffgen
#!/bin/sh
#------------------------------------------------------------------------------#
MERGE="no"
CHECK_ONLY="no"
PROGNAME=`echo "$0" | sed 's@.*/@@g'`
#------------------------------------------------------------------------------#
USAGE="Usage: $PROGNAME [-m] [-c] [-b BRANCH] GITDIR"
HELP_MSG="
Unconditionally update a repo to match the remote. Generate a changelog.
$USAGE
Options:
-b BRANCH, Manually specify the remote's branch.
-c, Check for updates, but take no other action. Exit success
the repo is up-to-date.
-m, Merge the remote after fetching.
-h, Print this message and exit.
"
usage() {
local exit_code="$1"
local stream="1"
if [ "$exit_code" = "" ]; then
stream="2"
exit_code=0
fi
printf "$USAGE\n" >&$stream
exit $exit_code
}
help() {
local exit_code="$1"
local stream="1"
if [ "$exit_code" = "" ]; then
stream="2"
exit_code=0
fi
printf "$HELP_MSG\n" >&$stream
exit $exit_code
}
#------------------------------------------------------------------------------#
for arg in $@; do
if [ "$arg" = "--help" ]; then
help
fi
done
while getopts "mchb:" name $ARGS 2>/dev/null
do
case $name in
b) BRANCH="$OPTARG";;
m) MERGE="yes";;
c) CHECK_ONLY="yes";;
h) help;;
*) usage 1;;
esac
done
shift "$(($OPTIND-1))"
GITDIR="$1"
shift
if [ "$*" != "" ]; then
usage 1
fi
#------------------------------------------------------------------------------#
if [ "x$GITDIR" = "x" ]; then
usage 1
fi
if [ "x$BRANCH" = "x" ]; then
BRANCH=`git -C "$GITDIR" branch | grep -oP '(?<=[*] )[^(].*'`
fi
if [ "x$BRANCH" = "x" ]; then
echo "Error: couldn't guess branch of $GITDIR. Please specify with -b." >&2
exit 1
fi
#------------------------------------------------------------------------------#
in_set() {
# Succeeds if $query is in $set, and fails otherwise.
local set="$1"
local query="$2"
local item=""
for item in $set; do
if [ "$item" = "$query" ]; then
return 0
fi
done
return 1
}
difference() {
# Returns set_a - set_b.
local set_a="$1"
local set_b="$2"
local result=""
local item=""
for item in $set_a; do
if ! in_set "$set_b" "$item"; then
result="$result $item"
fi
done
echo "`echo $result`"
}
#------------------------------------------------------------------------------#
git -C "$GITDIR" fetch -f origin "$BRANCH" 1>/dev/null 2>&1
#------------------------------------------------------------------------------#
CURRENT="`git -C "$GITDIR" rev-parse HEAD`"
TARGET="`git -C "$GITDIR" rev-parse "origin/$BRANCH"`"
if [ "$CHECK_ONLY" = "yes" ]; then
if [ "$CURRENT" = "$TARGET" ]; then
exit 0
fi
exit 1
fi
#------------------------------------------------------------------------------#
BOTTOM="`git -C "$GITDIR" merge-base $CURRENT origin/$BRANCH`"
OLD_COMMITS=$(git -C "$GITDIR" log --pretty=format:"%H" $BOTTOM...$CURRENT)
NEW_COMMITS=$(git -C "$GITDIR" log --pretty=format:"%H" $BOTTOM...$TARGET)
TO_DELETE=`difference "$OLD_COMMITS" "$NEW_COMMITS"`
TO_ADD=`difference "$NEW_COMMITS" "$OLD_COMMITS"`
#------------------------------------------------------------------------------#
for record in $TO_ADD; do
git -C "$GITDIR" show -s $record --pretty=format:"+%h: %s" | cat
printf "\n"
done
for record in $TO_DELETE; do
git -C "$GITDIR" show -s $record --pretty=format:"-%h: %s" | cat
printf "\n"
done
#------------------------------------------------------------------------------#
if [ "$MERGE" != "yes" ]; then
exit 0
fi
git -C "$GITDIR" checkout origin/$BRANCH 1>/dev/null
git -C "$GITDIR" branch -m $BRANCH __old_$BRANCH 1>/dev/null
git -C "$GITDIR" branch $BRANCH 1>/dev/null
git -C "$GITDIR" checkout $BRANCH 1>/dev/null
git -C "$GITDIR" branch -D __old_$BRANCH 1>/dev/null
git -C "$GITDIR" branch -u origin/$BRANCH $BRANCH 1>/dev/null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment