Patchwork [STABLE] rebase: ensure rebase revision remains visible (issue4504)

login
register
mail settings
Submitter Pierre-Yves David
Date Jan. 28, 2015, 11:34 p.m.
Message ID <44351dd85385d8ea8207.1422488097@waste.org>
Download mbox | patch
Permalink /patch/7574/
State Accepted
Commit 8a544fb645bb00995f5a0836b3a8aab0852c3e49
Headers show

Comments

Pierre-Yves David - Jan. 28, 2015, 11:34 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1422362036 0
#      Tue Jan 27 12:33:56 2015 +0000
# Branch stable
# Node ID 44351dd85385d8ea8207712411cb17192d594160
# Parent  f1c127df7c4f645db6538a56d9a1c416505796cc
rebase: ensure rebase revision remains visible (issue4504)

Before this changeset rebase was getting very confused if any revision in the
rebase set became hidden. This wans fairly easy to achieve if a rebased revision
was made visible by the working copy location. The rebase process would update
somewhere else and the revision would become hidden.

This work around this issue we ensure rebased revision remain visible for the
whole process.

This is a simple change suitable for stable. More subtle usage of unfiltered
repository in rebase may solve this issue more cleanly.
Matt Mackall - Jan. 29, 2015, 5:56 a.m.
On Wed, 2015-01-28 at 17:34 -0600, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@fb.com>
> # Date 1422362036 0
> #      Tue Jan 27 12:33:56 2015 +0000
> # Branch stable
> # Node ID 44351dd85385d8ea8207712411cb17192d594160
> # Parent  f1c127df7c4f645db6538a56d9a1c416505796cc
> rebase: ensure rebase revision remains visible (issue4504)

This is queued for stable, thanks.

Patch

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -16,7 +16,7 @@ 
 
 from mercurial import hg, util, repair, merge, cmdutil, commands, bookmarks
 from mercurial import extensions, patch, scmutil, phases, obsolete, error
-from mercurial import copies
+from mercurial import copies, repoview
 from mercurial.commands import templateopts
 from mercurial.node import nullrev, nullid, hex, short
 from mercurial.lock import release
@@ -778,6 +778,7 @@ 
 
 def clearstatus(repo):
     'Remove the status files'
+    _clearrebasesetvisibiliy(repo)
     util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
 
 def restorestatus(repo):
@@ -831,6 +832,7 @@ 
         repo.ui.debug('computed skipped revs: %s\n' %
                       (' '.join(str(r) for r in sorted(skipped)) or None))
         repo.ui.debug('rebase status resumed\n')
+        _setrebasesetvisibility(repo, state.keys())
         return (originalwd, target, state, skipped,
                 collapse, keep, keepbranches, external, activebookmark)
     except IOError, err:
@@ -892,6 +894,7 @@ 
     dest: context
     rebaseset: set of rev
     '''
+    _setrebasesetvisibility(repo, rebaseset)
 
     # This check isn't strictly necessary, since mq detects commits over an
     # applied patch. But it prevents messing up the working directory when
@@ -1044,6 +1047,31 @@ 
             raise util.Abort(_('--tool can only be used with --rebase'))
         orig(ui, repo, *args, **opts)
 
+def _setrebasesetvisibility(repo, revs):
+    """store the currently rebased set on the repo object
+
+    This is used by another function to prevent rebased revision to because
+    hidden (see issue4505)"""
+    repo = repo.unfiltered()
+    revs = set(revs)
+    repo._rebaseset = revs
+    # invalidate cache if visibility changes
+    hiddens = repo.filteredrevcache.get('visible', set())
+    if revs & hiddens:
+        repo.invalidatevolatilesets()
+
+def _clearrebasesetvisibiliy(repo):
+    """remove rebaseset data from the repo"""
+    repo = repo.unfiltered()
+    if '_rebaseset' in vars(repo):
+        del repo._rebaseset
+
+def _rebasedvisible(orig, repo):
+    """ensure rebased revs stay visible (see issue4505)"""
+    blockers = orig(repo)
+    blockers.update(getattr(repo, '_rebaseset', ()))
+    return blockers
+
 def summaryhook(ui, repo):
     if not os.path.exists(repo.join('rebasestate')):
         return
@@ -1062,7 +1090,7 @@ 
               (len(state) - numrebased)))
 
 def uisetup(ui):
-    'Replace pull with a decorator to provide --rebase option'
+    #Replace pull with a decorator to provide --rebase option
     entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
     entry[1].append(('', 'rebase', None,
                      _("rebase working directory to branch head")))
@@ -1072,3 +1100,6 @@ 
     cmdutil.unfinishedstates.append(
         ['rebasestate', False, False, _('rebase in progress'),
          _("use 'hg rebase --continue' or 'hg rebase --abort'")])
+    # ensure rebased rev are not hidden
+    extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
+
diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t
--- a/tests/test-rebase-obsolete.t
+++ b/tests/test-rebase-obsolete.t
@@ -498,3 +498,45 @@ 
   |/
   o  0:cd010b8cd998 A
   
+
+Test hidden changesets in the rebase set (issue4504)
+
+  $ hg up --hidden 9
+  3 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo J > J
+  $ hg add J
+  $ hg commit -m J
+  $ hg debugobsolete `hg log --rev . -T '{node}'`
+
+  $ hg rebase --rev .~1::. --dest 'max(desc(D))' --traceback
+  rebasing 9:4bde274eefcf "I"
+  rebasing 13:06edfc82198f "J" (tip)
+  $ hg log -G
+  @  15:5ae8a643467b J
+  |
+  o  14:9ad579b4a5de I
+  |
+  | o  12:acd174b7ab39 I
+  | |
+  | o  11:6c11a6218c97 H
+  | |
+  o |  10:b5313c85b22e D
+  |/
+  | o    8:53a6a128b2b7 M
+  | |\
+  | | x  7:02de42196ebe H
+  | | |
+  o---+  6:eea13746799a G
+  | | |
+  | | o  5:24b6387c8c8c F
+  | | |
+  o---+  4:9520eea781bc E
+   / /
+  x |  3:32af7686d403 D
+  | |
+  o |  2:5fddd98957c8 C
+  | |
+  o |  1:42ccdea3bb16 B
+  |/
+  o  0:cd010b8cd998 A
+