Preserve picked patch name when possible
[stgit.git] / stgit / commands / goto.py
blob7f86f9d6eb97eaf95f44f9b1f6264037e49c0b02
1 import re
3 from stgit import argparse
4 from stgit.commands.common import (
5 CmdException,
6 DirectoryHasRepository,
7 check_head_top_equal,
8 check_index_and_worktree_clean,
10 from stgit.lib import transaction
11 from stgit.out import out
13 __copyright__ = """
14 Copyright (C) 2006, Catalin Marinas <catalin.marinas@gmail.com>
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License version 2 as
18 published by the Free Software Foundation.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, see http://www.gnu.org/licenses/.
27 """
29 help = 'Push or pop patches to the given one'
30 kind = 'stack'
31 usage = ['[options] [--] <patch-name>']
32 description = """
33 Push/pop patches to/from the stack until the one given on the command
34 line becomes current."""
36 args = ['other_applied_patches', 'unapplied_patches']
37 options = argparse.keep_option() + argparse.merged_option()
39 directory = DirectoryHasRepository()
42 def func(parser, options, args):
43 if len(args) != 1:
44 parser.error('incorrect number of arguments')
45 name = args[0]
47 stack = directory.repository.current_stack
48 iw = stack.repository.default_iw
50 check_head_top_equal(stack)
51 if not options.keep:
52 check_index_and_worktree_clean(stack)
54 trans = transaction.StackTransaction(stack)
56 if name not in trans.all_patches:
57 candidates = [pn for pn in trans.all_patches if name in pn]
58 if len(candidates) == 1:
59 name = candidates[0]
60 elif len(candidates) > 1:
61 out.info('Possible patches:\n %s' % '\n '.join(candidates))
62 raise CmdException('Ambiguous patch name "%s"' % name)
63 elif re.match('[0-9A-Fa-f]{4,40}$', name):
64 sha1 = name
65 name = stack.patches.name_from_sha1(sha1)
66 if not name:
67 raise CmdException('No patch associated with %s' % sha1)
68 else:
69 raise CmdException('Patch "%s" does not exist' % name)
71 if name in trans.applied:
72 to_pop = set(trans.applied[trans.applied.index(name) + 1 :])
73 popped_extra = trans.pop_patches(lambda pn: pn in to_pop)
74 assert not popped_extra
75 elif name in trans.unapplied:
76 try:
77 to_push = trans.unapplied[: trans.unapplied.index(name) + 1]
78 if options.merged:
79 merged = set(trans.check_merged(to_push))
80 else:
81 merged = set()
82 for pn in to_push:
83 trans.push_patch(
84 pn, iw, allow_interactive=True, already_merged=pn in merged
86 except transaction.TransactionHalted:
87 pass
88 else:
89 raise CmdException('Cannot goto a hidden patch')
90 return trans.execute('goto', iw)