With the changeover to mercurial, I've missed Teamware's resolve
command for resolving merge conflicts.  Not the filemerge GUI, but the
terminal-based interface for merging, editing, and diffing the various
versions.  So, I created an hg-merge script to emulate resolve's
interface.

I place the script in /home/johnz/bin.eng/hg-merge, a copy can be found
below.  I've placed the following lines in my ~/.hgrc:
        [merge-tools]
        hgmerge.executable=/home/johnz/bin.eng/hg-merge
        hgmerge.args=$local $base $other $output
        hgmerge.priority=2
        hgmerge.premerge=False
        hgmerge.checkconflicts=True
        hgmerge.checkchanged=True


Note: Due to mercurial's use of the term commit, I've replaced
resolve's commit command with accept m.
The help subcommand shows:

a = ancestor, c = child, p = parent, m = merged result
accept c|p|m            Accept the child,  parent, or merged version of the file
diff [diff options] a|c|p|m a|c|p|m     Show diffs between the two versions
edit a|c|p|m            Edit the ancestor, child, parent, or merged file
help                    Help
names                   Show names of  ancestor, child, parent, and merged file
merge                   Merge the child file with the parent
page a|c|p|m            Show contents of ancestor, child, parent, or merged file
sh [command]            Invoke the shell
!  [command]            Invoke the shell
quit                    Quit

                                I hope you find this useful     -JZ


--------------8<-----------------8<------------------
#!/bin/sh

# adapted from original found on
# http://www.selenic.com/mercurial/wiki/index.cgi/MergingManuallyInEditor
# via http://www.selenic.com/mercurial/wiki/index.cgi/MergeProgram

prog=$0
progbase=`basename $prog`

help() {
        sed -e'/^#/d' <<- EOF
a = ancestor, c = child, p = parent, m = merged result
accept c|p|m            Accept the child,  parent, or merged version of the file
diff [diff options] a|c|p|m a|c|p|m     Show diffs between the two versions
edit a|c|p|m            Edit the ancestor, child, parent, or merged file
help                    Help
#history c|p            Show history of child or parent file
#list                   List files still in conflict
names                   Show names of  ancestor, child, parent, and merged file
merge                   Merge the child file with the parent
page a|c|p|m            Show contents of ancestor, child, parent, or merged file
#skip [number]          Skip to file numbered number or skip to next file.
sh [command]            Invoke the shell
!  [command]            Invoke the shell
quit                    Quit
#=not yet implemented
        EOF
}

if test $# -ne 4 ; then
        echo >&2 "usage: $progbase CHILD ANCESTOR PARENT OUTPUT"
        exit 1
fi

# Keep a local copy of the filenames involved in the merge.
CHILD="$1"
ANCESTOR="$2"
PARENT="$3"
OUTPUT="$4"
MERGE="$4..merge.."

cleanup() {
        if test -n "${EDSCRIPT}" ; then
                /bin/rm -f "${EDSCRIPT}"
        fi
        if test -n "${WC}" ; then
                /bin/rm -f "${WC}"
        fi
}

err() {
        errcode=$1
        shift
        echo >&2 "$progbase: error: $*"
        cleanup
        exit $errcode
}

trap cleanup 0
trap "err 1 HUP signal" 1
trap "err 1 interrupted" 2
trap "err 1 QUIT signal" 3
trap "err 1 PIPE signal" 13
trap "err 1 TERM signal" 15

argtofile() {
        case "$1" in
        [aA])   echo $ANCESTOR;;
        [cC])   echo $CHILD;;
        [pP])   echo $PARENT;;
        [mM])   echo $MERGE;;
        *)      echo;;
        esac
}

# Since this script depends on manual edits being performed to the files being
# merged, make sure that ${EDITOR} is truly set to something, even if this is
# just plain good ol' vi(1).
EDITOR="${EDITOR:-vi}"
export EDITOR

# Get a value for PAGER
PAGER="${PAGER:-more}"
export PAGER

# Pick a SHELL
SHELL="${SHELL:-sh}"
export SHELL

# First make sure $TMPDIR points to a meaningful directory.  We will be using
# this shell variable further down, so it's a good idea to make sure it isn't
# empty later on.
TMPDIR="${TMPDIR:-/var/tmp}"
export TMPDIR

