Implement fast-forward when only tree (but not
[stgit] / stgit / stack.py
index cfac219..7109186 100644 (file)
@@ -92,7 +92,9 @@ def edit_file(series, string, comment, show_patch = True):
     f.close()
 
     # the editor
-    if 'EDITOR' in os.environ:
+    if config.has_option('stgit', 'editor'):
+        editor = config.get('stgit', 'editor')
+    elif 'EDITOR' in os.environ:
         editor = os.environ['EDITOR']
     else:
         editor = 'vi'
@@ -168,7 +170,11 @@ class Patch:
 
     def set_bottom(self, string, backup = False):
         if backup:
-            self.__set_field('bottom.old', self.__get_field('bottom'))
+            curr = self.__get_field('bottom')
+            if curr != string:
+                self.__set_field('bottom.old', curr)
+            else:
+                self.__set_field('bottom.old', None)
         self.__set_field('bottom', string)
 
     def get_top(self):
@@ -176,7 +182,11 @@ class Patch:
 
     def set_top(self, string, backup = False):
         if backup:
-            self.__set_field('top.old', self.__get_field('top'))
+            curr = self.__get_field('top')
+            if curr != string:
+                self.__set_field('top.old', curr)
+            else:
+                self.__set_field('top.old', None)
         self.__set_field('top', string)
 
     def restore_old_boundaries(self):
@@ -186,8 +196,9 @@ class Patch:
         if top and bottom:
             self.__set_field('bottom', bottom)
             self.__set_field('top', top)
+            return True
         else:
-            raise StackException, 'No patch undo information'
+            return False
 
     def get_description(self):
         return self.__get_field('description', True)
@@ -255,6 +266,11 @@ class Series:
             self.__unapplied_file = os.path.join(self.__patch_dir, 'unapplied')
             self.__current_file = os.path.join(self.__patch_dir, 'current')
 
+    def get_branch(self):
+        """Return the branch name for the Series object
+        """
+        return self.__name
+
     def __set_current(self, name):
         """Sets the topmost patch
         """
@@ -406,7 +422,9 @@ class Series:
 
         return commit_id
 
-    def new_patch(self, name, message = None, can_edit = True, show_patch = False,
+    def new_patch(self, name, message = None, can_edit = True,
+                  unapplied = False, show_patch = False,
+                  top = None, bottom = None,
                   author_name = None, author_email = None, author_date = None,
                   committer_name = None, committer_email = None):
         """Creates a new patch
@@ -427,8 +445,16 @@ class Series:
 
         patch = Patch(name, self.__patch_dir)
         patch.create()
-        patch.set_bottom(head)
-        patch.set_top(head)
+
+        if bottom:
+            patch.set_bottom(bottom)
+        else:
+            patch.set_bottom(head)
+        if top:
+            patch.set_top(top)
+        else:
+            patch.set_top(head)
+
         patch.set_description(descr)
         patch.set_authname(author_name)
         patch.set_authemail(author_email)
@@ -436,8 +462,15 @@ class Series:
         patch.set_commname(committer_name)
         patch.set_commemail(committer_email)
 
-        append_string(self.__applied_file, patch.get_name())
-        self.__set_current(name)
+        if unapplied:
+            patches = [patch.get_name()] + self.get_unapplied()
+
+            f = file(self.__unapplied_file, 'w+')
+            f.writelines([line + '\n' for line in patches])
+            f.close()
+        else:
+            append_string(self.__applied_file, patch.get_name())
+            self.__set_current(name)
 
     def delete_patch(self, name):
         """Deletes a patch
@@ -484,13 +517,40 @@ class Series:
             # top != bottom always since we have a commit for each patch
             if head == bottom:
                 # reset the backup information
-                patch.set_bottom(bottom, backup = True)
+                patch.set_bottom(head, backup = True)
                 patch.set_top(top, backup = True)
 
             else:
-                top = head
-                # stop the fast-forwarding, must do a real merge
-                break
+                head_tree = git.get_commit(head).get_tree()
+                bottom_tree = git.get_commit(bottom).get_tree()
+                if head_tree == bottom_tree:
+                    # We must just reparent this patch and create a new commit
+                    # for it
+                    descr = patch.get_description()
+                    author_name = patch.get_authname()
+                    author_email = patch.get_authemail()
+                    author_date = patch.get_authdate()
+                    committer_name = patch.get_commname()
+                    committer_email = patch.get_commemail()
+
+                    top_tree = git.get_commit(top).get_tree()
+
+                    top = git.commit(message = descr, parents = [head],
+                                     cache_update = False,
+                                     tree_id = top_tree,
+                                     allowempty = True,
+                                     author_name = author_name,
+                                     author_email = author_email,
+                                     author_date = author_date,
+                                     committer_name = committer_name,
+                                     committer_email = committer_email)
+
+                    patch.set_bottom(head, backup = True)
+                    patch.set_top(top, backup = True)
+                else:
+                    top = head
+                    # stop the fast-forwarding, must do a real merge
+                    break
 
             forwarded+=1
             unapplied.remove(name)
@@ -569,7 +629,7 @@ class Series:
         patch = Patch(name, self.__patch_dir)
         git.reset()
         self.pop_patch(name)
-        patch.restore_old_boundaries()
+        return patch.restore_old_boundaries()
 
     def pop_patch(self, name):
         """Pops the top patch from the stack