#!/usr/bin/env bash
#
# Pulls changes from remote branch to the local GIT repository.
# Copyright (c) Petr Baudis, 2005
#
# See cg-branch-add for some description.
#
# Takes the branch' name.

. cg-Xlib

name=$1


[ "$name" ] || die "where to pull from?"
uri=$(cat ".git/branches/$name" 2>/dev/null) || die "unknown branch"

rembranch=master
if echo "$uri" | grep -q '#'; then
	rembranch=$(echo $uri | cut -d '#' -f 2)
	uri=$(echo $uri | cut -d '#' -f 1)
fi


fetch_rsync () {
	filter="cat"
	if [ "$1" = "-s" ]; then # subsequent
		# We already saw the MOTD, thank you very much.
		filter="grep -v ^MOTD:"
		shift
	fi

	rsync_flags_l=
	if [ "$1" = "-u" ]; then # update
		rsync_flags_l="--ignore-existing"
		shift
	fi

	appenduri=
	if [ "$1" = "-d" ]; then # directory
		appenduri="/." # CowboyNeal
		shift
	fi

	rsync $RSYNC_FLAGS $rsync_flags_l --whole-file -v -Lr \
		"$1$appenduri" "$2$appenduri" | $filter
	return ${PIPESTATUS[0]}
}

fetch_local () {
	[ "$1" = "-s" ] && shift

	cp_flags_l="-va"
	if [ "$1" = "-u" ]; then
		cp_flags_l="$cp_flags_l -lu"
		shift
	fi

	cut_last=
	if [ "$1" = "-d" ]; then
		cut_last=1
		shift
	fi

	src="$1"
	dest="$2"
	[ "$cut_last" ] && dest=${dest%/*}

	cp $cp_flags_l "$src" "$dest"
}

if echo "$uri" | grep -q ":"; then
	fetch=fetch_rsync
else
	[ -d $uri/.git ] && uri=$uri/.git
	fetch=fetch_local
fi


orig_head=
[ -s ".git/refs/heads/$name" ] && orig_head=$(cat ".git/refs/heads/$name")


mkdir -p .git/refs/heads
rsyncerr=
$fetch "$uri/refs/heads/$rembranch" ".git/refs/heads/$name" 2>/dev/null || rsyncerr=1
if [ "$rsyncerr" ]; then
	rsyncerr=
	$fetch -s "$uri/heads/$rembranch" ".git/refs/heads/$name" || rsyncerr=1
fi
if [ "$rsyncerr" ] && [ "$rembranch" = "master" ]; then
	rsyncerr=
	$fetch -s "$uri/HEAD" ".git/refs/heads/$name" || rsyncerr=1
fi
[ "$rsyncerr" ] && die "unable to get the head pointer of branch $rembranch"

[ -d .git/objects ] || mkdir -p .git/objects
$fetch -s -u -d "$uri/objects" ".git/objects" || die "rsync error"

# FIXME: Warn about conflicting tag names?
# XXX: We now throw stderr to /dev/null since not all repositories
# may have tags/ and users were confused by the harmless errors.
[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
rsyncerr=
$fetch -s -u -d "$uri/refs/tags" ".git/refs/tags" 2>/dev/null || rsyncerr=1
if [ "$rsyncerr" ]; then
	rsyncerr=
	$fetch -s -u -d "$uri/tags" ".git/refs/tags" 2>/dev/null || rsyncerr=1
fi
[ "$rsyncerr" ] && echo "unable to get tags list (non-fatal)" >&2


new_head=$(cat ".git/refs/heads/$name")

if [ ! "$orig_head" ]; then
	echo "New branch: $new_head"

elif [ "$orig_head" != "$new_head" ]; then
	echo "Tree change: $orig_head:$new_head"
	diff-tree -r $(tree-id $orig_head) $(tree-id $new_head)

else
	echo "Up to date."
	exit
fi
