[PATCH] Allow fast-forward pushing.
authorPaolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Fri, 2 Sep 2005 09:25:24 +0000 (11:25 +0200)
committerCatalin Marinas <catalin.marinas@gmail.com>
Fri, 2 Sep 2005 16:24:03 +0000 (17:24 +0100)
Pushing patches is too slow. It's a lot slower than quilt, and possibly
even slower than patch-scripts.

Especially, we never fast-forward patches even when we can, because when we
reorder patches that's not always safe.

It is safe to fast-forward a patch sequence if the first patch in the
sequence "chains" correctly with the current HEAD and each patch chains
with the previous one. With chaining I mean "HEAD commit id matches the
bottom id of the patch".

In this patch I fast-forward the longest possible sequence starting from
the first patch.

Since a single commit stores via parent links the entire history, after a
patch doesn't chain there's almost no need to try to chain other patches.

Actually it could maybe happen (but I'm not trying to exploit that case):
create a patch stack, pop it, apply a couple of subsequent patches out of
order (so it's reparented), pop it, and repush the stack in the old order.

The chained sequence will stop at the changed patch, but (should we reuse
the old commit id when repushing, and we can, provided we delete the .old
file when refreshing) we'd reapply again the same commits.

TODO: do fast-forward even when just the tree objects chain, but the
commits don't (for instance, after changing a patch description, we can't
fast-forward with this patch). We can do that with git-commit-tree, which
creates a new commit based on a given tree, parent, description, without
necessarily checking it out.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
stgit/commands/push.py
stgit/stack.py
stgit/utils.py

index 6fbd779..c653ce7 100644 (file)
@@ -116,7 +116,18 @@ def func(parser, options, args):
     if options.reverse:
         patches.reverse()
 
-    for p in patches:
+    print 'Trying fast-forward...'
+
+    forwarded = crt_series.forward_patches(patches)
+    if forwarded > 1:
+        print 'Fast-forwarded patches "%s" - "%s"' % (patches[0],
+                                                      patches[forwarded - 1])
+    elif forwarded == 1:
+        print 'Fast-forwarded patch "%s"' % patches[0]
+    else:
+        print 'Fast-forwarding failed, using normal pushing'
+
+    for p in patches[forwarded:]:
         if p not in unapplied:
             raise CmdException, 'Patch "%s" not unapplied' % p
 
index 8970c04..cfac219 100644 (file)
@@ -460,6 +460,53 @@ class Series:
         f.writelines([line + '\n' for line in unapplied])
         f.close()
 
+    def forward_patches(self, names):
+        """Try to fast-forward an array of patches.
+
+        On return, patches in names[0:returned_value] have been pushed on the
+        stack. Apply the rest with push_patch
+        """
+        unapplied = self.get_unapplied()
+        self.__begin_stack_check()
+
+        forwarded = 0
+        top = git.get_head()
+
+        for name in names:
+            assert(name in unapplied)
+
+            patch = Patch(name, self.__patch_dir)
+
+            head = top
+            bottom = patch.get_bottom()
+            top = patch.get_top()
+
+            # 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_top(top, backup = True)
+
+            else:
+                top = head
+                # stop the fast-forwarding, must do a real merge
+                break
+
+            forwarded+=1
+            unapplied.remove(name)
+
+        git.switch(top)
+
+        append_strings(self.__applied_file, names[0:forwarded])
+
+        f = file(self.__unapplied_file, 'w+')
+        f.writelines([line + '\n' for line in unapplied])
+        f.close()
+
+        self.__set_current(name)
+
+        return forwarded
+
     def push_patch(self, name):
         """Pushes a patch on the stack
         """
index 9465fe0..b941f7c 100644 (file)
@@ -39,6 +39,14 @@ def write_string(filename, string, multiline = False):
         print >> f, string
     f.close()
 
+def append_strings(filename, strings):
+    """Appends string sequence to file
+    """
+    f = file(filename, 'a+')
+    for string in strings:
+        print >> f, string
+    f.close()
+
 def append_string(filename, string):
     """Appends string to file
     """