changeset 3500:bd8339976504

Merge with mpm
author Brendan Cully <brendan@kublai.com>
date Tue, 24 Oct 2006 13:42:21 -0700
parents e0db0b7934f2 (diff) ceaa3fefc10c (current diff)
children 89820e9b94f2
files mercurial/localrepo.py
diffstat 8 files changed, 291 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/zsh_completion
+++ b/contrib/zsh_completion
@@ -14,29 +14,50 @@
 
 local curcontext="$curcontext" state line
 typeset -A opt_args
-local subcmds repos tags newFiles addedFiles includeExclude commitMessage
+local repos newFiles addedFiles includeExclude commitMessage
+local ridx _hgroot
+
+# FIXME: why isn't opt_args available?
+[[ -d .hg ]] && _hgroot="$PWD"
+ridx=$words[(i)-R]
+(( $ridx < $#words )) && _hgroot="${words[$ridx+1]}"
 
-_mq_state () {
+# hg dispatch (borrowed from _cvs)
+(( $+functions[_hg_cmd] )) ||
+_hg_cmd () {
+  _call_program hg hg -R "$_hgroot" "$@"
+}
+
+(( $+functions[_hg_state] )) ||
+_hg_state () {
   case "$state" in
+    (tags)
+      compadd $(_hg_cmd tags 2> /dev/null |
+        sed -e 's/[0-9]*:[a-f0-9]*$//; s/ *$//')
+    ;;
     (qapplied)
-      compadd $(hg qapplied)
+      compadd $(_hg_cmd qapplied)
     ;;
     (qunapplied)
-      compadd $(hg qunapplied)
+      compadd $(_hg_cmd qunapplied)
     ;;
   esac
 }
 
-tags=($(hg tags 2> /dev/null | sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//'))
-subcmds=($(hg -v help | sed -e '1,/^list of commands:/d' \
+(( $+_hg_commands )) ||
+_hg_commands=($(hg -v help | sed -e '1,/^list of commands:/d' \
       -e '/^global options:/,$d' -e '/^ [^ ]/!d; s/[,:].*//g;'))
 
 # A lot of commands have these arguments
 includeExclude=(
-        '*-I-[include names matching the given patterns]:dir:_files -W $(hg root) -/'
-        '*--include-[include names matching the given patterns]:dir:_files -W $(hg root) -/'
-        '*-X-[exclude names matching the given patterns]:dir:_files -W $(hg root) -/'
-        '*--exclude-[exclude names matching the given patterns]:dir:_files -W $(hg root) -/')
+        '*-I-[include names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/'
+        '*--include-[include names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/'
+        '*-X-[exclude names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/'
+        '*--exclude-[exclude names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/')
+
+styleOpts=(
+        '--style[display using template map file]:'
+        '--template[display with template]:')
 
 commitMessage=(
         '(-m --message -l --logfile --edit)-e[edit commit message]'
@@ -68,7 +89,7 @@ if [[ $service == "hg" ]]; then
     '*::command:->subcmd' && return 0
 
     if (( CURRENT == 1 )); then
-        _wanted commands expl 'hg command' compadd -a subcmds
+        _wanted commands expl 'hg command' compadd -a _hg_commands
         return
     fi
     service="$words[1]"
@@ -77,7 +98,7 @@ fi
 
 case $service in
     (add)
-        newFiles=(${(ps:\0:)"$(hg status -0un .)"})
+        newFiles=(${(ps:\0:)"$(_hg_cmd status -0un .)"})
         _arguments $includeExclude \
         '*:file:->unknown'
         _wanted files expl 'unknown files' compadd -a newFiles
@@ -89,7 +110,7 @@ case $service in
     ;;
 
     (forget)
-        addedFiles=(${(ps:\0:)"$(hg status -0an .)"})
+        addedFiles=(${(ps:\0:)"$(_hg_cmd status -0an .)"})
         _arguments $includeExclude  \
         '*:file:->added'
         _wanted files expl 'newly added files' compadd -a addedFiles
@@ -128,8 +149,8 @@ case $service in
 
     (diff)
         _arguments $includeExclude \
-        '*-r[revision]:revision:($tags)' \
-        '*--rev[revision]:revision:($tags)' \
+        '*-r[revision]:revision:->tags' \
+        '*--rev[revision]:revision:->tags' \
         '(--text)-a[treat all files as text]' \
         '(-a)--text[treat all files as text]' \
         '*:file:_files'
@@ -153,10 +174,10 @@ case $service in
     ;;
 
     (revert)
-        addedFiles=(${(ps:\0:)"$(hg status -0amrn .)"})
+        addedFiles=(${(ps:\0:)"$(_hg_cmd status -0amrn .)"})
         _arguments \
-        '(--rev)-r[revision to revert to]:revision:($tags)' \
-        '(-r)--rev[revision to revert to]:revision:($tags)' \
+        '(--rev)-r[revision to revert to]:revision:->tags' \
+        '(-r)--rev[revision to revert to]:revision:->tags' \
         '(--nonrecursive)-n[do not recurse into subdirectories]' \
         '(-n)--nonrecursive[do not recurse into subdirectories]' \
         '*:file:->modified'
@@ -164,7 +185,7 @@ case $service in
     ;;
 
     (commit|ci)
-        addedFiles=(${(ps:\0:)"$(hg status -0amrn .)"})
+        addedFiles=(${(ps:\0:)"$(_hg_cmd status -0amrn .)"})
         _arguments $includeExclude \
         '(--addremove)-A[run addremove during commit]' \
         '(-A)--addremove[run addremove during commit]' \
@@ -184,15 +205,15 @@ case $service in
         _arguments $includeExclude \
         '(--output)-o[print output to file with formatted name]:filespec:' \
         '(-o)--output[print output to file with formatted name]:filespec:' \
-        '(--rev)-r[revision]:revision:($tags)' \
-        '(-r)--rev[revision]:revision:($tags)' \
+        '(--rev)-r[revision]:revision:->tags' \
+        '(-r)--rev[revision]:revision:->tags' \
         '*:file:_files'
     ;;
 
     (annotate)
         _arguments $includeExclude \
-        '(--rev)-r[annotate the specified revision]:revision:($tags)' \
-        '(-r)--rev[annotate the specified revision]:revision:($tags)' \
+        '(--rev)-r[annotate the specified revision]:revision:->tags' \
+        '(-r)--rev[annotate the specified revision]:revision:->tags' \
         '(--text)-a[treat all files as text]' \
         '(-a)--text[treat all files as text]' \
         '(--user)-u[list the author]' \
@@ -206,8 +227,8 @@ case $service in
 
     (grep)
         _arguments $includeExclude \
-        '*-r[search in given revision range]:revision:($tags)' \
-        '*--rev[search in given revision range]:revision:($tags)' \
+        '*-r[search in given revision range]:revision:->tags' \
+        '*--rev[search in given revision range]:revision:->tags' \
         '--all[print all revisions with matches]' \
         '(-print0)-0[end filenames with NUL, for use with xargs]' \
         '(-0)--print0[end filenames with NUL, for use with xargs]' \
@@ -224,8 +245,8 @@ case $service in
 
     (locate)
         _arguments $includeExclude \
-        '(--rev)-r[search repository as it stood at revision]:revision:($tags)' \
-        '(-r)--rev[search repository as it stood at revision]:revision:($tags)' \
+        '(--rev)-r[search repository as it stood at revision]:revision:->tags' \
+        '(-r)--rev[search repository as it stood at revision]:revision:->tags' \
         '(--print0)-0[end filenames with NUL, for use with xargs]' \
         '(-0)--print0[end filenames with NUL, for use with xargs]' \
         '(--fullpath)-f[print complete paths]' \
@@ -234,9 +255,9 @@ case $service in
     ;;
 
     (log|history)
-        _arguments $includeExclude \
-        '*-r[show the specified revision or range]:revision:($tags)' \
-        '*--rev[show the specified revision or range]:revision:($tags)' \
+        _arguments $includeExclude $styleOpts \
+        '*-r[show the specified revision or range]:revision:->tags' \
+        '*--rev[show the specified revision or range]:revision:->tags' \
         '(--no-merges -M --only-merges)-m[show only merge revisions]' \
         '(--no-merges -M -m)--only-merges[show only merge revisions]' \
         '(--only-merges -m --no-merges)-M[do not show merge revisions]' \
@@ -258,7 +279,7 @@ case $service in
         '(-C --clean -m)--merge[allow merging of branches]' \
         '(-m --merge --clean)-C[overwrite locally modified files]' \
         '(-m --merge -C)--clean[overwrite locally modified files]' \
-        '*:revision or tag:($tags)'
+        '*:revision or tag:->tags'
     ;;
 
     (tag)
@@ -271,12 +292,12 @@ case $service in
         '(-d)--date[record datecode as commit date]:date code:' \
         '(--user)-u[record user as commiter]:user:' \
         '(-u)--user[record user as commiter]:user:' \
-        '*:name, then revision:($tags)'
+        '*:name, then revision:->tags'
     ;;
 
     (clone)
         if (( CURRENT == 2 )); then
-            repos=( $(hg paths | sed -e 's/^.*= //') )
+            repos=( $(_hg_cmd paths | sed -e 's/^.*= //') )
             _arguments \
             '(--no-update)-U[do not update the new working directory]' \
             '(-U)--no-update[do not update the new working directory]' \
@@ -293,8 +314,8 @@ case $service in
 
     (rawcommit)
         _arguments \
-        '(--parent)-p[parent revision]:revision:($tags)' \
-        '(-p)--parent[parent revision]:revision:($tags)' \
+        '(--parent)-p[parent revision]:revision:->tags' \
+        '(-p)--parent[parent revision]:revision:->tags' \
         '(--date)-d[record datecode as commit date]:date code:' \
         '(-d)--date[record datecode as commit date]:date code:' \
         '(--user)-u[record user as commiter]:user:' \
@@ -321,7 +342,7 @@ case $service in
     ;;
 
     (incoming)
-        _arguments \
+        _arguments $styleOpts \
         '(--patch)-p[show patch]' \
         '(-p)--patch[show patch]' \
         '(--no-merges)-M[do not show merge revisions]' \
@@ -337,13 +358,13 @@ case $service in
         '(-p)--strip[directory strip option for patch (default: 1)]:count:' \
         '(--force)-f[skip check for outstanding uncommitted changes]' \
         '(-f)--force[skip check for outstanding uncommitted changes]' \
-        '(--base)-b[base directory to read patches from]:file:_files -W $(hg root) -/' \
-        '(-b)--base[base directory to read patches from]:file:_files -W $(hg root) -/' \
+        '(--base)-b[base directory to read patches from]:file:_files -W $(_hg_cmd root) -/' \
+        '(-b)--base[base directory to read patches from]:file:_files -W $(_hg_cmd root) -/' \
         '*:patch file:_files'
     ;;
 
     (pull)
-        repos=( $(hg paths | sed -e 's/^.*= //') )
+        repos=( $(_hg_cmd paths | sed -e 's/^.*= //') )
         _arguments \
         '(--update)-u[update working directory to tip after pull]' \
         '(-u)--update[update working directory to tip after pull]' \
@@ -355,7 +376,7 @@ case $service in
     ;;
 
     (outgoing)
-        _arguments \
+        _arguments $styleOpts \
         '(--patch)-p[show patch]' \
         '(-p)--patch[show patch]' \
         '(--no-merges)-M[do not show merge revisions]' \
@@ -377,7 +398,7 @@ case $service in
     ;;
 
     (push)
-        repos=( $(hg paths | sed -e 's/^.*= //') )
+        repos=( $(_hg_cmd paths | sed -e 's/^.*= //') )
         _arguments \
         '(--force)-f[force push]' \
         '(-f)--force[force push]' \
@@ -409,11 +430,11 @@ case $service in
     ;;
 
     (help)
-        _wanted commands expl 'hg command' compadd -a subcmds
+        _wanted commands expl 'hg command' compadd -a _hg_commands
     ;;
 
     (heads)
-        _arguments \
+        _arguments $styleOpts \
         '(--branches)-b[find branch info]' \
         '(-b)--branches[find branch info]'
     ;;
@@ -427,15 +448,26 @@ case $service in
     ;;
 
     (manifest)
-        _arguments '*:revision:($tags)'
+        _arguments '*:revision:->tags'
+    ;;
+
+    (par*)
+        _arguments $styleOpts \
+        '(--rev 1)-r[show parents of the specified rev]:revision:->tags' \
+        '(-r 1)--rev[show parents of the specified rev]:revision:->tags' \
+	'::revision:->tags'
     ;;
 
-    (parents)
-        _arguments '*:revision:($tags)'
+    (identify|recover|root|undo|verify|version|ct|tags)
+        # no arguments for these commands
     ;;
 
-    (identify|recover|root|undo|view|verify|version|ct|tags)
-        # no arguments for these commands
+    # HGK
+    (vi*)
+        _arguments \
+        '(--limit)-l[limit number of changes displayed]:' \
+        '(-l)--limit[limit number of changes displayed]:' \
+        '::revision range:->tags'
     ;;
 
     # MQ commands
@@ -444,7 +476,6 @@ case $service in
             {-k,--keep}'[keep patch file]' \
             {-r,--rev}'[revision]:applied patch:->qapplied' \
             '*:unapplied patches:->qunapplied'
-        _mq_state
     ;;
 
     (qnew)
@@ -454,12 +485,10 @@ case $service in
     ;;
 
     (qpo*)
-        applied=( $(hg qapplied) )
         _arguments \
             (1){-a,--all}'[pop all patches]' \
             {-f,--force}'[forget any local changes]' \
             ':applied patch:->qapplied'
-        _mq_state
     ;;
 
     (qpu*)
@@ -467,7 +496,6 @@ case $service in
             (1){-a,--all}'[apply all patches]' \
             {-f,--force}'[apply if the patch has rejects]' \
             ':unapplied patch:->qunapplied'
-        _mq_state
     ;;
     (qref*)
         _arguments $commitMessage $includeExclude \
@@ -479,3 +507,5 @@ case $service in
         _message "unknown hg command completion: $service"
     ;;
 esac
+
+_hg_state
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -2003,6 +2003,35 @@ def reposetup(ui, repo):
 
             return tagscache
 
+        def branchtags(self):
+            if self.branchcache != None:
+                return self.branchcache
+
+            q = self.mq
+            if not q.applied:
+                return super(mqrepo, self).branchtags()
+
+            self.branchcache = {} # avoid recursion in changectx
+            cl = self.changelog
+            partial, last, lrev = self._readbranchcache()
+
+            qbase = cl.rev(revlog.bin(q.applied[0].rev))
+            start = lrev + 1
+            if start < qbase:
+                # update the cache (excluding the patches) and save it
+                self._updatebranchcache(partial, lrev+1, qbase)
+                self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
+                start = qbase
+            # if start = qbase, the cache is as updated as it should be.
+            # if start > qbase, the cache includes (part of) the patches.
+            # we might as well use it, but we won't save it.
+
+            # update the cache up to the tip
+            self._updatebranchcache(partial, start, cl.count())
+
+            self.branchcache = partial
+            return self.branchcache
+
     if repo.local():
         repo.__class__ = mqrepo
         repo.mq = queue(ui, repo.join(""))
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -527,6 +527,23 @@ class hgweb(object):
                              date = t)
                 parity += 1
 
+        def heads(**map):
+            parity = 0
+            count = 0
+
+            for node in self.repo.heads():
+                count += 1
+                if count > 10:
+                    break;
+
+                ctx = self.repo.changectx(node)
+
+                yield {'parity': self.stripes(parity),
+                       'branch': ctx.branch(),
+                       'node': hex(node),
+                       'date': ctx.date()}
+                parity += 1
+
         def changelist(**map):
             parity = 0
             cl = self.repo.changelog
@@ -560,6 +577,7 @@ class hgweb(object):
                           self.repo.ui.config("web", "author", "unknown")), # also
                  lastchange = cl.read(cl.tip())[2],
                  tags = tagentries,
+                 heads = heads,
                  shortlog = changelist,
                  node = hex(cl.tip()),
                  archives=self.archivelist("tip"))
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -295,6 +295,18 @@ class localrepository(repo.repository):
 
         self.branchcache = {} # avoid recursion in changectx
 
+        partial, last, lrev = self._readbranchcache()
+
+        tiprev = self.changelog.count() - 1
+        if lrev != tiprev:
+            self._updatebranchcache(partial, lrev+1, tiprev+1)
+            self._writebranchcache(partial, self.changelog.tip(), tiprev)
+
+        self.branchcache = partial
+        return self.branchcache
+
+    def _readbranchcache(self):
+        partial = {}
         try:
             f = self.opener("branches.cache")
             last, lrev = f.readline().rstrip().split(" ", 1)
@@ -303,34 +315,30 @@ class localrepository(repo.repository):
                 self.changelog.node(lrev) == last): # sanity check
                 for l in f:
                     node, label = l.rstrip().split(" ", 1)
-                    self.branchcache[label] = bin(node)
+                    partial[label] = bin(node)
             else: # invalidate the cache
                 last, lrev = nullid, -1
             f.close()
         except IOError:
             last, lrev = nullid, -1
+        return partial, last, lrev
 
-        tip = self.changelog.count() - 1
-        if lrev != tip:
-            for r in xrange(lrev + 1, tip + 1):
-                c = self.changectx(r)
-                b = c.branch()
-                if b:
-                    self.branchcache[b] = c.node()
-            self._writebranchcache()
-
-        return self.branchcache
-
-    def _writebranchcache(self):
+    def _writebranchcache(self, branches, tip, tiprev):
         try:
             f = self.opener("branches.cache", "w")
-            t = self.changelog.tip()
-            f.write("%s %s\n" % (hex(t), self.changelog.count() - 1))
-            for label, node in self.branchcache.iteritems():
+            f.write("%s %s\n" % (hex(tip), tiprev))
+            for label, node in branches.iteritems():
                 f.write("%s %s\n" % (hex(node), label))
         except IOError:
             pass
 
+    def _updatebranchcache(self, partial, start, end):
+        for r in xrange(start, end):
+            c = self.changectx(r)
+            b = c.branch()
+            if b:
+                partial[b] = c.node()
+
     def lookup(self, key):
         if key == '.':
             key = self.dirstate.parents()[0]
--- a/templates/gitweb/map
+++ b/templates/gitweb/map
@@ -39,6 +39,7 @@ filerevchild = '<tr><td class="metatag">
 fileannotatechild = '<tr><td class="metatag">child {rev}:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
 tags = tags.tmpl
 tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/#node|short#{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
+headentry = '<tr class="parity{parity}"><td class="age"><i>{date|age} ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>{node|short}</td><td>{branch|escape}</td><td class="link"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/{node|short}{sessionvars%urlparameter}">manifest</a></td></tr>'
 diffblock = '<pre>#lines#</pre>'
 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
 changesettag = '<tr><td>tag</td><td>#tag|escape#</td></tr>'
--- a/templates/gitweb/summary.tmpl
+++ b/templates/gitweb/summary.tmpl
@@ -36,4 +36,12 @@ summary |
 <tr class="light"><td colspan="3"><a class="list" href="{url}tags{sessionvars%urlparameter}">...</a></td></tr>
 </table>
 
+<div><a class="title"
+href="#">heads</a></div>
+<table cellspacing="0">
+{heads%headentry}
+<tr class="light">
+  <td colspan="3"><a class="list"  href="#">...</a></td>
+</tr>
+</table>
 #footer#
new file mode 100755
--- /dev/null
+++ b/tests/test-mq-caches
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+echo '[extensions]' >> $HGRCPATH
+echo 'hgext.mq=' >> $HGRCPATH
+
+show_branch_cache()
+{
+    branches=.hg/branches.cache
+    hg log -r tip --template 'tip: #rev#\n'
+    if [ -f $branches ]; then
+	sort $branches
+    else
+	echo No $branches
+    fi
+    if [ "$1" = 1 ]; then
+	for b in foo bar; do
+	    hg log -r $b --template "branch $b: "'#rev#\n'
+	done
+    fi
+}
+
+hg init a
+cd a
+hg qinit -c
+
+echo '# mq patch on an empty repo'
+hg qnew p1
+show_branch_cache
+
+echo > pfile
+hg add pfile
+hg qrefresh -m 'patch 1'
+show_branch_cache
+
+echo
+echo '# some regular revisions'
+hg qpop
+echo foo > foo
+hg add foo
+echo foo > .hg/branch
+hg ci -m 'branch foo' -d '1000000 0'
+
+echo bar > bar
+hg add bar
+echo bar > .hg/branch
+hg ci -m 'branch bar' -d '1000000 0'
+show_branch_cache
+
+echo
+echo '# add some mq patches'
+hg qpush
+show_branch_cache
+
+hg qnew p2
+echo foo > .hg/branch
+echo foo2 >> foo
+hg qrefresh -m 'patch 2'
+show_branch_cache 1
+
+echo
+echo '# removing the cache'
+rm -f .hg/branches.cache
+show_branch_cache 1
+
+echo
+echo '# importing rev 1 (the cache now ends in one of the patches)'
+hg qimport -r 1 -n p0
+show_branch_cache 1
+hg log -r qbase --template 'qbase: #rev#\n'
+
+echo
+echo '# detect an invalid cache'
+hg qpop -a
+hg qpush -a
+show_branch_cache
+
new file mode 100644
--- /dev/null
+++ b/tests/test-mq-caches.out
@@ -0,0 +1,53 @@
+# mq patch on an empty repo
+tip: 0
+No .hg/branches.cache
+tip: 0
+No .hg/branches.cache
+
+# some regular revisions
+Patch queue now empty
+tip: 1
+3f910abad313ff802d3a23a7529433872df9b3ae 1
+3f910abad313ff802d3a23a7529433872df9b3ae bar
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff foo
+
+# add some mq patches
+applying p1
+Now at: p1
+tip: 2
+3f910abad313ff802d3a23a7529433872df9b3ae 1
+3f910abad313ff802d3a23a7529433872df9b3ae bar
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff foo
+tip: 3
+3f910abad313ff802d3a23a7529433872df9b3ae 1
+3f910abad313ff802d3a23a7529433872df9b3ae bar
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff foo
+branch foo: 3
+branch bar: 2
+
+# removing the cache
+tip: 3
+3f910abad313ff802d3a23a7529433872df9b3ae 1
+3f910abad313ff802d3a23a7529433872df9b3ae bar
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff foo
+branch foo: 3
+branch bar: 2
+
+# importing rev 1 (the cache now ends in one of the patches)
+tip: 3
+3f910abad313ff802d3a23a7529433872df9b3ae 1
+3f910abad313ff802d3a23a7529433872df9b3ae bar
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff foo
+branch foo: 3
+branch bar: 2
+qbase: 1
+
+# detect an invalid cache
+Patch queue now empty
+applying p0
+applying p1
+applying p2
+Now at: p2
+tip: 3
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff 0
+9539f35bdc80732cc9a3f84e46508f1ed1ec8cff foo