view hgmerge @ 1031:503aaf19a040

Rewrite log command. New version is faster and more featureful. The original implementation of log walked backwards through history, which had terrible behaviour. It took several minutes to view complete kernel change history on a fast machine, for example. The rewrite uses a windowed approach to walk hunks of history forwards, while still giving results in reverse order. This reduces run time from five minutes to five seconds on my system. In addition, the rewrite uses our normal name handling mechanisms, so you can run a command like "hg log net/ipv4/**.c" and get a useful answer. It optimises for three different cases (no arguments, only files, and anything goes), so it performs well in all circumstances I've tested.
author Bryan O'Sullivan <bos@serpentine.com>
date Wed, 24 Aug 2005 12:39:10 -0700
parents 9c918287d10b
children 696851b1bba9
line wrap: on
line source

#!/bin/sh
#
# hgmerge - default merge helper for Mercurial
#
# This tries to find a way to do three-way merge on the current system.
# The result ought to end up in $1.

set -e # bail out quickly on failure

LOCAL="$1"
BASE="$2"
OTHER="$3"

if [ -z "$EDITOR" ]; then
    EDITOR="vi"
fi

# Back up our file
cp "$LOCAL" "$LOCAL.orig"

# Attempt to do a non-interactive merge
if type merge > /dev/null 2>&1; then
    merge "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && exit 0
    cp "$LOCAL.orig" "$LOCAL"
elif type diff3 > /dev/null 2>&1; then
    diff3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && exit 0
    cp "$LOCAL.orig" "$LOCAL"
fi

if [ -n "$DISPLAY" ]; then
    # try using kdiff3, which is fairly nice
    if type kdiff3 > /dev/null 2>&1; then
	kdiff3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || exit 1
	exit 0
    fi

    # try using tkdiff, which is a bit less sophisticated
    if type tkdiff > /dev/null 2>&1; then
	tkdiff "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || exit 1
	exit 0
    fi
fi

# Attempt to do a merge with $EDITOR
if type merge > /dev/null 2>&1; then
    echo "conflicts detected in $LOCAL"
    merge "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL"
    exit 0
fi

if type diff3 > /dev/null 2>&1; then
    echo "conflicts detected in $LOCAL"
    diff3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || $EDITOR "$LOCAL"
    exit 0
fi

HGTMP=""
cleanup_exit() {
    rm -rf "$HGTMP"
}

# attempt to manually merge with diff and patch
if type diff > /dev/null 2>&1 && type patch > /dev/null 2>&1; then
    # Remove temporary files even if we get interrupted
    trap "cleanup_exit" 0 # normal exit
    trap "exit 1" 1 2 3 6 15 # HUP INT QUIT ABRT TERM

    HGTMP="${TMPDIR-/tmp}/hgmerge.$RANDOM.$RANDOM.$RANDOM.$$"
    (umask 077 && mkdir "$HGTMP") || {
	echo "Could not create temporary directory! Exiting." 1>&2
	exit 1
    }

    diff -u "$BASE" "$OTHER" > "$HGTMP/diff"
    if patch "$LOCAL" < "$HGTMP/diff"; then
	exit 0
    else
	# If rejects are empty after using the editor, merge was ok
	$EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || exit 0
    fi
    exit 1
fi

echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!"
exit 1