D4353: bookflow: support shelve and enforce working directory pointing to the active bookmark

idlsoft (Sandu Turcan) phabricator at mercurial-scm.org
Wed Aug 22 14:02:02 UTC 2018


idlsoft created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D4353

AFFECTED FILES
  hgext/bookflow.py
  tests/test-bookflow.t

CHANGE DETAILS

diff --git a/tests/test-bookflow.t b/tests/test-bookflow.t
--- a/tests/test-bookflow.t
+++ b/tests/test-bookflow.t
@@ -1,6 +1,5 @@
 initialize
-  $ alias hgg="hg --config extensions.bookflow=`dirname $TESTDIR`/hgext/bookflow.py"
-  $ make_changes() { d=`pwd`; [ ! -z $1 ] && cd $1; echo "test $(basename `pwd`)" >> test; hgg commit -Am"${2:-test}"; r=$?; cd $d; return $r; }
+  $ make_changes() { d=`pwd`; [ ! -z $1 ] && cd $1; echo "test $(basename `pwd`)" >> test; hg commit -Am"${2:-test}"; r=$?; cd $d; return $r; }
   $ assert_clean() { ls -1 $1 | grep -v "test$" | cat;}
   $ ls -1a
   .
@@ -17,29 +16,31 @@
   $ hg clone ../a .
   updating to branch default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hgg branch X
-  abort: Branching should be done using bookmarks:
+  $ echo "[extensions]" >> .hg/hgrc
+  $ echo "bookflow=" >> .hg/hgrc
+  $ hg branch X
+  abort: branching should be done using bookmarks:
   hg bookmark X
   [255]
-  $ hgg bookmark X
-  $ hgg bookmarks
+  $ hg bookmark X
+  $ hg bookmarks
   * X                         0:* (glob)
   $ make_changes
-  $ hgg push ../a > /dev/null
+  $ hg push ../a > /dev/null
 
   $ hg bookmarks
    \* X                         1:* (glob)
 
 change a
   $ cd ../a
-  $ hgg up
+  $ hg up
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ echo 'test' >> test; hg commit -Am'test'
 
 
 pull in b
   $ cd ../b
-  $ hgg pull -u
+  $ hg pull -u
   pulling from $TESTTMP/a
   searching for changes
   adding changesets
@@ -54,62 +55,62 @@
      X                         1:* (glob)
 
 check protection of @ bookmark
-  $ hgg bookmark @
-  $ hgg bookmarks
+  $ hg bookmark @
+  $ hg bookmarks
    \* @                         2:* (glob)
      X                         1:* (glob)
   $ make_changes
-  abort: Can't commit, bookmark @ is protected
+  abort: can't commit, bookmark @ is protected
   [255]
 
   $ assert_clean
-  $ hgg bookmarks
+  $ hg bookmarks
    \* @                         2:* (glob)
      X                         1:* (glob)
 
-  $ hgg --config bookflow.protect= commit  -Am"Updated test"
+  $ hg --config bookflow.protect= commit  -Am"Updated test"
 
-  $ hgg bookmarks
+  $ hg bookmarks
    \* @                         3:* (glob)
      X                         1:* (glob)
 
 check requirement for an active bookmark
-  $ hgg bookmark -i
-  $ hgg bookmarks
+  $ hg bookmark -i
+  $ hg bookmarks
      @                         3:* (glob)
      X                         1:* (glob)
   $ make_changes
-  abort: Can't commit without an active bookmark
+  abort: can't commit without an active bookmark
   [255]
-  $ hgg revert test
+  $ hg revert test
   $ rm test.orig
   $ assert_clean
 
 
 make the bookmark move by updating it on a, and then pulling
 # add a commit to a
   $ cd ../a
   $ hg bookmark X
-  $ hgg bookmarks
+  $ hg bookmarks
    \* X                         2:* (glob)
   $ make_changes
-  $ hgg bookmarks
+  $ hg bookmarks
    * X                         3:81af7977fdb9
 
 # go back to b, and check out X
   $ cd ../b
-  $ hgg up X
+  $ hg up X
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark X)
-  $ hgg bookmarks
+  $ hg bookmarks
      @                         3:* (glob)
    \* X                         1:* (glob)
 
 # pull, this should move the bookmark forward, because it was changed remotely
-  $ hgg pull -u | grep "updating to active bookmark X"
+  $ hg pull -u | grep "updating to active bookmark X"
   updating to active bookmark X
 
-  $ hgg bookmarks
+  $ hg bookmarks
      @                         3:* (glob)
    * X                         4:81af7977fdb9
 
@@ -120,69 +121,160 @@
   $ make_changes ../b
   $ assert_clean ../a
   $ assert_clean ../b
-  $ hgg --cwd ../a bookmarks
+  $ hg --cwd ../a bookmarks
    * X                         4:238292f60a57
