Commit | Line | Data |
---|---|---|
3a3a4f2f KH |
1 | # -*- coding: utf-8 -*- |
2 | ||
3 | __copyright__ = """ | |
4 | Copyright (C) 2008, Karl Hasselström <kha@treskal.com> | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License version 2 as | |
8 | published by the Free Software Foundation. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | """ | |
19 | ||
9690617a | 20 | from stgit.argparse import opt |
3a3a4f2f KH |
21 | from stgit.commands import common |
22 | from stgit.lib import git, log, transaction | |
23 | from stgit.out import out | |
24 | ||
25 | help = 'Reset the patch stack to an earlier state' | |
26 | kind = 'stack' | |
9690617a | 27 | usage = ['[options] <state> [<patchnames>]'] |
3a3a4f2f KH |
28 | description = """ |
29 | Reset the patch stack to an earlier state. The state is specified with | |
30 | a commit from a stack log; for a branch foo, StGit stores the stack | |
31 | log in foo.stgit^. So to undo the last N StGit commands (or rather, | |
32 | the last N log entries; there is not an exact one-to-one | |
33 | relationship), you would say | |
34 | ||
35 | stg reset foo.stgit^~N | |
36 | ||
37 | or, if you are not sure how many steps to undo, you can view the log | |
38 | with "git log" or gitk | |
39 | ||
40 | gitk foo.stgit^ | |
41 | ||
42 | and then reset to any sha1 you see in the log. | |
43 | ||
44 | If one or more patch names are given, reset only those patches, and | |
45 | leave the rest alone.""" | |
46 | ||
9690617a KH |
47 | options = [ |
48 | opt('--hard', action = 'store_true', | |
49 | short = 'Discard changes in your index/worktree')] | |
3a3a4f2f KH |
50 | |
51 | directory = common.DirectoryHasRepositoryLib() | |
52 | ||
9690617a | 53 | def reset_stack(stack, iw, state, only_patches, hard): |
3a3a4f2f KH |
54 | only_patches = set(only_patches) |
55 | def mask(s): | |
56 | if only_patches: | |
57 | return s & only_patches | |
58 | else: | |
59 | return s | |
60 | patches_to_reset = mask(set(state.applied + state.unapplied + state.hidden)) | |
61 | existing_patches = set(stack.patchorder.all) | |
62 | to_delete = mask(existing_patches - patches_to_reset) | |
9690617a | 63 | trans = transaction.StackTransaction(stack, 'reset', discard_changes = hard) |
3a3a4f2f KH |
64 | |
65 | # If we have to change the stack base, we need to pop all patches | |
66 | # first. | |
67 | if not only_patches and trans.base != state.base: | |
68 | trans.pop_patches(lambda pn: True) | |
69 | out.info('Setting stack base to %s' % state.base.sha1) | |
70 | trans.base = state.base | |
71 | ||
72 | # In one go, do all the popping we have to in order to pop the | |
73 | # patches we're going to delete or modify. | |
74 | def mod(pn): | |
75 | if only_patches and not pn in only_patches: | |
76 | return False | |
77 | if pn in to_delete: | |
78 | return True | |
79 | if stack.patches.get(pn).commit != state.patches.get(pn, None): | |
80 | return True | |
81 | return False | |
82 | trans.pop_patches(mod) | |
83 | ||
84 | # Delete and modify/create patches. We've previously popped all | |
85 | # patches that we touch in this step. | |
86 | trans.delete_patches(lambda pn: pn in to_delete) | |
87 | for pn in patches_to_reset: | |
88 | if pn in existing_patches: | |
89 | if trans.patches[pn] == state.patches[pn]: | |
90 | continue | |
91 | else: | |
92 | out.info('Resetting %s' % pn) | |
93 | else: | |
94 | if pn in state.hidden: | |
95 | trans.hidden.append(pn) | |
96 | else: | |
97 | trans.unapplied.append(pn) | |
98 | out.info('Resurrecting %s' % pn) | |
99 | trans.patches[pn] = state.patches[pn] | |
100 | ||
101 | # Push/pop patches as necessary. | |
102 | try: | |
103 | if only_patches: | |
104 | # Push all the patches that we've popped, if they still | |
105 | # exist. | |
106 | pushable = set(trans.unapplied) | |
107 | for pn in stack.patchorder.applied: | |
108 | if pn in pushable: | |
109 | trans.push_patch(pn, iw) | |
110 | else: | |
111 | # Recreate the exact order specified by the goal state. | |
112 | trans.reorder_patches(state.applied, state.unapplied, | |
113 | state.hidden, iw) | |
114 | except transaction.TransactionHalted: | |
115 | pass | |
116 | return trans.run(iw) | |
117 | ||
118 | def func(parser, options, args): | |
119 | stack = directory.repository.current_stack | |
120 | if len(args) >= 1: | |
121 | ref, patches = args[0], args[1:] | |
67b01c13 KH |
122 | state = log.get_log_entry(stack.repository, ref, |
123 | stack.repository.rev_parse(ref)) | |
3a3a4f2f KH |
124 | else: |
125 | raise common.CmdException('Wrong number of arguments') | |
9690617a KH |
126 | return reset_stack(stack, stack.repository.default_iw, state, patches, |
127 | options.hard) |