Fix stg repair for hidden patches
[stgit] / stgit / commands / repair.py
index a5156cd..2e22150 100644 (file)
@@ -26,6 +26,7 @@ from stgit.run import *
 from stgit import stack, git
 
 help = 'Fix StGit metadata if branch was modified with git commands'
+kind = 'stack'
 usage = ['']
 description = """
 If you modify an StGit stack (branch) with some git commands -- such
@@ -33,8 +34,9 @@ as commit, pull, merge, and rebase -- you will leave the StGit
 metadata in an inconsistent state. In that situation, you have two
 options:
 
-  1. Use "git reset" or similar to undo the effect of the git
-     command(s).
+  1. Use "stg undo" to undo the effect of the git commands. (If you
+     know what you are doing and want more control, "git reset" or
+     similar will work too.)
 
   2. Use "stg repair". This will fix up the StGit metadata to
      accomodate the modifications to the branch. Specifically, it will
@@ -47,8 +49,8 @@ options:
        * However, merge commits cannot become patches; if you have
          committed a merge on top of your stack, "repair" will simply
          mark all patches below the merge unapplied, since they are no
-         longer reachable. If this is not what you want, use "git
-         reset" to get rid of the merge and run "stg repair" again.
+         longer reachable. If this is not what you want, use "stg
+         undo" to get rid of the merge and run "stg repair" again.
 
        * The applied patches are supposed to be precisely those that
          are reachable from the branch head. If you have used e.g.
@@ -67,9 +69,10 @@ NOTE: If using git commands on the stack was a mistake, running "stg
 repair" is _not_ what you want. In that case, what you want is option
 (1) above."""
 
+args = []
 options = []
 
-directory = DirectoryGotoToplevel()
+directory = DirectoryGotoToplevel(log = True)
 
 class Commit(object):
     def __init__(self, id):
@@ -105,7 +108,7 @@ def read_commit_dag(branch):
             commits[id].children.add(commits[cs[0]])
     for line in Run('git', 'show-ref').output_lines():
         id, ref = line.split()
-        m = re.match(r'^refs/patches/%s/(.+)$' % branch, ref)
+        m = re.match(r'^refs/patches/%s/(.+)$' % re.escape(branch), ref)
         if m and not m.group(1).endswith('.log'):
             c = commits[id]
             c.patch = m.group(1)
@@ -118,6 +121,7 @@ def func(parser, options, args):
 
     orig_applied = crt_series.get_applied()
     orig_unapplied = crt_series.get_unapplied()
+    orig_hidden = crt_series.get_hidden()
 
     if crt_series.get_protected():
         raise CmdException(
@@ -181,22 +185,29 @@ def func(parser, options, args):
             names.add(name)
         out.done()
 
+    # Figure out hidden
+    orig_patches = orig_applied + orig_unapplied + orig_hidden
+    orig_applied_name_set = set(orig_applied)
+    orig_unapplied_name_set = set(orig_unapplied)
+    orig_hidden_name_set = set(orig_hidden)
+    orig_patches_name_set = set(orig_patches)
+    hidden = [p for p in patches if p.patch in orig_hidden_name_set]
+
     # Write the applied/unapplied files.
     out.start('Checking patch appliedness')
-    unapplied = patches - set(applied)
+    unapplied = patches - set(applied) - set(hidden)
     applied_name_set = set(p.patch for p in applied)
     unapplied_name_set = set(p.patch for p in unapplied)
+    hidden_name_set = set(p.patch for p in hidden)
     patches_name_set = set(p.patch for p in patches)
-    orig_patches = orig_applied + orig_unapplied
-    orig_applied_name_set = set(orig_applied)
-    orig_unapplied_name_set = set(orig_unapplied)
-    orig_patches_name_set = set(orig_patches)
     for name in orig_patches_name_set - patches_name_set:
         out.info('%s is gone' % name)
     for name in applied_name_set - orig_applied_name_set:
         out.info('%s is now applied' % name)
     for name in unapplied_name_set - orig_unapplied_name_set:
         out.info('%s is now unapplied' % name)
+    for name in hidden_name_set - orig_hidden_name_set:
+        out.info('%s is now hidden' % name)
     orig_order = dict(zip(orig_patches, xrange(len(orig_patches))))
     def patchname_cmp(p1, p2):
         i1 = orig_order.get(p1, len(orig_order))
@@ -204,4 +215,5 @@ def func(parser, options, args):
         return cmp((i1, p1), (i2, p2))
     crt_series.set_applied(p.patch for p in applied)
     crt_series.set_unapplied(sorted(unapplied_name_set, cmp = patchname_cmp))
+    crt_series.set_hidden(sorted(hidden_name_set, cmp = patchname_cmp))
     out.done()