-  $ hgg --cwd ../b bookmarks
+  $ hg --cwd ../b bookmarks
      @                         3:* (glob)
    * X                         5:096f7e86892d
   $ cd ../b
   $ # make sure we can't push after bookmarks diverged
-  $ hgg push -B X | grep abort
+  $ hg push -B X | grep abort
   abort: push creates new remote head * with bookmark 'X'! (glob)
   (pull and merge or see 'hg help push' for details about pushing new heads)
   [1]
-  $ hgg pull -u | grep divergent
+  $ hg pull -u | grep divergent
   divergent bookmark X stored as X at default
   1 other divergent bookmarks for "X"
-  $ hgg bookmarks
+  $ hg bookmarks
      @                         3:* (glob)
    * X                         5:096f7e86892d
      X at default                 6:238292f60a57
-  $ hgg id -in
+  $ hg id -in
   096f7e86892d 5
   $ make_changes
   $ assert_clean
-  $ hgg bookmarks
+  $ hg bookmarks
      @                         3:* (glob)
    * X                         7:227f941aeb07
      X at default                 6:238292f60a57
 
 now merge with the remote bookmark
-  $ hgg merge X at default --tool :local > /dev/null
+  $ hg merge X at default --tool :local > /dev/null
   $ assert_clean
-  $ hgg commit -m"Merged with X at default"
-  $ hgg bookmarks
+  $ hg commit -m"Merged with X at default"
+  $ hg bookmarks
      @                         3:* (glob)
    * X                         8:26fed9bb3219
-  $ hgg push -B X | grep bookmark
+  $ hg push -B X | grep bookmark
   pushing to $TESTTMP/a (?)
   updating bookmark X
   $ cd ../a
-  $ hgg up > /dev/null
-  $ hgg bookmarks
+  $ hg up > /dev/null
+  $ hg bookmarks
    * X                         7:26fed9bb3219
 
 test hg pull when there is more than one descendant
   $ cd ../a
-  $ hgg bookmark Z
-  $ hgg bookmark Y
+  $ hg bookmark Z
+  $ hg bookmark Y
   $ make_changes . YY
-  $ hgg up Z > /dev/null
+  $ hg up Z > /dev/null
   $ make_changes . ZZ
   created new head
-  $ hgg bookmarks
+  $ hg bookmarks
      X                         7:26fed9bb3219
      Y                         8:131e663dbd2a
    * Z                         9:b74a4149df25
   $ hg log -r 'p1(Y)' -r 'p1(Z)' -T '{rev}\n' # prove that Y and Z share the same parent
   7
-  $ hgg log -r 'Y%Z' -T '{rev}\n'  # revs in Y but not in Z
+  $ hg log -r 'Y%Z' -T '{rev}\n'  # revs in Y but not in Z
   8
-  $ hgg log -r 'Z%Y' -T '{rev}\n'  # revs in Z but not in Y
+  $ hg log -r 'Z%Y' -T '{rev}\n'  # revs in Z but not in Y
   9
   $ cd ../b
-  $ hgg pull -u > /dev/null
-  $ hgg id
+  $ hg pull -u > /dev/null
+  $ hg id
   b74a4149df25 tip Z
-  $ hgg bookmarks | grep \*  # no active bookmark
+  $ hg bookmarks | grep \*  # no active bookmark
   [1]
