chiark / gitweb /
[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 6fbd77979810a3f60c06f85728afbd791f48daec..c653ce7c18a68e1eb82cdeff159847ddd8c40699 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 8970c04cda8bde7daa8cd3d6ea433eeb6de9ab5d..cfac219a67e4dbb298ade76b02f7a962d907e67f 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 9465fe02550eb517ec2af78627836aec8b88460a..b941f7ca9dad9c90781917f82673f226132d3578 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
     """