+ write_strings(self.__unapplied_file, unapplied)
+
+ 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()
+
+ forwarded = 0
+ top = git.get_head()
+
+ for name in names:
+ assert(name in unapplied)
+
+ patch = self.get_patch(name)
+
+ 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. No logging since the
+ # patch hasn't changed
+ patch.set_top(top, backup = True)
+
+ else:
+ 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_top(top, backup = True)
+
+ self.log_patch(patch, 'push(f)')
+ else:
+ top = head
+ # stop the fast-forwarding, must do a real merge
+ break
+
+ forwarded+=1
+ unapplied.remove(name)
+
+ if forwarded == 0:
+ return 0
+
+ git.switch(top)
+
+ append_strings(self.__applied_file, names[0:forwarded])
+ write_strings(self.__unapplied_file, unapplied)
+
+ return forwarded
+
+ def merged_patches(self, names):
+ """Test which patches were merged upstream by reverse-applying
+ them in reverse order. The function returns the list of
+ patches detected to have been applied. The state of the tree
+ is restored to the original one
+ """
+ patches = [self.get_patch(name) for name in names]
+ patches.reverse()
+
+ merged = []
+ for p in patches:
+ if git.apply_diff(p.get_top(), p.get_bottom()):
+ merged.append(p.get_name())
+ merged.reverse()
+
+ git.reset()
+
+ return merged
+
+ def push_empty_patch(self, name):
+ """Pushes an empty patch on the stack
+ """
+ unapplied = self.get_unapplied()
+ assert(name in unapplied)
+
+ # patch = self.get_patch(name)
+ head = git.get_head()
+
+ append_string(self.__applied_file, name)
+
+ unapplied.remove(name)
+ write_strings(self.__unapplied_file, unapplied)
+
+ self.refresh_patch(bottom = head, cache_update = False, log = 'push(m)')