+
+
+test shelving
+  $ cd ../a
+  $ echo anotherfile > anotherfile # this change should not conflict
+  $ hg add anotherfile
+  $ hg commit -m"Change in a"
+  $ cd ../b
+  $ hg up Z | grep Z
+  (activating bookmark Z)
+  $ hg book | grep \* # make sure active bookmark
+   \* Z                         10:* (glob)
+  $ echo "test b" >> test
+  $ hg diff --stat
+   test |  1 +
+   1 files changed, 1 insertions(+), 0 deletions(-)
+  $ hg --config extensions.shelve= shelve
+  shelved as Z
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg pull -u > /dev/null
+  $ hg --trace --config extensions.shelve= unshelve
+  unshelving change 'Z'
+  rebasing shelved changes
+  $ hg diff --stat
+   test |  1 +
+   1 files changed, 1 insertions(+), 0 deletions(-)
+
+
+make the bookmark move by updating it on a, and then pulling with a local change
+# add a commit to a
+  $ cd ../a
+  $ hg up -C X |fgrep  "activating bookmark X"
+  (activating bookmark X)
+# go back to b, and check out X
+  $ cd ../b
+  $ hg up -C X |fgrep  "activating bookmark X"
+  (activating bookmark X)
+# update and push from a
+  $ make_changes ../a > /dev/null
+  $ echo "more" >> test
+  $ hg pull -u 2>&1 | fgrep -v TESTTMP| fgrep -v "searching for changes" | fgrep -v adding
+  pulling from $TESTTMP/a
+  added 1 changesets with 0 changes to 0 files (+1 heads)
+  updating bookmark X
+  new changesets * (glob)
+  updating to active bookmark X
+  merging test
+  warning: conflicts while merging test! (edit, then use 'hg resolve --mark')
+  0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+  use 'hg resolve' to retry unresolved file merges
+  $ hg update -C > /dev/null
+  $ rm test.orig
+
+make sure that commits aren't possible if working directory is not pointing to active bookmark
+  $ assert_clean ../a
+  $ assert_clean ../b
+  $ hg --cwd ../a id -i
+  36a6e592ec06
+  $ hg --cwd ../a book | grep X
+   \* X                         \d+:36a6e592ec06 (re)
+  $ hg --cwd ../b id -i
+  36a6e592ec06
+  $ hg --cwd ../b book | grep X
+   \* X                         \d+:36a6e592ec06 (re)
+  $ make_changes ../a
+  $ hg --cwd ../a book | grep X
+   \* X                         \d+:f73a71c992b8 (re)
+  $ cd ../b
+  $ hg pull  2>&1 | grep -v add|grep -v pulling|grep -v searching|grep -v changeset
+  updating bookmark X
+  (run 'hg update' to get a working copy)
+  working directory out of sync with active bookmark.
+  Run: hg up X
+  $ hg id -i # we're still on the old commit
+  36a6e592ec06
+  $ hg book | grep X # while the bookmark moved
+   \* X                         \d+:f73a71c992b8 (re)
+  $ make_changes
+  abort: can't commit, working directory out of sync with active bookmark.
+  Run: hg up X
+  [255]
+  $ hg up -C -r . > /dev/null # cleanup local changes
+  $ assert_clean
+  $ hg id -i # we're still on the old commit
+  36a6e592ec06
+  $ hg up X > /dev/null
+  $ hg id -i # now we're on X
+  f73a71c992b8
+  $ hg book | grep X
+   \* X                         \d+:f73a71c992b8 (re)
+
diff --git a/hgext/bookflow.py b/hgext/bookflow.py
--- a/hgext/bookflow.py
+++ b/hgext/bookflow.py
@@ -22,7 +22,7 @@
     extensions
 )
 
-MY_NAME = __name__[len('hgext_'):] if __name__.startswith('hgext_') else __name__
+MY_NAME = 'bookflow'
 
 configtable = {}
 configitem = registrar.configitem(configtable)
@@ -36,10 +36,13 @@
 
 def commit_hook(ui, repo, **kwargs):
     active = repo._bookmarks.active
-    if not active and ui.configbool(MY_NAME, 'require_bookmark', True):
-        raise error.Abort(_('Can\'t commit without an active bookmark'))
-    elif active in ui.configlist(MY_NAME, 'protect'):
-        raise error.Abort(_('Can\'t commit, bookmark {} is protected').format(active))
+    if active:
+        if active in ui.configlist(MY_NAME, 'protect'):
+            raise error.Abort(_('can\'t commit, bookmark {} is protected').format(active))
+        if not cwd_at_bookmark(repo, active):
+            raise error.Abort(_('can\'t commit, working directory out of sync with active bookmark.\nRun: hg up {}').format(active))
+    elif ui.configbool(MY_NAME, 'require_bookmark', True):
+        raise error.Abort(_('can\'t commit without an active bookmark'))
     return 0
 
 
@@ -51,34 +54,43 @@
         # 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))
+                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.\nRun: hg up {}\n").format(active))
+    return rc
+
+def cwd_at_bookmark(repo, mark):
+    mark_id = repo._bookmarks[mark]
+    cur_id = repo.lookup('.')
+    return cur_id == mark_id
 
 def commands_branch(orig, ui, repo, label=None, **opts):
-    if label and not opts.get('clean') and not opts.get('rev'):
-        raise error.Abort("Branching should be done using bookmarks:\nhg bookmark " + label)
+    if label and not opts.get(r'clean') and not opts.get(r'rev'):
+        raise error.Abort(_("branching should be done using bookmarks:\nhg bookmark {}").format(label))
     return orig(ui, repo, label, **opts)
 
-
 def reposetup(ui, repo):
     extensions.wrapfunction(bookmarks, 'update', bookmarks_update)
     extensions.wrapfunction(bookmarks, 'addbookmarks', bookmarks_addbookmarks)
-    ui.setconfig('hooks', 'pretxncommit.' + MY_NAME, commit_hook, source=MY_NAME)
-
+    # commit hook conflicts with shelving
+    # ui.setconfig('hooks', 'pretxncommit.' + MY_NAME, commit_hook, source=MY_NAME)
 
 def uisetup(ui):
     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)



To: idlsoft, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list