changeset 5276:aea35488ea66

merge with crew-stable
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Fri, 31 Aug 2007 22:31:43 +0200
parents d3874a286b51 (current diff) 5c2ca6d6ab21 (diff)
children a32a8e50d233 ed6df6b1c29a b62a59fa9d26
files mercurial/hg.py tests/test-changelog-exec tests/test-convert-git tests/test-pull-r tests/test-url-rev
diffstat 21 files changed, 452 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/convert/git.py
+++ b/hgext/convert/git.py
@@ -1,6 +1,7 @@
 # git support for the convert extension
 
 import os
+from mercurial import util
 
 from common import NoRepo, commit, converter_source
 
@@ -14,6 +15,24 @@ def recode(s):
             return s.decode("utf-8", "replace").encode("utf-8")
 
 class convert_git(converter_source):
+    # Windows does not support GIT_DIR= construct while other systems
+    # cannot remove environment variable. Just assume none have
+    # both issues.
+    if hasattr(os, 'unsetenv'):
+        def gitcmd(self, s):
+            prevgitdir = os.environ.get('GIT_DIR')
+            os.environ['GIT_DIR'] = self.path
+            try:
+                return os.popen(s)
+            finally:
+                if prevgitdir is None:
+                    del os.environ['GIT_DIR']
+                else:
+                    os.environ['GIT_DIR'] = prevgitdir
+    else:
+        def gitcmd(self, s):
+            return os.popen('GIT_DIR=%s %s' % (self.path, s))
+    
     def __init__(self, ui, path):
         if os.path.isdir(path + "/.git"):
             path += "/.git"
@@ -23,13 +42,13 @@ class convert_git(converter_source):
             raise NoRepo("couldn't open GIT repo %s" % path)
 
     def getheads(self):
-        fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path)
+        fh = self.gitcmd("git-rev-parse --verify HEAD")
         return [fh.read()[:-1]]
 
     def catfile(self, rev, type):
         if rev == "0" * 40: raise IOError()
-        fh = os.popen("GIT_DIR=%s git-cat-file %s %s 2>/dev/null"
-                      % (self.path, type, rev))
+        fh = self.gitcmd("git-cat-file %s %s 2>%s" % (type, rev,
+                                                      util.nulldev))
         return fh.read()
 
     def getfile(self, name, rev):
@@ -40,8 +59,7 @@ class convert_git(converter_source):
 
     def getchanges(self, version):
         self.modecache = {}
-        fh = os.popen("GIT_DIR=%s git-diff-tree --root -m -r %s"
-                      % (self.path, version))
+        fh = self.gitcmd("git-diff-tree --root -m -r %s" % version)
         changes = []
         for l in fh:
             if "\t" not in l: continue
@@ -89,7 +107,8 @@ class convert_git(converter_source):
 
     def gettags(self):
         tags = {}
-        fh = os.popen('git-ls-remote --tags "%s" 2>/dev/null' % self.path)
+        fh = self.gitcmd('git-ls-remote --tags "%s" 2>%s' % (self.path,
+                                                             util.nulldev))
         prefix = 'refs/tags/'
         for line in fh:
             line = line.strip()
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -1490,6 +1490,11 @@ def clone(ui, source, dest=None, **opts)
     Source patch repository is looked for in <src>/.hg/patches by
     default.  Use -p <url> to change.
     '''
+    def patchdir(repo):
+        url = repo.url()
+        if url.endswith('/'):
+            url = url[:-1]
+        return url + '/.hg/patches'
     cmdutil.setremoteconfig(ui, opts)
     if dest is None:
         dest = hg.defaultdest(source)
@@ -1511,10 +1516,8 @@ def clone(ui, source, dest=None, **opts)
                       update=False,
                       stream=opts['uncompressed'])
     ui.note(_('cloning patch repo\n'))
-    spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
-                        dr.url() + '/.hg/patches',
-                        pull=opts['pull'],
-                        update=not opts['noupdate'],
+    spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
+                        pull=opts['pull'], update=not opts['noupdate'],
                         stream=opts['uncompressed'])
     if dr.local():
         if qbase:
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -462,10 +462,10 @@ def parseurl(url, revs):
     '''parse url#branch, returning url, branch + revs'''
 
     if '#' not in url:
-        return url, (revs or None)
+        return url, (revs or None), None
 
     url, rev = url.split('#', 1)
