* [StGit PATCH 1/5] Expose transaction abort function
2007-12-14 6:32 [StGit PATCH 0/5] More experimental patches Karl Hasselström
@ 2007-12-14 6:32 ` Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 2/5] stg coalesce: Support --file and --save-template Karl Hasselström
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Karl Hasselström @ 2007-12-14 6:32 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git, David Kågedal
Users of stack transactions may call abort() instead of run(), if they
wish to roll back the transaction instead of committing it.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/lib/transaction.py | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 77333b3..663d393 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -77,6 +77,10 @@ class StackTransaction(object):
return self.__patches[self.__applied[-1]]
else:
return self.__stack.base
+ def abort(self, iw = None):
+ # The only state we need to restore is index+worktree.
+ if iw:
+ self.__checkout(self.__stack.head.data.tree, iw)
def run(self, iw = None):
self.__check_consistency()
new_head = self.__head
@@ -85,9 +89,8 @@ class StackTransaction(object):
try:
self.__checkout(new_head.data.tree, iw)
except git.CheckoutException:
- # We have to abort the transaction. The only state we need
- # to restore is index+worktree.
- self.__checkout(self.__stack.head.data.tree, iw)
+ # We have to abort the transaction.
+ self.abort(iw)
self.__abort()
self.__stack.set_head(new_head, self.__msg)
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [StGit PATCH 2/5] stg coalesce: Support --file and --save-template
2007-12-14 6:32 [StGit PATCH 0/5] More experimental patches Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 1/5] Expose transaction abort function Karl Hasselström
@ 2007-12-14 6:32 ` Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 3/5] Set exit code to 3 on merge conflict Karl Hasselström
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Karl Hasselström @ 2007-12-14 6:32 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git, David Kågedal
--save-template was a bit tricky, because we want that
* if we reached the stage where the message is needed without
conflicts, the message should be written and no other side effects
should occur; but
* if we run into conflicts before reaching that point, behave just
as if --save-template was not given.
This makes this script
stg coalesce --save-template <patches>
if template was saved:
let user edit template
if user didn't abort:
stg coalesce --file <patches>
equivalent to
stg coalesce <patches>
with the added benefit that the user can abort the whole thing without
visible side effects.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/coalesce.py | 28 +++++++++++++++++++---------
1 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/stgit/commands/coalesce.py b/stgit/commands/coalesce.py
index e3e1629..2330231 100644
--- a/stgit/commands/coalesce.py
+++ b/stgit/commands/coalesce.py
@@ -34,11 +34,13 @@ you specify, you will have to resolve them manually just as if you had
done a sequence of pushes and pops yourself."""
directory = common.DirectoryHasRepositoryLib()
-options = [make_option('-n', '--name', help = 'name of coalesced patch'),
- make_option('-m', '--message',
- help = 'commit message of coalesced patch')]
+options = [make_option('-n', '--name', help = 'name of coalesced patch')
+ ] + utils.make_message_options()
-def _coalesce_patches(trans, patches, msg):
+class SaveTemplateDone(Exception):
+ pass
+
+def _coalesce_patches(trans, patches, msg, save_template):
cd = trans.patches[patches[0]].data
cd = git.Commitdata(tree = cd.tree, parents = cd.parents)
for pn in patches[1:]:
@@ -53,12 +55,16 @@ def _coalesce_patches(trans, patches, msg):
msg = '\n\n'.join('%s\n\n%s' % (pn.ljust(70, '-'),
trans.patches[pn].data.message)
for pn in patches)
- msg = utils.edit_string(msg, '.stgit-coalesce.txt').strip()
+ if save_template:
+ save_template(msg)
+ raise SaveTemplateDone()
+ else:
+ msg = utils.edit_string(msg, '.stgit-coalesce.txt').strip()
cd = cd.set_message(msg)
return cd
-def _coalesce(stack, iw, name, msg, patches):
+def _coalesce(stack, iw, name, msg, save_template, patches):
# If a name was supplied on the command line, make sure it's OK.
def bad_name(pn):
@@ -75,8 +81,8 @@ def _coalesce(stack, iw, name, msg, patches):
trans = transaction.StackTransaction(stack, 'stg coalesce')
push_new_patch = bool(set(patches) & set(trans.applied))
- new_commit_data = _coalesce_patches(trans, patches, msg)
try:
+ new_commit_data = _coalesce_patches(trans, patches, msg, save_template)
if new_commit_data:
# We were able to construct the coalesced commit
# automatically. So just delete its constituent patches.
@@ -88,7 +94,8 @@ def _coalesce(stack, iw, name, msg, patches):
to_push = trans.pop_patches(lambda pn: pn in patches)
for pn in patches:
trans.push_patch(pn, iw)
- new_commit_data = _coalesce_patches(trans, patches, msg)
+ new_commit_data = _coalesce_patches(trans, patches, msg,
+ save_template)
assert not trans.delete_patches(lambda pn: pn in patches)
make_coalesced_patch(trans, new_commit_data)
@@ -98,6 +105,9 @@ def _coalesce(stack, iw, name, msg, patches):
trans.push_patch(get_name(new_commit_data), iw)
for pn in to_push:
trans.push_patch(pn, iw)
+ except SaveTemplateDone:
+ trans.abort(iw)
+ return
except transaction.TransactionHalted:
pass
trans.run(iw)
@@ -109,4 +119,4 @@ def func(parser, options, args):
if len(patches) < 2:
raise common.CmdException('Need at least two patches')
_coalesce(stack, stack.repository.default_iw(),
- options.name, options.message, patches)
+ options.name, options.message, options.save_template, patches)
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [StGit PATCH 3/5] Set exit code to 3 on merge conflict
2007-12-14 6:32 [StGit PATCH 0/5] More experimental patches Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 1/5] Expose transaction abort function Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 2/5] stg coalesce: Support --file and --save-template Karl Hasselström
@ 2007-12-14 6:32 ` Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 4/5] Convert "stg commit" to new infrastructure Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 5/5] Make "stg commit" fancier Karl Hasselström
4 siblings, 0 replies; 6+ messages in thread
From: Karl Hasselström @ 2007-12-14 6:32 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git, David Kågedal
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/coalesce.py | 6 +++---
stgit/commands/goto.py | 2 +-
stgit/lib/transaction.py | 7 ++++++-
stgit/main.py | 4 ++--
stgit/utils.py | 1 +
5 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/stgit/commands/coalesce.py b/stgit/commands/coalesce.py
index 2330231..d2cba3e 100644
--- a/stgit/commands/coalesce.py
+++ b/stgit/commands/coalesce.py
@@ -110,7 +110,7 @@ def _coalesce(stack, iw, name, msg, save_template, patches):
return
except transaction.TransactionHalted:
pass
- trans.run(iw)
+ return trans.run(iw)
def func(parser, options, args):
stack = directory.repository.current_stack
@@ -118,5 +118,5 @@ def func(parser, options, args):
+ list(stack.patchorder.unapplied)))
if len(patches) < 2:
raise common.CmdException('Need at least two patches')
- _coalesce(stack, stack.repository.default_iw(),
- options.name, options.message, options.save_template, patches)
+ return _coalesce(stack, stack.repository.default_iw(), options.name,
+ options.message, options.save_template, patches)
diff --git a/stgit/commands/goto.py b/stgit/commands/goto.py
index d78929d..763a8af 100644
--- a/stgit/commands/goto.py
+++ b/stgit/commands/goto.py
@@ -48,4 +48,4 @@ def func(parser, options, args):
pass
else:
raise common.CmdException('Patch "%s" does not exist' % patch)
- trans.run(iw)
+ return trans.run(iw)
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 663d393..0ca647e 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -1,4 +1,4 @@
-from stgit import exception
+from stgit import exception, utils
from stgit.out import *
from stgit.lib import git
@@ -111,6 +111,11 @@ class StackTransaction(object):
self.__stack.patchorder.applied = self.__applied
self.__stack.patchorder.unapplied = self.__unapplied
+ if self.__error:
+ return utils.STGIT_CONFLICT
+ else:
+ return utils.STGIT_SUCCESS
+
def __halt(self, msg):
self.__error = msg
raise TransactionHalted(msg)
diff --git a/stgit/main.py b/stgit/main.py
index a95eeb9..2577693 100644
--- a/stgit/main.py
+++ b/stgit/main.py
@@ -273,7 +273,7 @@ def main():
else:
command.crt_series = Series()
- command.func(parser, options, args)
+ ret = command.func(parser, options, args)
except (StgException, IOError, ParsingError, NoSectionError), err:
out.error(str(err), title = '%s %s' % (prog, cmd))
if debug_level > 0:
@@ -283,4 +283,4 @@ def main():
except KeyboardInterrupt:
sys.exit(utils.STGIT_GENERAL_ERROR)
- sys.exit(utils.STGIT_SUCCESS)
+ sys.exit(ret or utils.STGIT_SUCCESS)
diff --git a/stgit/utils.py b/stgit/utils.py
index 6568da5..2ff1d74 100644
--- a/stgit/utils.py
+++ b/stgit/utils.py
@@ -317,6 +317,7 @@ def make_message_options():
STGIT_SUCCESS = 0 # everything's OK
STGIT_GENERAL_ERROR = 1 # seems to be non-command-specific error
STGIT_COMMAND_ERROR = 2 # seems to be a command that failed
+STGIT_CONFLICT = 3 # merge conflict, otherwise OK
def strip_leading(prefix, s):
"""Strip leading prefix from a string. Blow up if the prefix isn't
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [StGit PATCH 4/5] Convert "stg commit" to new infrastructure
2007-12-14 6:32 [StGit PATCH 0/5] More experimental patches Karl Hasselström
` (2 preceding siblings ...)
2007-12-14 6:32 ` [StGit PATCH 3/5] Set exit code to 3 on merge conflict Karl Hasselström
@ 2007-12-14 6:32 ` Karl Hasselström
2007-12-14 6:32 ` [StGit PATCH 5/5] Make "stg commit" fancier Karl Hasselström
4 siblings, 0 replies; 6+ messages in thread
From: Karl Hasselström @ 2007-12-14 6:32 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git, David Kågedal
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/commit.py | 42 ++++++++++++++----------------------------
stgit/lib/transaction.py | 7 ++++++-
2 files changed, 20 insertions(+), 29 deletions(-)
diff --git a/stgit/commands/commit.py b/stgit/commands/commit.py
index e56f5a0..f822181 100644
--- a/stgit/commands/commit.py
+++ b/stgit/commands/commit.py
@@ -15,13 +15,9 @@ 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.commands import common
+from stgit.lib import transaction
from stgit.out import *
-from stgit import stack, git
help = 'permanently store the applied patches into stack base'
usage = """%prog [options]
@@ -32,7 +28,7 @@ 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."""
-directory = DirectoryGotoToplevel()
+directory = common.DirectoryHasRepositoryLib()
options = []
@@ -43,25 +39,15 @@ def func(parser, options, args):
if len(args) != 0:
parser.error('incorrect number of arguments')
- check_local_changes()
- check_conflicts()
- check_head_top_equal(crt_series)
-
- applied = crt_series.get_applied()
- if not applied:
- raise CmdException, 'No patches applied'
-
- if crt_series.get_protected():
- raise CmdException, 'This branch is protected. Commit is not permitted'
-
- crt_head = git.get_head()
-
- out.start('Committing %d patches' % len(applied))
-
- crt_series.pop_patch(applied[0])
- git.switch(crt_head)
-
- for patch in applied:
- crt_series.delete_patch(patch)
-
+ stack = directory.repository.current_stack
+ patches = stack.patchorder.applied
+ if not patches:
+ raise CmdException('No patches to commit')
+ out.start('Committing %d patches' % len(patches))
+ trans = transaction.StackTransaction(stack, 'stg commit')
+ for pn in patches:
+ trans.patches[pn] = None
+ trans.applied = []
+ trans.base = stack.head
+ trans.run()
out.done()
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 0ca647e..a7c4f7e 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -41,6 +41,7 @@ class StackTransaction(object):
self.__unapplied = list(self.__stack.patchorder.unapplied)
self.__error = None
self.__current_tree = self.__stack.head.data.tree
+ self.__base = self.__stack.base
stack = property(lambda self: self.__stack)
patches = property(lambda self: self.__patches)
def __set_applied(self, val):
@@ -49,6 +50,10 @@ class StackTransaction(object):
def __set_unapplied(self, val):
self.__unapplied = list(val)
unapplied = property(lambda self: self.__unapplied, __set_unapplied)
+ def __set_base(self, val):
+ assert not self.__applied
+ self.__base = val
+ base = property(lambda self: self.__base, __set_base)
def __checkout(self, tree, iw):
if not self.__stack.head_top_equal():
out.error(
@@ -76,7 +81,7 @@ class StackTransaction(object):
if self.__applied:
return self.__patches[self.__applied[-1]]
else:
- return self.__stack.base
+ return self.__base
def abort(self, iw = None):
# The only state we need to restore is index+worktree.
if iw:
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [StGit PATCH 5/5] Make "stg commit" fancier
2007-12-14 6:32 [StGit PATCH 0/5] More experimental patches Karl Hasselström
` (3 preceding siblings ...)
2007-12-14 6:32 ` [StGit PATCH 4/5] Convert "stg commit" to new infrastructure Karl Hasselström
@ 2007-12-14 6:32 ` Karl Hasselström
4 siblings, 0 replies; 6+ messages in thread
From: Karl Hasselström @ 2007-12-14 6:32 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git, David Kågedal
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
^ permalink raw reply related [flat|nested] 6+ messages in thread