Don't write a log entry if there were no changes
[stgit] / stgit / commands / reset.py
CommitLineData
3a3a4f2f
KH
1# -*- coding: utf-8 -*-
2
3__copyright__ = """
4Copyright (C) 2008, Karl Hasselström <kha@treskal.com>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License version 2 as
8published by the Free Software Foundation.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18"""
19
9690617a 20from stgit.argparse import opt
3a3a4f2f
KH
21from stgit.commands import common
22from stgit.lib import git, log, transaction
23from stgit.out import out
24
25help = 'Reset the patch stack to an earlier state'
26kind = 'stack'
9690617a 27usage = ['[options] <state> [<patchnames>]']
3a3a4f2f
KH
28description = """
29Reset the patch stack to an earlier state. The state is specified with
30a commit from a stack log; for a branch foo, StGit stores the stack
31log in foo.stgit^. So to undo the last N StGit commands (or rather,
32the last N log entries; there is not an exact one-to-one
33relationship), you would say
34
35 stg reset foo.stgit^~N
36
37or, if you are not sure how many steps to undo, you can view the log
38with "git log" or gitk
39
40 gitk foo.stgit^
41
42and then reset to any sha1 you see in the log.
43
44If one or more patch names are given, reset only those patches, and
45leave the rest alone."""
46
9690617a
KH
47options = [
48 opt('--hard', action = 'store_true',
49 short = 'Discard changes in your index/worktree')]
3a3a4f2f
KH
50
51directory = common.DirectoryHasRepositoryLib()
52
9690617a 53def 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
118def 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)