diff -r 9072a890e523 -r 9cec7a36bab8 hgext/bookflow.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/bookflow.py Mon Dec 03 14:17:38 2018 -0500 @@ -0,0 +1,103 @@ +"""implements bookmark-based branching (EXPERIMENTAL) + + - Disables creation of new branches (config: enable_branches=False). + - Requires an active bookmark on commit (config: require_bookmark=True). + - Doesn't move the active bookmark on update, only on commit. + - Requires '--rev' for moving an existing bookmark. + - Protects special bookmarks (config: protect=@). + + flow related commands + + :hg book NAME: create a new bookmark + :hg book NAME -r REV: move bookmark to revision (fast-forward) + :hg up|co NAME: switch to bookmark + :hg push -B .: push active bookmark +""" +from __future__ import absolute_import + +from mercurial.i18n import _ +from mercurial import ( + bookmarks, + commands, + error, + extensions, + registrar, +) + +MY_NAME = 'bookflow' + +configtable = {} +configitem = registrar.configitem(configtable) + +configitem(MY_NAME, 'protect', ['@']) +configitem(MY_NAME, 'require-bookmark', True) +configitem(MY_NAME, 'enable-branches', False) + +cmdtable = {} +command = registrar.command(cmdtable) + +def commit_hook(ui, repo, **kwargs): + active = repo._bookmarks.active + if active: + if active in ui.configlist(MY_NAME, 'protect'): + raise error.Abort( + _('cannot commit, bookmark {} is protected').format(active)) + if not cwd_at_bookmark(repo, active): + raise error.Abort( + _('cannot commit, working directory out of sync with active bookmark'), + hint=_("run 'hg up {}'").format(active)) + elif ui.configbool(MY_NAME, 'require-bookmark', True): + raise error.Abort(_('cannot commit without an active bookmark')) + return 0 + +def bookmarks_update(orig, repo, parents, node): + if len(parents) == 2: + # called during commit + return orig(repo, parents, node) + else: + # called during update + return False + +def bookmarks_addbookmarks( + orig, repo, tr, names, rev=None, force=False, inactive=False): + if not rev: + marks = repo._bookmarks + for name in names: + if name in marks: + raise error.Abort( + _("bookmark {} already exists, to move use the --rev option" + ).format(name)) + return orig(repo, tr, names, rev, force, inactive) + +def commands_commit(orig, ui, repo, *args, **opts): + commit_hook(ui, repo) + return orig(ui, repo, *args, **opts) + +def commands_pull(orig, ui, repo, *args, **opts): + rc = orig(ui, repo, *args, **opts) + active = repo._bookmarks.active + if active and not cwd_at_bookmark(repo, active): + ui.warn(_( + "working directory out of sync with active bookmark, run 'hg up {}'" + ).format(active)) + return rc + +def commands_branch(orig, ui, repo, label=None, **opts): + if label and not opts.get(r'clean') and not opts.get(r'rev'): + raise error.Abort( + _("creating named branches is disabled and you should use bookmarks"), + hint="see 'hg help bookflow'") + return orig(ui, repo, label, **opts) + +def cwd_at_bookmark(repo, mark): + mark_id = repo._bookmarks[mark] + cur_id = repo.lookup('.') + return cur_id == mark_id + +def uisetup(ui): + extensions.wrapfunction(bookmarks, 'update', bookmarks_update) + extensions.wrapfunction(bookmarks, 'addbookmarks', bookmarks_addbookmarks) + extensions.wrapcommand(commands.table, 'commit', commands_commit) + extensions.wrapcommand(commands.table, 'pull', commands_pull) + if not ui.configbool(MY_NAME, 'enable-branches'): + extensions.wrapcommand(commands.table, 'branch', commands_branch)