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

[StGit PATCH 5/5] Make "stg commit" fancier

From
Karl Hasselström <kha@treskal.com>
Date
Dec 14, 2007, 06:32 UTC
Message-ID
<20071214063236.29290.77674.stgit@yoghurt>
In-Reply-To
<20071214062618.29290.70792.stgit@yoghurt>

Allow the user to commit any patch. Changed behavior: with no parameters, commit one applied patch, not all applied patches -- this is what uncommit does.

Signed-off-by: Karl Hasselström <kha@treskal.com>
---
 stgit/commands/commit.py   |   87 +++++++++++++++++++++++++++++++++-----------
 stgit/commands/uncommit.py |    2 +
 stgit/lib/transaction.py   |    3 +-
 t/t1300-uncommit.sh        |   12 +++---
 4 files changed, 74 insertions(+), 30 deletions(-)
diff --git a/stgit/commands/commit.py b/stgit/commands/commit.py
index f822181..1d741b3 100644
--- a/stgit/commands/commit.py
+++ b/stgit/commands/commit.py
@@ -15,39 +15,82 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
+from optparse import make_option
 from stgit.commands import common
 from stgit.lib import transaction
 from stgit.out import *
 
 help = 'permanently store the applied patches into stack base'
-usage = """%prog [options]
+usage = """%prog [<patchnames>] | -n NUM | --all
 
-Merge the applied patches into the base of the current stack and
-remove them from the series while advancing the base.
+Merge one or more patches into the base of the current stack and
+remove them from the series while advancing the base. This is the
+opposite of 'stg uncommit'. Use this command if you no longer want to
+manage a patch with StGIT.
 
-Use this command only if you want to permanently store the applied
-patches and no longer manage them with StGIT."""
+By default, the bottommost patch is committed. If patch names are
+given, the stack is rearranged so that those patches are at the
+bottom, and then they are committed.
 
-directory = common.DirectoryHasRepositoryLib()
-options = []
+The -n/--number option specifies the number of applied patches to
+commit (counting from the bottom of the stack). If -a/--all is given,
+all applied patches are committed."""
 
+directory = common.DirectoryHasRepositoryLib()
+options = [make_option('-n', '--number', type = 'int',
+                       help = 'commit the specified number of patches'),
+           make_option('-a', '--all', action = 'store_true',
+                       help = 'commit all applied patches')]
 
 def func(parser, options, args):
-    """Merge the applied patches into the base of the current stack
-       and remove them from the series while advancing the base
-    """
-    if len(args) != 0:
-        parser.error('incorrect number of arguments')
-
+    """Commit a number of patches."""
     stack = directory.repository.current_stack
-    patches = stack.patchorder.applied
+    args = common.parse_patches(args, (list(stack.patchorder.applied)
+                                       + list(stack.patchorder.unapplied)))
+    if len([x for x in [args, options.number != None, options.all] if x]) > 1:
+        parser.error('too many options')
+    if args:
+        patches = [pn for pn in (stack.patchorder.applied
+                                 + stack.patchorder.unapplied) if pn in args]
+        bad = set(args) - set(patches)
+        if bad:
+            raise common.CmdException('Bad patch names: %s'
+                                      % ', '.join(sorted(bad)))
+    elif options.number != None:
+        if options.number <= len(stack.patchorder.applied):
+            patches = stack.patchorder.applied[:options.number]
+        else:
+            raise common.CmdException('There are not that many applied patches')
+    elif options.all:
+        patches = stack.patchorder.applied
+    else:
+        patches = stack.patchorder.applied[:1]
     if not patches:
-        raise CmdException('No patches to commit')
-    out.start('Committing %d patches' % len(patches))
+        raise common.CmdException('No patches to commit')
+
+    iw = stack.repository.default_iw()
     trans = transaction.StackTransaction(stack, 'stg commit')
