#!/usr/bin/env bash # Copyright (c) 2005, Intel Corporation, James Ketrenos function die() { ret=$1 shift echo $@ >&2 exit $ret } [ ! "$MERGE" ] && die 1 "MERGE must be set to merge program (ie, export MERGE=kdiff3)" parent= branch= function get_parent_and_branch() { [ ! -e .git/refs/parent ] && return 1 parent=$(cat .git/refs/parent) [ ! "$parent" ] && return 1 if echo ${parent} | egrep -q "#"; then branch="refs/heads/"$(echo $parent | sed -ne "s,.*#\(.*\),\1,p") parent=$(echo $parent | sed -e "s,\([^#]*\).*,\1,") else branch="HEAD" fi echo $parent | grep "/\$" || parent="${parent}/" return 0 } function merge_parent() { [ -e ".git/refs/heads/repository.merge" ] && die 9 "Prior merge failed and not un-done." repo=$1 branch=$2 echo $repo | grep "/\$" || repo="${repo}/" # First verify there are no uncommitted changes, then proceed... # (TODO: Add script commands for checking for uncommitted changes) # # Obtain the parent's HEAD and store as .git/refs/heads/parent.tip and # .git/refs/heads/parent.merge echo "Checking for updates from ${repo}${branch}..." rsync ${RSYNC_FLAGS} -vpL ${repo}${branch} .git/refs/heads/parent.tip || return 1 parent=$(cat .git/refs/heads/parent) new_parent=$(cat .git/refs/heads/parent.tip) echo $new_parent > .git/refs/heads/parent.merge || return 2 # Check for an update; if no update, we're done [ "$parent" == "$new_parent" ] && return 0 child=$(cat .git/HEAD) # Grab the latest objects from the parent echo "Pulling object files" rsync ${RSYNC_FLAGS} -avpr ${repo}objects/ .git/objects/ || return 3 # Copy the current HEAD to .git/refs/heads/repository.merge echo "Caching HEAD in repository.merge" cp .git/HEAD .git/refs/heads/repository.merge || return 4 # Update the GIT index echo "Setting local repository to mirror parent" echo $new_parent > .git/HEAD || return 5 rm .git/index git-read-tree -m HEAD || return 6 # git-checkout-cache -f -u -a # At this point, our local repository is now a mirror of the # parent repository. # Merge and commit the repository changes back into the current parent echo "Merging child back into parent" git-merge-heads $new_parent $child || return 7 # Update parent / repo index links mv -f .git/refs/heads/parent.tip .git/refs/heads/parent || return 12 mv .git/refs/heads/repository.merge .git/refs/heads/pre-merge echo "Updating ancestors file..." url=$(cat .git/refs/parent) sed -i -e "s#$url\t$parent#$url\t$new_parent#g" \ .git/refs/ancestors return 0 } function merge_cleanup() { # If any of the above fails, the repository should be changed back # to its original state: rm -f .git/refs/heads/{parent,repository}.merge \ .git/refs/heads/parent.tip || \ return 1 ln -sf refs/heads/master .git/HEAD || return 2 git-read-tree -m HEAD || return 3 git-checkout-files -q -f -u -a || return 4 return 0 } if ! get_parent_and_branch; then # merge_cleanup exit 1 fi echo -e "Attempting merging with:\n\t$parent\n..." merge_parent $parent $branch || die 12 "Error merging parent." rm -rf .git/merge* exit 0