Skip to content

Instantly share code, notes, and snippets.

@ar45
Created March 2, 2015 04:35
Show Gist options
  • Save ar45/035b56b5b5bf4ff8c785 to your computer and use it in GitHub Desktop.
Save ar45/035b56b5b5bf4ff8c785 to your computer and use it in GitHub Desktop.
Keep your forked repository in sync with upstream
#
# Script to keep github forked repository in sync with upstream.
# synchronizes branches which names match between REMOTE and UPSTREAM
#
# Uses the following shell variables, maybe passed on the command line
# path=/path/to/git/dir upstream=upstream_repo remote=origin ./syncrepository.sh
#
# Author: Aron Podrigal <[email protected]>
#
#!/bin/bash
# repository directory
GIT_DIR=${path:-"./"}
# SET THIS TO YOUR UPSTREAM NAME
UPSTREAM=${upstream:-"upstream"}
# NMAE OF REMOTE
REMOTE=${remote:-"origin"}
# FORCE CHECKOUT WITH -f OPTION "yes/no".
# if checkout to remote branch fails and this is
# set to "no", then it will try to
# stash any local changes, and pop it afterwards
FORCE_CHECKOUT=no
# set file LOGFILE=~/sync.log to redirect stdout
LOGFILE=
# set file ERROR_LOG=~/sync_err.log to redirect stderr
ERROR_LOG=
# redirect output
[ ! -z $LOGFILE ] && exec 1>>$LOGFILE
[ ! -z $ERROR_LOG ] && exec 2>>$ERROR_LOG
# logger function
function mlog()
{
if [ ! -z ${!2} ]; then
echo "[`date`] $1" >> ${!2}
else
if [ "$2" = "ERROR_LOG" ]; then
echo "[`date`] $1" >&2
else
echo "[`date`] $1"
fi
fi
}
cd $GIT_DIR || exit 1
git fetch || { mlog "Couldn't fetch remotes. terminating" "ERROR_LOG"; exit 1; }
UPSTREAM_BRANCHES=`git branch --list -r $UPSTREAM/* |awk '{sub(/^'$UPSTREAM'\//,"",$1); print $1}'`
REMOTE_BRANCHES=`git branch --list -r $REMOTE/* |awk '{sub(/^'$REMOTE'\//,"",$1); print $1}'`
if [ -z $UPSTREAM_BRANCHES ]; then
mlog "NOTICE: no upstream branches found for '$UPSTREAM'." "LOGFILE"
fi
# initialize stashed to false
stashed=1
for branch in $UPSTREAM_BRANCHES; do
remote_exists=1;
for remote_b in $REMOTE_BRANCHES; do
if [ $remote_b = $branch ]; then
remote_exists=0
break
fi
done
if [ $remote_exists ]; then
# checkout the remote branch and merge in upstream
git checkout $REMOTE/$branch
if [ $? -ne 0 ]; then
mlog "git checkout returned error" "ERROR_LOG"
if [ $stashed -eq 0 ]; then
mlog "working directory was previously stashed, so we're forcing checkout" "LOGFILE"
git checkout $REMOTE/$branch -f || { mlog "couldn't checkout ${REMOTE}/${branch}, terminating." "ERROR_LOG"; exit 1; }
else
mlog "trying to stash before checkout.." "LOGFILE"
git stash || { mlog "could not stash either terminating" "ERROR_LOG"; exit 1; }
# keep track that we've stashed away, so we'll pop afterwards
stashed=0
git checkout $REMOTE/$branch || { mlog "couldn't checkout ${REMOTE}/${branch}, terminating." "ERROR_LOG"; exit 1; }
fi
fi
git merge --ff $UPSTREAM/$branch || { mlog "'git merge --ff ${UPSTREAM}/${branch}' into ${REMOTE}/${branch} failed." "ERROR_LOG"; }
git push $REMOTE HEAD:$branch && mlog "'git merge --ff ${UPSTREAM}/${branch}' into ${REMOTE}/${branch} successfuly pushed to remote." "LOGFILE" \
|| { mlog "'git merge --ff ${UPSTREAM}/${branch}' into ${REMOTE}/${branch} failed to push to remote." "ERROR_LOG"; }
else
mlog "New upstream branch '$branch' found" "LOGFILE"
# push to remote
git push $REMOTE $UPSTREAM/$branch:refs/heads/$branch && mlog "'git push $REMOTE $UPSTREAM/$branch:refs/heads/$branch' <New Branch> successful." "LOGFILE" \
|| { mlog "'git push $REMOTE $UPSTREAM/$branch:refs/heads/$branch' <New Branch> failed." "ERROR_LOG"; }
fi
done
if [ $stashed -eq 0 ]; then
git stash pop
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment