#!/usr/bin/env bash
#
# Merge a branch to the current tree.
# Copyright (c) Petr Baudis, 2005
#
# Takes a parameter identifying the branch to be merged.
#
# You have to examine the tree after the merge and then do `cg-commit`.
#
# Alternatively, it will just bring the 'HEAD' forward, if your current
# 'HEAD' is also the merge base.
#
# OPTIONS
# -------
# -b BASE_COMMIT::
#	Parameter specifies the base commit for the merge.
#
# -c::
#	Parameter specifies that you want to have tree merge never
#	autocomitted, but want to review and commit it manually.

USAGE="cg-merge [-c] [-b BASE_COMMIT] BRANCH_NAME"

. ${COGITO_LIB}cg-Xlib

head=$(commit-id)


careful=
if [ "$1" = "-c" ]; then
	shift
	careful=1
fi

base=
if [ "$1" = "-b" ]; then
	shift
	[ "$1" ] || usage
	base=$(commit-id "$1") || exit 1; shift
fi

[ "$1" ] || usage
branchname="$1"
branch=$(commit-id "$branchname") || exit 1

[ "$base" ] || base=$(git-merge-base "$head" "$branch")
[ "$base" ] || die "unable to automatically determine merge base"


[ -s $_git/blocked ] && die "merge blocked: $(cat $_git/blocked)"


if [ "$base" = "$branch" ]; then
	echo "Branch already fully merged." >&2
	exit 0
fi

if [ "$head" = "$base" ]; then
	# No need to do explicit merge with a merge commit; just bring
	# the HEAD forward.

	echo "Fast-forwarding $base -> $branch" >&2
	echo -e "\ton top of $head..." >&2

	tree_timewarp "forward" "yes, rollback (or rather rollforth) the tree!" $base $branch

	exit 0
fi


[ "$(git-diff-files -s)" ] && update_index

echo "Merging $base -> $branch" >&2
echo -e "\tto $head..." >&2


git-read-tree -u -m $(tree-id $base) $(tree-id $head) $(tree-id $branch) ||
	die "git-read-tree failed (merge likely blocked by local changes)"

echo $base >>$_git/merge-base
echo $branch >>$_git/merging
echo $branchname >>$_git/merging-sym

if ! git-merge-cache -o ${COGITO_LIB}cg-Xmergefile -a || [ "$careful" ]; then
	# "Resolve" merges still in the cache (conflicts).
	# We will resolve only those caught by merge-cache;
	# that is "three-way conflicts". Others should still
	# be resolved manually on the lower level by the user.
	git-ls-files --unmerged | {
		stage1mode=
		stage1hash=
		stage1name=
		stage2seen=
		while read mode sha1 stage filename; do
			case $stage in
			1)
				stage1mode="$mode"
				stage1hash="$sha1"
				stage1name="$filename"
				continue
				;;
			2)
				stage2seen=
				[ "$stage1name" = "$filename" ] && stage2seen=1
				continue
				;;
			3)
				[ "$stage1name" = "$filename" ] || continue
				[ "$stage2seen" ] || continue
				stage2seen=
			esac
			git-update-cache --cacheinfo $stage1mode $stage1hash $stage1name
		done
	}

	[ ! "$careful" ] && cat >&2 <<__END__

	Conflicts during merge. Do cg-commit after resolving them.
__END__
	exit 2
fi
git-checkout-cache -f -u -a

echo
readtree=
cg-commit -C || { readtree=1 ; echo "cg-merge: COMMIT FAILED, retry manually" >&2; }

[ "$readtree" ] && git-read-tree -m HEAD
update_index
