Commits

ZyX_I  committed 0af5542 Merge

Merged bzr-support into default. Ref #60

  • Participants
  • Parent commits aa4eeb6, 24fcb2f
  • Tags release-1.6

Comments (0)

Files changed (16)

File aurum-addon-info.txt

         "autoload/aurum/cmdutils.vim",
         "autoload/aurum/commit.vim",
         "autoload/aurum/diff.vim",
+        "autoload/aurum/drivers/bazaar.vim",
         "autoload/aurum/drivers/common/hypsites.vim",
         "autoload/aurum/drivers/common/utils.vim",
         "autoload/aurum/drivers/common/xml.vim",
         "syntax/aurumstatus.vim",
         "test/addEmessages.vim",
         "test/addmessages.vim",
+        "test/bzrtestrepo.tar.xz",
         "test/cmd+maps-commit.in",
         "test/cmd+maps-commit.ok",
         "test/cmd+maps-vimdiff.in",
         "test/cmdaus.ok",
         "test/copyout-postproc.zsh",
         "test/cptowine.zsh",
+        "test/createbzrrepo.zsh",
         "test/creategitrepo.zsh",
         "test/createhgrepo.zsh",
         "test/createsvnrepo.zsh",
+        "test/drivers-bazaar.in",
+        "test/drivers-bazaar.ok",
+        "test/drivers-bazaar.pre",
+        "test/drivers-bazaar.vim",
         "test/drivers-git-first-two.tar.xz",
         "test/drivers-git.in",
         "test/drivers-git.ok",

File autoload/aurum.vim

 let s:_augroups+=['AuRCSwitchBuffers']
 "▶1 aurum#repository
 function aurum#repository()
+    " TODO Path instead of buffer cache to reduce number of shell calls
+    " TODO Maybe somehow tell repo.get function not to update repository
     let repo=s:_r.cache.get('repo', s:_r.repo.get, [':'], {})
     if repo is 0
         return {}

File autoload/aurum/drivers/bazaar.vim

