--- a/contrib/bash_completion Sun Feb 05 20:52:55 2006 -0500
+++ b/contrib/bash_completion Sun Feb 05 22:18:38 2006 -0600
@@ -2,36 +2,36 @@
_hg_command_list()
{
- hg --debug help 2>/dev/null | \
+ "$hg" --debug help 2>/dev/null | \
awk 'function command_line(line) {
- gsub(/,/, "", line)
- gsub(/:.*/, "", line)
- split(line, aliases)
- command = aliases[1]
- delete aliases[1]
- print command
- for (i in aliases)
- if (index(command, aliases[i]) != 1)
- print aliases[i]
- }
- /^list of commands:/ {commands=1}
- commands && /^ debug/ {a[i++] = $0; next;}
- commands && /^ [^ ]/ {command_line($0)}
- /^global options:/ {exit 0}
- END {for (i in a) command_line(a[i])}'
+ gsub(/,/, "", line)
+ gsub(/:.*/, "", line)
+ split(line, aliases)
+ command = aliases[1]
+ delete aliases[1]
+ print command
+ for (i in aliases)
+ if (index(command, aliases[i]) != 1)
+ print aliases[i]
+ }
+ /^list of commands:/ {commands=1}
+ commands && /^ debug/ {a[i++] = $0; next;}
+ commands && /^ [^ ]/ {command_line($0)}
+ /^global options:/ {exit 0}
+ END {for (i in a) command_line(a[i])}'
}
_hg_option_list()
{
- hg -v help $1 2> /dev/null | \
- awk '/^ *-/ {
- for (i = 1; i <= NF; i ++) {
+ "$hg" -v help $1 2>/dev/null | \
+ awk '/^ *-/ {
+ for (i = 1; i <= NF; i ++) {
if (index($i, "-") != 1)
- break;
+ break;
print $i;
- }
- }'
+ }
+ }'
}
@@ -56,29 +56,29 @@
_hg_paths()
{
- local paths="$(hg paths 2> /dev/null | sed -e 's/ = .*$//')"
- COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W '$paths' -- "$cur" ))
+ local paths="$("$hg" paths 2>/dev/null | sed -e 's/ = .*$//')"
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur"))
}
_hg_repos()
{
local i
- for i in $( compgen -d -- "$cur" ); do
- test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
+ for i in $(compgen -d -- "$cur"); do
+ test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
done
}
_hg_status()
{
- local files="$( hg status -n$1 . 2> /dev/null)"
- COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W '$files' -- "$cur" ))
+ local files="$("$hg" status -n$1 . 2>/dev/null)"
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
}
_hg_tags()
{
- local tags="$(hg tags 2> /dev/null |
- sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//')"
- COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur") )
+ local tags="$("$hg" tags 2>/dev/null |
+ sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//')"
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur"))
}
# this is "kind of" ugly...
@@ -87,7 +87,7 @@
local i count=0
local filters="$1"
- for (( i=1; $i<=$COMP_CWORD; i++ )); do
+ for ((i=1; $i<=$COMP_CWORD; i++)); do
if [[ "${COMP_WORDS[i]}" != -* ]]; then
if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then
continue
@@ -104,6 +104,7 @@
local cur prev cmd opts i
# global options that receive an argument
local global_args='--cwd|-R|--repository'
+ local hg="$1"
COMPREPLY=()
cur="$2"
@@ -112,7 +113,7 @@
# searching for the command
# (first non-option argument that doesn't follow a global option that
# receives an argument)
- for (( i=1; $i<=$COMP_CWORD; i++ )); do
+ for ((i=1; $i<=$COMP_CWORD; i++)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
cmd="${COMP_WORDS[i]}"
@@ -124,7 +125,7 @@
if [[ "$cur" == -* ]]; then
opts=$(_hg_option_list $cmd)
- COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur") )
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur"))
return
fi
@@ -146,7 +147,7 @@
fi
# canonicalize command name
- cmd=$(hg -q help "$cmd" 2> /dev/null | sed -e 's/^hg //; s/ .*//; 1q')
+ cmd=$("$hg" -q help "$cmd" 2>/dev/null | sed -e 's/^hg //; s/ .*//; 1q')
if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" = --rev ]; then
_hg_tags
@@ -190,17 +191,17 @@
if [ $count = 1 ]; then
_hg_paths
fi
- _hg_repos
+ _hg_repos
;;
debugindex|debugindexdot)
- COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -X "!*.i" -- "$cur" ))
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur"))
;;
debugdata)
- COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -X "!*.d" -- "$cur" ))
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur"))
;;
esac
}
-complete -o bashdefault -o default -F _hg hg 2> /dev/null \
+complete -o bashdefault -o default -F _hg hg 2>/dev/null \
|| complete -o default -F _hg hg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/macosx/Readme.html Sun Feb 05 22:18:38 2006 -0600
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Style-Type" content="text/css">
+ <title></title>
+ <style type="text/css">
+ p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
+ p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
+ p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
+ p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #000fed}
+ span.s1 {text-decoration: underline}
+ span.s2 {font: 12.0px Courier}
+ </style>
+</head>
+<body>
+<p class="p1"><b>Before you install</b></p>
+<p class="p2"><br></p>
+<p class="p3">This is <i>not</i> a stand-alone version of Mercurial.</p>
+<p class="p2"><br></p>
+<p class="p3">To use it, you must have the “official unofficial” MacPython 2.4.1 installed.</p>
+<p class="p2"><br></p>
+<p class="p3">You can download MacPython 2.4.1 from here:</p>
+<p class="p4"><span class="s1"><a href="http://python.org/ftp/python/2.4.1/MacPython-OSX-2.4.1-1.dmg">http://python.org/ftp/python/2.4.1/MacPython-OSX-2.4.1-1.dmg</a></span></p>
+<p class="p2"><br></p>
+<p class="p3">For more information on MacPython, go here:</p>
+<p class="p4"><span class="s1"><a href="http://undefined.org/python/">http://undefined.org/python</a></span></p>
+<p class="p2"><br></p>
+<p class="p1"><b>After you install</b></p>
+<p class="p2"><br></p>
+<p class="p3">This package installs the <span class="s2">hg</span> executable in <span class="s2">/usr/local/bin</span>. This directory may not be in your shell's search path. Don't forget to check.</p>
+<p class="p2"><br></p>
+<p class="p1"><b>Reporting problems</b></p>
+<p class="p2"><br></p>
+<p class="p3">If you run into any problems, please file a bug online:</p>
+<p class="p3"><a href="http://www.selenic.com/mercurial/bts">http://www.selenic.com/mercurial/bts</a></p>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/macosx/Welcome.html Sun Feb 05 22:18:38 2006 -0600
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Style-Type" content="text/css">
+ <title></title>
+ <style type="text/css">
+ p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
+ p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
+ </style>
+</head>
+<body>
+<p class="p1">This is a prepackaged release of <a href="http://www.selenic.com/mercurial">Mercurial</a> for Mac OS X.</p>
+<p class="p2"><br></p>
+<p class="p1">It is based on Mercurial 0.8.</p>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/macosx/macosx-build.txt Sun Feb 05 22:18:38 2006 -0600
@@ -0,0 +1,11 @@
+to build a new macosx binary package:
+
+install macpython from http://undefined.org/python/
+
+install py2app from http://pythonmac.org/packages/
+
+make sure /usr/local/bin is in your path
+
+run bdist_mpkg in top-level hg directory
+
+find packaged stuff in dist directory
--- a/contrib/patchbomb Sun Feb 05 20:52:55 2006 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +0,0 @@
-#!/usr/bin/python
-#
-# Interactive script for sending a collection of Mercurial changesets
-# as a series of patch emails.
-#
-# The series is started off with a "[PATCH 0 of N]" introduction,
-# which describes the series as a whole.
-#
-# Each patch email has a Subject line of "[PATCH M of N] ...", using
-# the first line of the changeset description as the subject text.
-# The message contains two or three body parts:
-#
-# The remainder of the changeset description.
-#
-# [Optional] If the diffstat program is installed, the result of
-# running diffstat on the patch.
-#
-# The patch itself, as generated by "hg export".
-#
-# Each message refers to all of its predecessors using the In-Reply-To
-# and References headers, so they will show up as a sequence in
-# threaded mail and news readers, and in mail archives.
-#
-# For each changeset, you will be prompted with a diffstat summary and
-# the changeset summary, so you can be sure you are sending the right
-# changes.
-#
-# It is best to run this script with the "-n" (test only) flag before
-# firing it up "for real", in which case it will use your pager to
-# display each of the messages that it would send.
-#
-# To configure a default mail host, add a section like this to your
-# hgrc file:
-#
-# [smtp]
-# host = my_mail_host
-# port = 1025
-# tls = yes # or omit if not needed
-# username = user # if SMTP authentication required
-# password = password # if SMTP authentication required - PLAINTEXT
-#
-# To configure other defaults, add a section like this to your hgrc
-# file:
-#
-# [patchbomb]
-# from = My Name <my@email>
-# to = recipient1, recipient2, ...
-# cc = cc1, cc2, ...
-
-from email.MIMEMultipart import MIMEMultipart
-from email.MIMEText import MIMEText
-from mercurial import commands
-from mercurial import fancyopts
-from mercurial import hg
-from mercurial import ui
-import os
-import popen2
-import smtplib
-import socket
-import sys
-import tempfile
-import time
-
-try:
- # readline gives raw_input editing capabilities, but is not
- # present on windows
- import readline
-except ImportError: pass
-
-def diffstat(patch):
- fd, name = tempfile.mkstemp()
- try:
- p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
- try:
- for line in patch: print >> p.tochild, line
- p.tochild.close()
- if p.wait(): return
- fp = os.fdopen(fd, 'r')
- stat = []
- for line in fp: stat.append(line.lstrip())
- last = stat.pop()
- stat.insert(0, last)
- stat = ''.join(stat)
- if stat.startswith('0 files'): raise ValueError
- return stat
- except: raise
- finally:
- try: os.unlink(name)
- except: pass
-
-def patchbomb(ui, repo, *revs, **opts):
- def prompt(prompt, default = None, rest = ': ', empty_ok = False):
- if default: prompt += ' [%s]' % default
- prompt += rest
- while True:
- r = raw_input(prompt)
- if r: return r
- if default is not None: return default
- if empty_ok: return r
- ui.warn('Please enter a valid value.\n')
-
- def confirm(s):
- if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
- raise ValueError
-
- def cdiffstat(summary, patch):
- s = diffstat(patch)
- if s:
- if summary:
- ui.write(summary, '\n')
- ui.write(s, '\n')
- confirm('Does the diffstat above look okay')
- return s
-
- def makepatch(patch, idx, total):
- desc = []
- node = None
- body = ''
- for line in patch:
- if line.startswith('#'):
- if line.startswith('# Node ID'): node = line.split()[-1]
- continue
- if line.startswith('diff -r'): break
- desc.append(line)
- if not node: raise ValueError
-
- #body = ('\n'.join(desc[1:]).strip() or
- # 'Patch subject is complete summary.')
- #body += '\n\n\n'
-
- if opts['plain']:
- while patch and patch[0].startswith('# '): patch.pop(0)
- if patch: patch.pop(0)
- while patch and not patch[0].strip(): patch.pop(0)
- if opts['diffstat']:
- body += cdiffstat('\n'.join(desc), patch) + '\n\n'
- body += '\n'.join(patch)
- msg = MIMEText(body)
- subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
- if subj.endswith('.'): subj = subj[:-1]
- msg['Subject'] = subj
- msg['X-Mercurial-Node'] = node
- return msg
-
- start_time = int(time.time())
-
- def genmsgid(id):
- return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn())
-
- patches = []
-
- class exportee:
- def __init__(self, container):
- self.lines = []
- self.container = container
- self.name = 'email'
-
- def write(self, data):
- self.lines.append(data)
-
- def close(self):
- self.container.append(''.join(self.lines).split('\n'))
- self.lines = []
-
- commands.export(ui, repo, *args, **{'output': exportee(patches),
- 'switch_parent': False,
- 'text': None})
-
- jumbo = []
- msgs = []
-
- ui.write('This patch series consists of %d patches.\n\n' % len(patches))
-
- for p, i in zip(patches, range(len(patches))):
- jumbo.extend(p)
- msgs.append(makepatch(p, i + 1, len(patches)))
-
- ui.write('\nWrite the introductory message for the patch series.\n\n')
-
- sender = (opts['from'] or ui.config('patchbomb', 'from') or
- prompt('From', ui.username()))
-
- msg = MIMEMultipart()
- msg['Subject'] = '[PATCH 0 of %d] %s' % (
- len(patches),
- opts['subject'] or
- prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
-
- def getaddrs(opt, prpt, default = None):
- addrs = opts[opt] or (ui.config('patchbomb', opt) or
- prompt(prpt, default = default)).split(',')
- return [a.strip() for a in addrs if a.strip()]
- to = getaddrs('to', 'To')
- cc = getaddrs('cc', 'Cc', '')
-
- ui.write('Finish with ^D or a dot on a line by itself.\n\n')
-
- body = []
-
- while True:
- try: l = raw_input()
- except EOFError: break
- if l == '.': break
- body.append(l)
-
- msg.attach(MIMEText('\n'.join(body) + '\n'))
-
- ui.write('\n')
-
- if opts['diffstat']:
- d = cdiffstat('Final summary:\n', jumbo)
- if d: msg.attach(MIMEText(d))
-
- msgs.insert(0, msg)
-
- if not opts['test']:
- s = smtplib.SMTP()
- s.connect(host = ui.config('smtp', 'host', 'mail'),
- port = int(ui.config('smtp', 'port', 25)))
- if ui.configbool('smtp', 'tls'):
- s.ehlo()
- s.starttls()
- s.ehlo()
- username = ui.config('smtp', 'username')
- password = ui.config('smtp', 'password')
- if username and password:
- s.login(username, password)
- parent = None
- tz = time.strftime('%z')
- for m in msgs:
- try:
- m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
- except TypeError:
- m['Message-Id'] = genmsgid('patchbomb')
- if parent:
- m['In-Reply-To'] = parent
- else:
- parent = m['Message-Id']
- m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz
- start_time += 1
- m['From'] = sender
- m['To'] = ', '.join(to)
- if cc: m['Cc'] = ', '.join(cc)
- ui.status('Sending ', m['Subject'], ' ...\n')
- if opts['test']:
- fp = os.popen(os.getenv('PAGER', 'more'), 'w')
- fp.write(m.as_string(0))
- fp.write('\n')
- fp.close()
- else:
- s.sendmail(sender, to + cc, m.as_string(0))
- if not opts['test']:
- s.close()
-
-if __name__ == '__main__':
- optspec = [('c', 'cc', [], 'email addresses of copy recipients'),
- ('d', 'diffstat', None, 'add diffstat output to messages'),
- ('f', 'from', '', 'email address of sender'),
- ('', 'plain', None, 'omit hg patch header'),
- ('n', 'test', None, 'print messages that would be sent'),
- ('s', 'subject', '', 'subject of introductory message'),
- ('t', 'to', [], 'email addresses of recipients')]
- options = {}
- try:
- args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec,
- options)
- except fancyopts.getopt.GetoptError, inst:
- u = ui.ui()
- u.warn('error: %s' % inst)
- sys.exit(1)
-
- u = ui.ui(options["verbose"], options["debug"], options["quiet"],
- not options["noninteractive"])
- repo = hg.repository(ui = u)
-
- patchbomb(u, repo, *args, **options)
--- a/contrib/win32/ReadMe.html Sun Feb 05 20:52:55 2006 -0500
+++ b/contrib/win32/ReadMe.html Sun Feb 05 22:18:38 2006 -0600
@@ -5,7 +5,7 @@
</head>
<body>
- <h1>Mercurial version 0.7 for Windows</h1>
+ <h1>Mercurial version 0.8 for Windows</h1>
<p>Welcome to Mercurial for Windows!</p>
--- a/contrib/win32/mercurial.iss Sun Feb 05 20:52:55 2006 -0500
+++ b/contrib/win32/mercurial.iss Sun Feb 05 22:18:38 2006 -0600
@@ -4,7 +4,7 @@
[Setup]
AppCopyright=Copyright 2005 Matt Mackall and others
AppName=Mercurial
-AppVerName=Mercurial version 0.7
+AppVerName=Mercurial version 0.8
InfoAfterFile=contrib/win32/postinstall.txt
LicenseFile=COPYING
ShowLanguageDialog=yes
@@ -14,10 +14,10 @@
AppUpdatesURL=http://www.selenic.com/mercurial
AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}
AppContact=mercurial@selenic.com
-OutputBaseFilename=Mercurial-0.7
+OutputBaseFilename=Mercurial-0.8
DefaultDirName={sd}\Mercurial
SourceDir=C:\hg\hg-release
-VersionInfoVersion=0.7
+VersionInfoVersion=0.8
VersionInfoDescription=Mercurial distributed SCM
VersionInfoCopyright=Copyright 2005 Matt Mackall and others
VersionInfoCompany=Matt Mackall and others
--- a/contrib/win32/postinstall.txt Sun Feb 05 20:52:55 2006 -0500
+++ b/contrib/win32/postinstall.txt Sun Feb 05 22:18:38 2006 -0600
@@ -8,6 +8,27 @@
Release Notes
-------------
+2006-01-29 v0.8
+
+* Upgrade notes:
+
+ - diff and status command are now repo-wide by default
+ (use 'hg diff .' for the old behavior)
+ - GPG signing is now done with the gpg extension
+ - the --text option for commit, rawcommit, and tag has been removed
+ - the copy/rename --parents option has been removed
+
+* Major changes from 0.7 to 0.8:
+
+ - faster status, diff, and commit
+ - reduced memory usage for push and pull
+ - improved extension API
+ - new bisect, gpg, hgk, and win32text extensions
+ - short URLs, binary file handling, and optional gitweb skin for hgweb
+ - numerous new command options including log --keyword and pull --rev
+ - improved hooks and file filtering
+
+
2005-09-21 v0.7 with modifications
* New INI files have been added to control Mercurial's behaviour:
--- a/doc/Makefile Sun Feb 05 20:52:55 2006 -0500
+++ b/doc/Makefile Sun Feb 05 22:18:38 2006 -0600
@@ -15,7 +15,7 @@
asciidoc -d manpage -b docbook $*.txt
%.html: %.txt
- asciidoc -b html4 $*.txt
+ asciidoc -b html4 $*.txt || asciidoc -b html $*.txt
clean:
$(RM) $(MAN) $(MAN:%=%.xml) $(MAN:%=%.html)
--- a/hgext/gpg.py Sun Feb 05 20:52:55 2006 -0500
+++ b/hgext/gpg.py Sun Feb 05 22:18:38 2006 -0600
@@ -1,6 +1,14 @@
-import os, tempfile, binascii, errno
+# GnuPG signing extension for Mercurial
+#
+# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import os, tempfile, binascii
from mercurial import util
from mercurial import node as hgnode
+from mercurial.i18n import gettext as _
class gpg:
def __init__(self, path, key=None):
@@ -14,6 +22,7 @@
def verify(self, data, sig):
""" returns of the good and bad signatures"""
try:
+ # create temporary files
fd, sigfile = tempfile.mkstemp(prefix="hggpgsig")
fp = os.fdopen(fd, 'wb')
fp.write(sig)
@@ -22,8 +31,8 @@
fp = os.fdopen(fd, 'wb')
fp.write(data)
fp.close()
- gpgcmd = "%s --logger-fd 1 --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile)
- #gpgcmd = "%s --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile)
+ gpgcmd = ("%s --logger-fd 1 --status-fd 1 --verify "
+ "\"%s\" \"%s\"" % (self.path, sigfile, datafile))
ret = util.filter("", gpgcmd)
except:
for f in (sigfile, datafile):
@@ -41,7 +50,7 @@
continue
l = l[9:]
if l.startswith("ERRSIG"):
- err = "error while verifying signature"
+ err = _("error while verifying signature")
break
elif l.startswith("VALIDSIG"):
# fingerprint of the primary key
@@ -61,12 +70,97 @@
return err, keys
def newgpg(ui, **opts):
+ """create a new gpg instance"""
gpgpath = ui.config("gpg", "cmd", "gpg")
gpgkey = opts.get('key')
if not gpgkey:
gpgkey = ui.config("gpg", "key", None)
return gpg(gpgpath, gpgkey)
+def sigwalk(repo):
+ """
+ walk over every sigs, yields a couple
+ ((node, version, sig), (filename, linenumber))
+ """
+ def parsefile(fileiter, context):
+ ln = 1
+ for l in fileiter:
+ if not l:
+ continue
+ yield (l.split(" ", 2), (context, ln))
+ ln +=1
+
+ fl = repo.file(".hgsigs")
+ h = fl.heads()
+ h.reverse()
+ # read the heads
+ for r in h:
+ fn = ".hgsigs|%s" % hgnode.short(r)
+ for item in parsefile(fl.read(r).splitlines(), fn):
+ yield item
+ try:
+ # read local signatures
+ fn = "localsigs"
+ for item in parsefile(repo.opener(fn), fn):
+ yield item
+ except IOError:
+ pass
+
+def getkeys(ui, repo, mygpg, sigdata, context):
+ """get the keys who signed a data"""
+ fn, ln = context
+ node, version, sig = sigdata
+ prefix = "%s:%d" % (fn, ln)
+ node = hgnode.bin(node)
+
+ data = node2txt(repo, node, version)
+ sig = binascii.a2b_base64(sig)
+ err, keys = mygpg.verify(data, sig)
+ if err:
+ ui.warn("%s:%d %s\n" % (fn, ln , err))
+ return None
+
+ validkeys = []
+ # warn for expired key and/or sigs
+ for key in keys:
+ if key[0] == "BADSIG":
+ ui.write(_("%s Bad signature from \"%s\"\n") % (prefix, key[2]))
+ continue
+ if key[0] == "EXPSIG":
+ ui.write(_("%s Note: Signature has expired"
+ " (signed by: \"%s\")\n") % (prefix, key[2]))
+ elif key[0] == "EXPKEYSIG":
+ ui.write(_("%s Note: This key has expired"
+ " (signed by: \"%s\")\n") % (prefix, key[2]))
+ validkeys.append((key[1], key[2], key[3]))
+ return validkeys
+
+def sigs(ui, repo):
+ """list signed changesets"""
+ mygpg = newgpg(ui)
+ revs = {}
+
+ for data, context in sigwalk(repo):
+ node, version, sig = data
+ fn, ln = context
+ try:
+ n = repo.lookup(node)
+ except KeyError:
+ ui.warn(_("%s:%d node does not exist\n") % (fn, ln))
+ continue
+ r = repo.changelog.rev(n)
+ keys = getkeys(ui, repo, mygpg, data, context)
+ if not keys:
+ continue
+ revs.setdefault(r, [])
+ revs[r].extend(keys)
+ nodes = list(revs)
+ nodes.reverse()
+ for rev in nodes:
+ for k in revs[rev]:
+ r = "%5d:%s" % (rev, hgnode.hex(repo.changelog.node(rev)))
+ ui.write("%-30s %s\n" % (keystr(ui, k), r))
+
def check(ui, repo, rev):
"""verify all the signatures there may be for a particular revision"""
mygpg = newgpg(ui)
@@ -74,63 +168,30 @@
hexrev = hgnode.hex(rev)
keys = []
- def addsig(fn, ln, l):
- if not l: return
- n, v, sig = l.split(" ", 2)
- if n == hexrev:
- data = node2txt(repo, rev, v)
- sig = binascii.a2b_base64(sig)
- err, k = mygpg.verify(data, sig)
- if not err:
- keys.append((k, fn, ln))
- else:
- ui.warn("%s:%d %s\n" % (fn, ln , err))
-
- fl = repo.file(".hgsigs")
- h = fl.heads()
- h.reverse()
- # read the heads
- for r in h:
- ln = 1
- for l in fl.read(r).splitlines():
- addsig(".hgsigs|%s" % hgnode.short(r), ln, l)
- ln +=1
- try:
- # read local signatures
- ln = 1
- f = repo.opener("localsigs")
- for l in f:
- addsig("localsigs", ln, l)
- ln +=1
- except IOError:
- pass
+ for data, context in sigwalk(repo):
+ node, version, sig = data
+ if node == hexrev:
+ k = getkeys(ui, repo, mygpg, data, context)
+ if k:
+ keys.extend(k)
if not keys:
- ui.write("%s not signed\n" % hgnode.short(rev))
+ ui.write(_("No valid signature for %s\n") % hgnode.short(rev))
return
- valid = []
- # warn for expired key and/or sigs
- for k, fn, ln in keys:
- prefix = "%s:%d" % (fn, ln)
- for key in k:
- if key[0] == "BADSIG":
- ui.write("%s Bad signature from \"%s\"\n" % (prefix, key[2]))
- continue
- if key[0] == "EXPSIG":
- ui.write("%s Note: Signature has expired"
- " (signed by: \"%s\")\n" % (prefix, key[2]))
- elif key[0] == "EXPKEYSIG":
- ui.write("%s Note: This key has expired"
- " (signed by: \"%s\")\n" % (prefix, key[2]))
- valid.append((key[1], key[2], key[3]))
+
# print summary
ui.write("%s is signed by:\n" % hgnode.short(rev))
- for keyid, user, fingerprint in valid:
- role = getrole(ui, fingerprint)
- ui.write(" %s (%s)\n" % (user, role))
+ for key in keys:
+ ui.write(" %s\n" % keystr(ui, key))
-def getrole(ui, fingerprint):
- return ui.config("gpg", fingerprint, "no role defined")
+def keystr(ui, key):
+ """associate a string to a key (username, comment)"""
+ keyid, user, fingerprint = key
+ comment = ui.config("gpg", fingerprint, None)
+ if comment:
+ return "%s (%s)" % (user, comment)
+ else:
+ return user
def sign(ui, repo, *revs, **opts):
"""add a signature for the current tip or a given revision"""
@@ -150,7 +211,7 @@
data = node2txt(repo, n, sigver)
sig = mygpg.sign(data)
if not sig:
- raise util.Abort("Error while signing")
+ raise util.Abort(_("Error while signing"))
sig = binascii.b2a_base64(sig)
sig = sig.replace("\n", "")
sigmessage += "%s %s %s\n" % (hexnode, sigver, sig)
@@ -162,9 +223,9 @@
for x in repo.changes():
if ".hgsigs" in x and not opts["force"]:
- raise util.Abort("working copy of .hgsigs is changed "
- "(please commit .hgsigs manually"
- "or use --force)")
+ raise util.Abort(_("working copy of .hgsigs is changed "
+ "(please commit .hgsigs manually "
+ "or use --force)"))
repo.wfile(".hgsigs", "ab").write(sigmessage)
@@ -176,7 +237,8 @@
message = opts['message']
if not message:
- message = "\n".join(["Added signature for changeset %s" % hgnode.hex(n)
+ message = "\n".join([_("Added signature for changeset %s")
+ % hgnode.hex(n)
for n in nodes])
try:
repo.commit([".hgsigs"], message, opts['user'], opts['date'])
@@ -188,19 +250,20 @@
if ver == "0":
return "%s\n" % hgnode.hex(node)
else:
- util.Abort("unknown signature version")
+ raise util.Abort(_("unknown signature version"))
cmdtable = {
"sign":
(sign,
- [('l', 'local', None, "make the signature local"),
- ('f', 'force', None, "sign even if the sigfile is modified"),
- ('', 'no-commit', None, "do not commit the sigfile after signing"),
- ('m', 'message', "", "commit message"),
- ('d', 'date', "", "date code"),
- ('u', 'user', "", "user"),
- ('k', 'key', "", "the key id to sign with")],
- "hg sign [OPTION]... REVISIONS"),
- "sigcheck": (check, [], 'hg sigcheck REVISION')
+ [('l', 'local', None, _("make the signature local")),
+ ('f', 'force', None, _("sign even if the sigfile is modified")),
+ ('', 'no-commit', None, _("do not commit the sigfile after signing")),
+ ('m', 'message', "", _("commit message")),
+ ('d', 'date', "", _("date code")),
+ ('u', 'user', "", _("user")),
+ ('k', 'key', "", _("the key id to sign with"))],
+ _("hg sign [OPTION]... [REVISION]...")),
+ "sigcheck": (check, [], _('hg sigcheck REVISION')),
+ "sigs": (sigs, [], _('hg sigs')),
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/patchbomb.py Sun Feb 05 22:18:38 2006 -0600
@@ -0,0 +1,275 @@
+# Command for sending a collection of Mercurial changesets as a series
+# of patch emails.
+#
+# The series is started off with a "[PATCH 0 of N]" introduction,
+# which describes the series as a whole.
+#
+# Each patch email has a Subject line of "[PATCH M of N] ...", using
+# the first line of the changeset description as the subject text.
+# The message contains two or three body parts:
+#
+# The remainder of the changeset description.
+#
+# [Optional] If the diffstat program is installed, the result of
+# running diffstat on the patch.
+#
+# The patch itself, as generated by "hg export".
+#
+# Each message refers to all of its predecessors using the In-Reply-To
+# and References headers, so they will show up as a sequence in
+# threaded mail and news readers, and in mail archives.
+#
+# For each changeset, you will be prompted with a diffstat summary and
+# the changeset summary, so you can be sure you are sending the right
+# changes.
+#
+# It is best to run this script with the "-n" (test only) flag before
+# firing it up "for real", in which case it will use your pager to
+# display each of the messages that it would send.
+#
+# To configure a default mail host, add a section like this to your
+# hgrc file:
+#
+# [smtp]
+# host = my_mail_host
+# port = 1025
+# tls = yes # or omit if not needed
+# username = user # if SMTP authentication required
+# password = password # if SMTP authentication required - PLAINTEXT
+#
+# To configure other defaults, add a section like this to your hgrc
+# file:
+#
+# [patchbomb]
+# from = My Name <my@email>
+# to = recipient1, recipient2, ...
+# cc = cc1, cc2, ...
+
+from email.MIMEMultipart import MIMEMultipart
+from email.MIMEText import MIMEText
+from mercurial import commands
+from mercurial import hg
+from mercurial import ui
+from mercurial.i18n import gettext as _
+import os
+import popen2
+import smtplib
+import socket
+import sys
+import tempfile
+import time
+
+try:
+ # readline gives raw_input editing capabilities, but is not
+ # present on windows
+ import readline
+except ImportError: pass
+
+def diffstat(patch):
+ fd, name = tempfile.mkstemp()
+ try:
+ p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
+ try:
+ for line in patch: print >> p.tochild, line
+ p.tochild.close()
+ if p.wait(): return
+ fp = os.fdopen(fd, 'r')
+ stat = []
+ for line in fp: stat.append(line.lstrip())
+ last = stat.pop()
+ stat.insert(0, last)
+ stat = ''.join(stat)
+ if stat.startswith('0 files'): raise ValueError
+ return stat
+ except: raise
+ finally:
+ try: os.unlink(name)
+ except: pass
+
+def patchbomb(ui, repo, *revs, **opts):
+ '''send changesets as a series of patch emails
+
+ The series starts with a "[PATCH 0 of N]" introduction, which
+ describes the series as a whole.
+
+ Each patch email has a Subject line of "[PATCH M of N] ...", using
+ the first line of the changeset description as the subject text.
+ The message contains two or three body parts. First, the rest of
+ the changeset description. Next, (optionally) if the diffstat
+ program is installed, the result of running diffstat on the patch.
+ Finally, the patch itself, as generated by "hg export".'''
+ def prompt(prompt, default = None, rest = ': ', empty_ok = False):
+ if default: prompt += ' [%s]' % default
+ prompt += rest
+ while True:
+ r = raw_input(prompt)
+ if r: return r
+ if default is not None: return default
+ if empty_ok: return r
+ ui.warn(_('Please enter a valid value.\n'))
+
+ def confirm(s):
+ if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
+ raise ValueError
+
+ def cdiffstat(summary, patch):
+ s = diffstat(patch)
+ if s:
+ if summary:
+ ui.write(summary, '\n')
+ ui.write(s, '\n')
+ confirm(_('Does the diffstat above look okay'))
+ return s
+
+ def makepatch(patch, idx, total):
+ desc = []
+ node = None
+ body = ''
+ for line in patch:
+ if line.startswith('#'):
+ if line.startswith('# Node ID'): node = line.split()[-1]
+ continue
+ if line.startswith('diff -r'): break
+ desc.append(line)
+ if not node: raise ValueError
+
+ #body = ('\n'.join(desc[1:]).strip() or
+ # 'Patch subject is complete summary.')
+ #body += '\n\n\n'
+
+ if opts['plain']:
+ while patch and patch[0].startswith('# '): patch.pop(0)
+ if patch: patch.pop(0)
+ while patch and not patch[0].strip(): patch.pop(0)
+ if opts['diffstat']:
+ body += cdiffstat('\n'.join(desc), patch) + '\n\n'
+ body += '\n'.join(patch)
+ msg = MIMEText(body)
+ subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
+ if subj.endswith('.'): subj = subj[:-1]
+ msg['Subject'] = subj
+ msg['X-Mercurial-Node'] = node
+ return msg
+
+ start_time = int(time.time())
+
+ def genmsgid(id):
+ return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn())
+
+ patches = []
+
+ class exportee:
+ def __init__(self, container):
+ self.lines = []
+ self.container = container
+ self.name = 'email'
+
+ def write(self, data):
+ self.lines.append(data)
+
+ def close(self):
+ self.container.append(''.join(self.lines).split('\n'))
+ self.lines = []
+
+ commands.export(ui, repo, *revs, **{'output': exportee(patches),
+ 'switch_parent': False,
+ 'text': None})
+
+ jumbo = []
+ msgs = []
+
+ ui.write(_('This patch series consists of %d patches.\n\n') % len(patches))
+
+ for p, i in zip(patches, range(len(patches))):
+ jumbo.extend(p)
+ msgs.append(makepatch(p, i + 1, len(patches)))
+
+ ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
+
+ sender = (opts['from'] or ui.config('patchbomb', 'from') or
+ prompt('From', ui.username()))
+
+ msg = MIMEMultipart()
+ msg['Subject'] = '[PATCH 0 of %d] %s' % (
+ len(patches),
+ opts['subject'] or
+ prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
+
+ def getaddrs(opt, prpt, default = None):
+ addrs = opts[opt] or (ui.config('patchbomb', opt) or
+ prompt(prpt, default = default)).split(',')
+ return [a.strip() for a in addrs if a.strip()]
+ to = getaddrs('to', 'To')
+ cc = getaddrs('cc', 'Cc', '')
+
+ ui.write(_('Finish with ^D or a dot on a line by itself.\n\n'))
+
+ body = []
+
+ while True:
+ try: l = raw_input()
+ except EOFError: break
+ if l == '.': break
+ body.append(l)
+
+ msg.attach(MIMEText('\n'.join(body) + '\n'))
+
+ ui.write('\n')
+
+ if opts['diffstat']:
+ d = cdiffstat(_('Final summary:\n'), jumbo)
+ if d: msg.attach(MIMEText(d))
+
+ msgs.insert(0, msg)
+
+ if not opts['test']:
+ s = smtplib.SMTP()
+ s.connect(host = ui.config('smtp', 'host', 'mail'),
+ port = int(ui.config('smtp', 'port', 25)))
+ if ui.configbool('smtp', 'tls'):
+ s.ehlo()
+ s.starttls()
+ s.ehlo()
+ username = ui.config('smtp', 'username')
+ password = ui.config('smtp', 'password')
+ if username and password:
+ s.login(username, password)
+ parent = None
+ tz = time.strftime('%z')
+ for m in msgs:
+ try:
+ m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
+ except TypeError:
+ m['Message-Id'] = genmsgid('patchbomb')
+ if parent:
+ m['In-Reply-To'] = parent
+ else:
+ parent = m['Message-Id']
+ m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz
+ start_time += 1
+ m['From'] = sender
+ m['To'] = ', '.join(to)
+ if cc: m['Cc'] = ', '.join(cc)
+ ui.status('Sending ', m['Subject'], ' ...\n')
+ if opts['test']:
+ fp = os.popen(os.getenv('PAGER', 'more'), 'w')
+ fp.write(m.as_string(0))
+ fp.write('\n')
+ fp.close()
+ else:
+ s.sendmail(sender, to + cc, m.as_string(0))
+ if not opts['test']:
+ s.close()
+
+cmdtable = {
+ 'email':
+ (patchbomb,
+ [('c', 'cc', [], 'email addresses of copy recipients'),
+ ('d', 'diffstat', None, 'add diffstat output to messages'),
+ ('f', 'from', '', 'email address of sender'),
+ ('', 'plain', None, 'omit hg patch header'),
+ ('n', 'test', None, 'print messages that would be sent'),
+ ('s', 'subject', '', 'subject of introductory message'),
+ ('t', 'to', [], 'email addresses of recipients')],
+ "hg email [OPTION]... [REV]...")
+ }
--- a/mercurial/localrepo.py Sun Feb 05 20:52:55 2006 -0500
+++ b/mercurial/localrepo.py Sun Feb 05 22:18:38 2006 -0600
@@ -1399,6 +1399,13 @@
modified, added, removed, deleted, unknown = self.changes()
+ # is this a jump, or a merge? i.e. is there a linear path
+ # from p1 to p2?
+ linear_path = (pa == p1 or pa == p2)
+
+ if allow and linear_path:
+ raise util.Abort(_("there is nothing to merge, "
+ "just use 'hg update'"))
if allow and not forcemerge:
if modified or added or removed:
raise util.Abort(_("outstanding uncommited changes"))
@@ -1411,10 +1418,6 @@
raise util.Abort(_("'%s' already exists in the working"
" dir and differs from remote") % f)
- # is this a jump, or a merge? i.e. is there a linear path
- # from p1 to p2?
- linear_path = (pa == p1 or pa == p2)
-
# resolve the manifest to determine which files
# we care about merging
self.ui.note(_("resolving manifests\n"))
--- a/setup.py Sun Feb 05 20:52:55 2006 -0500
+++ b/setup.py Sun Feb 05 22:18:38 2006 -0600
@@ -81,7 +81,7 @@
author='Matt Mackall',
author_email='mpm@selenic.com',
url='http://selenic.com/mercurial',
- description='scalable distributed SCM',
+ description='Scalable distributed SCM',
license='GNU GPL',
packages=['mercurial', 'hgext'],
ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
@@ -92,6 +92,10 @@
glob.glob('templates/*.tmpl'))],
cmdclass=cmdclass,
scripts=['hg', 'hgmerge'],
+ options=dict(bdist_mpkg=dict(zipdist=True,
+ license='COPYING',
+ readme='contrib/macosx/Readme.html',
+ welcome='contrib/macosx/Welcome.html')),
**py2exe_opts)
finally:
mercurial.version.forget_version()
--- a/templates/fileannotate-gitweb.tmpl Sun Feb 05 20:52:55 2006 -0500
+++ b/templates/fileannotate-gitweb.tmpl Sun Feb 05 22:18:38 2006 -0600
@@ -10,7 +10,7 @@
</div>
<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate<br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
</div>
<div class="title">#file|escape#</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/fileannotate-raw.tmpl Sun Feb 05 22:18:38 2006 -0600
@@ -0,0 +1,5 @@
+#header#
+#annotate%annotateline#
+#footer#
+
+
--- a/templates/fileannotate.tmpl Sun Feb 05 20:52:55 2006 -0500
+++ b/templates/fileannotate.tmpl Sun Feb 05 22:18:38 2006 -0600
@@ -10,6 +10,7 @@
<a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a>
<a href="?f=#filenode|short#;file=#file|urlescape#">file</a>
<a href="?fl=#filenode|short#;file=#file|urlescape#">revisions</a>
+<a href="?fa=#filenode|short#;file=#file|urlescape#;style=raw">raw</a>
</div>
<h2>Annotate #file|escape#</h2>
--- a/templates/map Sun Feb 05 20:52:55 2006 -0500
+++ b/templates/map Sun Feb 05 22:18:38 2006 -0600
@@ -43,7 +43,7 @@
filelogparent = "<tr><td align="right">parent #rev#: </td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
filediffchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
filelogchild = "<tr><td align="right">child #rev#: </td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
-indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#shortdesc|escape#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>"
+indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#shortdesc#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>"
index = index.tmpl
archiveentry = "<a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> "
notfound = notfound.tmpl
--- a/templates/map-raw Sun Feb 05 20:52:55 2006 -0500
+++ b/templates/map-raw Sun Feb 05 22:18:38 2006 -0600
@@ -1,15 +1,16 @@
header = header-raw.tmpl
footer = ""
changeset = changeset-raw.tmpl
-annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cmd=changeset;node=#node#">#author#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>"
-difflineplus = "#line|escape#"
-difflineminus = "#line|escape#"
-difflineat = "#line|escape#"
-diffline = "#line|escape#"
+difflineplus = "#line#"
+difflineminus = "#line#"
+difflineat = "#line#"
+diffline = "#line#"
changesetparent = "# parent: #node#"
changesetchild = "# child: #node#"
-filenodelink = "#file|urlescape#"
+filenodelink = ""
filerevision = filerevision-raw.tmpl
-fileline = "#line|escape#"
+fileline = "#line#"
diffblock = "#lines#"
filediff = filediff-raw.tmpl
+fileannotate = fileannotate-raw.tmpl
+annotateline = "#author#@#rev#: #line#"
--- a/tests/test-up-local-change Sun Feb 05 20:52:55 2006 -0500
+++ b/tests/test-up-local-change Sun Feb 05 22:18:38 2006 -0600
@@ -24,11 +24,34 @@
cd ../r2
hg -q pull ../r1
hg status
+hg parents
hg --debug up
+hg parents
+hg --debug up 0
+hg parents
hg --debug up -m || echo failed
-hg --debug up -f -m
+hg parents
+hg --debug up
hg parents
hg -v history
hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+# create a second head
+cd ../r1
+hg up 0
+echo b2 > b
+echo a3 > a
+hg addremove
+hg commit -m "3" -d "0 0"
+
+cd ../r2
+hg -q pull ../r1
+hg status
+hg parents
+hg --debug up || echo failed
+hg --debug up -m || echo failed
+hg --debug up -f -m
+hg parents
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-up-local-change.out Sun Feb 05 20:52:55 2006 -0500
+++ b/tests/test-up-local-change.out Sun Feb 05 22:18:38 2006 -0600
@@ -7,6 +7,11 @@
+abc
adding b
M a
+changeset: 0:c19d34741b0a
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 1
+
resolving manifests
force None allow None moddirstate True linear True
ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
@@ -16,11 +21,38 @@
merging a
resolving a
file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
-abort: outstanding uncommited changes
-failed
+changeset: 1:1e71731e6fbb
+tag: tip
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 2
+
resolving manifests
- force None allow 1 moddirstate True linear True
- ancestor 1165e8bd193e local 1165e8bd193e remote 1165e8bd193e
+ force None allow None moddirstate True linear True
+ ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
+remote deleted b
+removing b
+changeset: 0:c19d34741b0a
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 1
+
+abort: there is nothing to merge, just use 'hg update'
+failed
+changeset: 0:c19d34741b0a
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 1
+
+resolving manifests
+ force None allow None moddirstate True linear True
+ ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
+ a versions differ, resolve
+remote created b
+getting b
+merging a
+resolving a
+file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
changeset: 1:1e71731e6fbb
tag: tip
user: test
@@ -50,3 +82,52 @@
@@ -1,1 +1,1 @@ a2
-a2
+abc
+adding b
+M a
+changeset: 1:1e71731e6fbb
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 2
+
+resolving manifests
+ force None allow None moddirstate True linear False
+ ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
+ a versions differ, resolve
+ b versions differ, resolve
+this update spans a branch affecting the following files:
+ a (resolve)
+ b (resolve)
+aborting update spanning branches!
+(use update -m to merge across branches or -C to lose changes)
+failed
+abort: outstanding uncommited changes
+failed
+resolving manifests
+ force None allow 1 moddirstate True linear False
+ ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
+ a versions differ, resolve
+ b versions differ, resolve
+merging a
+resolving a
+file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2
+merging b
+resolving b
+file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000
+changeset: 1:1e71731e6fbb
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 2
+
+changeset: 2:83c51d0caff4
+tag: tip
+parent: 0:c19d34741b0a
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: 3
+
+diff -r 1e71731e6fbb a
+--- a/a
++++ b/a
+@@ -1,1 +1,1 @@ a2
+-a2
++abc