# We will be using a temporary file with the diff3(1) output as the merge
# buffer, until either the merge removes all conflict markers from the working
# copy of the file or we fail somehow to complete the merge.
EDSCRIPT=`mktemp "${TMPDIR}/hgmerge-XXXXXX"`
if test $? -ne 0 ; then
        err 1 "Cannot create temporary file at ${TMPDIR}/hgmerge-XXXXXX"
fi
WC=`mktemp "${TMPDIR}/hgmerge-XXXXXX"`
if test $? -ne 0 ; then
        err 1 "Cannot create temporary file at ${TMPDIR}/hgmerge-XXXXXX"
fi

# We depend on diff3(1) being available to do the first pass of the merge,
# adding conflict markers around the areas that should be edited.
which diff3 >/dev/null 2>&1
if test $? -ne 0 ; then
        err 1 "No diff3(1) utility found in the current PATH."
fi

#
# Enter command loop
#
echo merging $OUTPUT:
OUTbase="`basename $OUTPUT`"
if [ -f "${MERGE}" ]; then
        cnt=`grep -c "^<<<<<<<" "${MERGE}"`
        echo "$cnt unresolved differences in existing merge"
fi
while : ; do
        echo "$OUTbase? \\c"
        read cmd opts
        if [ -z "$cmd" ]; then
                help
                continue
        fi

        case "$cmd" in
        accept)
                file=`argtofile $opts`
                if [ -z "$file" ]; then
                        help
                        continue
                fi
                if [ ! -f "$file" ]; then
                        echo "$progbase: can't accept $file" 1>&2
                        continue
                fi
                if grep '^<<<<<<<' "${file}" >/dev/null 2>&1 ||
                   grep '^=======' "${file}" >/dev/null 2>&1 ||
                   grep '^>>>>>>>' "${file}" >/dev/null 2>&1 ; then
                        echo "conflict markers still found in the merge copy."
                        continue
                fi
                cp "$file" "${OUTPUT}"
                echo "revised version of ${OUTPUT}"
                ls -ld "${OUTPUT}"
                rm -f "${MERGE}"
                exit 0
                ;;
        diff)   set -- $opts
                dopts=
                while test $# -gt 2 ; do
                        dopts="$dopts $1"
                        shift
                done
                darg1=`argtofile $1`
                darg2=`argtofile $2`
                if [ -z "$darg1" -o -z "$darg2" ]; then
                        help
                        continue
                fi
                diff $dopts $darg1 $darg2 | $PAGER
                ;;
        edit)
                file=`argtofile $opts`
                echo file=$file 1>&2
                if [ -z "$file" ]; then
                        help
                        continue
                fi
                ${EDITOR} $file
                ;;
        merge)
                diff3 -E "${CHILD}" "${ANCESTOR}" "${PARENT}" > "${EDSCRIPT}"
                rc=$?
                if [ $rc -ne 0 ]; then
                        err 1 "serious diff3 error, while trying to merge"
                fi
                cp "${CHILD}" "${MERGE}"
                ed "${MERGE}" < "${EDSCRIPT}" > /dev/null 2>&1
                rc=$?
                if [ $rc -ne 0 ]; then
                        err 1 "serious ed error, while trying to merge"
                fi
                cnt=`grep -c "^<<<<<<<" "${MERGE}"`
                echo "$cnt unresolved differences"
                ;;
        names)
                echo "ancestor: ${ANCESTOR}"
                echo "child:    ${CHILD}"
                echo "merge:    ${MERGE}"
                echo "parent:   ${PARENT}"
                echo "OUTPUT:   ${OUTPUT}"
                ;;
        page)
                file=`argtofile $opts`
                echo file=$file 1>&2
                if [ -z "$file" ]; then
                        help
                        continue
                fi
                ${PAGER} $file
                ;;
        sh|!)
                if [ -z "$opts" ]; then
                        $SHELL
                else
                        $SHELL -c "$opts"
                fi
                ;;
        quit)   exit 1;;
        trap)   trap;;
        *)      help;;
        esac
done

# should exit directly from loop
exit 1

Reply via email to