+"▶1
+scriptencoding utf-8
+execute frawor#Setup('0.0', {'@%aurum/drivers/common/hypsites': '0.0',
+            \                                   '@%aurum/repo': '5.0',
+            \                   '@%aurum/drivers/common/utils': '1.0',
+            \                                           '@/os': '0.1',
+            \                                      '@/options': '0.0',})
+let s:_messages={
+            \   'revnof': 'Failed to get working directory revision '.
+            \             'from the repository %s: %s',
+            \     'logf': 'Failed to list all revisions '.
+            \             'in the repository %s: %s',
+            \      'csf': 'Failed to get information about revision %s '.
+            \             'in the repository %s: %s',
+            \      'lsf': 'Failed to list files in the changeset %s '.
+            \             'from the repository %s: %s',
+            \    'statf': 'Failed to get status in the repository %s: %s',
+            \'lsignoref': 'Failed to list ignored files '.
+            \             'in the repository %s: %s',
+            \   'labelf': 'Failed to set %s “%s” for the changeset %s '.
+            \             'in the repository %s: %s',
+            \  'revertf': 'Failet to revert to the changeset %s '.
+            \             'in the repository %s: %s',
+            \  'updatef': 'Failed to update to the changeset %s '.
+            \             'in the repository %s: %s',
+            \      'mvf': 'Failed to move %s to %s in the repository %s: %s',
+            \     'addf': 'Failed to add file %s to the repository %s: %s',
+            \      'fgf': 'Failed to forget file %s in the repository %s: %s',
+            \      'rmf': 'Failed to removed file %s in the repository %s: %s',
+            \  'ignoref': 'Failed to ignore %s in the repository %s: %s',
+            \     'catf': 'Failed to get file %s in the changeset %s '.
+            \             'of the repository %s: %s',
+            \'annotatef': 'Failed to annotate file %s in the changeset %s '.
+            \             'of the repository %s: %s',
+            \    'difff': 'Failed to get diff between %s and %s for files %s '.
+            \             'in the repository %s: %s',
+            \    'nickf': 'Failed to get branch name for the repository %s: %s',
+            \ 'nicksetf': 'Failed to set nick %s for the repository %s: %s',
+            \  'configf': 'Failed to get parent_location '.
+            \             'of the repository %s: %s',
+            \     'tagf': 'Failed to list tags in the repository %s: %s',
+            \    'pushf': 'Failed to push the repository %s: %s',
+            \    'pullf': 'Failed to pull to the repository %s: %s',
+            \  'commitf': 'Failed to commit changes to the repository %s: %s',
+            \  'p_empty': 'Parser error: expected 60 dashes, but got nothing',
+            \  'p_nobeg': 'Parser error: expected 60 dashes, but got %s',
+            \ 'p_nospec': 'Parser error: expected “spec: value”, but got %s',
+            \'p_dateerr': 'Parser error: date exited with code %u '.
+            \             'while trying to parse “%s”: %s',
+            \    'ndate': 'You must install “date” programm in order to get '.
+            \             'time information for bazaar revisions',
+            \     'rene': 'Failed to get rename information: '.
+            \             'no “ => ” in string %s',
+            \    'renze': 'Failed to get rename information: '.
+            \             '“ => ” found at the start of the string %s',
+            \   'renz2e': 'Failed to get rename information: '.
+            \             '“ => ” found at the end of the string %s',
+            \   'cbnimp': 'Bazaar driver is not able to close branch',
+            \  'upfnimp': 'Bazaar driver is not able to force update',
+            \  'revnimp': 'In order to get reverse diff you must specify '.
+            \             'both revisions',
+            \   'bfnimp': 'Can’t force branch nick creation',
+            \   'drnimp': 'Dry run not implemented',
+            \    'nocfg': 'Can’t get property %s of the repository %s',
+        \}
+let s:bzr={}
+let s:_options={
+        \}
+"▶1 s:hypsites
+" TODO Support for git and subversion hypsites
+let s:hypsites=s:_r.hypsites.bzr
+"▶1 bzrcmd :: cmd, args, kwargs → String
+function s:F.bzrcmd(...)
+    return ['bzr', '--no-aliases']+call(s:_r.utils.getcmd, a:000, {})
+endfunction
+"▶1 bzr :: repo, cmd, args, kwargs, has0[, msgid[, marg1[, …]]] → [String] + ?
+function s:F.bzr(repo, cmd, args, kwargs, hasnulls, ...)
+    let cmd=s:F.bzrcmd(a:cmd, a:args, a:kwargs)
+    let [r, exit_code]=s:_r.utils.run(cmd, a:hasnulls, a:repo.path)
+    if a:0
+        if a:1 is 0
+            return [r, exit_code]
+        elseif exit_code
+            call call(s:_f.throw, a:000+[a:repo.path, join(r[:-1-(a:hasnulls)],
+                        \                                  "\n")], {})
+        endif
+    endif
+    return r
+endfunction
+"▶1 bzrm :: {bzr args} → + :echom
+function s:F.bzrm(...)
+    return s:_r.utils.printm(call(s:F.bzr, a:000, {}))
+endfunction
+"▶1 parsecs :: csdata, lstart::UInt → (cs, line::UInt)
+" hash-parent hashes-timestamp
+"  (refs)
+" author name
+" author email
+" 1-indented commit message
+let s:logkwargs={'long': 1, 'show-ids': 1}
+let s:hasdateexe=executable('date')
+function s:F.parsecs(csdata, ...)
+    if empty(a:csdata)
+        call s:_f.throw('p_empty')
+    elseif a:csdata[0]!~#'\v^\s*\-{60}$'
+        call s:_f.throw('p_nobeg', a:csdata[0])
+    endif
+    let indent=stridx(remove(a:csdata, 0), '-')
+    " FIXME children:[]
+    let cs={'parents': [], 'copies': {}, 'children': [], 'phase': 'unknown',
+                \'bookmarks': [], 'tags': []}
+    while !empty(a:csdata) && a:csdata[0]!~#'\v^\s*\-{60}$'
+        let line=remove(a:csdata, 0)[(indent):]
+        if line is# 'message:'
+            let description=[]
+            " XXX message can have line “----”
+            let regex='\v^('.((indent)?
+                        \       (join(map(range(0, indent/4),
+                        \                 '"\\s{".(v:val*4)."}"'), '|')):
+                        \       ('')).'|\s{'.(indent+4).'})\-{60}$'
+            while !empty(a:csdata) && a:csdata[0] !~# regex
+                call add(description, remove(a:csdata, 0)[(indent+2):])
+            endwhile
+            let cs.description=join(description, "\n")
+            break
+        endif
+        let match=matchlist(line, '\v^([^:]+)\: ?(.*)$')[1:2]
+        if empty(match)
+            call s:_f.throw('p_nospec', line)
+        endif
+        let [spec, value]=match
+        if spec is# 'revno'
+            let cs.rev=matchstr(value, '\v^\S+')
+        elseif spec is# 'revision-id'
+            if a:0 && has_key(a:1, value)
+                let spaces=repeat(' ', indent-1)
+                while a:csdata[:(indent-1)] is# spaces
+                    call remove(a:csdata, 0)
+                endwhile
+                return {'hex': value}
+            else
+                let cs.hex=value
+            endif
+        elseif spec is# 'parent'
+            let cs.parents+=[value]
+        elseif spec is# 'author'
+            let cs.user=value
+        elseif spec is# 'committer' && !has_key(cs, 'user')
+            let cs.user=value
+        elseif spec is# 'branch nick'
+            let cs.branch=value
+        elseif spec is# 'tags'
+            " FIXME There may be “, ” in the tag, use “bzr tags” to fix it
+            " XXX Can’t fix with “bzr tags” completely: tag may contain spaces 
+            "     at the end
+            let cs.tags=split(value, ', ')
+        elseif spec is# 'timestamp'
+            if s:hasdateexe || executable('date')
+                let s:hasdateexe=1
+                let time=system('date --date='.shellescape(value).' +%s')
+                if v:shell_error
+                    call s:_f.throw('p_dateerr', v:shell_error, value, time)
+                endif
+                let cs.time=+time
+            else
+                call s:_f.warn('ndate')
+                let cs.time=0
+            endif
+        endif
+    endwhile
+    return cs
+endfunction
+"▶1 bzr.getcs :: repo, rev → cs
+let s:gcslogkwargs=extend({'levels': '1'}, s:logkwargs)
+function s:bzr.getcs(repo, rev)
+    let kwargs=copy(s:gcslogkwargs)
+    let kwargs.revision=''.a:rev
+    let log=s:F.bzr(a:repo, 'log', [], kwargs, 0, 'csf', a:rev)
+    let cs=s:F.parsecs(log)
+    " XXX This construct is used to preserve information like “allfiles” etc
+    let a:repo.changesets[cs.hex]=extend(get(a:repo.changesets, cs.hex, {}), cs)
+    return a:repo.changesets[cs.hex]
+endfunction
+"▶1 bzr.getwork :: repo → cs
+function s:bzr.getwork(repo)
+    let rev=+s:F.bzr(a:repo, 'revno', [], {'tree': 1}, 0, 'revnof')[0]
+    return a:repo.functions.getcs(a:repo, rev)
+endfunction
+"▶1 bzr.getchangesets :: repo[, rangestart, rangeend] → [cs]
+let s:gcsslogkwargs=extend({'levels': '0'}, s:logkwargs)
+function s:bzr.getchangesets(repo, ...)
+    let kwargs=copy(s:gcsslogkwargs)
+    if a:0
+        let kwargs.revision=a:1.'..'.a:2
+    endif
+    let log=s:F.bzr(a:repo, 'log', [], kwargs, 0, 'logf')
+    let cslist=[]
+    let csmap={}
+    while !empty(log)
+        let cs=s:F.parsecs(log, csmap)
+        if has_key(csmap, cs.hex)
+            let pos=remove(csmap, cs.hex)
+            call map(csmap, '(v:val>'.pos.')?(v:val-1):(v:val)')
+            let cs=remove(cslist, pos)
+        else
+            let a:repo.changesets[cs.hex]=cs
+        endif
+        let csmap[cs.hex]=len(cslist)
+        call insert(cslist, cs)
+    endwhile
+    return cslist
+endfunction
+"▶1 bzr.revrange :: repo, rev1, rev2 → [cs]
+let s:bzr.revrange=s:bzr.getchangesets
+"▶1 bzr.updatechangesets :: repo → _
+function s:bzr.updatechangesets(...)
+    " FIXME Get new changesets
+endfunction
+"▶1 bzr.getrevhex :: repo, rev → hex
+let s:prevrevhex={}
+function s:bzr.getrevhex(repo, rev)
+    return a:repo.functions.getcs(a:repo, a:rev).hex
+endfunction
+"▶1 bzr.getworkhex :: repo → hex
+function s:bzr.getworkhex(repo)
+    return a:repo.functions.getwork(a:repo).hex
+endfunction
+"▶1 bzr.gettiphex :: repo → hex
+function s:bzr.gettiphex(repo)
+    return a:repo.functions.getrevhex(a:repo, '-1')
+endfunction
+"▶1 getstatdict :: repo, kwargs → statdict
+function s:F.getstatdict(repo, args, kwargs)
+    let status=s:F.bzr(a:repo, 'status', a:args,
+                \      extend({'no-classify': 1}, a:kwargs), 0,
+                \      'statf')[:-2]
+    let curstatus=0
+    let statdict={}
+    while !empty(status)
+        let line=remove(status, 0)
+        if line[:1] is# '  '
+            " XXX File name is not expected to contain " => "
+            let statdict[curstatus]+=[line[2:]]
+        elseif line =~# '\v^[a-z]+%(\ [a-z]+)*\:$'
+            let curstatus=line[:-2]
+            let statdict[curstatus]=[]
+        elseif !empty(get(statdict, curstatus, 0))
+            " XXX Support for file with newlines is very limited here: it 
+            "     does not expect them containing "\n  " or "\nabc:". Bazaar 
+            "     crashes when trying to commit file with newline in its 
+            "     name, though it is probably not a problem
+            let statdict[curstatus][-1].="\n".line
+        endif
+    endwhile
+    return statdict
+endfunction
+"▶1 getrenames :: statdict → renames
+function s:F.getrenames(statdict)
+    if !has_key(a:statdict, 'renamed')
+        return {}
+    endif
+    let renames={}
+    for rename in a:statdict.renamed
+        let idx=stridx(rename, " => ")
+        if idx==-1
+            call s:_f.throw('rene', rename)
+        elseif idx==0
+            call s:_f.throw('renze', rename)
+        endif
+        let old=rename[:(idx-1)]
+        let new=rename[idx+4:]
+        try
+            let renames[new]=old
+        catch /^Vim(let):E713:/
+            call s:_f.throw('renz2e', rename)
+        endtry
+    endfor
+    return renames
+endfunction
+"▶1 bzr.setcsprop :: repo, cs, propname → propvalue
+function s:bzr.setcsprop(repo, cs, prop)
+    if a:prop is# 'allfiles'
+        let r=s:_r.utils.nullnl(
+                    \s:F.bzr(a:repo, 'ls', [], {'revision': 'revid:'.a:cs.hex,
+                    \                          'recursive': 1,
+                    \                               'null': 1}, 2,
+                    \        'lsf', a:cs.hex))[:-2]
+    elseif       a:prop is# 'renames' || a:prop is# 'changes' ||
+                \a:prop is# 'files'   || a:prop is# 'removes'
+        let statdict=s:F.getstatdict(a:repo, [], {'change': 'revid:'.a:cs.hex})
+        let a:cs.removes=[]
+        let a:cs.files=[]
+        call map(['added', 'modified', 'kind changed'],
+                    \'extend(a:cs.files, get(statdict, v:val, []))')
+        if has_key(statdict, 'removed')
+            let a:cs.removes+=statdict.removed
+        endif
+        let a:cs.renames=s:F.getrenames(statdict)
+        let a:cs.removes+=sort(values(a:cs.renames))
+        let a:cs.files  +=sort(keys(  a:cs.renames))
+        let a:cs.changes=a:cs.removes+a:cs.files
+        return a:cs[a:prop]
+    endif
+    let a:cs[a:prop]=r
+    return r
+endfunction
+"▶1 bzr.status :: repo[, rev1[, rev2[, files[, clean[, ign]]]]] → {type:[file]}
+let s:statstats={'added': 'added', 'removed': 'removed', 'modified': 'modified',
+            \    'kind changed': 'modified', 'unknown': 'unknown',
+            \    'missing': 'deleted'}
+function s:bzr.status(repo, ...)
+    let args=['--']+((a:0>2 && a:3 isnot 0)?(a:3):([]))
+    let statdict=s:F.getstatdict(a:repo, args,
+                \                ((a:0>1 && a:1 isnot 0 && a:2 isnot 0)?
+                \                   ({'revision': a:1.'..'.a:2}):
+                \                ((a:0>0 && a:1 isnot 0)?
+                \                   ({'revision': a:1.'..'}):
+                \                ((a:0>1 && a:2 isnot 0)?
+                \                   ({'revision': a:2.'..'}):
+                \                   ({})))))
+    let r=deepcopy(s:_r.utils.emptystatdct)
+    " XXX There cannot be deleted files similar to mercurial, but there can be 
+    "     files that have 2 statuses
+    "     (missing is a bit different: it is shown after deleting added file)
+    for [sdkey, skey] in items(filter(copy(s:statstats),
+                \                     'has_key(statdict, v:key)'))
+        let r[skey]+=statdict[sdkey]
+    endfor
+    let renames=s:F.getrenames(statdict)
+    call filter(r.modified, '!has_key(renames, v:val)')
+    let r.added+=sort(keys(renames))
+    let r.removed+=sort(values(renames))
+    if a:0>1 && a:1 is 0 && a:2 isnot 0
+        let [r.deleted, r.unknown]=[r.unknown, r.deleted]
+        let [r.added,   r.removed]=[r.removed, r.added  ]
+    endif
+    if a:0>3 && a:4
+        if a:1 is 0
+            if a:2 is 0
+                let rev=a:repo.functions.getworkhex(a:repo)
+            else
+                let rev=a:2
+            endif
+        else
+            let rev=a:1
+        endif
+        let allfiles=copy(a:repo.functions.getcsprop(a:repo, rev, 'allfiles'))
+        if !empty(a:3)
+            let allfiles=filter(allfiles, 'index(a:3, v:val)!=-1')
+        endif
+        let files=r.modified+r.added+r.removed+r.deleted+r.unknown
+        let r.clean=filter(allfiles, 'index(files, v:val)==-1')
+    endif
+    if (a:0>4 && a:5 && a:1 is 0 && a:2 is 0)
+        let r.ignored=s:_r.utils.nullnl(
+                    \ s:F.bzr(a:repo, 'ls', args, {'ignored': 1, 'null': 1}, 2,
+                    \                 'lsignoref', a:repo))[:-2]
+    endif
+    return r
+endfunction
+"▶1 bzr.commit :: repo, message[, files[, user[, date[, _]]]]
+function s:bzr.commit(repo, message, ...)
+    let kwargs={}
+    let args=[]
+    if a:0
+        if !empty(a:1)
+            let args+=['--']+a:1
+            call s:_r.utils.addfiles(a:repo, a:1)
+        endif
+        if a:0>1 && !empty(a:2)
+            let kwargs.author=a:2
+        endif
+        if a:0>2 && !empty(a:3)
+            let kwargs['commit-time']=a:3.' +0000'
+        endif
+        if a:0>3 && !empty(a:4)
+            call s:_f.throw('cbnimp')
+        endif
+    endif
+    return s:_r.utils.usefile(a:repo, a:message, 'file', 'message',
+                \             s:F.bzrm, args, kwargs, 0, 'commitf')
+endfunction
+"▶1 bzr.branch :: repo, branchname, force → + FS
+function s:bzr.branch(repo, branch, force)
+    if a:force
+        call s:_f.throw('bfnimp')
+    endif
+    return s:F.bzrm(a:repo, 'nick', ['--', a:branch], {}, 0,
+                \   'nicksetf', a:branch)
+endfunction
+"▶1 bzr.label :: repo, type, label, rev, force, local → + FS
+function s:bzr.label(repo, type, label, rev, force, local)
+    if a:local
+        call s:_f.throw('nloc')
+    endif
+    let args=['--', a:label]
+    let kwargs={}
+    if a:force
+        let kwargs.force=1
+    endif
+    if a:rev is 0
+        let kwargs.delete=1
+    else
+        let kwargs.revision=''.a:rev
+    endif
+    return s:F.bzrm(a:repo, a:type, args, kwargs, 0,
+                \   'labelf', a:type, a:label, a:rev)
+endfunction
+"▶1 bzr.update :: repo, rev, force → + FS
+function s:bzr.update(repo, rev, force)
+    let kwargs={}
+    let kwargs.revision=''.a:rev
+    if a:force
+        call s:F.bzrm(a:repo, 'revert', [], kwargs, 0, 'revertf', a:rev)
+    endif
+    return s:F.bzrm(a:repo, 'update', [], kwargs, 0, 'updatef', a:rev)
+endfunction
+"▶1 bzr.move :: repo, force, source, destination → + FS
+function s:bzr.move(repo, force, source, destination)
+    return s:F.bzrm(a:repo, 'mv', ['--', a:source, a:destination], {}, 0,
+                \   'mvf', a:source, a:destination)
+endfunction
+"▶1 bzr.add :: repo, file → + FS
+function s:bzr.add(repo, file)
+    return s:F.bzrm(a:repo, 'add', ['--', a:file], {}, 0, 'addf', a:file)
+endfunction
+"▶1 bzr.forget :: repo, file → + FS
+function s:bzr.forget(repo, file)
+    return s:F.bzrm(a:repo, 'rm', ['--', a:file], {'keep': 1}, 0,
+                \   'fgf', a:file)
+endfunction
+"▶1 bzr.remove :: repo, file → + FS
+function s:bzr.remove(repo, file)
+    return s:F.bzrm(a:repo, 'rm', ['--', a:file], {'no-backup': 1}, 0,
+                \   'rmf', a:file)
+endfunction
+"▶1 bzr.ignore :: repo, file → + FS
+function s:bzr.ignore(repo, file)
+    return a:repo.functions.ignoreglob(a:repo,
+                \'RE:'.substitute(a:file, '\W', '\\\0', 'g'))
+endfunction
+"▶1 bzr.ignoreglob :: repo, glob → + FS
+function s:bzr.ignoreglob(repo, glob)
+    return s:F.bzrm(a:repo, 'ignore', ['--', a:glob], {}, 0, 'ignoref', a:glob)
+endfunction
+"▶1 bzr.readfile :: repo, rev, file → [String]
+function s:bzr.readfile(repo, rev, file)
+    return s:F.bzr(a:repo, 'cat', ['--', a:file], {'revision': ''.a:rev}, 2,
+                \  'catf', a:rev, a:file)
+endfunction
+"▶1 bzr.annotate :: repo, rev, file → [(file, hex, linenumber)]
+" XXX Bazaar supports annotating current state, it uses id=current:
+function s:bzr.annotate(repo, rev, file)
+    let ann=s:F.bzr(a:repo, 'annotate', ['--', a:file],
+                \   {'rev': a:rev, 'show-ids': 1, 'all': 1}, 2,
+                \   'annotatef', a:file, a:rev)[:-2]
+    let lastid=0
+    let r=[]
+    let idamap={}
+    for line in ann
+        let id=line[match(line, '\S'):(stridx(line, '|')-2)]
+        let r+=[[id, 0]]
+        let idamap[id]=get(idamap, id, [])+[r[-1]]
+    endfor
+    " XXX Bazaar annotation respects renames, but it does not show old filename, 
+    "     thus rename information is to be used
+    for [id, lists] in items(idamap)
+        let renames=s:F.getrenames(s:F.getstatdict(a:repo, ['--', a:file],
+                    \                              {'revision': a:rev.'..'.id}))
+        let file=get(renames, a:file, a:file)
+        call map(lists, 'insert(v:val, '.string(file).')')
+    endfor
+    return r
+endfunction
+"▶1 bzr.diff :: repo, rev, rev, files, opts → [String]
+let s:difftrans={
+            \ 'numlines': 'unified',
+            \ 'ignorews': 'ignore-all-space',
+            \'iwsamount': 'ignore-space-change',
+            \  'iblanks': 'ignore-blank-lines',
+            \ 'showfunc': 'show-c-function',
+            \  'alltext': 'text',
+        \}
+function s:bzr.diff(repo, rev1, rev2, files, opts)
+    let reverse=get(a:opts, 'reverse', 0)
+    let diffopts=s:_r.utils.diffopts(a:opts, a:repo.diffopts, s:difftrans)
+    let kwargs={}
+    if !empty(diffopts)
+        let kwargs['diff-options']=join(s:_r.utils.kwargstolst(diffopts))
+    endif
+    let args=[]
+    if empty(a:rev2)
+        if reverse
+            call s:_f.throw('revnimp')
+        endif
+        if !empty(a:rev1)
+            let kwargs.change=''.a:rev1
+        endif
+    else
+        if reverse
+            if empty(a:rev1)
+                call s:_f.throw('revnimp')
+            endif
+            let kwargs.revision=a:rev1.'..'.a:rev2
+        else
+            let kwargs.revision=''.a:rev2
+            if !empty(a:rev1)
+                let kwargs.revision.='..'.a:rev1
+            endif
+        endif
+    endif
+    if !empty(a:files)
+        let args+=['--']+a:files
+    endif
+    let [r, exit_code]=s:F.bzr(a:repo, 'diff', args, kwargs, 1, 0)
+    " 0 is returned when repository is unchanged
+    " 1 is returned when repository has changes
+    " 2 and further indicate an error
+    if exit_code>1
+        call s:_f.throw('difff', a:rev1, a:rev2, join(a:files, ', '),
+                    \            a:repo.path, join(r, "\n"))
+    endif
+    return r
+endfunction
+"▶1 bzr.diffre :: _, opts → Regex
+let s:diffre='\m^=== \v(\a+)\ file\ (.*)'
+function s:bzr.diffre(repo, opts)
+    return s:diffre
+endfunction
+"▶1 bzr.diffname :: _, line, diffre, _ → rpath
+function s:bzr.diffname(repo, line, diffre, opts)
+    let match=matchlist(a:line, a:diffre)[1:2]
+    if empty(match)
+        return 0
+    elseif match[0] is# 'renamed'
+        return matchstr(match[1], '\v%(\''.*\''\V => ''\v)@<=.*%(\''$)@=')
+    else
+        return match[1][1:-2]
+    endif
+endfunction
+"▶1 bzr.getrepoprop :: repo, propname → a
+function s:bzr.getrepoprop(repo, prop)
+    if a:prop is# 'branch'
+        return join(s:F.bzr(a:repo, 'nick', [], {}, 0, 'nickf')[:-2], "\n")
+    elseif a:prop is# 'url'
+        return s:F.bzr(a:repo, 'config', ['parent_location'], {}, 0,
+                    \  'configf')[:-2]
+    elseif a:prop is# 'brancheslist'
+        return []
+        " FIXME Use “bzr branches”?
+    elseif a:prop is# 'tagslist'
+        return map(s:F.bzr(a:repo, 'tags', [], {}, 0, 'tagf')[:-2],
+                    \'substitute(v:val, '' \+\S\+$'', "", "")')
+    elseif a:prop is# 'bookmarkslist'
+        return []
+    endif
+    call s:_f.throw('nocfg', a:prop, a:repo.path)
+endfunction
+"▶1 bzr.push :: repo, dryrun, force[, URL[, rev]]
+function s:bzr.push(repo, dryrun, force, ...)
+    if a:dryrun
+        call s:_f.throw('drnimp')
+    endif
+    let args=[]
+    let kwargs={}
+    if a:force
+        let kwargs.overwrite=1
+        let kwargs['use-existing-dir']=1
+        let kwargs['create-prefix']=1
+    endif
+    if a:0 && a:1 isnot 0
+        let args+=['--', a:1]
+    endif
+    if a:0>1 && a:2 isnot 0
+        let kwargs.revision=''.a:2
+    endif
+    return s:F.bzrm(a:repo, 'push', args, kwargs, 0, 'pushf')
+endfunction
+"▶1 bzr.pull :: repo, dryrun, force[, URL[, rev]]
+function s:bzr.pull(repo, dryrun, force, ...)
+    if a:dryrun
+        call s:_f.throw('drnimp')
+    endif
+    let args=[]
+    let kwargs={}
+    if a:force
+        let kwargs.overwrite=1
+    endif
+    if a:0 && a:1 isnot 0
+        let args+=['--', a:1]
+    endif
+    if a:0>1 && a:2 isnot 0
+        let kwargs.revision=''.a:2
+    endif
+    return s:F.bzrm(a:repo, 'pull', args, kwargs, 0, 'pullf')
+endfunction
+"▶1 bzr.repo :: path → repo
+function s:bzr.repo(path)
+    let repo={'path': a:path, 'changesets': {}, 'mutable': {},
+                \'local': (stridx(a:path, '://')==-1),
+                \'labeltypes': ['tag'],
+                \'revreg': '\v\d+(\.\d+)*',
+                \'hexreg': '\v[a-zA-Z0-9_.\-+]+\@[a-zA-Z0-9_.\-+]+',
+                \'hasrevisions': 1, 'requires_sort': 0,
+                \'hypsites': deepcopy(s:hypsites),
+                \}
+    return repo
+endfunction
+"▶1 bzr.checkdir :: dir → Bool
+function s:bzr.checkdir(dir)
+    return s:_r.os.path.isdir(s:_r.os.path.join(a:dir, '.bzr'))
+endfunction
+"▶1 iterfuncs
+" TODO
+"▶1 Register driver
+call s:_f.regdriver('Bazaar', s:bzr)
+"▶1
+call frawor#Lockvar(s:, 'hasdateexe')
+" vim: ft=vim ts=4 sts=4 et fmr=▶,▲

