Skip to content

Commit

Permalink
git-ffwd: use the push branch as the upstream, if no upstream configured
Browse files Browse the repository at this point in the history
  • Loading branch information
jszakmeister committed Sep 19, 2014
1 parent 6901660 commit 17d56c9
Showing 1 changed file with 88 additions and 28 deletions.
116 changes: 88 additions & 28 deletions git-addons/git-ffwd
Expand Up @@ -2,40 +2,100 @@
SUBDIRECTORY_OK=1 source "$(git --exec-path)/git-sh-setup" ||
die "Not a git repository."


has_matching_push() {
# push.default is setup for 'simple', 'current', or 'matching'.
case "$(git config --get push.default || echo "matching")" in
current | simple | matching)
return 0
esac

return 1
}


if has_matching_push; then
MATCHING_PUSH=t
else
MATCHING_PUSH=
fi


determine_upstream_branch() {
local ref="${1#refs/heads/}"
local upstream="$(git for-each-ref --format='%(upstream:short)' "refs/heads/$ref")"
local publish_branch

if [[ -n "$upstream" ]]; then
echo "$upstream"
return 0
fi

if [[ -z "$MATCHING_PUSH" ]]; then
return 1
fi

# Use the push location as the upstream.
local remote=$(git config --get branch.${ref}.pushremote ||
git config --get remote.pushdefault ||
git config --get branch.${ref}.remote)
if [ -z "$remote" -a -n "$(git config --get remote.origin.url 2> /dev/null)" ]; then
remote="origin"
fi
if [[ -n "$remote" ]]; then
git rev-parse "$remote/$ref" > /dev/null 2>&1 &&
publish_branch="$remote/$ref"
fi

if [[ -n "$publish_branch" ]]; then
echo "$publish_branch"
return 0
fi

return 1
}


# Taken from http://stackoverflow.com/questions/620650/can-i-easily-update-all-local-git-branches-from-remote-branches-simultaneously/answer-9076361
# with a small tweak by me to make the fast-forward merge use --ff-only, and to
# help prune remote branches.
# help prune remote branches. It has also been updated to treat the push branch
# as the default upstream, if no upstream is configured.
main() {
REMOTES="$@";
if [ -z "$REMOTES" ]; then
REMOTES=$(git remote);
fi
REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
CLB=$(git branch -l|awk '/^\*/{print $2}');
echo "$REMOTES" | while read REMOTE; do
local upstream
local ALR
local LR

local CLB=$(git branch -l|awk '/^\*/{print $2}')

local REMOTES="$@"
if [ -z "$REMOTES" ]; then
REMOTES="$(git remote)"
fi
REMOTES="$(echo "$REMOTES" | xargs -n1 echo)"

git remote update -p $REMOTE
git remote show $REMOTE -n \
| awk '/merges with remote/{print $5" "$1}' \
| while read line; do
RB=$(echo "$line"|cut -f1 -d" ");
ARB="refs/remotes/$REMOTE/$RB";
LB=$(echo "$line"|cut -f2 -d" ");
ALB="refs/heads/$LB";
NBEHIND=$(( $(git rev-list --count $ALB..$ARB 2>/dev/null) +0));
NAHEAD=$(( $(git rev-list --count $ARB..$ALB 2>/dev/null) +0));
if [ "$NBEHIND" -gt 0 ]; then
if [ "$NAHEAD" -gt 0 ]; then
echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
elif [ "$LB" = "$CLB" ]; then
echo " branch $LB was $NBEHIND commit(s) behind $REMOTE/$RB. fast-forward merge";
git merge --ff --ff-only -q $ARB;
else
echo " branch $LB was $NBEHIND commit(s) behind $REMOTE/$RB. resetting local branch to remote";
git branch -l -f $LB -t $ARB >/dev/null;
git show-ref --heads | cut -d ' ' -f 2 | while read ALB; do
LB="${ALB#refs/heads/}"
RB="$(determine_upstream_branch "${LB}")"
if [ -z "${RB}" ]; then
continue
fi

NBEHIND=$(( $(git rev-list --count $LB..$RB 2>/dev/null) +0))
NAHEAD=$(( $(git rev-list --count $RB..$LB 2>/dev/null) +0))

if [ "$NBEHIND" -gt 0 ]; then
if [ "$NAHEAD" -gt 0 ]; then
echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $RB. could not be fast-forwarded"
elif [ "$LB" = "$CLB" ]; then
echo " branch $LB was $NBEHIND commit(s) behind $RB. fast-forward merge";
git merge --ff --ff-only -q $RB
else
echo " branch $LB was $NBEHIND commit(s) behind $RB. resetting local branch to remote"
git branch -l -f $LB -t $RB >/dev/null
fi
fi
fi
done
done
}

main $@

0 comments on commit 17d56c9

Please sign in to comment.