##// END OF EJS Templates
tests: update test-copies-chain-merge.t to not use empty files...
tests: update test-copies-chain-merge.t to not use empty files Merging empty files is not very interesting or realistic. Differential Revision: https://phab.mercurial-scm.org/D9172

File last commit:

r45357:f189c528 stable
r46294:deeb215b default
Show More
bookmarks.py
1060 lines | 32.7 KiB | text/x-python | PythonLexer
Matt Mackall
bookmarks: move basic io to core
r13350 # Mercurial bookmark support code
#
# Copyright 2008 David Soria Parra <dsp@php.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
bookmarks: use absolute_import
r25917 from __future__ import absolute_import
import errno
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 import struct
Gregory Szorc
bookmarks: use absolute_import
r25917
from .i18n import _
from .node import (
bin,
hex,
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 short,
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 wdirid,
Gregory Szorc
bookmarks: use absolute_import
r25917 )
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from .pycompat import getattr
Gregory Szorc
bookmarks: use absolute_import
r25917 from . import (
encoding,
liscju
bookmarks: abort 'push -B .' when no active bookmark
r29354 error,
obsutil: move 'foreground' to the new modules...
r33147 obsutil,
Pulkit Goyal
py3: fix kwargs handling for `hg bookmarks`
r33092 pycompat,
Sean Farley
commands: move checkformat to bookmarks module...
r32955 scmutil,
FUJIWARA Katsunori
bookmarks: check HG_PENDING strictly...
r31052 txnutil,
Gregory Szorc
bookmarks: use absolute_import
r25917 util,
)
Matt Mackall
bookmarks: move basic io to core
r13350
Sean Farley
commands: move activebookmarklabel to bookmarks module...
r33009 # label constants
# until 3.5, bookmarks.current was the advertised name, not
# bookmarks.active, so we must use both to avoid breaking old
# custom styles
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 activebookmarklabel = b'bookmarks.active bookmarks.current'
Sean Farley
commands: move activebookmarklabel to bookmarks module...
r33009
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 BOOKMARKS_IN_STORE_REQUIREMENT = b'bookmarksinstore'
Martin von Zweigbergk
bookmarks: keep bookmarks in .hg/store if new config set...
r42512
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
bookmarks: keep bookmarks in .hg/store if new config set...
r42512 def bookmarksinstore(repo):
return BOOKMARKS_IN_STORE_REQUIREMENT in repo.requirements
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
bookmarks: keep bookmarks in .hg/store if new config set...
r42512 def bookmarksvfs(repo):
return repo.svfs if bookmarksinstore(repo) else repo.vfs
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
bookmarks: hoist getbkfile out of bmstore class...
r27186 def _getbkfile(repo):
"""Hook so that extensions that mess with the store can hook bm storage.
For core, this just handles wether we should see pending
bookmarks or the committed ones. Other extensions (like share)
may need to tweak this behavior further.
"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fp, pending = txnutil.trypending(
repo.root, bookmarksvfs(repo), b'bookmarks'
)
FUJIWARA Katsunori
bookmarks: check HG_PENDING strictly...
r31052 return fp
Augie Fackler
bookmarks: hoist getbkfile out of bmstore class...
r27186
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 class bmstore(object):
Gregory Szorc
global: make some docstrings raw strings...
r41674 r"""Storage for bookmarks.
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 This object should do all bookmark-related reads and writes, so
that it's fairly simple to replace the storage underlying
bookmarks without having to clone the logic surrounding
bookmarks. This type also should manage the active bookmark, if
any.
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922
This particular bmstore implementation stores bookmarks as
{hash}\s{name}\n (the same format as localtags) in
.hg/bookmarks. The mapping is stored as {name: nodeid}.
"""
Matt Mackall
bookmarks: move read methods to core
r13351
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 def __init__(self, repo):
self._repo = repo
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 self._refmap = refmap = {} # refspec: node
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 self._nodemap = nodemap = {} # node: sorted([refspec, ...])
bookmarks: move variable initialization earlier...
r32738 self._clean = True
self._aclean = True
index: use `index.has_node` in `bookmarks.bmstore`...
r43944 has_node = repo.changelog.index.has_node
Augie Fackler
formatting: blacken the codebase...
r43346 tonode = bin # force local lookup
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 try:
bookmarks: make sure we close the bookmark file after reading...
r32794 with _getbkfile(repo) as bkfile:
for line in bkfile:
line = line.strip()
if not line:
continue
try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 sha, refspec = line.split(b' ', 1)
bookmarks: make sure we close the bookmark file after reading...
r32794 node = tonode(sha)
index: use `index.has_node` in `bookmarks.bmstore`...
r43944 if has_node(node):
bookmarks: make sure we close the bookmark file after reading...
r32794 refspec = encoding.tolocal(refspec)
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 refmap[refspec] = node
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 nrefs = nodemap.get(node)
if nrefs is None:
nodemap[node] = [refspec]
else:
nrefs.append(refspec)
if nrefs[-2] > refspec:
# bookmarks weren't sorted before 4.5
nrefs.sort()
bookmarks: make sure we close the bookmark file after reading...
r32794 except (TypeError, ValueError):
# TypeError:
# - bin(...)
# ValueError:
# - node in nm, for non-20-bytes entry
# - split(...), for string without ' '
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bookmarkspath = b'.hg/bookmarks'
Martin von Zweigbergk
bookmarks: keep bookmarks in .hg/store if new config set...
r42512 if bookmarksinstore(repo):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bookmarkspath = b'.hg/store/bookmarks'
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'malformed line in %s: %r\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % (bookmarkspath, pycompat.bytestr(line))
)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 if inst.errno != errno.ENOENT:
raise
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 self._active = _readactive(repo, self)
@property
def active(self):
return self._active
@active.setter
def active(self, mark):
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 if mark is not None and mark not in self._refmap:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise AssertionError(b'bookmark %s does not exist!' % mark)
Augie Fackler
bmstore: add handling of the active bookmark...
r27698
self._active = mark
self._aclean = False
Augie Fackler
bmstore: add basic clean-state tracking...
r27187
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 def __len__(self):
return len(self._refmap)
def __iter__(self):
return iter(self._refmap)
def iteritems(self):
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 return pycompat.iteritems(self._refmap)
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866
def items(self):
return self._refmap.items()
# TODO: maybe rename to allnames()?
def keys(self):
return self._refmap.keys()
# TODO: maybe rename to allnodes()? but nodes would have to be deduplicated
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 # could be self._nodemap.keys()
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 def values(self):
return self._refmap.values()
def __contains__(self, mark):
return mark in self._refmap
def __getitem__(self, mark):
return self._refmap[mark]
def get(self, mark, default=None):
return self._refmap.get(mark, default)
Boris Feld
bookmark: deprecate direct set of a bookmark value...
r33517
Yuya Nishihara
bookmarks: make argument names of _set/_del() more specific
r37868 def _set(self, mark, node):
Augie Fackler
bmstore: add basic clean-state tracking...
r27187 self._clean = False
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 if mark in self._refmap:
self._del(mark)
Yuya Nishihara
bookmarks: make argument names of _set/_del() more specific
r37868 self._refmap[mark] = node
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 nrefs = self._nodemap.get(node)
if nrefs is None:
self._nodemap[node] = [mark]
else:
nrefs.append(mark)
nrefs.sort()
Boris Feld
bookmark: deprecate direct del of a bookmark value...
r33518
Yuya Nishihara
bookmarks: make argument names of _set/_del() more specific
r37868 def _del(self, mark):
Valentin Gatien-Baron
bookmarks: avoid traceback when two pushes race to delete the same bookmark...
r44852 if mark not in self._refmap:
return
Augie Fackler
bmstore: add basic clean-state tracking...
r27187 self._clean = False
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 node = self._refmap.pop(mark)
nrefs = self._nodemap[node]
if len(nrefs) == 1:
assert nrefs[0] == mark
del self._nodemap[node]
else:
nrefs.remove(mark)
Boris Feld
bookmark: deprecate direct update of a bookmark value...
r35697
Yuya Nishihara
bookmarks: extract function that looks up bookmark names by node
r37867 def names(self, node):
"""Return a sorted list of bookmarks pointing to the specified node"""
Yuya Nishihara
bookmarks: cache reverse mapping (issue5868)...
r37869 return self._nodemap.get(node, [])
Yuya Nishihara
bookmarks: extract function that looks up bookmark names by node
r37867
Boris Feld
bookmark: introduce a 'applychanges' function to gather bookmark movement...
r33480 def applychanges(self, repo, tr, changes):
"""Apply a list of changes to bookmarks
"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bmchanges = tr.changes.get(b'bookmarks')
Boris Feld
bookmark: introduce a 'applychanges' function to gather bookmark movement...
r33480 for name, node in changes:
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 old = self._refmap.get(name)
Boris Feld
bookmark: introduce a 'applychanges' function to gather bookmark movement...
r33480 if node is None:
Boris Feld
bookmark: deprecate direct del of a bookmark value...
r33518 self._del(name)
Boris Feld
bookmark: introduce a 'applychanges' function to gather bookmark movement...
r33480 else:
Boris Feld
bookmark: deprecate direct set of a bookmark value...
r33517 self._set(name, node)
Boris Feld
bookmark: track bookmark changes at the transaction level...
r33516 if bmchanges is not None:
# if a previous value exist preserve the "initial" value
previous = bmchanges.get(name)
if previous is not None:
old = previous[0]
bmchanges[name] = (old, node)
Boris Feld
bookmark: deprecate 'recordchange' in favor of 'applychanges'...
r33515 self._recordchange(tr)
Boris Feld
bookmark: introduce a 'applychanges' function to gather bookmark movement...
r33480
Boris Feld
bookmark: deprecate 'recordchange' in favor of 'applychanges'...
r33515 def _recordchange(self, tr):
Pierre-Yves David
bookmark: add a `bmstore.recordupdate` to plug bookmarks into the transaction...
r22665 """record that bookmarks have been changed in a transaction
The transaction is then responsible for updating the file content."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 location = b'' if bookmarksinstore(self._repo) else b'plain'
Augie Fackler
formatting: blacken the codebase...
r43346 tr.addfilegenerator(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'bookmarks', (b'bookmarks',), self._write, location=location
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tr.hookargs[b'bookmark_moved'] = b'1'
Pierre-Yves David
bookmark: add a `bmstore.recordupdate` to plug bookmarks into the transaction...
r22665
Ryan McElroy
bookmarks: factor out repository lookup from writing bookmarks file...
r23469 def _writerepo(self, repo):
"""Factored out for extensibility"""
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 rbm = repo._bookmarks
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 if rbm.active not in self._refmap:
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 rbm.active = None
rbm._writeactive()
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922
Martin von Zweigbergk
bookmarks: keep bookmarks in .hg/store if new config set...
r42512 if bookmarksinstore(repo):
vfs = repo.svfs
lock = repo.lock()
else:
vfs = repo.vfs
lock = repo.wlock()
with lock:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with vfs(b'bookmarks', b'w', atomictemp=True, checkambig=True) as f:
Martin von Zweigbergk
bookmarks: use context manager when writing files...
r42502 self._write(f)
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 def _writeactive(self):
if self._aclean:
return
Bryan O'Sullivan
with: use context manager for wlock in _writeactive
r27800 with self._repo.wlock():
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 if self._active is not None:
Augie Fackler
formatting: blacken the codebase...
r43346 with self._repo.vfs(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'bookmarks.current', b'w', atomictemp=True, checkambig=True
Augie Fackler
formatting: blacken the codebase...
r43346 ) as f:
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 f.write(encoding.fromlocal(self._active))
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._repo.vfs.tryunlink(b'bookmarks.current')
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 self._aclean = True
Pierre-Yves David
bookmarks: split bookmark serialization and file handling...
r22664 def _write(self, fp):
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for name, node in sorted(pycompat.iteritems(self._refmap)):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fp.write(b"%s %s\n" % (hex(node), encoding.fromlocal(name)))
Augie Fackler
bmstore: add basic clean-state tracking...
r27187 self._clean = True
Augie Fackler
bookmarks: properly invalidate volatile sets when writing bookmarks...
r29066 self._repo.invalidatevolatilesets()
Pierre-Yves David
bookmarks: split bookmark serialization and file handling...
r22664
liscju
bookmarks: add 'hg push -B .' for pushing the active bookmark (issue4917)
r28182 def expandname(self, bname):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if bname == b'.':
liscju
bookmarks: abort 'push -B .' when no active bookmark
r29354 if self.active:
return self.active
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.RepoLookupError(_(b"no active bookmark"))
liscju
bookmarks: add 'hg push -B .' for pushing the active bookmark (issue4917)
r28182 return bname
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 def checkconflict(self, mark, force=False, target=None):
"""check repo for a potential clash of mark with an existing bookmark,
branch, or hash
If target is supplied, then check that we are moving the bookmark
forward.
If force is supplied, then forcibly move the bookmark to a new commit
regardless if it is a move forward.
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513
If divergent bookmark are to be deleted, they will be returned as list.
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 """
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cur = self._repo[b'.'].node()
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 if mark in self._refmap and not force:
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 if target:
Yuya Nishihara
bookmarks: hide dict behind bmstore class...
r37866 if self._refmap[mark] == target and target == cur:
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 # re-activating a bookmark
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 return []
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 rev = self._repo[target].rev()
anc = self._repo.changelog.ancestors([rev])
Augie Fackler
bookmarks: remove changectx() method from bmstore (API)...
r43248 bmctx = self._repo[self[mark]]
Augie Fackler
formatting: blacken the codebase...
r43346 divs = [
self._refmap[b]
for b in self._refmap
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b.split(b'@', 1)[0] == mark.split(b'@', 1)[0]
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Sean Farley
commands: move checkconflict to bookmarks module...
r32956
# allow resolving a single divergent bookmark even if moving
# the bookmark across branches when a revision is specified
# that contains a divergent bookmark
if bmctx.rev() not in anc and target in divs:
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 return divergent2delete(self._repo, [target], mark)
Sean Farley
commands: move checkconflict to bookmarks module...
r32956
Augie Fackler
formatting: blacken the codebase...
r43346 deletefrom = [
b for b in divs if self._repo[b].rev() in anc or b == target
]
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 delbms = divergent2delete(self._repo, deletefrom, mark)
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 if validdest(self._repo, bmctx, self._repo[target]):
self._repo.ui.status(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"moving bookmark '%s' forward from %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (mark, short(bmctx.node()))
)
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 return delbms
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"bookmark '%s' already exists (use -f to force)") % mark
Augie Fackler
formatting: blacken the codebase...
r43346 )
if (
mark in self._repo.branchmap()
or mark == self._repo.dirstate.branch()
) and not force:
raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"a bookmark cannot have the name of an existing branch")
Augie Fackler
formatting: blacken the codebase...
r43346 )
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 if len(mark) > 3 and not force:
try:
Martin von Zweigbergk
bookmarks: use isrevsymbol() for detecting collision with existing symbol...
r37415 shadowhash = scmutil.isrevsymbol(self._repo, mark)
Sean Farley
commands: move checkconflict to bookmarks module...
r32956 except error.LookupError: # ambiguous identifier
shadowhash = False
if shadowhash:
self._repo.ui.warn(
Augie Fackler
formatting: blacken the codebase...
r43346 _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"bookmark %s matches a changeset hash\n"
b"(did you leave a -r out of an 'hg bookmark' "
b"command?)\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% mark
)
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 return []
Sean Farley
commands: move checkconflict to bookmarks module...
r32956
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 def _readactive(repo, marks):
Ryan McElroy
bookmarks: rename readcurrent to readactive (API)...
r24946 """
Get the active bookmark. We can have an active bookmark that updates
itself as we commit. This function returns the name of that bookmark.
It is stored in .hg/bookmarks.current
"""
Martin von Zweigbergk
bookmarks: use vfs.tryread() instead of reimplementing it...
r42503 # No readline() in osutil.posixfile, reading everything is
# cheap.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 content = repo.vfs.tryread(b'bookmarks.current')
mark = encoding.tolocal((content.splitlines() or [b''])[0])
if mark == b'' or mark not in marks:
Martin von Zweigbergk
bookmarks: use vfs.tryread() instead of reimplementing it...
r42503 mark = None
Matt Mackall
bookmarks: move read methods to core
r13351 return mark
Augie Fackler
formatting: blacken the codebase...
r43346
Ryan McElroy
bookmarks: rename setcurrent to activate (API)...
r24945 def activate(repo, mark):
"""
Set the given bookmark to be 'active', meaning that this bookmark will
follow new commits that are made.
Matt Mackall
bookmarks: move basic io to core
r13350 The name is recorded in .hg/bookmarks.current
Ryan McElroy
bookmarks: rename setcurrent to activate (API)...
r24945 """
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 repo._bookmarks.active = mark
repo._bookmarks._writeactive()
Matt Mackall
bookmarks: move update into core
r13352
Augie Fackler
formatting: blacken the codebase...
r43346
Ryan McElroy
bookmarks: rename unsetcurrent to deactivate (API)...
r24944 def deactivate(repo):
"""
Mads Kiilerich
spelling: trivial spell checking
r26781 Unset the active bookmark in this repository.
Ryan McElroy
bookmarks: rename unsetcurrent to deactivate (API)...
r24944 """
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 repo._bookmarks.active = None
repo._bookmarks._writeactive()
Idan Kamara
update: delete bookmarks.current when explicitly updating to a rev (issue3276)
r16191
Augie Fackler
formatting: blacken the codebase...
r43346
Ryan McElroy
bookmarks: simplify iscurrent to isactivewdirparent (API)...
r24986 def isactivewdirparent(repo):
"""
Tell whether the 'active' bookmark (the one that follows new commits)
points to one of the parents of the current working directory (wdir).
Kevin Bullock
update: update to current bookmark if it moved out from under us (issue3682)...
r18471
Ryan McElroy
bookmarks: simplify iscurrent to isactivewdirparent (API)...
r24986 While this is normally the case, it can on occasion be false; for example,
immediately after a pull, the active bookmark can be moved to point
to a place different than the wdir. This is solved by running `hg update`.
"""
mark = repo._activebookmark
Kevin Bullock
update: update to current bookmark if it moved out from under us (issue3682)...
r18471 marks = repo._bookmarks
Ryan McElroy
bookmarks: simplify iscurrent to isactivewdirparent (API)...
r24986 parents = [p.node() for p in repo[None].parents()]
Augie Fackler
formatting: blacken the codebase...
r43346 return mark in marks and marks[mark] in parents
Kevin Bullock
update: update to current bookmark if it moved out from under us (issue3682)...
r18471
Boris Feld
bookmark: split out target computation from 'deletedivergent'...
r33510 def divergent2delete(repo, deletefrom, bm):
"""find divergent versions of bm on nodes in deletefrom.
the list of bookmark to delete."""
todelete = []
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513 marks = repo._bookmarks
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 divergent = [
b for b in marks if b.split(b'@', 1)[0] == bm.split(b'@', 1)[0]
]
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513 for mark in divergent:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mark == b'@' or b'@' not in mark:
Matt Mackall
bookmarks: avoid deleting primary bookmarks on rebase...
r21843 # can't be divergent by definition
continue
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513 if mark and marks[mark] in deletefrom:
if mark != bm:
Boris Feld
bookmark: split out target computation from 'deletedivergent'...
r33510 todelete.append(mark)
return todelete
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
localrepo: extract bookmarkheads method to bookmarks.py...
r32381 def headsforactive(repo):
"""Given a repo with an active bookmark, return divergent bookmark nodes.
Args:
repo: A repository with an active bookmark.
Returns:
A list of binary node ids that is the full list of other
revisions with bookmarks divergent from the active bookmark. If
there were no divergent bookmarks, then this list will contain
only one entry.
"""
if not repo._activebookmark:
raise ValueError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'headsforactive() only makes sense with an active bookmark'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 name = repo._activebookmark.split(b'@', 1)[0]
Augie Fackler
localrepo: extract bookmarkheads method to bookmarks.py...
r32381 heads = []
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for mark, n in pycompat.iteritems(repo._bookmarks):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if mark.split(b'@', 1)[0] == name:
Augie Fackler
localrepo: extract bookmarkheads method to bookmarks.py...
r32381 heads.append(n)
return heads
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
bookmarks: drop always-None argument from calculateupdate()...
r37393 def calculateupdate(ui, repo):
Martin von Zweigbergk
bookmarks: calculateupdate() returns a bookmark, not a rev...
r37377 '''Return a tuple (activemark, movemarkfrom) indicating the active bookmark
and where to move the active bookmark from, if needed.'''
Martin von Zweigbergk
bookmarks: drop always-None argument from calculateupdate()...
r37393 checkout, movemarkfrom = None, None
activemark = repo._activebookmark
if isactivewdirparent(repo):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 movemarkfrom = repo[b'.'].node()
Martin von Zweigbergk
bookmarks: drop always-None argument from calculateupdate()...
r37393 elif activemark:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"updating to active bookmark %s\n") % activemark)
Martin von Zweigbergk
bookmarks: drop always-None argument from calculateupdate()...
r37393 checkout = activemark
Kevin Bullock
bookmarks: pull --update updates to active bookmark if it moved (issue4007)...
r19523 return (checkout, movemarkfrom)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
bookmarks: move update into core
r13352 def update(repo, parents, node):
Sean Farley
bookmarks: resolve divergent bookmarks when moving active bookmark forward...
r19110 deletefrom = parents
Matt Mackall
bookmarks: move update into core
r13352 marks = repo._bookmarks
Augie Fackler
bmstore: add handling of the active bookmark...
r27698 active = marks.active
Ryan McElroy
bookmarks: rename current to active in variables and comments...
r25100 if not active:
David Soria Parra
bookmarks: delete divergent bookmarks on merge
r16706 return False
Boris Feld
bookmarks: use 'applychanges' for bookmark update...
r33491 bmchanges = []
Ryan McElroy
bookmarks: rename current to active in variables and comments...
r25100 if marks[active] in parents:
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513 new = repo[node]
Augie Fackler
formatting: blacken the codebase...
r43346 divs = [
repo[marks[b]]
for b in marks
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b.split(b'@', 1)[0] == active.split(b'@', 1)[0]
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Sean Farley
bookmarks: resolve divergent bookmarks when moving active bookmark forward...
r19110 anc = repo.changelog.ancestors([new.rev()])
deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
Augie Fackler
bookmarks: remove changectx() method from bmstore (API)...
r43248 if validdest(repo, repo[marks[active]], new):
Boris Feld
bookmarks: use 'applychanges' for bookmark update...
r33491 bmchanges.append((active, new.node()))
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513
Boris Feld
bookmark: use 'divergent2delete' when updating a bookmark
r33512 for bm in divergent2delete(repo, deletefrom, active):
bmchanges.append((bm, None))
Siddharth Agarwal
bookmarks: factor out delete divergent code...
r18513
Boris Feld
bookmark: use 'divergent2delete' when updating a bookmark
r33512 if bmchanges:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.lock(), repo.transaction(b'bookmark') as tr:
Boris Feld
bookmarks: use 'applychanges' for bookmark update...
r33491 marks.applychanges(repo, tr, bmchanges)
Boris Feld
bookmark: use 'divergent2delete' when updating a bookmark
r33512 return bool(bmchanges)
Matt Mackall
bookmarks: move pushkey functions into core
r13353
Augie Fackler
formatting: blacken the codebase...
r43346
Valentin Gatien-Baron
bookmarks: refactor in preparation for next commit...
r44853 def isdivergent(b):
return b'@' in b and not b.endswith(b'@')
Stanislau Hlebik
bookmarks: introduce listbinbookmarks()...
r30481 def listbinbookmarks(repo):
# We may try to list bookmarks on a repo type that does not
# support it (e.g., statichttprepository).
marks = getattr(repo, '_bookmarks', {})
hasnode = repo.changelog.hasnode
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for k, v in pycompat.iteritems(marks):
Stanislau Hlebik
bookmarks: introduce listbinbookmarks()...
r30481 # don't expose local divergent bookmarks
Valentin Gatien-Baron
bookmarks: refactor in preparation for next commit...
r44853 if hasnode(v) and not isdivergent(k):
Stanislau Hlebik
bookmarks: introduce listbinbookmarks()...
r30481 yield k, v
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
bookmarks: move pushkey functions into core
r13353 def listbookmarks(repo):
d = {}
Stanislau Hlebik
bookmarks: use listbinbookmarks() in listbookmarks()
r30482 for book, node in listbinbookmarks(repo):
d[book] = hex(node)
Matt Mackall
bookmarks: move pushkey functions into core
r13353 return d
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
bookmarks: move pushkey functions into core
r13353 def pushbookmark(repo, key, old, new):
Valentin Gatien-Baron
bookmarks: prevent pushes of divergent bookmarks (foo@remote)...
r44854 if isdivergent(key):
return False
Martin von Zweigbergk
bookmarks: keep bookmarks in .hg/store if new config set...
r42512 if bookmarksinstore(repo):
wlock = util.nullcontextmanager()
else:
wlock = repo.wlock()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with wlock, repo.lock(), repo.transaction(b'bookmarks') as tr:
Matt Mackall
bookmarks: move pushkey functions into core
r13353 marks = repo._bookmarks
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 existing = hex(marks.get(key, b''))
Durham Goode
bookmarks: allow pushkey if new equals current...
r22364 if existing != old and existing != new:
Matt Mackall
bookmarks: move pushkey functions into core
r13353 return False
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if new == b'':
Boris Feld
bookmark: use 'applychanges' when updating a bookmark through pushkey
r33485 changes = [(key, None)]
Matt Mackall
bookmarks: move pushkey functions into core
r13353 else:
if new not in repo:
return False
Boris Feld
bookmark: use 'applychanges' when updating a bookmark through pushkey
r33485 changes = [(key, repo[new].node())]
marks.applychanges(repo, tr, changes)
Matt Mackall
bookmarks: move pushkey functions into core
r13353 return True
Matt Mackall
bookmarks: move diff to core
r13354
Augie Fackler
formatting: blacken the codebase...
r43346
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024 '''Compare bookmarks between srcmarks and dstmarks
This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
differ, invalid)", each are list of bookmarks below:
:addsrc: added on src side (removed on dst side, perhaps)
:adddst: added on dst side (removed on src side, perhaps)
:advsrc: advanced on src side
:advdst: advanced on dst side
:diverge: diverge
:differ: changed, but changeset referred on src is unknown on dst
:invalid: unknown on both side
Gregory Szorc
bookmarks: explicitly track identical bookmarks...
r23081 :same: same on both side
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024
Each elements of lists in result tuple is tuple "(bookmark name,
changeset ID on source side, changeset ID on destination
Valentin Gatien-Baron
doc: fix up confusing doc comment...
r43184 side)". Each changeset ID is a binary node or None.
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024
Changeset IDs of tuples in "addsrc", "adddst", "differ" or
"invalid" list may be unknown for repo.
If "targets" is specified, only bookmarks listed in it are
examined.
'''
if targets:
bset = set(targets)
else:
srcmarkset = set(srcmarks)
dstmarkset = set(dstmarks)
Gregory Szorc
bookmarks: explicitly track identical bookmarks...
r23081 bset = srcmarkset | dstmarkset
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024
Gregory Szorc
bookmarks: explicitly track identical bookmarks...
r23081 results = ([], [], [], [], [], [], [], [])
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024 addsrc = results[0].append
adddst = results[1].append
advsrc = results[2].append
advdst = results[3].append
diverge = results[4].append
differ = results[5].append
invalid = results[6].append
Gregory Szorc
bookmarks: explicitly track identical bookmarks...
r23081 same = results[7].append
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024
for b in sorted(bset):
if b not in srcmarks:
if b in dstmarks:
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 adddst((b, None, dstmarks[b]))
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024 else:
invalid((b, None, None))
elif b not in dstmarks:
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 addsrc((b, srcmarks[b], None))
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024 else:
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 scid = srcmarks[b]
dcid = dstmarks[b]
Gregory Szorc
bookmarks: explicitly track identical bookmarks...
r23081 if scid == dcid:
same((b, scid, dcid))
elif scid in repo and dcid in repo:
FUJIWARA Katsunori
bookmarks: add function to centralize the logic to compare bookmarks...
r20024 sctx = repo[scid]
dctx = repo[dcid]
if sctx.rev() < dctx.rev():
if validdest(repo, sctx, dctx):
advdst((b, scid, dcid))
else:
diverge((b, scid, dcid))
else:
if validdest(repo, dctx, sctx):
advsrc((b, scid, dcid))
else:
diverge((b, scid, dcid))
else:
# it is too expensive to examine in detail, in this case
differ((b, scid, dcid))
return results
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: reuse @number bookmark, if it refers changeset referred remotely...
r24355 def _diverge(ui, b, path, localmarks, remotenode):
FUJIWARA Katsunori
bookmarks: prevent divergent bookmark from being updated unexpectedly...
r24353 '''Return appropriate diverged bookmark for specified ``path``
This returns None, if it is failed to assign any divergent
bookmark name.
FUJIWARA Katsunori
bookmarks: reuse @number bookmark, if it refers changeset referred remotely...
r24355
This reuses already existing one with "@number" suffix, if it
refers ``remotenode``.
FUJIWARA Katsunori
bookmarks: prevent divergent bookmark from being updated unexpectedly...
r24353 '''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b == b'@':
b = b''
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025 # try to use an @pathalias suffix
# if an @pathalias already exists, we overwrite (update) it
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if path.startswith(b"file:"):
Matt Mackall
bookmarks: fix divergent bookmark path normalization
r22629 path = util.url(path).path
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for p, u in ui.configitems(b"paths"):
if u.startswith(b"file:"):
Matt Mackall
bookmarks: fix divergent bookmark path normalization
r22629 u = util.url(u).path
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025 if path == u:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'%s@%s' % (b, p)
FUJIWARA Katsunori
bookmarks: check @pathalias suffix before available @number for efficiency...
r24354
# assign a unique "@number" suffix newly
for x in range(1, 100):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 n = b'%s@%d' % (b, x)
FUJIWARA Katsunori
bookmarks: reuse @number bookmark, if it refers changeset referred remotely...
r24355 if n not in localmarks or localmarks[n] == remotenode:
FUJIWARA Katsunori
bookmarks: check @pathalias suffix before available @number for efficiency...
r24354 return n
return None
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025
Augie Fackler
formatting: blacken the codebase...
r43346
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 def unhexlifybookmarks(marks):
binremotemarks = {}
for name, node in marks.items():
binremotemarks[name] = bin(node)
return binremotemarks
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _binaryentry = struct.Struct(b'>20sH')
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 def binaryencode(bookmarks):
"""encode a '(bookmark, node)' iterable into a binary stream
the binary format is:
<node><bookmark-length><bookmark-name>
:node: is a 20 bytes binary node,
:bookmark-length: an unsigned short,
:bookmark-name: the name of the bookmark (of length <bookmark-length>)
wdirid (all bits set) will be used as a special value for "missing"
"""
binarydata = []
for book, node in bookmarks:
Augie Fackler
formatting: blacken the codebase...
r43346 if not node: # None or ''
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 node = wdirid
binarydata.append(_binaryentry.pack(node, len(book)))
binarydata.append(book)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(binarydata)
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 def binarydecode(stream):
"""decode a binary stream into an '(bookmark, node)' iterable
the binary format is:
<node><bookmark-length><bookmark-name>
:node: is a 20 bytes binary node,
:bookmark-length: an unsigned short,
:bookmark-name: the name of the bookmark (of length <bookmark-length>))
wdirid (all bits set) will be used as a special value for "missing"
"""
entrysize = _binaryentry.size
books = []
while True:
entry = stream.read(entrysize)
if len(entry) < entrysize:
if entry:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'bad bookmark stream'))
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 break
node, length = _binaryentry.unpack(entry)
bookmark = stream.read(length)
if len(bookmark) < length:
if entry:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'bad bookmark stream'))
Boris Feld
bookmark: add methods to binary encode and decode bookmark values...
r35258 if node == wdirid:
node = None
books.append((bookmark, node))
return books
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
pull: perform bookmark updates in the transaction
r22666 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b"checking for updated bookmarks\n")
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 localmarks = repo._bookmarks
Augie Fackler
formatting: blacken the codebase...
r43346 (
addsrc,
adddst,
advsrc,
advdst,
diverge,
differ,
invalid,
same,
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 ) = comparebookmarks(repo, remotemarks, localmarks)
Matt Mackall
bookmarks: mark divergent bookmarks with book@pathalias when source in [paths]
r15614
Pierre-Yves David
bookmarks: allow `updatefromremote` to be quiet...
r22644 status = ui.status
warn = ui.warn
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if ui.configbool(b'ui', b'quietbookmarkmove'):
Pierre-Yves David
bookmarks: allow `updatefromremote` to be quiet...
r22644 status = warn = ui.debug
Pierre-Yves David
pull: merge bookmark updates and imports...
r22659 explicit = set(explicit)
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025 changed = []
for b, scid, dcid in addsrc:
Augie Fackler
formatting: blacken the codebase...
r43346 if scid in repo: # add remote bookmarks for changes we already have
changed.append(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b, scid, status, _(b"adding remote bookmark %s\n") % b)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
bookmark: informs of failure to upgrade a bookmark...
r25564 elif b in explicit:
explicit.remove(b)
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"remote bookmark %s points to locally missing %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (b, hex(scid)[:12])
)
Pierre-Yves David
bookmark: informs of failure to upgrade a bookmark...
r25564
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025 for b, scid, dcid in advsrc:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 changed.append((b, scid, status, _(b"updating bookmark %s\n") % b))
Pierre-Yves David
pull: merge bookmark updates and imports...
r22659 # remove normal movement from explicit set
explicit.difference_update(d[0] for d in changed)
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025 for b, scid, dcid in diverge:
Pierre-Yves David
pull: merge bookmark updates and imports...
r22659 if b in explicit:
explicit.discard(b)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b))
Pierre-Yves David
pull: merge bookmark updates and imports...
r22659 else:
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 db = _diverge(ui, b, path, localmarks, scid)
FUJIWARA Katsunori
bookmarks: prevent divergent bookmark from being updated unexpectedly...
r24353 if db:
Augie Fackler
formatting: blacken the codebase...
r43346 changed.append(
(
db,
scid,
warn,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"divergent bookmark %s stored as %s\n") % (b, db),
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
FUJIWARA Katsunori
bookmarks: prevent divergent bookmark from being updated unexpectedly...
r24353 else:
Augie Fackler
formatting: blacken the codebase...
r43346 warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"warning: failed to assign numbered name "
b"to divergent bookmark %s\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% b
)
Pierre-Yves David
pull: merge bookmark updates and imports...
r22659 for b, scid, dcid in adddst + advdst:
if b in explicit:
explicit.discard(b)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b))
Pierre-Yves David
bookmark: informs of failure to upgrade a bookmark...
r25564 for b, scid, dcid in differ:
if b in explicit:
explicit.remove(b)
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"remote bookmark %s points to locally missing %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (b, hex(scid)[:12])
)
Pierre-Yves David
pull: merge bookmark updates and imports...
r22659
David Soria Parra
bookmarks: separate bookmarks update code from localrepo's pull....
r13646 if changed:
Pierre-Yves David
pull: perform bookmark updates in the transaction
r22666 tr = trfunc()
Boris Feld
bookmark: use 'applychanges' when updating from a remote
r33484 changes = []
Valentin Gatien-Baron
py3: fix exception in pull when several things happen to a bookmark...
r45357 key = lambda t: (t[0], t[1] or b'')
for b, node, writer, msg in sorted(changed, key=key):
Boris Feld
bookmark: use 'applychanges' when updating from a remote
r33484 changes.append((b, node))
FUJIWARA Katsunori
bookmarks: rewrite "updatefromremote()" by "compare()"...
r20025 writer(msg)
Boris Feld
bookmark: use 'applychanges' when updating from a remote
r33484 localmarks.applychanges(repo, tr, changes)
David Soria Parra
bookmarks: separate bookmarks update code from localrepo's pull....
r13646
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
bookmarks: use command executor for wire protocol commands...
r37659 def incoming(ui, repo, peer):
FUJIWARA Katsunori
bookmarks: add incoming() to replace diff() for incoming bookmarks...
r24397 '''Show bookmarks incoming from other to repo
'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"searching for changed bookmarks\n"))
FUJIWARA Katsunori
bookmarks: add incoming() to replace diff() for incoming bookmarks...
r24397
Gregory Szorc
bookmarks: use command executor for wire protocol commands...
r37659 with peer.commandexecutor() as e:
Augie Fackler
formatting: blacken the codebase...
r43346 remotemarks = unhexlifybookmarks(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result()
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
bookmarks: use command executor for wire protocol commands...
r37659
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
FUJIWARA Katsunori
bookmarks: add incoming() to replace diff() for incoming bookmarks...
r24397 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
incomings = []
if ui.debugflag:
getid = lambda id: id
else:
getid = lambda id: id[:12]
FUJIWARA Katsunori
bookmarks: show detailed status about incoming bookmarks...
r24660 if ui.verbose:
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: show detailed status about incoming bookmarks...
r24660 def add(b, id, st):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 incomings.append(b" %-25s %s %s\n" % (b, getid(id), st))
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: show detailed status about incoming bookmarks...
r24660 else:
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: show detailed status about incoming bookmarks...
r24660 def add(b, id, st):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 incomings.append(b" %-25s %s\n" % (b, getid(id)))
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: add incoming() to replace diff() for incoming bookmarks...
r24397 for b, scid, dcid in addsrc:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "added" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'added'))
FUJIWARA Katsunori
bookmarks: show incoming bookmarks more exactly...
r24657 for b, scid, dcid in advsrc:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "advanced" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'advanced'))
FUJIWARA Katsunori
bookmarks: show incoming bookmarks more exactly...
r24657 for b, scid, dcid in diverge:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "diverged" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'diverged'))
FUJIWARA Katsunori
bookmarks: show incoming bookmarks more exactly...
r24657 for b, scid, dcid in differ:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "changed" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'changed'))
FUJIWARA Katsunori
bookmarks: add incoming() to replace diff() for incoming bookmarks...
r24397
if not incomings:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"no changed bookmarks found\n"))
FUJIWARA Katsunori
bookmarks: add incoming() to replace diff() for incoming bookmarks...
r24397 return 1
for s in sorted(incomings):
ui.write(s)
return 0
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
r24398 def outgoing(ui, repo, other):
'''Show bookmarks outgoing from repo to other
'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"searching for changed bookmarks\n"))
FUJIWARA Katsunori
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
r24398
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 remotemarks = unhexlifybookmarks(other.listkeys(b'bookmarks'))
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
FUJIWARA Katsunori
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
r24398 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
outgoings = []
if ui.debugflag:
getid = lambda id: id
else:
getid = lambda id: id[:12]
FUJIWARA Katsunori
bookmarks: show detailed status about outgoing bookmarks...
r24661 if ui.verbose:
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: show detailed status about outgoing bookmarks...
r24661 def add(b, id, st):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 outgoings.append(b" %-25s %s %s\n" % (b, getid(id), st))
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: show detailed status about outgoing bookmarks...
r24661 else:
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: show detailed status about outgoing bookmarks...
r24661 def add(b, id, st):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 outgoings.append(b" %-25s %s\n" % (b, getid(id)))
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
r24398 for b, scid, dcid in addsrc:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "added refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'added'))
FUJIWARA Katsunori
bookmarks: show outgoing bookmarks more exactly...
r24658 for b, scid, dcid in adddst:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "deleted" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, b' ' * 40, _(b'deleted'))
FUJIWARA Katsunori
bookmarks: show outgoing bookmarks more exactly...
r24658 for b, scid, dcid in advsrc:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "advanced" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'advanced'))
FUJIWARA Katsunori
bookmarks: show outgoing bookmarks more exactly...
r24658 for b, scid, dcid in diverge:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "diverged" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'diverged'))
FUJIWARA Katsunori
bookmarks: show outgoing bookmarks more exactly...
r24658 for b, scid, dcid in differ:
Wagner Bruna
bookmarks: add i18n hints to bookmark sync states
r24832 # i18n: "changed" refers to a bookmark
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 add(b, hex(scid), _(b'changed'))
FUJIWARA Katsunori
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
r24398
if not outgoings:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"no changed bookmarks found\n"))
FUJIWARA Katsunori
bookmarks: add outgoing() to replace diff() for outgoing bookmarks...
r24398 return 1
for s in sorted(outgoings):
ui.write(s)
return 0
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
bookmarks: use command executor for wire protocol commands...
r37659 def summary(repo, peer):
FUJIWARA Katsunori
bookmarks: rewrite comparing bookmarks in commands.summary() by compare()...
r24400 '''Compare bookmarks between repo and other for "hg summary" output
This returns "(# of incoming, # of outgoing)" tuple.
'''
Gregory Szorc
bookmarks: use command executor for wire protocol commands...
r37659 with peer.commandexecutor() as e:
Augie Fackler
formatting: blacken the codebase...
r43346 remotemarks = unhexlifybookmarks(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result()
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
bookmarks: use command executor for wire protocol commands...
r37659
Stanislau Hlebik
bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)...
r30583 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
FUJIWARA Katsunori
bookmarks: rewrite comparing bookmarks in commands.summary() by compare()...
r24400 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
return (len(addsrc), len(adddst))
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
bookmarks: extract valid destination logic in a dedicated function...
r17550 def validdest(repo, old, new):
"""Is the new bookmark destination a valid update from the old one"""
Pierre-Yves David
clfilter: `bookmark.validdest` should run on unfiltered repo...
r18008 repo = repo.unfiltered()
Pierre-Yves David
bookmark: take successors into account when updating (issue3561)...
r17551 if old == new:
# Old == new -> nothing to update.
FUJIWARA Katsunori
bookmarks: avoid redundant creation/assignment of "validdests" in "validdest()"
r17625 return False
Pierre-Yves David
bookmark: take successors into account when updating (issue3561)...
r17551 elif not old:
# old is nullrev, anything is valid.
# (new != nullrev has been excluded by the previous check)
FUJIWARA Katsunori
bookmarks: avoid redundant creation/assignment of "validdests" in "validdest()"
r17625 return True
Pierre-Yves David
bookmark: take successors into account when updating (issue3561)...
r17551 elif repo.obsstore:
obsutil: move 'foreground' to the new modules...
r33147 return new.node() in obsutil.foreground(repo, [old.node()])
Pierre-Yves David
bookmark: take successors into account when updating (issue3561)...
r17551 else:
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 # still an independent clause as it is lazier (and therefore faster)
Martin von Zweigbergk
context: rename descendant() to isancestorof()...
r38692 return old.isancestorof(new)
Sean Farley
commands: move checkformat to bookmarks module...
r32955
Augie Fackler
formatting: blacken the codebase...
r43346
Sean Farley
commands: move checkformat to bookmarks module...
r32955 def checkformat(repo, mark):
"""return a valid version of a potential bookmark name
Raises an abort error if the bookmark name is not valid.
"""
mark = mark.strip()
if not mark:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"bookmark names cannot consist entirely of whitespace")
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 scmutil.checknewlabel(repo, mark, b'bookmark')
Sean Farley
commands: move checkformat to bookmarks module...
r32955 return mark
Sean Farley
bookmarks: factor out delete logic from commands...
r33005
Augie Fackler
formatting: blacken the codebase...
r43346
Sean Farley
bookmarks: factor out delete logic from commands...
r33005 def delete(repo, tr, names):
"""remove a mark from the bookmark store
Raises an abort error if mark does not exist.
"""
marks = repo._bookmarks
Boris Feld
bookmark: use 'applychanges' for bookmark deletion
r33481 changes = []
Sean Farley
bookmarks: factor out delete logic from commands...
r33005 for mark in names:
if mark not in marks:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"bookmark '%s' does not exist") % mark)
Sean Farley
bookmarks: factor out delete logic from commands...
r33005 if mark == repo._activebookmark:
deactivate(repo)
Boris Feld
bookmark: use 'applychanges' for bookmark deletion
r33481 changes.append((mark, None))
marks.applychanges(repo, tr, changes)
Sean Farley
bookmarks: factor out rename logic from commands...
r33006
Augie Fackler
formatting: blacken the codebase...
r43346
Sean Farley
bookmarks: factor out rename logic from commands...
r33006 def rename(repo, tr, old, new, force=False, inactive=False):
"""rename a bookmark from old to new
If force is specified, then the new name can overwrite an existing
bookmark.
If inactive is specified, then do not activate the new bookmark.
Raises an abort error if old is not in the bookmark store.
"""
marks = repo._bookmarks
mark = checkformat(repo, new)
if old not in marks:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"bookmark '%s' does not exist") % old)
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 changes = []
for bm in marks.checkconflict(mark, force):
changes.append((bm, None))
changes.extend([(mark, marks[old]), (old, None)])
Boris Feld
bookmark: use 'applychanges' for bookmark renaming
r33482 marks.applychanges(repo, tr, changes)
Sean Farley
bookmarks: factor out rename logic from commands...
r33006 if repo._activebookmark == old and not inactive:
activate(repo, mark)
Sean Farley
bookmarks: factor out adding a list of bookmarks logic from commands...
r33007
Augie Fackler
formatting: blacken the codebase...
r43346
Sean Farley
bookmarks: factor out adding a list of bookmarks logic from commands...
r33007 def addbookmarks(repo, tr, names, rev=None, force=False, inactive=False):
"""add a list of bookmarks
If force is specified, then the new name can overwrite an existing
bookmark.
If inactive is specified, then do not activate any bookmark. Otherwise, the
first bookmark is activated.
Raises an abort error if old is not in the bookmark store.
"""
marks = repo._bookmarks
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cur = repo[b'.'].node()
Sean Farley
bookmarks: factor out adding a list of bookmarks logic from commands...
r33007 newact = None
Boris Feld
bookmark: use 'applychanges' for adding new bookmark
r33483 changes = []
Pulkit Goyal
bookmarks: calculate visibility exceptions only once...
r35665
# unhide revs if any
if rev:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
Yuya Nishihara
bookmarks: use changectx instead of remembering hex of hidden revision...
r43998
Yuya Nishihara
bookmarks: accept explicit -r 'wdir()' when adding new bookmarks (issue6218)...
r43999 ctx = scmutil.revsingle(repo, rev, None)
# bookmarking wdir means creating a bookmark on p1 and activating it
activatenew = not inactive and ctx.rev() is None
if ctx.node() is None:
ctx = ctx.p1()
Yuya Nishihara
bookmarks: use changectx instead of remembering hex of hidden revision...
r43998 tgt = ctx.node()
Yuya Nishihara
bookmarks: accept explicit -r 'wdir()' when adding new bookmarks (issue6218)...
r43999 assert tgt
Pulkit Goyal
bookmarks: calculate visibility exceptions only once...
r35665
Sean Farley
bookmarks: factor out adding a list of bookmarks logic from commands...
r33007 for mark in names:
mark = checkformat(repo, mark)
if newact is None:
newact = mark
if inactive and mark == repo._activebookmark:
deactivate(repo)
Yuya Nishihara
bookmarks: fix handling of multiple bookmarks with one to be deactivated...
r43996 continue
Boris Feld
bookmark: use 'divergent2delete' in checkconflict...
r33513 for bm in marks.checkconflict(mark, force, tgt):
changes.append((bm, None))
Boris Feld
bookmark: use 'applychanges' for adding new bookmark
r33483 changes.append((mark, tgt))
Pulkit Goyal
bookmarks: calculate visibility exceptions only once...
r35665
Yuya Nishihara
bookmarks: fix handling of multiple bookmarks with one to be deactivated...
r43996 # nothing changed but for the one deactivated above
if not changes:
return
Yuya Nishihara
bookmarks: use changectx instead of remembering hex of hidden revision...
r43998 if ctx.hidden():
repo.ui.warn(_(b"bookmarking hidden changeset %s\n") % ctx.hex()[:12])
Boris Feld
bookmarks: display the obsfate of hidden revision we create a bookmark on...
r35730
if ctx.obsolete():
Yuya Nishihara
bookmarks: use changectx instead of remembering hex of hidden revision...
r43998 msg = obsutil._getfilteredreason(repo, ctx.hex()[:12], ctx)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(b"(%s)\n" % msg)
Boris Feld
bookmarks: display the obsfate of hidden revision we create a bookmark on...
r35730
Boris Feld
bookmark: use 'applychanges' for adding new bookmark
r33483 marks.applychanges(repo, tr, changes)
Yuya Nishihara
bookmarks: accept explicit -r 'wdir()' when adding new bookmarks (issue6218)...
r43999 if activatenew and cur == marks[newact]:
Sean Farley
bookmarks: factor out adding a list of bookmarks logic from commands...
r33007 activate(repo, newact)
elif cur != tgt and newact == repo._activebookmark:
deactivate(repo)
Sean Farley
bookmarks: factor out bookmark printing from commands
r33010
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
bookmarks: pass in formatter to printbookmarks() instead of opts (API)...
r39782 def _printbookmarks(ui, repo, fm, bmarks):
Sean Farley
bookmarks: factor method _printer out of for loop in printbookmarks...
r33011 """private method to print bookmarks
Provides a way for extensions to control how bookmarks are printed (e.g.
prepend or postpend names)
"""
hexfn = fm.hexfunc
if len(bmarks) == 0 and fm.isplain():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"no bookmarks set\n"))
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for bmark, (n, prefix, label) in sorted(pycompat.iteritems(bmarks)):
Sean Farley
bookmarks: factor method _printer out of for loop in printbookmarks...
r33011 fm.startitem()
Yuya Nishihara
formatter: replace contexthint() with demand loading of ctx object...
r39660 fm.context(repo=repo)
Sean Farley
bookmarks: factor method _printer out of for loop in printbookmarks...
r33011 if not ui.quiet:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fm.plain(b' %s ' % prefix, label=label)
fm.write(b'bookmark', b'%s', bmark, label=label)
pad = b" " * (25 - encoding.colwidth(bmark))
Augie Fackler
formatting: blacken the codebase...
r43346 fm.condwrite(
not ui.quiet,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'rev node',
pad + b' %d:%s',
Augie Fackler
formatting: blacken the codebase...
r43346 repo.changelog.rev(n),
hexfn(n),
label=label,
)
Sean Farley
bookmarks: factor method _printer out of for loop in printbookmarks...
r33011 fm.data(active=(activebookmarklabel in label))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fm.plain(b'\n')
Sean Farley
bookmarks: factor method _printer out of for loop in printbookmarks...
r33011
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
bookmarks: add explicit option to list bookmarks of the given names...
r39789 def printbookmarks(ui, repo, fm, names=None):
Yuya Nishihara
bookmarks: pass in formatter to printbookmarks() instead of opts (API)...
r39782 """print bookmarks by the given formatter
Sean Farley
bookmarks: factor out bookmark printing from commands
r33010
Provides a way for extensions to control how bookmarks are printed.
"""
marks = repo._bookmarks
Sean Farley
bookmarks: factor method _printer out of for loop in printbookmarks...
r33011 bmarks = {}
Augie Fackler
formatting: blacken the codebase...
r43346 for bmark in names or marks:
Yuya Nishihara
bookmarks: add explicit option to list bookmarks of the given names...
r39789 if bmark not in marks:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"bookmark '%s' does not exist") % bmark)
Sean Farley
bookmarks: factor out bookmark printing from commands
r33010 active = repo._activebookmark
if bmark == active:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefix, label = b'*', activebookmarklabel
Sean Farley
bookmarks: factor out bookmark printing from commands
r33010 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefix, label = b' ', b''
Sean Farley
bookmarks: factor out bookmark printing from commands
r33010
Yuya Nishihara
bookmarks: add explicit option to list bookmarks of the given names...
r39789 bmarks[bmark] = (marks[bmark], prefix, label)
Yuya Nishihara
bookmarks: pass in formatter to printbookmarks() instead of opts (API)...
r39782 _printbookmarks(ui, repo, fm, bmarks)
Boris Feld
bookmark: add a dedicated txnclose-bookmark hook...
r34709
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
bookmark: add a dedicated txnclose-bookmark hook...
r34709 def preparehookargs(name, old, new):
if new is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 new = b''
Boris Feld
bookmark: add a dedicated txnclose-bookmark hook...
r34709 if old is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 old = b''
return {b'bookmark': name, b'node': hex(new), b'oldnode': hex(old)}