File autoload/aurum/drivers/common/hypsites.vim

 "▶1
 scriptencoding utf-8
-execute frawor#Setup('0.1', {'@/resources': '0.0',})
+execute frawor#Setup('0.2', {'@/resources': '0.0',})
 "▶1 s:hypsites
 let s:dport='domain.(empty(port)?"":":".port)'
 let s:link='shellescape("http://".'.s:dport.'.path)'
 \]
 unlet s:svngcbase s:svngcfile
 unlet s:rhdicts
+"▶1 bazaar
+let s:hyp.bzr=[
+\]
 "▶1 post resource
 unlet s:gcproj s:dl s:bbdict s:dport
 call s:_f.postresource('hypsites', s:hyp)

File autoload/aurum/drivers/common/utils.vim

     endtry
 endif
 "▶1 utils.run :: cmd, hasnulls::0|1|2, path → [String] + shell
+" TODO Add utils.runtobuf for use in difftobuf functions
 function s:utils.run(cmd, hasnulls, cdpath)
     if a:hasnulls==2
         if has_key(s:F, 'readsystem')

File autoload/aurum/log/templates.vim

             \           "$empty\n".
             \           "$hide#$# $stat\n".
             \           "$hide#:#$patch\n",
+            \'bzr':     "revno: $rev\n".
+            \           "tags: $tags\n".
+            \           "revision-id: $hex\n".
+            \           "parent: $parents_\n".
+            \           "author: $user\n".
+            \           "branch nick: $branch\n".
+            \           "timestamp: $time#%a %Y-%m-%d %H:%M:%S#\n".
+            \           "message:\n".
+            \           "$hide#@# $description\n".
+            \           "$hide#$#$stat\n".
+            \           "$hide#:#$patch\n".
+            \           "$empty",
+            \'bzrshort': '$rev $user#expr:matchstr(@@@\,''\v^%(%(\ \<)@!.)*'')# '.
+            \               "$time#%Y-%m-%d#$tags#pref: {,suf:}#".
+            \               "$parents#expr:len(@@@)>1?' [merge]'\\:'',".
+            \                        "synreg:\\V\\( [merge]\\)\\?#\n".
+            \            "$hide#@# $description\n".
+            \            "$hide#$#$stat\n".
+            \            "$hide#:#$patch\n".
+            \            "$empty",
+            \'bzrline': '$rev: $user#expr:matchstr(@@@\,''\v^%(%(\ \<)@!.)*'')# '.
+            \               "$time#%Y-%m-%d#$tags#pref: {,suf:}#".
+            \               "$parents#expr:len(@@@)>1?' [merge]'\\:'',".
+            \                        "synreg:\\V\\( [merge]\\)\\?#".
+            \               " $summary\n".
+            \            "$hide#$#$stat\n".
+            \            "$hide#:#$patch",
         \}
 "▶1 s:kwexpr
 " TODO Add bisection status and phases

File doc/aurum.txt

         10.1. Mercurial                              |aurum-driver-Mercurial|
         10.2. Git                                    |aurum-driver-Git|
         10.3. Subversion                             |aurum-driver-Subversion|
+        10.4. Bazaar                                 |aurum-driver-Bazaar|
     11. Changelog                                    |aurum-changelog|
 
 ==============================================================================
       Guess bar is better name for baz
       And barbaz is not worse
 
