git-force/git-force

137 lines
3.4 KiB
Bash
Executable File

#!/bin/sh
if [ "$1" = "--help" ] || [ "$1" = "-h" ]
then
echo "Usage:"
echo " git force"
echo " git force <remote>"
echo " git force <remote> <branch>"
exit 0
fi
git rev-parse --is-inside-work-tree > /dev/null 2>&1
if [ "$?" != "0" ]
then
echo "error: not a git repository"
exit 10
fi
REMOTE=""
BRANCH=""
PRETTY="--pretty=format:%h, %an <%ae>, %cr: %s"
if [ "$#" = "0" ]
then
BRANCH="$(git branch --show-current)"
if [ "$BRANCH" = "" ]
then
echo "error: currently in detached HEAD state" >&2
exit 1
fi
fi
if [ "$#" -gt "0" ]
then
REMOTE="$1"
git config "remote.$REMOTE.url" > /dev/null 2>&1
if [ "$?" != "0" ]
then
echo "error: specified remote is invalid" >&2
exit 2
fi
fi
if [ "$#" -gt "1" ]
then
BRANCH="$2"
git rev-parse --verify "$BRANCH" > /dev/null 2>&1
if [ "$?" != "0" ]
then
echo "error: specified branch is invalid" >&2
exit 3
fi
fi
if [ "$REMOTE" = "" ]
then
REMOTE=$(git config "branch.$BRANCH.remote")
if [ "$?" != "0" ]
then
echo "error: current branch does not have a remote and no remote was specified" >&2
echo "see: git force --help"
exit 4
fi
fi
if [ "$REMOTE" = "" ] || [ "$BRANCH" = "" ]
then
echo "assertion failed: remote or branch is blank" >&2
exit 5
fi
REMOTE_BRANCH="$REMOTE/$BRANCH"
REMOTE_HASH="$(git rev-parse "$REMOTE_BRANCH")" # later used to throw errors if something changes remote or local
if [ "$?" != "0" ] || [ "$REMOTE_HASH" = "" ]
then
echo "internal error: failed to fetch remote hash" >&2
exit 5
fi
LOCAL_HASH="$(git rev-parse "$BRANCH")" # as that may cause the user unintentionally pushing/overwriting unwanted things
if [ "$?" != "0" ] || [ "$LOCAL_HASH" = "" ]
then
echo "internal error: failed to fetch local hash" >&2
exit 5
fi
if [ "$REMOTE_HASH" = "$LOCAL_HASH" ]
then
echo "error: the branches are already the same" >&2
exit 8
fi
if [ "$REMOTE_HASH" = "$FORK_POINT" ]
then
echo "error: the branches have not diverged" >&2
exit 9
fi
FORK_POINT="$(git merge-base "$BRANCH" "$REMOTE_BRANCH")"
if [ "$?" != "0" ]
then
echo "The branches do not have a common ancestor, the latest commits for each are listed below:"
echo ""
echo "remote:"
git show -s "$PRETTY" "$REMOTE_HASH"
echo ""
echo "local:"
git show -s "$PRETTY" "$LOCAL_HASH"
else
echo "The following commits will be OVERWRITTEN:"
git log "$PRETTY" "$FORK_POINT..$REMOTE_HASH"
echo ""
echo "The following commits will overwrite the above commits:"
git log "$PRETTY" "$FORK_POINT..$LOCAL_HASH"
fi
echo ""
read -p "Continue? [y/N] " SHOULD_CONTINUE
if [ "$SHOULD_CONTINUE" != "y" ]
then
echo "Abort." >&2
exit 6
fi
REMOTE_HASH_2="$(git rev-parse "$REMOTE_BRANCH")"
LOCAL_HASH_2="$(git rev-parse "$BRANCH")"
if [ "$REMOTE_HASH_2" != "$REMOTE_HASH" ]
then
echo "@@@@@@@@@@@@@@@@@@@@@@@@@" >&2
echo "@ REMOTE HAS UPDATED! @" >&2
echo "@@@@@@@@@@@@@@@@@@@@@@@@@" >&2
echo "" >&2
echo "The remote updated from $REMOTE_HASH"
echo "to $REMOTE_HASH_2 while you were confirming."
echo "Please re-run this command and check again."
exit 7
fi
if [ "$LOCAL_HASH_2" != "$LOCAL_HASH" ]
then
echo "@@@@@@@@@@@@@@@@@@@@@@@@" >&2
echo "@ LOCAL HAS UPDATED! @" >&2
echo "@@@@@@@@@@@@@@@@@@@@@@@@" >&2
echo "" >&2
echo "The local updated from $LOCAL_HASH"
echo "to $LOCAL_HASH_2 while you were confirming."
echo "Please re-run this command and check again."
exit 7
fi
git push --force-with-lease "$REMOTE" "$BRANCH"