Subject: [StGit PATCH v2] Add a --set-tree flag to stg push

From: David Kågedal <[email-masked]>
Date: Tue, 19 May 2009 11:35:48 +0200

This flag makes the push simply restore the tree that the patch used
before, rather than doing any kind of merge.

Signed-off-by: David Kågedal <[email-masked]>
---
Here's an updated patch, based on feedback and discussion with Karl.

 stgit/commands/push.py   |   34 ++++++++++++++++++++++++----------
 stgit/lib/transaction.py |   22 ++++++++++++++++++++++
 t/t1207-push-tree.sh     |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 10 deletions(-)
 create mode 100755 t/t1207-push-tree.sh

diff --git a/stgit/commands/push.py b/stgit/commands/push.py
index 0d25a65..dbecf1f 100644
--- a/stgit/commands/push.py
+++ b/stgit/commands/push.py
@@ -43,7 +43,17 @@ options = [
     opt('-n', '--number', type = 'int',
         short = 'Push the specified number of patches'),
     opt('--reverse', action = 'store_true',
-        short = 'Push the patches in reverse order')
+        short = 'Push the patches in reverse order'),
+    opt('--set-tree', action = 'store_true',
+        short = 'Push the patch with the original tree', long = """
+        Push the patches, but don't perform a merge. Instead, the
+        resulting tree will be identical to the tree that the patch
+        previously created. This can be useful when splitting a patch
+        by first popping the patch and creating a new patch with some
+        of the changes. Pushing the original patch with --set-tree
+        will avoid conflicts and only the remaining changes will be in
+        the patch.
+        """)
     ] + argparse.keep_option() + argparse.merged_option()
 
 directory = common.DirectoryHasRepositoryLib()
@@ -74,14 +84,18 @@ def func(parser, options, args):
     if options.reverse:
         patches.reverse()
 
-    try:
-        if options.merged:
-            merged = set(trans.check_merged(patches))
-        else:
-            merged = set()
+    if options.set_tree:
         for pn in patches:
-            trans.push_patch(pn, iw, allow_interactive = True,
-                             already_merged = pn in merged)
-    except transaction.TransactionHalted:
-        pass
+            trans.push_tree(pn)
+    else:
+        try:
+            if options.merged:
+                merged = set(trans.check_merged(patches))
+            else:
+                merged = set()
+            for pn in patches:
+                trans.push_patch(pn, iw, allow_interactive = True,
+                                 already_merged = pn in merged)
+        except transaction.TransactionHalted:
+            pass
     return trans.run(iw)
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 4148ff3..bce3df1 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -372,6 +372,28 @@ class StackTransaction(object):
             # Update immediately.
             update()
 
+    def push_tree(self, pn):
+        """Push the named patch without updating its tree."""
+        orig_cd = self.patches[pn].data
+        cd = orig_cd.set_committer(None).set_parent(self.top)
+
+        s = ''
+        if any(getattr(cd, a) != getattr(orig_cd, a) for a in
+               ['parent', 'tree', 'author', 'message']):
+            self.patches[pn] = self.__stack.repository.commit(cd)
+        else:
+            s = ' (unmodified)'
+        if cd.is_nochange():
+            s = ' (empty)'
+        out.info('Pushed %s%s' % (pn, s))
+
+        if pn in self.hidden:
+            x = self.hidden
+        else:
+            x = self.unapplied
+        del x[x.index(pn)]
+        self.applied.append(pn)
+
     def reorder_patches(self, applied, unapplied, hidden = None, iw = None):
         """Push and pop patches to attain the given ordering."""
         if hidden is None:
diff --git a/t/t1207-push-tree.sh b/t/t1207-push-tree.sh
new file mode 100755
index 0000000..9d0b1cc
--- /dev/null
+++ b/t/t1207-push-tree.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 David Kågedal
+#
+
+test_description='Exercise pushing patches with --set-tree.'
+
+. ./test-lib.sh
+
+test_expect_success \
+    'Create initial patches' '
+    stg init &&
+    stg new A -m A &&
+    echo hello world > a &&
+    git add a &&
+    stg refresh
+    stg new B -m B &&
+    echo HELLO WORLD > a &&
+    stg refresh
+'
+
+test_expect_success \
+    'Back up and create a partial patch' '
+    stg pop &&
+    stg new C -m C &&
+    echo hello WORLD > a &&
+    stg refresh
+'
+
+test_expect_success \
+    'Reapply patch B' '
+    stg push --set-tree B
+'
+
+test_expect_success \
+    'Compare results' '
+    stg pop -a &&
+    stg push &&
+    test "$(echo $(cat a))" = "hello world" &&
+    stg push &&
+    test "$(echo $(cat a))" = "hello WORLD" &&
+    stg push &&
+    test "$(echo $(cat a))" = "HELLO WORLD"
+'
+
+test_done