+bzr                                                          *aurum-style-bzr*
+    Bzr-like style: >
+      revno: 1
+      tags: tip
+      revision-id: 454ae580ce74
+      parent: 000000000000
+      author: Bob <bob@example.com>
+      timestamp: Sun 2011-01-01 00:00:00
+      message:
+        Guess bar is better name for baz
+        And barbaz is not worse
+bzrshort                                                *aurum-style-bzrshort*
+    Bzr --short-like style: >
+      1 Bob 2011-01-01 {tip}
+        Guess bar is better name for baz
+        And barbaz is not worse
+
+bzrline                                                  *aurum-style-bzrline*
+    Bzr --line-like style: >
+      1 Bob 2011-01-01 {tip} Guess bar is better name for baz
+
 ==============================================================================
 7. Record mode                                                  *aurum-record*
 
 mutable :: a                                              *aurum-repo.mutable*
     Any mutable data needed by repository functions. This and previous keys 
     are the only ones that are not locked after repository object was created.
-csnum :: UInt                                               *aurum-repo.csnum*
-    Total number of revisions in repository. For any changeset 
-    cs.rev<repo.csnum. See also |aurum-cs.rev|.
 local :: Bool                                               *aurum-repo.local*
     1 if repository is local, 0 otherwise.
     Note that aurum is really useless for working with remote repositories.
 |aurum-cs.tags| contains list of all references pointing to given commit, not 
     just tags.
 |aurum-cs.rev| contains truncated hash (for use in |aurum://annotate|).
+|aurum-cs.phase| is always “unknown”.
 |aurum-rf-status|: if at least one of first two optional arguments is 
     non-zero, then then unknown and deleted files won’t be shown (if any). 
     Ignored files are shown only when the first two optional arguments are 
 |aurum-cs.time| is always 0 if “date” programm from coreutils is missing.
 |aurum-cs.hex| contains the stringified value of |aurum-cs.rev| and thus is 
     not fixed-length.
+|aurum-cs.phase| is always “public”.
 |aurum-rf-diff|: Options "git", "iblanks", "dates", "alltext" are not 
     supported, option "reverse" is supported only if two revisions are given.
 |aurum-rf-status|: if at least one of first two optional arguments is 
 |aurum-rf-pull| uses “svn update” to pull and “svn log” for incoming.
 |aurum-rf-push| is not defined.
 
+------------------------------------------------------------------------------
+10.4. Bazaar                                             *aurum-driver-Bazaar*
+
+|aurum-rf-label|: Supported labels: tag (non-local).
+
+|aurum-cs.time| is always 0 if “date” programm from coreutils is missing.
+|aurum-cs.children| is always empty.
+|aurum-cs.phase| is always “unknown”.
+|aurum-rf-getchasgesets|, |aurum-rf-getcs| are unable to work with commits 
+    where description contains line with two spaces followed by 60 dashes.
+|aurum-rf-updatechangesets| is doing nothing.
+|aurum-rf-getrevhex| calls |aurum-rf-getcs| thus it may be slow.
+|aurum-rf-getcsprop| does not support “copies” property (because copies, 
+    unlike renames, are not supported by bazaar itself).
+|aurum-rf-status| assumes that when renaming old file name does not contain 
+    string “ => ” and all file names do not contain "\n  " or "\nsmth:".
+    Ignored files are shown only when the first two optional arguments are 
+    absent or equal to null.
+|aurum-rf-branch| renames branch instead of creating a new one.
+|aurum-rf-update| uses revert+update for forced update.
+|aurum-rf-grep| uses internal grep implementation based on 
+    |aurum-rf-readfile|. Thus it is slow, but supports vim |regexp|.
+    See more in |aurum-f-regdriver|.
+|aurum-rf-annotate| is not able to output line numbers.
+|aurum-rf-diff| requires “diff” programm from diffutils to be installed in 
+    order to pass any of diffoptions. Support for the reverse diff option is 
+    limited to the case when both revisions are specified.
+|aurum-rf-diffname| will work incorrectly if filenames containing “' => '” 
+    were renamed.
+|aurum-repo.iterfuncs| is missing (yet).
+
 ==============================================================================
 11. Changelog                                                *aurum-changelog*
 
     0.1: Added OpenAny and AnnotateAny mappings.
 @%aurum/drivers/common/hypsites:
     0.1: Added dict.hlines key (see version 0.4 of @aurum).
+    0.2: Added _r.hypsites.bzr list.
 @%aurum/drivers/common/utils:
     0.1: _r.utils.getcmd() now accepts kwargs key values 0 and [...]
     0.2: Added _r.utils.using_ansi_esc_echo

File plugin/aurum.vim

 call s:_f.postresource('ignfiles', s:ignfiles)
 call s:_f.postresource('diffopts', s:diffoptslst)
 let s:tlist=['default', 'compact', 'git', 'svn', 'hgdef', 'hgdescr', 'cdescr',
-            \'gitoneline']
+            \'gitoneline', 'bzr', 'bzrshort', 'bzrline']
 call s:_f.postresource('tlist', s:tlist)
 call s:_f.postresource('allcachekeys', s:allcachekeys)
 "▶1 Completion helpers

File test/bzrtestrepo.tar.xz

Binary file added.

File test/cmd-log-styles.in

 :ST git
 :ST gitoneline
 :ST svn
+:ST bzr
+:ST bzrshort
+:ST bzrline
 :source addmessages.vim

File test/cmd-log-styles.ok

 |  :+)
 |  :+tar cJf testrepo.tar.xz testrepo
 |  :
