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