-    for pn in patches:
-        trans.patches[pn] = None
-    trans.applied = []
-    trans.base = stack.head
-    trans.run()
-    out.done()
+    try:
+        common_prefix = 0
+        for i in xrange(min(len(stack.patchorder.applied), len(patches))):
+            if stack.patchorder.applied[i] == patches[i]:
+                common_prefix += 1
+        if common_prefix < len(patches):
+            to_push = trans.pop_patches(
+                lambda pn: pn in stack.patchorder.applied[common_prefix:])
+            for pn in patches[common_prefix:]:
+                trans.push_patch(pn, iw)
+        else:
+            to_push = []
+        new_base = trans.patches[patches[-1]]
+        for pn in patches:
+            trans.patches[pn] = None
+        trans.applied = [pn for pn in trans.applied if pn not in patches]
+        trans.base = new_base
+        out.info('Committed %d patch%s' % (len(patches),
+                                           ['es', ''][len(patches) == 1]))
+        for pn in to_push:
+            trans.push_patch(pn, iw)
+    except transaction.TransactionHalted:
+        pass
+    return trans.run(iw)
diff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py
index 8422952..933ec60 100644
--- a/stgit/commands/uncommit.py
+++ b/stgit/commands/uncommit.py
@@ -28,7 +28,7 @@ usage = """%prog [<patchnames>] | -n NUM [<prefix>]] | -t <committish> [-x]
 
 Take one or more git commits at the base of the current stack and turn
 them into StGIT patches. The new patches are created as applied patches
-at the bottom of the stack. This is the exact opposite of 'stg commit'.
+at the bottom of the stack. This is the opposite of 'stg commit'.
 
 By default, the number of patches to uncommit is determined by the
 number of patch names provided on the command line. First name is used
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index a7c4f7e..a60c5ff 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -51,7 +51,8 @@ class StackTransaction(object):
         self.__unapplied = list(val)
     unapplied = property(lambda self: self.__unapplied, __set_unapplied)
     def __set_base(self, val):
-        assert not self.__applied
+        assert (not self.__applied
+                or self.patches[self.applied[0]].data.parent == val)
         self.__base = val
     base = property(lambda self: self.__base, __set_base)
     def __checkout(self, tree, iw):
diff --git a/t/t1300-uncommit.sh b/t/t1300-uncommit.sh
index 85408fd..d86e579 100755
--- a/t/t1300-uncommit.sh
+++ b/t/t1300-uncommit.sh
@@ -35,7 +35,7 @@ test_expect_success \
 test_expect_success \
 	'Commit the patches' \
 	'
-	stg commit
+	stg commit --all
 	'
 
 test_expect_success \
@@ -43,7 +43,7 @@ test_expect_success \
 	'
 	stg uncommit bar foo &&
 	[ "$(stg id foo//top)" = "$(stg id bar//bottom)" ] &&
-	stg commit
+	stg commit --all
 	'
 
 test_expect_success \
@@ -51,7 +51,7 @@ test_expect_success \
 	'
 	stg uncommit --number=2 foobar &&
 	[ "$(stg id foobar1//top)" = "$(stg id foobar2//bottom)" ] &&
-	stg commit
+	stg commit --all
 	'
 
 test_expect_success \
@@ -59,7 +59,7 @@ test_expect_success \
 	'
 	stg uncommit --number=2 &&
 	[ "$(stg id foo-patch//top)" = "$(stg id bar-patch//bottom)" ] &&
-	stg commit
+	stg commit --all
 	'
 
 test_expect_success \
@@ -68,14 +68,14 @@ test_expect_success \
 	stg uncommit &&
 	stg uncommit &&
 	[ "$(stg id foo-patch//top)" = "$(stg id bar-patch//bottom)" ] &&
-	stg commit
+	stg commit --all
 	'
 
 test_expect_success \
     'Uncommit the patches with --to' '
     stg uncommit --to HEAD^ &&
     [ "$(stg id foo-patch//top)" = "$(stg id bar-patch//bottom)" ] &&
-    stg commit
+    stg commit --all
 '
 
 test_done
Previous: Karl Hasselström
Message 6 of 6 in “More experimental patches”
  1. 0/5 More experimental patchesKarl Hasselström, Dec 14, 2007
  2. 1/5 Expose transaction abort functionKarl Hasselström, Dec 14, 2007
  3. 2/5 stg coalesce: Support --file and --save-templateKarl Hasselström, Dec 14, 2007
  4. 3/5 Set exit code to 3 on merge conflictKarl Hasselström, Dec 14, 2007
  5. 4/5 Convert "stg commit" to new infrastructureKarl Hasselström, Dec 14, 2007
  6. 5/5 Make "stg commit" fancierKarl Hasselström, Dec 14, 2007

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.