+{{{1 bzr
+@  revno: 26
+|  tags: tip
+|  revision-id: 504f74154456dbb0e9441326514e42ce66279e62
+|  parent: d8140c0b7b0b670bafe0891bcf0c4582092de884
+|  author: A <a@example.com>
+|  timestamp: Mon 2002-02-11 05:43:00
+|  message:
+|  @ Added .hgignore
+|  @ Added directory/file
+|  $  .hgignore      | 2 0
+|  $  directory/file | 1 0
+|  $2 files changed, 3 insertions, 0 deletions
+|  :diff -r d8140c0b7b0b -r 504f74154456 .hgignore
+|  :--- /dev/null
+|  :+++ b/.hgignore
+|  :@@ -0,0 +1,2 @@
+|  :+syntax: glob
+|  :+ignored*
+|  :diff -r d8140c0b7b0b -r 504f74154456 directory/file
+|  :--- /dev/null
+|  :+++ b/directory/file
+|  :@@ -0,0 +1,1 @@
+|  :+File contents
+|  :
+|  
+o    revno: 25
+|\   revision-id: d8140c0b7b0b670bafe0891bcf0c4582092de884
+| |  parent: e021c634413b240b8c834a85200acc28d645f1f1
+| |  parent: e1eaeea486e48634588c778fd36a81ac5c8869a6
+| |  author: C <c@example.gov>
+| |  timestamp: Mon 2002-02-11 05:00:00
+| |  message:
+| |  @ Merge
+| |  $  elines.lst     |   0 19
+| |  $  emerged.lst    | 127  0
+| |  $  flines.lst     |   0  5
+| |  $  glines.lst     |  73  0
+| |  $  glinescopy.lst |  83  0
+| |  $5 files changed, 283 insertions, 24 deletions
+| |  :diff -r e021c634413b -r d8140c0b7b0b elines.lst
+| |  :--- a/elines.lst
+| |  :+++ /dev/null
+| |  :@@ -1,19 +0,0 @@
+| |  :-    hg init testrepo
+| |  :-    cd testrepo
+| |  :-    cp ../createrepo.zsh .
+| |  :-    hg commit -A -m 'Added «createrepo.zsh»' \
+| |  :-    hg mv createrepo.zsh crepo.zsh
+| |  :-    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| |  :-    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+| |  :-    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| |  :-    hg mv crepo.zsh chgrepo.zsh
+| |  :-    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :-    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :-    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :-    cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :-    cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :-    cat alines.lst | grep 'b' > ablines.lst
+| |  :-    cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :-    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :-    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :-tar cJf testrepo.tar.xz testrepo
+| |  :diff -r e021c634413b -r d8140c0b7b0b emerged.lst
+| |  :--- /dev/null
+| |  :+++ b/emerged.lst
+| |  :@@ -0,0 +1,127 @@
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+emulate -L zsh
+| |  :+set -e
+| |  :+local A='A <a@example.com>'
+| |  :+local B='B <b@example.org>'
+| |  :+local C='C <c@example.gov>'
+| |  :+    set -e
+| |  :+>>>>>>> other
+| |  :+    hg init testrepo
+| |  :+    cd testrepo
+| |  :+    cp ../createrepo.zsh .
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    # XXX Date test will work only till 2099
+| |  :+>>>>>>> other
+| |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+        --date '1999-01-02 5:20' --user $A
+| |  :+>>>>>>> other
+| |  :+    hg mv createrepo.zsh crepo.zsh
+| |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+        --date '2000-01-05 7:30' --user $A
+| |  :+>>>>>>> other
+| |  :+    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+| |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+        --date '2000-01-15 15:00' --user $B
+| |  :+>>>>>>> other
+| |  :+    hg mv crepo.zsh chgrepo.zsh
+| |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+        --date '2000-02-01 14:00' --user $B
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+| |  :+        --date '2000-05-10 4:23' --user $A
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added dlines.lst' \
+| |  :+        --date '2000-11-01 13:24' --user $B
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added alines.lst' \
+| |  :+        --date '2000-11-02 5:44' --user $A
+| |  :+>>>>>>> other
+| |  :+    cat alines.lst | grep 'b' > ablines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added ablines.lst' \
+| |  :+        --date '2000-11-02 14:13' --user $B
+| |  :+    hg tag ablines \
+| |  :+        --date '2000-11-02 14:14' --user $B
+| |  :+    hg update default
+| |  :+    hg merge -r ablines
+| |  :+    hg commit -m 'Merge from C' \
+| |  :+        --date '2001-01-01 00:00' --user $C
+| |  :+    hg update C
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added blines.lst' \
+| |  :+        --date '2001-02-01 05:18' --user $A
+| |  :+    hg tag blines \
+| |  :+        --date '2001-02-01 05:19' --user $A
+| |  :+    hg update -r -2
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added clines.lst' \
+| |  :+        --date '2001-02-01 14:56' --user $B
+| |  :+    hg tag clines \
+| |  :+        --date '2001-02-01 14:56:52' --user $B
+| |  :+    hg update A
+| |  :+    hg merge -r B
+| |  :+    hg commit -m 'Merge from B' \
+| |  :+        --date '2002-01-01 00:00' --user $C
+| |  :+    hg merge -r clines
+| |  :+    hg commit -m 'Merge from C:2' \
+| |  :+        --date '2002-01-01 00:00:15' --user $C
+| |  :+    hg update default
+| |  :+    hg merge -r blines
+| |  :+    hg commit -m 'Merge from C:1' \
+| |  :+        --date '2002-01-01 00:00:30' --user $C
+| |  :+    hg merge -r A
+| |  :+    hg commit -m 'Merge from A' \
+| |  :+        --date '2002-01-01 00:00:45' --user $C
+| |  :+    hg cp hglines.lst hglines2.lst
+| |  :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+| |  :+        --date '2002-02-10 05:00' --user $A
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added nohglines.lst' \
+| |  :+        --date '2002-02-10 15:33' --user $B
+| |  :+    cat nohglines.lst | rev > nohglinesrev.lst
+| |  :+    hg commit -A -m 'Added nohglinesrev.lst' \
+| |  :+        --date '2002-02-10 16:01' --user $B
+| |  :+    seq 1 10 | tr ' ' $'\n' > ignored10.lst
+| |  :+    hg commit -A -m 'Added ignored10.lst' \
+| |  :+        --date '2002-02-11 03:15' --user $A
+| |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| |  :+    hg commit -A -m 'Added .hgignore' \
+| |  :+        --date '2002-02-11 05:43' --user $A
+| |  :+    echo abc >> nohglinesrev.lst
+| |  :+    echo 'Def' > addeddef && hg add addeddef
+| |  :+    hg rm hglines2.lst
+| |  :+    rm nohglines.lst
+| |  :+    cat hglines.lst | rev > hglinesrev.lst
+| |  :+    echo 'Abc' > ignoredabc
+| |  :+>>>>>>> other
+| |  :+tar cJf testrepo.tar.xz testrepo
+| |  :diff -r e021c634413b -r d8140c0b7b0b flines.lst
+| |  :--- a/flines.lst
+| |  :+++ /dev/null
+| |  :@@ -1,5 +0,0 @@
+| |  :-    hg commit -m 'Merge from C' \
+| |  :-    hg commit -m 'Merge from B' \
+| |  :-    hg commit -m 'Merge from C:2' \
+| |  :-    hg commit -m 'Merge from C:1' \
+| |  :-    hg commit -m 'Merge from A' \
+| |  :diff -r e021c634413b -r d8140c0b7b0b glines.lst
+| |  :--- a/glines.lst
+| |  :+++ b/glines.lst
+| |  :@@ -1,10 +1,83 @@
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+local B='B <b@example.org>'
+| |  :+local C='C <c@example.gov>'
+| |  :+    hg init testrepo
+| |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| |  :+    hg mv createrepo.zsh crepo.zsh
+| |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| |  :+>>>>>>> other
+| |  :     hg mv crepo.zsh chgrepo.zsh
+| |  :     hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :     cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :     cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+| |  :+    hg branch A
+| |  :+>>>>>>> other
+| |  :     cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added dlines.lst' \
+| |  :+    hg branch B
+| |  :+>>>>>>> other
+| |  :     cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added alines.lst' \
+| |  :+    hg branch C
+| |  :+>>>>>>> other
+| |  :     cat alines.lst | grep 'b' > ablines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added ablines.lst' \
+| |  :+    hg tag ablines \
+| |  :+    hg update default
+| |  :+    hg merge -r ablines
+| |  :+    hg commit -m 'Merge from C' \
+| |  :+    hg update C
+| |  :+>>>>>>> other
+| |  :     cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added blines.lst' \
+| |  :+    hg tag blines \
+| |  :+    hg update -r -2
+| |  :+>>>>>>> other
+| |  :     cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added clines.lst' \
+| |  :+    hg tag clines \
+| |  :+    hg update A
+| |  :+    hg merge -r B
+| |  :+    hg commit -m 'Merge from B' \
+| |  :+    hg merge -r clines
+| |  :+    hg commit -m 'Merge from C:2' \
+| |  :+    hg update default
+| |  :+    hg merge -r blines
+| |  :+    hg commit -m 'Merge from C:1' \
+| |  :+    hg merge -r A
+| |  :+    hg commit -m 'Merge from A' \
+| |  :+    hg cp hglines.lst hglines2.lst
+| |  :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+| |  :+>>>>>>> other
+| |  :     cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added nohglines.lst' \
+| |  :+    cat nohglines.lst | rev > nohglinesrev.lst
+| |  :+    hg commit -A -m 'Added nohglinesrev.lst' \
+| |  :+    seq 1 10 | tr ' ' $'\n' > ignored10.lst
+| |  :+    hg commit -A -m 'Added ignored10.lst' \
+| |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| |  :+    hg commit -A -m 'Added .hgignore' \
+| |  :+    echo abc >> nohglinesrev.lst
+| |  :+    echo 'Def' > addeddef && hg add addeddef
+| |  :+    hg rm hglines2.lst
+| |  :+    rm nohglines.lst
+| |  :+    cat hglines.lst | rev > hglinesrev.lst
+| |  :+    echo 'Abc' > ignoredabc
+| |  :+>>>>>>> other
+| |  :diff -r e021c634413b -r d8140c0b7b0b glinescopy.lst
+| |  :--- /dev/null
+| |  :+++ b/glinescopy.lst
+| |  :@@ -0,0 +1,83 @@
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+local B='B <b@example.org>'
+| |  :+local C='C <c@example.gov>'
+| |  :+    hg init testrepo
+| |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| |  :+    hg mv createrepo.zsh crepo.zsh
+| |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| |  :+>>>>>>> other
+| |  :+    hg mv crepo.zsh chgrepo.zsh
+| |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+| |  :+    hg branch A
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added dlines.lst' \
+| |  :+    hg branch B
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added alines.lst' \
+| |  :+    hg branch C
+| |  :+>>>>>>> other
+| |  :+    cat alines.lst | grep 'b' > ablines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added ablines.lst' \
+| |  :+    hg tag ablines \
+| |  :+    hg update default
+| |  :+    hg merge -r ablines
+| |  :+    hg commit -m 'Merge from C' \
+| |  :+    hg update C
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added blines.lst' \
+| |  :+    hg tag blines \
+| |  :+    hg update -r -2
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added clines.lst' \
+| |  :+    hg tag clines \
+| |  :+    hg update A
+| |  :+    hg merge -r B
+| |  :+    hg commit -m 'Merge from B' \
+| |  :+    hg merge -r clines
+| |  :+    hg commit -m 'Merge from C:2' \
+| |  :+    hg update default
+| |  :+    hg merge -r blines
+| |  :+    hg commit -m 'Merge from C:1' \
+| |  :+    hg merge -r A
+| |  :+    hg commit -m 'Merge from A' \
+| |  :+    hg cp hglines.lst hglines2.lst
+| |  :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+| |  :+>>>>>>> other
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :+<<<<<<< local
+| |  :+=======
+| |  :+    hg commit -A -m 'Added nohglines.lst' \
+| |  :+    cat nohglines.lst | rev > nohglinesrev.lst
+| |  :+    hg commit -A -m 'Added nohglinesrev.lst' \
+| |  :+    seq 1 10 | tr ' ' $'\n' > ignored10.lst
+| |  :+    hg commit -A -m 'Added ignored10.lst' \
+| |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| |  :+    hg commit -A -m 'Added .hgignore' \
+| |  :+    echo abc >> nohglinesrev.lst
+| |  :+    echo 'Def' > addeddef && hg add addeddef
+| |  :+    hg rm hglines2.lst
+| |  :+    rm nohglines.lst
+| |  :+    cat hglines.lst | rev > hglinesrev.lst
+| |  :+    echo 'Abc' > ignoredabc
+| |  :+>>>>>>> other
+| |  :
+| |  
+o |  revno: 24
+| |  revision-id: e021c634413b240b8c834a85200acc28d645f1f1
+| |  parent: 5afd628b0861f6447ed813895d5ced58a1c42a72
+| |  author: A <a@example.com>
+| |  timestamp: Mon 2002-02-11 04:15:00
+| |  message:
+| |  @ Added elines.lst with eplines
+| |  @ Added flines.lst with frlines
+| |  @ Added glines.lst with grlines
+| |  $  elines.lst | 19 0
+| |  $  flines.lst |  5 0
+| |  $  glines.lst | 10 0
+| |  $3 files changed, 34 insertions, 0 deletions
+| |  :diff -r 5afd628b0861 -r e021c634413b elines.lst
+| |  :--- /dev/null
+| |  :+++ b/elines.lst
+| |  :@@ -0,0 +1,19 @@
+| |  :+    hg init testrepo
+| |  :+    cd testrepo
+| |  :+    cp ../createrepo.zsh .
+| |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| |  :+    hg mv createrepo.zsh crepo.zsh
+| |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| |  :+    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+| |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| |  :+    hg mv crepo.zsh chgrepo.zsh
+| |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :+    cat alines.lst | grep 'b' > ablines.lst
+| |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :+tar cJf testrepo.tar.xz testrepo
+| |  :diff -r 5afd628b0861 -r e021c634413b flines.lst
+| |  :--- /dev/null
+| |  :+++ b/flines.lst
+| |  :@@ -0,0 +1,5 @@
+| |  :+    hg commit -m 'Merge from C' \
+| |  :+    hg commit -m 'Merge from B' \
+| |  :+    hg commit -m 'Merge from C:2' \
+| |  :+    hg commit -m 'Merge from C:1' \
+| |  :+    hg commit -m 'Merge from A' \
+| |  :diff -r 5afd628b0861 -r e021c634413b glines.lst
+| |  :--- /dev/null
+| |  :+++ b/glines.lst
+| |  :@@ -0,0 +1,10 @@
+| |  :+    hg mv crepo.zsh chgrepo.zsh
+| |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :+    cat alines.lst | grep 'b' > ablines.lst
+| |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :
+| |  
+| o  revno: 23
+|/   revision-id: e1eaeea486e48634588c778fd36a81ac5c8869a6
+|    parent: 5afd628b0861f6447ed813895d5ced58a1c42a72
+|    author: A <a@example.com>
+|    timestamp: Mon 2002-02-11 04:15:00
+|    message:
+|    @ Added elines.lst, flines.lst and glines.lst
+|    $  elines.lst |  88 0
+|    $  flines.lst |  12 0
+|    $  glines.lst |  59 0
+|    $3 files changed, 159 insertions, 0 deletions
+|    :diff -r 5afd628b0861 -r e1eaeea486e4 elines.lst
+|    :--- /dev/null
+|    :+++ b/elines.lst
+|    :@@ -0,0 +1,88 @@
+|    :+emulate -L zsh
+|    :+set -e
+|    :+local A='A <a@example.com>'
+|    :+local B='B <b@example.org>'
+|    :+local C='C <c@example.gov>'
+|    :+    set -e
+|    :+    hg init testrepo
+|    :+    cd testrepo
+|    :+    cp ../createrepo.zsh .
+|    :+    # XXX Date test will work only till 2099
+|    :+    hg commit -A -m 'Added «createrepo.zsh»' \
+|    :+        --date '1999-01-02 5:20' --user $A
+|    :+    hg mv createrepo.zsh crepo.zsh
+|    :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+|    :+        --date '2000-01-05 7:30' --user $A
+|    :+    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+|    :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+|    :+        --date '2000-01-15 15:00' --user $B
+|    :+    hg mv crepo.zsh chgrepo.zsh
+|    :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+|    :+        --date '2000-02-01 14:00' --user $B
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+|    :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+|    :+        --date '2000-05-10 4:23' --user $A
+|    :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+|    :+    hg commit -A -m 'Added dlines.lst' \
+|    :+        --date '2000-11-01 13:24' --user $B
+|    :+    cat chgrepo.zsh | grep 'a' > alines.lst
+|    :+    hg commit -A -m 'Added alines.lst' \
+|    :+        --date '2000-11-02 5:44' --user $A
+|    :+    cat alines.lst | grep 'b' > ablines.lst
+|    :+    hg commit -A -m 'Added ablines.lst' \
+|    :+        --date '2000-11-02 14:13' --user $B
+|    :+    hg tag ablines \
+|    :+        --date '2000-11-02 14:14' --user $B
+|    :+    hg update default
+|    :+    hg merge -r ablines
+|    :+    hg commit -m 'Merge from C' \
+|    :+        --date '2001-01-01 00:00' --user $C
+|    :+    hg update C
+|    :+    cat chgrepo.zsh | grep 'b' > blines.lst
+|    :+    hg commit -A -m 'Added blines.lst' \
+|    :+        --date '2001-02-01 05:18' --user $A
+|    :+    hg tag blines \
+|    :+        --date '2001-02-01 05:19' --user $A
+|    :+    hg update -r -2
+|    :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+|    :+    hg commit -A -m 'Added clines.lst' \
+|    :+        --date '2001-02-01 14:56' --user $B
+|    :+    hg tag clines \
+|    :+        --date '2001-02-01 14:56:52' --user $B
+|    :+    hg update A
+|    :+    hg merge -r B
+|    :+    hg commit -m 'Merge from B' \
+|    :+        --date '2002-01-01 00:00' --user $C
+|    :+    hg merge -r clines
+|    :+    hg commit -m 'Merge from C:2' \
+|    :+        --date '2002-01-01 00:00:15' --user $C
+|    :+    hg update default
+|    :+    hg merge -r blines
+|    :+    hg commit -m 'Merge from C:1' \
+|    :+        --date '2002-01-01 00:00:30' --user $C
+|    :+    hg merge -r A
+|    :+    hg commit -m 'Merge from A' \
+|    :+        --date '2002-01-01 00:00:45' --user $C
+|    :+    hg cp hglines.lst hglines2.lst
+|    :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+|    :+        --date '2002-02-10 05:00' --user $A
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+|    :+    hg commit -A -m 'Added nohglines.lst' \
+|    :+        --date '2002-02-10 15:33' --user $B
+|    :+    cat nohglines.lst | rev > nohglinesrev.lst
+|    :+    hg commit -A -m 'Added nohglinesrev.lst' \
+|    :+        --date '2002-02-10 16:01' --user $B
+|    :+    seq 1 10 | tr ' ' $'\n' > ignored10.lst
+|    :+    hg commit -A -m 'Added ignored10.lst' \
+|    :+        --date '2002-02-11 03:15' --user $A
+|    :+    echo $'syntax: glob\nignored*' > .hgignore
+|    :+    hg commit -A -m 'Added .hgignore' \
+|    :+        --date '2002-02-11 05:43' --user $A
+|    :+    echo abc >> nohglinesrev.lst
+|    :+    echo 'Def' > addeddef && hg add addeddef
+|    :+    hg rm hglines2.lst
+|    :+    rm nohglines.lst
+|    :+    cat hglines.lst | rev > hglinesrev.lst
+|    :+    echo 'Abc' > ignoredabc
+|    :+tar cJf testrepo.tar.xz testrepo
+|    :diff -r 5afd628b0861 -r e1eaeea486e4 flines.lst
+|    :--- /dev/null
+|    :+++ b/flines.lst
+|    :@@ -0,0 +1,12 @@
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+|    :+    hg update default
+|    :+    hg commit -m 'Merge from C' \
+|    :+    hg commit -m 'Merge from B' \
+|    :+    hg commit -m 'Merge from C:2' \
+|    :+    hg update default
+|    :+    hg commit -m 'Merge from C:1' \
+|    :+    hg commit -m 'Merge from A' \
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+|    :+    echo 'Def' > addeddef && hg add addeddef
+|    :+tar cJf testrepo.tar.xz testrepo
+|    :diff -r 5afd628b0861 -r e1eaeea486e4 glines.lst
+|    :--- /dev/null
+|    :+++ b/glines.lst
+|    :@@ -0,0 +1,59 @@
+|    :+local B='B <b@example.org>'
+|    :+local C='C <c@example.gov>'
+|    :+    hg init testrepo
+|    :+    hg commit -A -m 'Added «createrepo.zsh»' \
+|    :+    hg mv createrepo.zsh crepo.zsh
+|    :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+|    :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+|    :+    hg mv crepo.zsh chgrepo.zsh
+|    :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+|    :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+|    :+    hg branch A
+|    :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+|    :+    hg commit -A -m 'Added dlines.lst' \
+|    :+    hg branch B
+|    :+    cat chgrepo.zsh | grep 'a' > alines.lst
+|    :+    hg commit -A -m 'Added alines.lst' \
+|    :+    hg branch C
+|    :+    cat alines.lst | grep 'b' > ablines.lst
+|    :+    hg commit -A -m 'Added ablines.lst' \
+|    :+    hg tag ablines \
+|    :+    hg update default
+|    :+    hg merge -r ablines
+|    :+    hg commit -m 'Merge from C' \
+|    :+    hg update C
+|    :+    cat chgrepo.zsh | grep 'b' > blines.lst
+|    :+    hg commit -A -m 'Added blines.lst' \
+|    :+    hg tag blines \
+|    :+    hg update -r -2
+|    :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+|    :+    hg commit -A -m 'Added clines.lst' \
+|    :+    hg tag clines \
+|    :+    hg update A
+|    :+    hg merge -r B
+|    :+    hg commit -m 'Merge from B' \
+|    :+    hg merge -r clines
+|    :+    hg commit -m 'Merge from C:2' \
+|    :+    hg update default
+|    :+    hg merge -r blines
+|    :+    hg commit -m 'Merge from C:1' \
+|    :+    hg merge -r A
+|    :+    hg commit -m 'Merge from A' \
+|    :+    hg cp hglines.lst hglines2.lst
+|    :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+|    :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+|    :+    hg commit -A -m 'Added nohglines.lst' \
+|    :+    cat nohglines.lst | rev > nohglinesrev.lst
+|    :+    hg commit -A -m 'Added nohglinesrev.lst' \
+|    :+    seq 1 10 | tr ' ' $'\n' > ignored10.lst
+|    :+    hg commit -A -m 'Added ignored10.lst' \
+|    :+    echo $'syntax: glob\nignored*' > .hgignore
+|    :+    hg commit -A -m 'Added .hgignore' \
+|    :+    echo abc >> nohglinesrev.lst
+|    :+    echo 'Def' > addeddef && hg add addeddef
+|    :+    hg rm hglines2.lst
+|    :+    rm nohglines.lst
+|    :+    cat hglines.lst | rev > hglinesrev.lst
+|    :+    echo 'Abc' > ignoredabc
+|    :
+|    
+o  revno: 22
+|  revision-id: 5afd628b0861f6447ed813895d5ced58a1c42a72
+|  parent: e85aa09aab1621b59b8be37f723410b219c8599c
+|  author: A <a@example.com>
+|  timestamp: Mon 2002-02-11 03:16:00
+|  message:
+|  @ Added tag oldtag for changeset 023aa55bd806
+|  $  .hgtags | 1 0
+|  $1 files changed, 1 insertions, 0 deletions
+|  :diff -r e85aa09aab16 -r 5afd628b0861 .hgtags
+|  :--- a/.hgtags
+|  :+++ b/.hgtags
+|  :@@ -1,1 +1,2 @@
+|  : c06107b7bcbe751d2dd40faf4179ee7d6aac44ac ablines
+|  :+023aa55bd8062179ce36adbdd78363e9b88718c1 oldtag
+|  :
+|  
+o  revno: 21
+|  revision-id: e85aa09aab1621b59b8be37f723410b219c8599c
+|  parent: 67cf252de26b12da6769114cc89b793357f5a46a
+|  author: A <a@example.com>
+|  timestamp: Mon 2002-02-11 03:15:00
+|  message:
+|  @ Added ignored10.lst
+|  $  ignored10.lst | 10 0
+|  $1 files changed, 10 insertions, 0 deletions
+|  :diff -r 67cf252de26b -r e85aa09aab16 ignored10.lst
+|  :--- /dev/null
+|  :+++ b/ignored10.lst
+|  :@@ -0,0 +1,10 @@
+|  :+1
+|  :+2
+|  :+3
+|  :+4
+|  :+5
+|  :+6
+|  :+7
+|  :+8
+|  :+9
+|  :+10
+|  :
+|  
+o  revno: 20
+|  revision-id: 67cf252de26b12da6769114cc89b793357f5a46a
+|  parent: 456e0b05b81af4f332405336f11df4769ec9f250
+|  author: B <b@example.org>
+|  timestamp: Sun 2002-02-10 16:01:00
+|  message:
+|  @ Added nohglinesrev.lst
+|  $  nohglinesrev.lst | 53 0
+|  $1 files changed, 53 insertions, 0 deletions
+|  :diff -r 456e0b05b81a -r 67cf252de26b nohglinesrev.lst
+|  :--- /dev/null
+|  :+++ b/nohglinesrev.lst
+|  :@@ -0,0 +1,53 @@
+|  :+hsz/nib/!#
+|  :+hsz L- etalume
+|  :+e- tes
+|  :+'>moc.elpmaxe@a< A'=A lacol
+|  :+'>gro.elpmaxe@b< B'=B lacol
+|  :+'>vog.elpmaxe@c< C'=C lacol
+|  :+{
+|  :+e- tes    
+|  :+opertset dc    
+|  :+. hsz.operetaerc/.. pc    
+|  :+9902 llit ylno krow lliw tset etaD XXX #    
+|  :+A$ resu-- '02:5 20-10-9991' etad--        
+|  :+A$ resu-- '03:7 50-10-0002' etad--        
+|  :+hsz.operc '/}{/}{/rt' e- i- p- lrep    
+|  :+B$ resu-- '00:51 51-10-0002' etad--        
+|  :+B$ resu-- '00:41 10-20-0002' etad--        
+|  :+tsl.senilgh > '/ gh    ^/ sselnu _$ fednu' e- i- p- lrep | hsz.operghc tac    
+|  :+tsl.seniletad > '/ gh    ^/ sselnu _$ fednu' e- i- p- lrep | hsz.operghc tac    
+|  :+A$ resu-- '32:4 01-50-0002' etad--        
+|  :+tsl.senild > 'd' perg | hsz.operghc tac    
+|  :+B$ resu-- '42:31 10-11-0002' etad--        
+|  :+tsl.senila > 'a' perg | hsz.operghc tac    
+|  :+A$ resu-- '44:5 20-11-0002' etad--        
+|  :+tsl.senilba > 'b' perg | tsl.senila tac    
+|  :+B$ resu-- '31:41 20-11-0002' etad--        
+|  :+B$ resu-- '41:41 20-11-0002' etad--        
+|  :+C$ resu-- '00:00 10-10-1002' etad--        
+|  :+tsl.senilb > 'b' perg | hsz.operghc tac    
+|  :+A$ resu-- '81:50 10-20-1002' etad--        
+|  :+A$ resu-- '91:50 10-20-1002' etad--        
+|  :+tsl.senilc > 'c' perg | tros | hsz.operghc tac    
+|  :+B$ resu-- '65:41 10-20-1002' etad--        
+|  :+B$ resu-- '25:65:41 10-20-1002' etad--        
+|  :+C$ resu-- '00:00 10-10-2002' etad--        
+|  :+C$ resu-- '51:00:00 10-10-2002' etad--        
+|  :+C$ resu-- '03:00:00 10-10-2002' etad--        
+|  :+C$ resu-- '54:00:00 10-10-2002' etad--        
+|  :+A$ resu-- '00:50 01-20-2002' etad--        
+|  :+tsl.senilghon > '/ gh    ^/ fi _$ fednu' e- i- p- lrep | hsz.operghc tac    
+|  :+B$ resu-- '33:51 01-20-2002' etad--        
+|  :+tsl.versenilghon > ver | tsl.senilghon tac    
+|  :+B$ resu-- '10:61 01-20-2002' etad--        
+|  :+tsl.01derongi > 'n\'$ ' ' rt | 01 1 qes    
+|  :+A$ resu-- '51:30 11-20-2002' etad--        
+|  :+erongigh. > '*derongin\bolg :xatnys'$ ohce    
+|  :+A$ resu-- '34:50 11-20-2002' etad--        
+|  :+tsl.versenilghon >> cba ohce    
+|  :+feddedda dda gh && feddedda > 'feD' ohce    
+|  :+tsl.senilghon mr    
+|  :+tsl.versenilgh > ver | tsl.senilgh tac    
+|  :+cbaderongi > 'cbA' ohce    
+|  :+}
+|  :+opertset zx.rat.opertset fJc rat
+|  :
+|  
+o  revno: 19
+|  revision-id: 456e0b05b81af4f332405336f11df4769ec9f250
+|  parent: f44a21859e57e4abc6155da804d08dd5069e798e
+|  author: B <b@example.org>
+|  timestamp: Sun 2002-02-10 15:33:00
+|  message:
+|  @ Added nohglines.lst
+|  $  nohglines.lst | 53 0
+|  $1 files changed, 53 insertions, 0 deletions
+|  :diff -r f44a21859e57 -r 456e0b05b81a nohglines.lst
+|  :--- /dev/null
+|  :+++ b/nohglines.lst
+|  :@@ -0,0 +1,53 @@
+|  :+#!/bin/zsh
+|  :+emulate -L zsh
+|  :+set -e
+|  :+local A='A <a@example.com>'
+|  :+local B='B <b@example.org>'
+|  :+local C='C <c@example.gov>'
+|  :+{
+|  :+    set -e
+|  :+    cd testrepo
+|  :+    cp ../createrepo.zsh .
+|  :+    # XXX Date test will work only till 2099
+|  :+        --date '1999-01-02 5:20' --user $A
+|  :+        --date '2000-01-05 7:30' --user $A
+|  :+    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+|  :+        --date '2000-01-15 15:00' --user $B
+|  :+        --date '2000-02-01 14:00' --user $B
+|  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+|  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+|  :+        --date '2000-05-10 4:23' --user $A
+|  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+|  :+        --date '2000-11-01 13:24' --user $B
+|  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+|  :+        --date '2000-11-02 5:44' --user $A
+|  :+    cat alines.lst | grep 'b' > ablines.lst
+|  :+        --date '2000-11-02 14:13' --user $B
+|  :+        --date '2000-11-02 14:14' --user $B
+|  :+        --date '2001-01-01 00:00' --user $C
+|  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+|  :+        --date '2001-02-01 05:18' --user $A
+|  :+        --date '2001-02-01 05:19' --user $A
+|  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+|  :+        --date '2001-02-01 14:56' --user $B
+|  :+        --date '2001-02-01 14:56:52' --user $B
+|  :+        --date '2002-01-01 00:00' --user $C
+|  :+        --date '2002-01-01 00:00:15' --user $C
+|  :+        --date '2002-01-01 00:00:30' --user $C
+|  :+        --date '2002-01-01 00:00:45' --user $C
+|  :+        --date '2002-02-10 05:00' --user $A
+|  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+|  :+        --date '2002-02-10 15:33' --user $B
+|  :+    cat nohglines.lst | rev > nohglinesrev.lst
+|  :+        --date '2002-02-10 16:01' --user $B
+|  :+    seq 1 10 | tr ' ' $'\n' > ignored10.lst
+|  :+        --date '2002-02-11 03:15' --user $A
+|  :+    echo $'syntax: glob\nignored*' > .hgignore
+|  :+        --date '2002-02-11 05:43' --user $A
+|  :+    echo abc >> nohglinesrev.lst
+|  :+    echo 'Def' > addeddef && hg add addeddef
+|  :+    rm nohglines.lst
+|  :+    cat hglines.lst | rev > hglinesrev.lst
+|  :+    echo 'Abc' > ignoredabc
+|  :+}
+|  :+tar cJf testrepo.tar.xz testrepo
+|  :
+|  
+o  revno: 18
+|  revision-id: f44a21859e57e4abc6155da804d08dd5069e798e
+|  parent: e5648a3eea574f3fc03709b4fdd799a38f649edd
+|  author: A <a@example.com>
+|  timestamp: Sun 2002-02-10 05:00:00
+|  message:
+|  @ Copied “hglines.lst” to “hglines2.lst”
+|  $  hglines2.lst | 41 0
+|  $1 files changed, 41 insertions, 0 deletions
+|  :diff -r e5648a3eea57 -r f44a21859e57 hglines2.lst
+|  :--- /dev/null
+|  :+++ b/hglines2.lst
+|  :@@ -0,0 +1,41 @@
+|  :+    hg init testrepo
+|  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+|  :+    hg mv createrepo.zsh crepo.zsh
+|  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+|  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+|  :+    hg mv crepo.zsh chgrepo.zsh
+|  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+|  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+|  :+    hg branch A
+|  :+    hg commit -A -m 'Added dlines.lst' \
+|  :+    hg branch B
+|  :+    hg commit -A -m 'Added alines.lst' \
+|  :+    hg branch C
+|  :+    hg commit -A -m 'Added ablines.lst' \
+|  :+    hg tag ablines \
+|  :+    hg update default
+|  :+    hg merge -r ablines
+|  :+    hg commit -m 'Merge from C' \
+|  :+    hg update C
+|  :+    hg commit -A -m 'Added blines.lst' \
+|  :+    hg tag blines \
+|  :+    hg update -r -2
+|  :+    hg commit -A -m 'Added clines.lst' \
+|  :+    hg tag clines \
+|  :+    hg update A
+|  :+    hg merge -r B
+|  :+    hg commit -m 'Merge from B' \
+|  :+    hg merge -r clines
+|  :+    hg commit -m 'Merge from C:2' \
+|  :+    hg update default
+|  :+    hg merge -r blines
+|  :+    hg commit -m 'Merge from C:1' \
+|  :+    hg merge -r A
+|  :+    hg commit -m 'Merge from A' \
+|  :+    hg cp hglines.lst hglines2.lst
+|  :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+|  :+    hg commit -A -m 'Added nohglines.lst' \
+|  :+    hg commit -A -m 'Added nohglinesrev.lst' \
+|  :+    hg commit -A -m 'Added ignored10.lst' \
+|  :+    hg commit -A -m 'Added .hgignore' \
+|  :+    hg rm hglines2.lst
+|  :
+|  
+o    revno: 17
+|\   revision-id: e5648a3eea574f3fc03709b4fdd799a38f649edd
+| |  parent: 462a1e95be86f96aaf6d7360f6f770826c3eb641
+| |  parent: be92227e3e43f4e7402408afe110098d209d2568
+| |  author: C <c@example.gov>
+| |  timestamp: Tue 2002-01-01 00:00:45
+| |  message:
+| |  @ Merge from A
+| |  $  clines.lst | 49 0
+| |  $1 files changed, 49 insertions, 0 deletions
+| |  :diff -r 462a1e95be86 -r e5648a3eea57 clines.lst
+| |  :--- /dev/null
+| |  :+++ b/clines.lst
+| |  :@@ -0,0 +1,49 @@
+| |  :+    cat alines.lst | grep 'b' > ablines.lst
+| |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| |  :+    cat hglines.lst | rev > hglinesrev.lst
+| |  :+    cat nohglines.lst | rev > nohglinesrev.lst
+| |  :+    cd testrepo
+| |  :+    cp ../createrepo.zsh .
+| |  :+    echo 'Abc' > ignoredabc
+| |  :+    echo abc >> nohglinesrev.lst
+| |  :+    echo 'Def' > addeddef && hg add addeddef
+| |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| |  :+    hg branch A
+| |  :+    hg branch B
+| |  :+    hg branch C
+| |  :+    hg commit -A -m 'Added ablines.lst' \
+| |  :+    hg commit -A -m 'Added alines.lst' \
+| |  :+    hg commit -A -m 'Added blines.lst' \
+| |  :+    hg commit -A -m 'Added clines.lst' \
+| |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| |  :+    hg commit -A -m 'Added dlines.lst' \
+| |  :+    hg commit -A -m 'Added .hgignore' \
+| |  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+| |  :+    hg commit -A -m 'Added ignored10.lst' \
+| |  :+    hg commit -A -m 'Added nohglines.lst' \
+| |  :+    hg commit -A -m 'Added nohglinesrev.lst' \
+| |  :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+| |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| |  :+    hg commit -m 'Merge from A' \
+| |  :+    hg commit -m 'Merge from B' \
+| |  :+    hg commit -m 'Merge from C' \
+| |  :+    hg commit -m 'Merge from C:1' \
+| |  :+    hg commit -m 'Merge from C:2' \
+| |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| |  :+    hg cp hglines.lst hglines2.lst
+| |  :+    hg merge -r clines
+| |  :+    hg mv createrepo.zsh crepo.zsh
+| |  :+    hg mv crepo.zsh chgrepo.zsh
+| |  :+    hg tag clines \
+| |  :+local A='A <a@example.com>'
+| |  :+local B='B <b@example.org>'
+| |  :+local C='C <c@example.gov>'
+| |  :+    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+| |  :+tar cJf testrepo.tar.xz testrepo
+| |  :
+| |  
+o |    revno: 16
+|\ \   revision-id: 462a1e95be86f96aaf6d7360f6f770826c3eb641
+| | |  parent: 269399222040415b3928a316f5d28792cc0be4dd
+| | |  parent: c4110a066208167dae46b08f4e0d8d2b37e842f3
+| | |  author: C <c@example.gov>
+| | |  timestamp: Tue 2002-01-01 00:00:30
+| | |  message:
+| | |  @ Merge from C:1
+| | |  $  .hgtags    |  1 0
+| | |  $  blines.lst | 16 0
+| | |  $2 files changed, 17 insertions, 0 deletions
+| | |  :diff -r 269399222040 -r 462a1e95be86 .hgtags
+| | |  :--- /dev/null
+| | |  :+++ b/.hgtags
+| | |  :@@ -0,0 +1,1 @@
+| | |  :+c06107b7bcbe751d2dd40faf4179ee7d6aac44ac ablines
+| | |  :diff -r 269399222040 -r 462a1e95be86 blines.lst
+| | |  :--- /dev/null
+| | |  :+++ b/blines.lst
+| | |  :@@ -0,0 +1,16 @@
+| | |  :+#!/bin/zsh
+| | |  :+local B='B <b@example.org>'
+| | |  :+    hg branch A
+| | |  :+    hg branch B
+| | |  :+    hg branch C
+| | |  :+    cat alines.lst | grep 'b' > ablines.lst
+| | |  :+    hg commit -A -m 'Added ablines.lst' \
+| | |  :+    hg tag ablines \
+| | |  :+    hg merge -r ablines
+| | |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| | |  :+    hg commit -A -m 'Added blines.lst' \
+| | |  :+    hg tag blines \
+| | |  :+    hg merge -r blines
+| | |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| | |  :+    echo abc >> nohglinesrev.lst
+| | |  :+    echo 'Abc' > ignoredabc
+| | |  :
+| | |  
+| | o    revno: 15
+| | |\   revision-id: be92227e3e43f4e7402408afe110098d209d2568
+| | | |  parent: 5e2f73d0c01dfb8ee0d3577e03d016a5f6df58b1
+| | | |  parent: 023aa55bd8062179ce36adbdd78363e9b88718c1
+| | | |  author: C <c@example.gov>
+| | | |  branch nick: A
+| | | |  timestamp: Tue 2002-01-01 00:00:15
+| | | |  message:
+| | | |  @ Merge from C:2
+| | | |  $  .hgtags     |  1 0
+| | | |  $  ablines.lst | 13 0
+| | | |  $  blines.lst  | 16 0
+| | | |  $  clines.lst  | 49 0
+| | | |  $4 files changed, 79 insertions, 0 deletions
+| | | |  :diff -r 5e2f73d0c01d -r be92227e3e43 .hgtags
+| | | |  :--- /dev/null
+| | | |  :+++ b/.hgtags
+| | | |  :@@ -0,0 +1,1 @@
+| | | |  :+c06107b7bcbe751d2dd40faf4179ee7d6aac44ac ablines
+| | | |  :diff -r 5e2f73d0c01d -r be92227e3e43 ablines.lst
+| | | |  :--- /dev/null
+| | | |  :+++ b/ablines.lst
+| | | |  :@@ -0,0 +1,13 @@
+| | | |  :+local B='B <b@example.org>'
+| | | |  :+    hg branch A
+| | | |  :+    hg branch B
+| | | |  :+    hg branch C
+| | | |  :+    cat alines.lst | grep 'b' > ablines.lst
+| | | |  :+    hg commit -A -m 'Added ablines.lst' \
+| | | |  :+    hg tag ablines \
+| | | |  :+    hg merge -r ablines
+| | | |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| | | |  :+    hg tag blines \
+| | | |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| | | |  :+    echo abc >> nohglinesrev.lst
+| | | |  :+    echo 'Abc' > ignoredabc
+| | | |  :diff -r 5e2f73d0c01d -r be92227e3e43 blines.lst
+| | | |  :--- /dev/null
+| | | |  :+++ b/blines.lst
+| | | |  :@@ -0,0 +1,16 @@
+| | | |  :+#!/bin/zsh
+| | | |  :+local B='B <b@example.org>'
+| | | |  :+    hg branch A
+| | | |  :+    hg branch B
+| | | |  :+    hg branch C
+| | | |  :+    cat alines.lst | grep 'b' > ablines.lst
+| | | |  :+    hg commit -A -m 'Added ablines.lst' \
+| | | |  :+    hg tag ablines \
+| | | |  :+    hg merge -r ablines
+| | | |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| | | |  :+    hg commit -A -m 'Added blines.lst' \
+| | | |  :+    hg tag blines \
+| | | |  :+    hg merge -r blines
+| | | |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| | | |  :+    echo abc >> nohglinesrev.lst
+| | | |  :+    echo 'Abc' > ignoredabc
+| | | |  :diff -r 5e2f73d0c01d -r be92227e3e43 clines.lst
+| | | |  :--- /dev/null
+| | | |  :+++ b/clines.lst
+| | | |  :@@ -0,0 +1,49 @@
+| | | |  :+    cat alines.lst | grep 'b' > ablines.lst
+| | | |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| | | |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| | | |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| | | |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| | | |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| | | |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| | | |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| | | |  :+    cat hglines.lst | rev > hglinesrev.lst
+| | | |  :+    cat nohglines.lst | rev > nohglinesrev.lst
+| | | |  :+    cd testrepo
+| | | |  :+    cp ../createrepo.zsh .
+| | | |  :+    echo 'Abc' > ignoredabc
+| | | |  :+    echo abc >> nohglinesrev.lst
+| | | |  :+    echo 'Def' > addeddef && hg add addeddef
+| | | |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| | | |  :+    hg branch A
+| | | |  :+    hg branch B
+| | | |  :+    hg branch C
+| | | |  :+    hg commit -A -m 'Added ablines.lst' \
+| | | |  :+    hg commit -A -m 'Added alines.lst' \
+| | | |  :+    hg commit -A -m 'Added blines.lst' \
+| | | |  :+    hg commit -A -m 'Added clines.lst' \
+| | | |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| | | |  :+    hg commit -A -m 'Added dlines.lst' \
+| | | |  :+    hg commit -A -m 'Added .hgignore' \
+| | | |  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+| | | |  :+    hg commit -A -m 'Added ignored10.lst' \
+| | | |  :+    hg commit -A -m 'Added nohglines.lst' \
+| | | |  :+    hg commit -A -m 'Added nohglinesrev.lst' \
+| | | |  :+    hg commit -A -m 'Copied “hglines.lst” to “hglines2.lst”' \
+| | | |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| | | |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| | | |  :+    hg commit -m 'Merge from A' \
+| | | |  :+    hg commit -m 'Merge from B' \
+| | | |  :+    hg commit -m 'Merge from C' \
+| | | |  :+    hg commit -m 'Merge from C:1' \
+| | | |  :+    hg commit -m 'Merge from C:2' \
+| | | |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| | | |  :+    hg cp hglines.lst hglines2.lst
+| | | |  :+    hg merge -r clines
+| | | |  :+    hg mv createrepo.zsh crepo.zsh
+| | | |  :+    hg mv crepo.zsh chgrepo.zsh
+| | | |  :+    hg tag clines \
+| | | |  :+local A='A <a@example.com>'
+| | | |  :+local B='B <b@example.org>'
+| | | |  :+local C='C <c@example.gov>'
+| | | |  :+    perl -p -i -e 'tr/{}/{}/' crepo.zsh
+| | | |  :+tar cJf testrepo.tar.xz testrepo
+| | | |  :
+| | | |  
+| | o |    revno: 14
+| | |\ \   revision-id: 5e2f73d0c01dfb8ee0d3577e03d016a5f6df58b1
+| | | | |  parent: d760b0fe4fe45adf585f5030181b8081899e26a9
+| | | | |  parent: 9fe0c28c3e1dd175e8372b742f13cbb7bd6799fe
+| | | | |  author: C <c@example.gov>
+| | | | |  branch nick: A
+| | | | |  timestamp: Tue 2002-01-01 00:00:00
+| | | | |  message:
+| | | | |  @ Merge from B
+| | | | |  $  alines.lst | 64 0
+| | | | |  $1 files changed, 64 insertions, 0 deletions
+| | | | |  :diff -r d760b0fe4fe4 -r 5e2f73d0c01d alines.lst
+| | | | |  :--- /dev/null
+| | | | |  :+++ b/alines.lst
+| | | | |  :@@ -0,0 +1,64 @@
+| | | | |  :+emulate -L zsh
+| | | | |  :+local A='A <a@example.com>'
+| | | | |  :+local B='B <b@example.org>'
+| | | | |  :+local C='C <c@example.gov>'
+| | | | |  :+    cp ../createrepo.zsh .
+| | | | |  :+    # XXX Date test will work only till 2099
+| | | | |  :+    hg commit -A -m 'Added «createrepo.zsh»' \
+| | | | |  :+        --date '1999-01-02 5:20' --user $A
+| | | | |  :+    hg mv createrepo.zsh crepo.zsh
+| | | | |  :+    hg commit -A -m 'Renamed «createrepo.zsh» to «crepo.zsh»' \
+| | | | |  :+        --date '2000-01-05 7:30' --user $A
+| | | | |  :+    hg commit -m $'Replaced\n    {\n        ...\n    }\nwith\n    {\n        ...\n    }' \
+| | | | |  :+        --date '2000-01-15 15:00' --user $B
+| | | | |  :+    hg commit -A -m 'Renamed «crepo.zsh» to «chgrepo.zsh»' \
+| | | | |  :+        --date '2000-02-01 14:00' --user $B
+| | | | |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > hglines.lst
+| | | | |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ unless /^    hg /' > datelines.lst
+| | | | |  :+    hg commit -A -m 'Added «hglines.lst» and «datelines.lst»' \
+| | | | |  :+        --date '2000-05-10 4:23' --user $A
+| | | | |  :+    hg branch A
+| | | | |  :+    cat chgrepo.zsh | grep 'd' > dlines.lst
+| | | | |  :+        --date '2000-11-01 13:24' --user $B
+| | | | |  :+    hg branch B
+| | | | |  :+    cat chgrepo.zsh | grep 'a' > alines.lst
+| | | | |  :+    hg commit -A -m 'Added alines.lst' \
+| | | | |  :+        --date '2000-11-02 5:44' --user $A
+| | | | |  :+    hg branch C
+| | | | |  :+    cat alines.lst | grep 'b' > ablines.lst
+| | | | |  :+    hg commit -A -m 'Added ablines.lst' \
+| | | | |  :+        --date '2000-11-02 14:13' --user $B
+| | | | |  :+    hg tag ablines \
+| | | | |  :+        --date '2000-11-02 14:14' --user $B
+| | | | |  :+    hg update default
+| | | | |  :+    hg merge -r ablines
+| | | | |  :+        --date '2001-01-01 00:00' --user $C
+| | | | |  :+    hg update C
+| | | | |  :+    cat chgrepo.zsh | grep 'b' > blines.lst
+| | | | |  :+        --date '2001-02-01 05:18' --user $A
+| | | | |  :+    hg tag blines \
+| | | | |  :+        --date '2001-02-01 05:19' --user $A
+| | | | |  :+    hg update -r -2
+| | | | |  :+    cat chgrepo.zsh | sort | grep 'c' > clines.lst
+| | | | |  :+        --date '2001-02-01 14:56' --user $B
+| | | | |  :+    hg tag clines \
+| | | | |  :+        --date '2001-02-01 14:56:52' --user $B
+| | | | |  :+    hg update A
+| | | | |  :+        --date '2002-01-01 00:00' --user $C
+| | | | |  :+        --date '2002-01-01 00:00:15' --user $C
+| | | | |  :+    hg update default
+| | | | |  :+        --date '2002-01-01 00:00:30' --user $C
+| | | | |  :+        --date '2002-01-01 00:00:45' --user $C
+| | | | |  :+        --date '2002-02-10 05:00' --user $A
+| | | | |  :+    cat chgrepo.zsh | perl -p -i -e 'undef $_ if /^    hg /' > nohglines.lst
+| | | | |  :+        --date '2002-02-10 15:33' --user $B
+| | | | |  :+    cat nohglines.lst | rev > nohglinesrev.lst
+| | | | |  :+        --date '2002-02-10 16:01' --user $B
+| | | | |  :+        --date '2002-02-11 03:15' --user $A
+| | | | |  :+    echo $'syntax: glob\nignored*' > .hgignore
+| | | | |  :+        --date &#