Skip to content

Instantly share code, notes, and snippets.

@datashaman
Last active April 9, 2019 07:48
Show Gist options
  • Select an option

  • Save datashaman/0dd6d294c68a16181141d9c41285e9fb to your computer and use it in GitHub Desktop.

Select an option

Save datashaman/0dd6d294c68a16181141d9c41285e9fb to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Lives here: https://gist.github.com/datashaman/0dd6d294c68a16181141d9c41285e9fb
#
# Refresh your working copy branches. Assumes that you have a source
# repository on _origin_ remote, and a fork on _$GIT_REFRESH_REMOTE_ remote.
#
# Required .env variables:
# GIT_REFRESH_REMOTE - set to the remote name for your fork.
#
# Optional .env variables:
# GIT_REFRESH_BASE - set to your base branch, defaults to master. Don't use origin.
# GIT_REFRESH_INTERACTIVE - Set to true if you want to rebase interactively. Doesn't check if rebase is necessary.
# GIT_REFRESH_PUSH - Set to true if you want to push to your fork during the refresh.
#
# It does as little work as possible to get a complete set of refreshed
# local branches.
#
# Steps:
#
# - Update remote branches (with prune)
# - Remove any local merged branches whose remote has disappeared
# - For each local branch:
# - Check hashes to see if rebase is necessary
# - If interactive or rebase is necessary:
# - Perform rebase on origin/$GIT_REFRESH_BASE
# - If the upstream is origin/$GIT_REFRESH_BASE:
# - If the branch is $GIT_REFRESH_BASE:
# - Push it to your fork
# - Else:
# - Push it to your fork and set upstream (new branch)
# - Else:
# - Force push (with lease) if necessary to your fork
# - Else:
# - Force push (with lease) if necessary to your fork
set -e
function maybe_push_branch ()
{
LOCAL_HASH=$(git rev-parse $REFNAME)
UPSTREAM_HASH=$(git rev-parse $UPSTREAM)
if [ "$LOCAL_HASH" != "$UPSTREAM_HASH" ]; then
git push --force-with-lease $GIT_REFRESH_REMOTE $REFNAME
fi
}
function push_rebase ()
{
if [ "$UPSTREAM" == "origin/$GIT_REFRESH_BASE" ]; then
if [ "$REFNAME" == "$GIT_REFRESH_BASE" ]; then
git push $GIT_REFRESH_REMOTE $REFNAME
else
git push -u $GIT_REFRESH_REMOTE $REFNAME
fi
else
maybe_push_branch
fi
}
function refresh_branch ()
{
ORIGIN_HASH=$(git rev-parse origin/$GIT_REFRESH_BASE)
BASE_HASH=$(git merge-base $GIT_REFRESH_BASE $REFNAME)
if [ "$GIT_REFRESH_INTERACTIVE" == "true" -o "$ORIGIN_HASH" != "$BASE_HASH" ]; then
git rebase $($GIT_REFRESH_INTERACTIVE && echo -i) origin/$GIT_REFRESH_BASE $REFNAME
$GIT_REFRESH_PUSH && push_rebase
else
$GIT_REFRESH_PUSH && maybe_push_branch
fi
}
function usage ()
{
cat <<EOF
Usage: ${0##*/} [-h] [-i] [-p]
refresh git branches
-h display this help and exit
-i rebase branches interactively
-p push to the fork during refresh
EOF
}
GIT_REFRESH_BASE=master
GIT_REFRESH_INTERACTIVE=false
GIT_REFRESH_PUSH=false
export HUSKY_IGNORE=true
source .env
OPTIND=1
while getopts "hip" opt
do
case "${opt}" in
h)
usage
exit 0
;;
i)
GIT_REFRESH_INTERACTIVE=true
;;
p)
GIT_REFRESH_PUSH=true
;;
*)
usage
exit 0
;;
esac
done
shift "$((OPTIND-1))"
if [ -z "$GIT_REFRESH_REMOTE" ]; then
echo "Please set GIT_REFRESH_REMOTE in .env"
exit 1
fi
git remote update -p origin $GIT_REFRESH_REMOTE
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
git checkout master
git branch -vv | grep ' gone' | cut -d' ' -f3 | xargs -r branch -d
BRANCHES=$(git for-each-ref --format='%(refname:short),%(upstream:short)' refs/heads/)
for BRANCH in $BRANCHES
do
REFNAME=${BRANCH%,*}
UPSTREAM=${BRANCH#*,}
refresh_branch $REFNAME $UPSTREAM
done
git checkout $CURRENT_BRANCH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment