Thread (29 messages) flat view 29 messages, 9 authors, 2016-06-15
DORMANTno replies

[PATCH 2/2] Add 'stg uncommit' command

From: Karl Hasselström <hidden>
Date: 2016-06-15 22:42:19
Subsystem: the rest · Maintainer: Linus Torvalds

Add an uncommit command, which is exactly the opposite of 'stg
commit'.

Signed-off-by: Karl Hasselström <redacted>

---

 stgit/commands/commit.py   |    5 ++-
 stgit/commands/uncommit.py |   80 ++++++++++++++++++++++++++++++++++++++++++++
 stgit/main.py              |    2 +
 stgit/stack.py             |   12 +++++--
 4 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/stgit/commands/commit.py b/stgit/commands/commit.py
index a3b7277..ed9a0b3 100644
--- a/stgit/commands/commit.py
+++ b/stgit/commands/commit.py
@@ -28,8 +28,9 @@ usage = """%prog [options]
 Merge the applied patches into the base of the current stack and
 remove them from the series while advancing the base.
 
-Use this command only if you want to permanently store the applied
-patches and no longer manage them with StGIT."""
+Use this command if you want to permanently store the applied patches
+and no longer manage them with StGIT. If you should change your mind
+later, use 'stg uncommit'."""
 
 options = []
 
diff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py
new file mode 100644
index 0000000..4ac0dfb
--- /dev/null
+++ b/stgit/commands/uncommit.py
@@ -0,0 +1,80 @@
+__copyright__ = """
+Copyright (C) 2006, Catalin Marinas <catalin.marinas@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import sys, os
+from optparse import OptionParser, make_option
+
+from stgit.commands.common import *
+from stgit.utils import *
+from stgit import stack, git
+
+help = 'turn regular git commits into StGIT patches'
+usage = """%prog [options] <patchname1> [<patchname2> ... ]
+
+Takes one or more git commits at the base of the current stack, and
+turns them into StGIT patches. These new patches are alreay applied,
+at the bottom of the stack. This is the exact opposite of 'stg
+commit'.
+
+You can either give one patch name for each commit you wish to
+uncommit, or use the --number option and exactly one patch name; StGIT
+will then create numbered patches with the given patch name as prefix.
+
+Only commits with exactly one parent can be uncommitted; in other
+words, you can't uncommmit a merge."""
+
+options = [make_option('-n', '--number', type = 'int',
+                       help = 'uncommit the specified number of commits')]
+
+def func(parser, options, args):
+    if len(args) == 0:
+        parser.error('you must specify at least one patch name')
+    if options.number:
+        if len(args) != 1:
+            parser.error('when using --number, specify exactly one patch name')
+        patchnames = ['%s%d' % (args[0], i)
+                      for i in xrange(options.number - 1, -1, -1)]
+    else:
+        patchnames = args
+
+    if crt_series.get_protected():
+        raise CmdException, 'This branch is protected. Uncommit is not permitted'
+
+    print 'Uncommitting %d patches...' % len(patchnames),
+    sys.stdout.flush()
+
+    for patchname in patchnames:
+        base_file = crt_series.get_base_file()
+        commit_id = read_string(base_file)
+        commit = git.Commit(commit_id)
+        try:
+            parent, = commit.get_parents()
+        except ValueError:
+            raise CmdException, ('Commit %s does not have exactly one parent'
+                                 % commit_id)
+        author_name, author_email, author_date = name_email_date(
+            commit.get_author())
+        crt_series.new_patch(patchname,
+                             can_edit = False, before_existing = True,
+                             top = commit_id, bottom = parent,
+                             message = commit.get_log(),
+                             author_name = author_name,
+                             author_email = author_email,
+                             author_date = author_date)
+        write_string(base_file, parent)
+
+    print 'done'
diff --git a/stgit/main.py b/stgit/main.py
index 6d86ee4..4a48668 100644
--- a/stgit/main.py
+++ b/stgit/main.py
@@ -57,6 +57,7 @@ import stgit.commands.series
 import stgit.commands.status
 import stgit.commands.top
 import stgit.commands.unapplied
+import stgit.commands.uncommit
 
 
 #
@@ -92,6 +93,7 @@ commands = {
     'status':   stgit.commands.status,
     'top':      stgit.commands.top,
     'unapplied':stgit.commands.unapplied,
+    'uncommit': stgit.commands.uncommit,
     }
 
 def print_help():
diff --git a/stgit/stack.py b/stgit/stack.py
index bc39d14..05389bb 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -621,7 +621,8 @@ class Series:
                   unapplied = False, show_patch = False,
                   top = None, bottom = None,
                   author_name = None, author_email = None, author_date = None,
-                  committer_name = None, committer_email = None):
+                  committer_name = None, committer_email = None,
+                  before_existing = False):
         """Creates a new patch
         """
         if self.__patch_applied(name) or self.__patch_unapplied(name):
@@ -664,8 +665,13 @@ class Series:
             f.writelines([line + '\n' for line in patches])
             f.close()
         else:
-            append_string(self.__applied_file, patch.get_name())
-            self.__set_current(name)
+            if before_existing:
+                insert_string(self.__applied_file, patch.get_name())
+                if not self.get_current():
+                    self.__set_current(name)
+            else:
+                append_string(self.__applied_file, patch.get_name())
+                self.__set_current(name)
 
     def delete_patch(self, name):
         """Deletes a patch
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help