-    return url, revs + [rev]
+    return url, revs + [rev], rev
 
 def revpair(repo, revs):
     '''return pair of nodes, given list of revisions. second item can
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -324,7 +324,7 @@ def bundle(ui, repo, fname, dest=None, *
                         visit.append(p)
     else:
         cmdutil.setremoteconfig(ui, opts)
-        dest, revs = cmdutil.parseurl(
+        dest, revs, checkout = cmdutil.parseurl(
             ui.expandpath(dest or 'default-push', dest or 'default'), revs)
         other = hg.repository(ui, dest)
         o = repo.findoutgoing(other, force=opts['force'])
@@ -1491,7 +1491,7 @@ def identify(ui, repo, source=None,
     output = []
 
     if source:
-        source, revs = cmdutil.parseurl(ui.expandpath(source), [])
+        source, revs, checkout = cmdutil.parseurl(ui.expandpath(source), [])
         srepo = hg.repository(ui, source)
         if not rev and revs:
             rev = revs[0]
@@ -1649,7 +1649,8 @@ def incoming(ui, repo, source="default",
 
     See pull for valid source format details.
     """
-    source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
+    source, revs, checkout = cmdutil.parseurl(ui.expandpath(source),
+                                              opts['rev'])
     cmdutil.setremoteconfig(ui, opts)
 
     other = hg.repository(ui, source)
@@ -1952,7 +1953,7 @@ def outgoing(ui, repo, dest=None, **opts
 
     See pull for valid destination format details.
     """
-    dest, revs = cmdutil.parseurl(
+    dest, revs, checkout = cmdutil.parseurl(
         ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
     cmdutil.setremoteconfig(ui, opts)
     if revs:
@@ -2020,12 +2021,12 @@ def paths(ui, repo, search=None):
         for name, path in ui.configitems("paths"):
             ui.write("%s = %s\n" % (name, path))
 
-def postincoming(ui, repo, modheads, optupdate):
+def postincoming(ui, repo, modheads, optupdate, checkout):
     if modheads == 0:
         return
     if optupdate:
-        if modheads <= 1:
-            return hg.update(repo, None)
+        if modheads <= 1 or checkout:
+            return hg.update(repo, checkout)
         else:
             ui.status(_("not updating, since new heads added\n"))
     if modheads > 1:
@@ -2074,7 +2075,8 @@ def pull(ui, repo, source="default", **o
       Alternatively specify "ssh -C" as your ssh command in your hgrc or
       with the --ssh command line option.
     """
-    source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
+    source, revs, checkout = cmdutil.parseurl(ui.expandpath(source),
+                                              opts['rev'])
     cmdutil.setremoteconfig(ui, opts)
 
     other = hg.repository(ui, source)
@@ -2087,7 +2089,7 @@ def pull(ui, repo, source="default", **o
             raise util.Abort(error)
 
     modheads = repo.pull(other, heads=revs, force=opts['force'])
-    return postincoming(ui, repo, modheads, opts['update'])
+    return postincoming(ui, repo, modheads, opts['update'], checkout)
 
 def push(ui, repo, dest=None, **opts):
     """push changes to the specified destination
@@ -2119,7 +2121,7 @@ def push(ui, repo, dest=None, **opts):
     Pushing to http:// and https:// URLs is only possible, if this
     feature is explicitly enabled on the remote Mercurial server.
     """
-    dest, revs = cmdutil.parseurl(
+    dest, revs, checkout = cmdutil.parseurl(
         ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
     cmdutil.setremoteconfig(ui, opts)
 
@@ -2336,6 +2338,14 @@ def revert(ui, repo, *pats, **opts):
     changes = repo.status(match=names.has_key, wlock=wlock)[:5]
     modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
 
+    # if f is a rename, also revert the source
+    cwd = repo.getcwd()
+    for f in added:
+        src = repo.dirstate.copied(f)
+        if src and src not in names and repo.dirstate[src][0] == 'r':
+            removed[src] = None
+            names[src] = (repo.pathto(src, cwd), True)
+
     revert = ([], _('reverting %s\n'))
     add = ([], _('adding %s\n'))
     remove = ([], _('removing %s\n'))
@@ -2659,7 +2669,7 @@ def unbundle(ui, repo, fname1, *fnames, 
         gen = changegroup.readbundle(f, fname)
         modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
 
-    return postincoming(ui, repo, modheads, opts['update'])
+    return postincoming(ui, repo, modheads, opts['update'], None)
 
 def update(ui, repo, node=None, rev=None, clean=False, date=None):
     """update working directory
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -99,7 +99,7 @@ def clone(ui, source, dest=None, pull=Fa
     """
 
     origsource = source
-    source, rev = cmdutil.parseurl(ui.expandpath(source), rev)
+    source, rev, checkout = cmdutil.parseurl(ui.expandpath(source), rev)
 
     if isinstance(source, str):
         src_repo = repository(ui, source)
@@ -141,7 +141,7 @@ def clone(ui, source, dest=None, pull=Fa
     abspath = origsource
     copy = False
     if src_repo.local() and islocal(dest):
-        abspath = os.path.abspath(origsource)
+        abspath = os.path.abspath(util.drop_scheme('file', origsource))
         copy = not pull and not rev
 
     src_lock, dest_lock = None, None
@@ -229,10 +229,11 @@ def clone(ui, source, dest=None, pull=Fa
             dest_lock.release()
 
         if update:
-            try:
-                checkout = dest_repo.lookup("default")
-            except:
-                checkout = dest_repo.changelog.tip()
+            if not checkout:
+                try:
+                    checkout = dest_repo.lookup("default")
+                except:
+                    checkout = dest_repo.changelog.tip()
             _update(dest_repo, checkout)
 
     return src_repo, dest_repo
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -612,7 +612,9 @@ class localrepository(repo.repository):
             elif fp1 != nullid: # copied on local side, reversed
                 meta["copyrev"] = hex(manifest2.get(cp))
                 fp2 = fp1
-            else: # directory rename
+            elif cp in manifest2: # directory rename on local side
+                meta["copyrev"] = hex(manifest2[cp])
+            else: # directory rename on remote side
                 meta["copyrev"] = hex(manifest1.get(cp, nullid))
             self.ui.debug(_(" %s: copy %s:%s\n") %
                           (fn, cp, meta["copyrev"]))
@@ -626,7 +628,7 @@ class localrepository(repo.repository):
                 fp2 = nullid
 
         # is the file unmodified from the parent? report existing entry
-        if fp2 == nullid and not fl.cmp(fp1, t):
+        if fp2 == nullid and not fl.cmp(fp1, t) and not meta:
             return fp1
 
         changelist.append(fn)
@@ -718,7 +720,7 @@ class localrepository(repo.repository):
                 new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
                 new_exec = is_exec(f)
                 new_link = is_link(f)
-                if not changed or changed[-1] != f:
+                if (not changed or changed[-1] != f) and m2.get(f) != new[f]:
                     # mention the file in the changelog if some flag changed,
                     # even if there was no content change.
                     old_exec = m1.execf(f)
@@ -1312,7 +1314,7 @@ class localrepository(repo.repository):
             mylock = True
 
         try:
-            fetch = self.findincoming(remote, force=force)
+            fetch = self.findincoming(remote, heads=heads, force=force)
             if fetch == [nullid]:
                 self.ui.status(_("requesting all changes\n"))
 
--- a/tests/hghave
+++ b/tests/hghave
@@ -51,9 +51,16 @@ def has_lsprof():
     except ImportError:
         return False
 
+def has_git():
+    fh = os.popen('git --version 2>&1')
+    s = fh.read()
+    ret = fh.close()
+    return ret is None and s.startswith('git version')
+
 checks = {
     "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
     "execbit": (has_executablebit, "executable bit"),
+    "git": (has_git, "git command line client"),
     "fifo": (has_fifo, "named pipes"),
     "hotshot": (has_hotshot, "python hotshot module"),
     "lsprof": (has_lsprof, "python lsprof module"),
new file mode 100755
--- /dev/null
+++ b/tests/test-changelog-exec
@@ -0,0 +1,32 @@
+#!/bin/sh
+# b51a8138292a introduced a regression where we would mention in the
+# changelog executable files added by the second parent of a merge.
+# Test that that doesn't happen anymore
+
+"$TESTDIR/hghave" execbit || exit 80
+
+hg init repo
+cd repo
+echo foo > foo
+hg ci -qAm 'add foo' -d '0 0'
+
+echo bar > bar
+chmod +x bar
+hg ci -qAm 'add bar' -d '0 0'
+echo '% manifest of p2:'
+hg manifest
+echo
+
+hg up -qC 0
+echo >> foo
+hg ci -m 'change foo' -d '0 0'
+echo '% manifest of p1:'
+hg manifest
+
+hg merge
+hg ci -m 'merge' -d '0 0'
+
+echo '% this should not mention bar:'
+hg tip -v
+
+hg debugindex .hg/store/data/bar.i
new file mode 100644
--- /dev/null
+++ b/tests/test-changelog-exec.out
@@ -0,0 +1,21 @@
+% manifest of p2:
+bar
+foo
+
+% manifest of p1:
+foo
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% this should not mention bar:
+changeset:   3:ef2fc9b4a51b
+tag:         tip
+parent:      2:ed1b79f46b9a
+parent:      1:d394a8db219b
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+description:
+merge
+
+
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       5      0       1 b004912a8510 000000000000 000000000000
--- a/tests/test-clone
+++ b/tests/test-clone
@@ -25,3 +25,11 @@ cd ../d
 hg clone ../a
 cd a
 hg cat a
+
+# check that we drop the file:// from the path before
+# writing the .hgrc
+cd ../..
+hg clone file://a e
+grep 'file:' e/.hg/hgrc
+
+exit 0
--- a/tests/test-clone.out
+++ b/tests/test-clone.out
@@ -14,3 +14,4 @@ 1 files, 1 changesets, 1 total revisions
 destination directory: a
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
new file mode 100755
--- /dev/null
+++ b/tests/test-convert-git
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+"$TESTDIR/hghave" git || exit 80
+
+echo "[extensions]" >> $HGRCPATH
+echo "convert=" >> $HGRCPATH
+
+mkdir git-repo
+cd git-repo
+git init-db >/dev/null 2>/dev/null
+echo a > a
+git add a
+git commit -m t1 >/dev/null 2>/dev/null || echo "git commit error"
+echo b >> a
+git commit -a -m t2 >/dev/null || echo "git commit error"
+cd ..
+
+hg convert git-repo
+
new file mode 100644
--- /dev/null
+++ b/tests/test-convert-git.out
@@ -0,0 +1,7 @@
+assuming destination git-repo-hg
+initializing destination git-repo-hg repository
+scanning source...
+sorting...
+converting...
+1 t1
+0 t2
new file mode 100755
--- /dev/null
+++ b/tests/test-pull-r
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+hg init repo
+cd repo
+echo foo > foo
+hg ci -qAm 'add foo' -d '0 0'
+echo >> foo
+hg ci -m 'change foo' -d '0 0'
+hg up -qC 0
+echo bar > bar
+hg ci -qAm 'add bar' -d '0 0'
+hg log
+cd ..
+hg init copy
+cd copy
+
+echo '% pull -r 0'
+hg pull -qr 0 ../repo
+hg log
+
+echo '% pull -r 1'
+hg pull -qr 1 ../repo
+hg log
+
+# this used to abort: received changelog group is empty
+echo '% pull -r 1 again'
+hg pull -qr 1 ../repo
new file mode 100644
--- /dev/null
+++ b/tests/test-pull-r.out
@@ -0,0 +1,37 @@
+changeset:   2:effea6de0384
+tag:         tip
+parent:      0:bbd179dfa0a7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add bar
+
+changeset:   1:ed1b79f46b9a
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change foo
+
+changeset:   0:bbd179dfa0a7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add foo
+
+% pull -r 0
+changeset:   0:bbd179dfa0a7
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add foo
+
+% pull -r 1
+changeset:   1:ed1b79f46b9a
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change foo
+
+changeset:   0:bbd179dfa0a7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add foo
+
+% pull -r 1 again
--- a/tests/test-rename-dir-merge
+++ b/tests/test-rename-dir-merge
@@ -24,9 +24,11 @@ hg merge --debug 1
 echo a/* b/*
 hg st -C
 hg ci -m "3 merge 2+1" -d "0 0"
+hg debugrename b/c
 
 hg co -C 1
 hg merge --debug 2
 echo a/* b/*
 hg st -C
 hg ci -m "4 merge 1+2" -d "0 0"
+hg debugrename b/c
--- a/tests/test-rename-dir-merge.out
+++ b/tests/test-rename-dir-merge.out
@@ -29,6 +29,7 @@ A b/c
 R a/a
 R a/b
 R a/c
+b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 resolving manifests
  overwrite None partial False
@@ -40,3 +41,4 @@ 1 files updated, 0 files merged, 0 files
 a/* b/a b/b b/c
 A b/c
   a/c
+b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88
--- a/tests/test-revert
+++ b/tests/test-revert
@@ -94,4 +94,9 @@ hg add newdir/newfile
 hg revert b newdir
 echo foobar > b/b
 hg revert .
-true
+
+echo % reverting a rename target should revert the source
+hg mv a newa
+hg revert newa
+hg st a newa
+
--- a/tests/test-revert.out
+++ b/tests/test-revert.out
@@ -63,3 +63,5 @@ adding b/b
 reverting b/b
 forgetting newdir/newfile
 reverting b/b
+% reverting a rename target should revert the source
+? newa
new file mode 100755
--- /dev/null
+++ b/tests/test-url-rev
@@ -0,0 +1,83 @@
+#!/bin/sh
+# test basic functionality of url#rev syntax
+
+hg init repo
+cd repo
+echo a > a
+hg ci -qAm 'add a' -d '0 0'
+hg branch foo
+echo >> a
+hg ci -m 'change a' -d '0 0'
+cd ..
+
+echo '% clone repo#foo'
+hg clone 'repo#foo' clone
+echo '% heads'
+hg --cwd clone heads
+echo '% parents'
+hg --cwd clone parents
+sed -e 's/default.*#/default = #/' clone/.hg/hgrc
+echo
+
+echo '% changing original repo'
+cd repo
+echo >> a
+hg ci -m 'new head of branch foo' -d '0 0'
+hg up -qC default
+echo bar > bar
+hg ci -qAm 'add bar' -d '0 0'
+hg log
+echo
+
+echo '% outgoing'
+hg -q outgoing '../clone#foo'
+echo
+
+echo '% push'
+hg -q push '../clone#foo'
+hg --cwd ../clone heads
+cd ..
+echo
+
+echo '% rolling back'
+cd clone
+hg rollback
+
+echo '% incoming'
+hg -q incoming
+
+echo '% pull'
+hg -q pull
+hg heads
+echo
+
+echo '% pull should not have updated'
+hg parents -q
+echo '% going back to the default branch'
+hg up -C 0
+hg parents
+echo '% no new revs, no update'
+hg pull -qu
+hg parents -q
+echo '% rollback'
+hg rollback
+hg up -C 0
+hg parents -q
+echo '% pull -u takes us back to branch foo'
+hg pull -qu
+hg parents
+
+echo '% rollback'
+hg rollback
+hg up -C 0
+echo '% parents'
+hg parents -q
+echo '% heads'
+hg heads -q
+echo '% pull -u -r otherrev url#rev updates to rev'
+hg pull -qur default default
+echo '% parents'
+hg parents
+echo '% heads'
+hg heads
+
new file mode 100644
--- /dev/null
+++ b/tests/test-url-rev.out
@@ -0,0 +1,130 @@
+marked working directory as branch foo
+% clone repo#foo
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% heads
+changeset:   1:cd2a86ecc814
+branch:      foo
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change a
+
+% parents
+changeset:   1:cd2a86ecc814
+branch:      foo
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change a
+
+[paths]
+default = #foo
+
+% changing original repo
+changeset:   3:4cd725637392
+tag:         tip
+parent:      0:1f0dee641bb7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add bar
+
+changeset:   2:faba9097cad4
+branch:      foo
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     new head of branch foo
+
+changeset:   1:cd2a86ecc814
+branch:      foo
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change a
+
+changeset:   0:1f0dee641bb7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add a
+
+
+% outgoing
+2:faba9097cad4
+
+% push
+changeset:   2:faba9097cad4
+branch:      foo
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     new head of branch foo
+
+
+% rolling back
+rolling back last transaction
+% incoming
+2:faba9097cad4
+% pull
+changeset:   2:faba9097cad4
+branch:      foo
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     new head of branch foo
+
+
+% pull should not have updated
+1:cd2a86ecc814
+% going back to the default branch
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+changeset:   0:1f0dee641bb7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add a
+
+% no new revs, no update
+0:1f0dee641bb7
+% rollback
+rolling back last transaction
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+0:1f0dee641bb7
+% pull -u takes us back to branch foo
+changeset:   2:faba9097cad4
+branch:      foo
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     new head of branch foo
+
+% rollback
+rolling back last transaction
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% parents
+0:1f0dee641bb7
+% heads
+1:cd2a86ecc814
+% pull -u -r otherrev url#rev updates to rev
+% parents
+changeset:   2:faba9097cad4
+branch:      foo
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     new head of branch foo
+
+% heads
+changeset:   3:4cd725637392
+tag:         tip
+parent:      0:1f0dee641bb7
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add bar
+
+changeset:   2:faba9097cad4
+branch:      foo
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     new head of branch foo
+