git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Karl Hasselström <kha@treskal.com>
Date
Feb 17, 2006, 04:31 UTC
Message-ID
<20060217043128.14175.60168.stgit@backpacker.hemma.treskal.com>
In-Reply-To
<20060217042728.14175.39928.stgit@backpacker.hemma.treskal.com>

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

Signed-off-by: Karl Hasselström <kha@treskal.com>
---
 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
Previous: Karl HasselströmNext: Catalin Marinas
Message 31 of 54 in “[ANNOUNCE] pg - A patch porcelain for GIT”
  1. Shawn PearceFeb 10, 2006
  2. Greg KHFeb 10, 2006
  3. Shawn PearceFeb 10, 2006
  4. Greg KHFeb 10, 2006
  5. Petr BaudisFeb 10, 2006
  6. Shawn PearceFeb 10, 2006
  7. Petr BaudisFeb 10, 2006
  8. Junio C HamanoFeb 10, 2006
  9. Petr BaudisFeb 13, 2006
  10. Catalin MarinasFeb 14, 2006
  11. Karl HasselströmFeb 14, 2006
  12. Chuck LeverFeb 14, 2006
  13. Karl HasselströmFeb 14, 2006
  14. Chuck LeverFeb 14, 2006
  15. Petr BaudisFeb 14, 2006
  16. Sam VilainFeb 15, 2006
  17. Shawn PearceFeb 15, 2006
  18. Petr BaudisFeb 15, 2006
  19. J. Bruce FieldsFeb 15, 2006
  20. Shawn PearceFeb 15, 2006
  21. J. Bruce FieldsFeb 15, 2006
  22. Junio C HamanoFeb 16, 2006
  23. Catalin MarinasFeb 16, 2006
  24. Fernando J. PeredaFeb 16, 2006
  25. Junio C HamanoFeb 16, 2006
  26. Catalin MarinasFeb 16, 2006
  27. Catalin MarinasFeb 15, 2006
  28. Karl HasselströmFeb 16, 2006
  29. 0/2 stg uncommitKarl Hasselström, Feb 17, 2006
  30. 1/2 Update .git/refs/heads/base after patch deletionKarl Hasselström, Feb 17, 2006
  31. 2/2 Add 'stg uncommit' commandKarl Hasselström, Feb 17, 2006
  32. Catalin MarinasFeb 19, 2006
  33. Karl HasselströmFeb 19, 2006
  34. Karl HasselströmFeb 19, 2006
  35. Sam VilainFeb 19, 2006
  36. Catalin MarinasFeb 20, 2006
  37. Karl HasselströmFeb 20, 2006
  38. Catalin MarinasFeb 20, 2006
  39. Karl HasselströmFeb 21, 2006
  40. Karl HasselströmFeb 15, 2006
  41. Andreas EricssonFeb 15, 2006
  42. Karl HasselströmFeb 15, 2006
  43. Karl HasselströmFeb 15, 2006
  44. Catalin MarinasFeb 17, 2006
  45. Sam VilainFeb 13, 2006
  46. Shawn PearceFeb 13, 2006
  47. Sam VilainFeb 13, 2006
  48. Shawn PearceFeb 13, 2006
  49. Catalin MarinasFeb 13, 2006
  50. Shawn PearceFeb 14, 2006
  51. Shawn PearceFeb 14, 2006
  52. Catalin MarinasFeb 15, 2006
  53. Catalin MarinasFeb 15, 2006
  54. Shawn PearceFeb 15, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.