##// END OF EJS Templates
histedit: improve discoverability of edit commit message
timeless@mozdev.org -
r26100:5706d130 default
parent child Browse files
Show More
@@ -1,1180 +1,1180 b''
1 # histedit.py - interactive history editing for mercurial
1 # histedit.py - interactive history editing for mercurial
2 #
2 #
3 # Copyright 2009 Augie Fackler <raf@durin42.com>
3 # Copyright 2009 Augie Fackler <raf@durin42.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 """interactive history editing
7 """interactive history editing
8
8
9 With this extension installed, Mercurial gains one new command: histedit. Usage
9 With this extension installed, Mercurial gains one new command: histedit. Usage
10 is as follows, assuming the following history::
10 is as follows, assuming the following history::
11
11
12 @ 3[tip] 7c2fd3b9020c 2009-04-27 18:04 -0500 durin42
12 @ 3[tip] 7c2fd3b9020c 2009-04-27 18:04 -0500 durin42
13 | Add delta
13 | Add delta
14 |
14 |
15 o 2 030b686bedc4 2009-04-27 18:04 -0500 durin42
15 o 2 030b686bedc4 2009-04-27 18:04 -0500 durin42
16 | Add gamma
16 | Add gamma
17 |
17 |
18 o 1 c561b4e977df 2009-04-27 18:04 -0500 durin42
18 o 1 c561b4e977df 2009-04-27 18:04 -0500 durin42
19 | Add beta
19 | Add beta
20 |
20 |
21 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
21 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
22 Add alpha
22 Add alpha
23
23
24 If you were to run ``hg histedit c561b4e977df``, you would see the following
24 If you were to run ``hg histedit c561b4e977df``, you would see the following
25 file open in your editor::
25 file open in your editor::
26
26
27 pick c561b4e977df Add beta
27 pick c561b4e977df Add beta
28 pick 030b686bedc4 Add gamma
28 pick 030b686bedc4 Add gamma
29 pick 7c2fd3b9020c Add delta
29 pick 7c2fd3b9020c Add delta
30
30
31 # Edit history between c561b4e977df and 7c2fd3b9020c
31 # Edit history between c561b4e977df and 7c2fd3b9020c
32 #
32 #
33 # Commits are listed from least to most recent
33 # Commits are listed from least to most recent
34 #
34 #
35 # Commands:
35 # Commands:
36 # p, pick = use commit
36 # p, pick = use commit
37 # e, edit = use commit, but stop for amending
37 # e, edit = use commit, but stop for amending
38 # f, fold = use commit, but combine it with the one above
38 # f, fold = use commit, but combine it with the one above
39 # r, roll = like fold, but discard this commit's description
39 # r, roll = like fold, but discard this commit's description
40 # d, drop = remove commit from history
40 # d, drop = remove commit from history
41 # m, mess = edit message without changing commit content
41 # m, mess = edit commit message without changing commit content
42 #
42 #
43
43
44 In this file, lines beginning with ``#`` are ignored. You must specify a rule
44 In this file, lines beginning with ``#`` are ignored. You must specify a rule
45 for each revision in your history. For example, if you had meant to add gamma
45 for each revision in your history. For example, if you had meant to add gamma
46 before beta, and then wanted to add delta in the same revision as beta, you
46 before beta, and then wanted to add delta in the same revision as beta, you
47 would reorganize the file to look like this::
47 would reorganize the file to look like this::
48
48
49 pick 030b686bedc4 Add gamma
49 pick 030b686bedc4 Add gamma
50 pick c561b4e977df Add beta
50 pick c561b4e977df Add beta
51 fold 7c2fd3b9020c Add delta
51 fold 7c2fd3b9020c Add delta
52
52
53 # Edit history between c561b4e977df and 7c2fd3b9020c
53 # Edit history between c561b4e977df and 7c2fd3b9020c
54 #
54 #
55 # Commits are listed from least to most recent
55 # Commits are listed from least to most recent
56 #
56 #
57 # Commands:
57 # Commands:
58 # p, pick = use commit
58 # p, pick = use commit
59 # e, edit = use commit, but stop for amending
59 # e, edit = use commit, but stop for amending
60 # f, fold = use commit, but combine it with the one above
60 # f, fold = use commit, but combine it with the one above
61 # r, roll = like fold, but discard this commit's description
61 # r, roll = like fold, but discard this commit's description
62 # d, drop = remove commit from history
62 # d, drop = remove commit from history
63 # m, mess = edit message without changing commit content
63 # m, mess = edit commit message without changing commit content
64 #
64 #
65
65
66 At which point you close the editor and ``histedit`` starts working. When you
66 At which point you close the editor and ``histedit`` starts working. When you
67 specify a ``fold`` operation, ``histedit`` will open an editor when it folds
67 specify a ``fold`` operation, ``histedit`` will open an editor when it folds
68 those revisions together, offering you a chance to clean up the commit message::
68 those revisions together, offering you a chance to clean up the commit message::
69
69
70 Add beta
70 Add beta
71 ***
71 ***
72 Add delta
72 Add delta
73
73
74 Edit the commit message to your liking, then close the editor. For
74 Edit the commit message to your liking, then close the editor. For
75 this example, let's assume that the commit message was changed to
75 this example, let's assume that the commit message was changed to
76 ``Add beta and delta.`` After histedit has run and had a chance to
76 ``Add beta and delta.`` After histedit has run and had a chance to
77 remove any old or temporary revisions it needed, the history looks
77 remove any old or temporary revisions it needed, the history looks
78 like this::
78 like this::
79
79
80 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
80 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
81 | Add beta and delta.
81 | Add beta and delta.
82 |
82 |
83 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
83 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
84 | Add gamma
84 | Add gamma
85 |
85 |
86 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
86 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
87 Add alpha
87 Add alpha
88
88
89 Note that ``histedit`` does *not* remove any revisions (even its own temporary
89 Note that ``histedit`` does *not* remove any revisions (even its own temporary
90 ones) until after it has completed all the editing operations, so it will
90 ones) until after it has completed all the editing operations, so it will
91 probably perform several strip operations when it's done. For the above example,
91 probably perform several strip operations when it's done. For the above example,
92 it had to run strip twice. Strip can be slow depending on a variety of factors,
92 it had to run strip twice. Strip can be slow depending on a variety of factors,
93 so you might need to be a little patient. You can choose to keep the original
93 so you might need to be a little patient. You can choose to keep the original
94 revisions by passing the ``--keep`` flag.
94 revisions by passing the ``--keep`` flag.
95
95
96 The ``edit`` operation will drop you back to a command prompt,
96 The ``edit`` operation will drop you back to a command prompt,
97 allowing you to edit files freely, or even use ``hg record`` to commit
97 allowing you to edit files freely, or even use ``hg record`` to commit
98 some changes as a separate commit. When you're done, any remaining
98 some changes as a separate commit. When you're done, any remaining
99 uncommitted changes will be committed as well. When done, run ``hg
99 uncommitted changes will be committed as well. When done, run ``hg
100 histedit --continue`` to finish this step. You'll be prompted for a
100 histedit --continue`` to finish this step. You'll be prompted for a
101 new commit message, but the default commit message will be the
101 new commit message, but the default commit message will be the
102 original message for the ``edit`` ed revision.
102 original message for the ``edit`` ed revision.
103
103
104 The ``message`` operation will give you a chance to revise a commit
104 The ``message`` operation will give you a chance to revise a commit
105 message without changing the contents. It's a shortcut for doing
105 message without changing the contents. It's a shortcut for doing
106 ``edit`` immediately followed by `hg histedit --continue``.
106 ``edit`` immediately followed by `hg histedit --continue``.
107
107
108 If ``histedit`` encounters a conflict when moving a revision (while
108 If ``histedit`` encounters a conflict when moving a revision (while
109 handling ``pick`` or ``fold``), it'll stop in a similar manner to
109 handling ``pick`` or ``fold``), it'll stop in a similar manner to
110 ``edit`` with the difference that it won't prompt you for a commit
110 ``edit`` with the difference that it won't prompt you for a commit
111 message when done. If you decide at this point that you don't like how
111 message when done. If you decide at this point that you don't like how
112 much work it will be to rearrange history, or that you made a mistake,
112 much work it will be to rearrange history, or that you made a mistake,
113 you can use ``hg histedit --abort`` to abandon the new changes you
113 you can use ``hg histedit --abort`` to abandon the new changes you
114 have made and return to the state before you attempted to edit your
114 have made and return to the state before you attempted to edit your
115 history.
115 history.
116
116
117 If we clone the histedit-ed example repository above and add four more
117 If we clone the histedit-ed example repository above and add four more
118 changes, such that we have the following history::
118 changes, such that we have the following history::
119
119
120 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
120 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
121 | Add theta
121 | Add theta
122 |
122 |
123 o 5 140988835471 2009-04-27 18:04 -0500 stefan
123 o 5 140988835471 2009-04-27 18:04 -0500 stefan
124 | Add eta
124 | Add eta
125 |
125 |
126 o 4 122930637314 2009-04-27 18:04 -0500 stefan
126 o 4 122930637314 2009-04-27 18:04 -0500 stefan
127 | Add zeta
127 | Add zeta
128 |
128 |
129 o 3 836302820282 2009-04-27 18:04 -0500 stefan
129 o 3 836302820282 2009-04-27 18:04 -0500 stefan
130 | Add epsilon
130 | Add epsilon
131 |
131 |
132 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
132 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
133 | Add beta and delta.
133 | Add beta and delta.
134 |
134 |
135 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
135 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
136 | Add gamma
136 | Add gamma
137 |
137 |
138 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
138 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
139 Add alpha
139 Add alpha
140
140
141 If you run ``hg histedit --outgoing`` on the clone then it is the same
141 If you run ``hg histedit --outgoing`` on the clone then it is the same
142 as running ``hg histedit 836302820282``. If you need plan to push to a
142 as running ``hg histedit 836302820282``. If you need plan to push to a
143 repository that Mercurial does not detect to be related to the source
143 repository that Mercurial does not detect to be related to the source
144 repo, you can add a ``--force`` option.
144 repo, you can add a ``--force`` option.
145
145
146 Histedit rule lines are truncated to 80 characters by default. You
146 Histedit rule lines are truncated to 80 characters by default. You
147 can customise this behavior by setting a different length in your
147 can customise this behavior by setting a different length in your
148 configuration file::
148 configuration file::
149
149
150 [histedit]
150 [histedit]
151 linelen = 120 # truncate rule lines at 120 characters
151 linelen = 120 # truncate rule lines at 120 characters
152 """
152 """
153
153
154 try:
154 try:
155 import cPickle as pickle
155 import cPickle as pickle
156 pickle.dump # import now
156 pickle.dump # import now
157 except ImportError:
157 except ImportError:
158 import pickle
158 import pickle
159 import errno
159 import errno
160 import os
160 import os
161 import sys
161 import sys
162
162
163 from mercurial import cmdutil
163 from mercurial import cmdutil
164 from mercurial import discovery
164 from mercurial import discovery
165 from mercurial import error
165 from mercurial import error
166 from mercurial import changegroup
166 from mercurial import changegroup
167 from mercurial import copies
167 from mercurial import copies
168 from mercurial import context
168 from mercurial import context
169 from mercurial import exchange
169 from mercurial import exchange
170 from mercurial import extensions
170 from mercurial import extensions
171 from mercurial import hg
171 from mercurial import hg
172 from mercurial import node
172 from mercurial import node
173 from mercurial import repair
173 from mercurial import repair
174 from mercurial import scmutil
174 from mercurial import scmutil
175 from mercurial import util
175 from mercurial import util
176 from mercurial import obsolete
176 from mercurial import obsolete
177 from mercurial import merge as mergemod
177 from mercurial import merge as mergemod
178 from mercurial.lock import release
178 from mercurial.lock import release
179 from mercurial.i18n import _
179 from mercurial.i18n import _
180
180
181 cmdtable = {}
181 cmdtable = {}
182 command = cmdutil.command(cmdtable)
182 command = cmdutil.command(cmdtable)
183
183
184 # Note for extension authors: ONLY specify testedwith = 'internal' for
184 # Note for extension authors: ONLY specify testedwith = 'internal' for
185 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
185 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
186 # be specifying the version(s) of Mercurial they are tested with, or
186 # be specifying the version(s) of Mercurial they are tested with, or
187 # leave the attribute unspecified.
187 # leave the attribute unspecified.
188 testedwith = 'internal'
188 testedwith = 'internal'
189
189
190 # i18n: command names and abbreviations must remain untranslated
190 # i18n: command names and abbreviations must remain untranslated
191 editcomment = _("""# Edit history between %s and %s
191 editcomment = _("""# Edit history between %s and %s
192 #
192 #
193 # Commits are listed from least to most recent
193 # Commits are listed from least to most recent
194 #
194 #
195 # Commands:
195 # Commands:
196 # p, pick = use commit
196 # p, pick = use commit
197 # e, edit = use commit, but stop for amending
197 # e, edit = use commit, but stop for amending
198 # f, fold = use commit, but combine it with the one above
198 # f, fold = use commit, but combine it with the one above
199 # r, roll = like fold, but discard this commit's description
199 # r, roll = like fold, but discard this commit's description
200 # d, drop = remove commit from history
200 # d, drop = remove commit from history
201 # m, mess = edit message without changing commit content
201 # m, mess = edit commit message without changing commit content
202 #
202 #
203 """)
203 """)
204
204
205 class histeditstate(object):
205 class histeditstate(object):
206 def __init__(self, repo, parentctxnode=None, rules=None, keep=None,
206 def __init__(self, repo, parentctxnode=None, rules=None, keep=None,
207 topmost=None, replacements=None, lock=None, wlock=None):
207 topmost=None, replacements=None, lock=None, wlock=None):
208 self.repo = repo
208 self.repo = repo
209 self.rules = rules
209 self.rules = rules
210 self.keep = keep
210 self.keep = keep
211 self.topmost = topmost
211 self.topmost = topmost
212 self.parentctxnode = parentctxnode
212 self.parentctxnode = parentctxnode
213 self.lock = lock
213 self.lock = lock
214 self.wlock = wlock
214 self.wlock = wlock
215 self.backupfile = None
215 self.backupfile = None
216 if replacements is None:
216 if replacements is None:
217 self.replacements = []
217 self.replacements = []
218 else:
218 else:
219 self.replacements = replacements
219 self.replacements = replacements
220
220
221 def read(self):
221 def read(self):
222 """Load histedit state from disk and set fields appropriately."""
222 """Load histedit state from disk and set fields appropriately."""
223 try:
223 try:
224 fp = self.repo.vfs('histedit-state', 'r')
224 fp = self.repo.vfs('histedit-state', 'r')
225 except IOError as err:
225 except IOError as err:
226 if err.errno != errno.ENOENT:
226 if err.errno != errno.ENOENT:
227 raise
227 raise
228 raise util.Abort(_('no histedit in progress'))
228 raise util.Abort(_('no histedit in progress'))
229
229
230 try:
230 try:
231 data = pickle.load(fp)
231 data = pickle.load(fp)
232 parentctxnode, rules, keep, topmost, replacements = data
232 parentctxnode, rules, keep, topmost, replacements = data
233 backupfile = None
233 backupfile = None
234 except pickle.UnpicklingError:
234 except pickle.UnpicklingError:
235 data = self._load()
235 data = self._load()
236 parentctxnode, rules, keep, topmost, replacements, backupfile = data
236 parentctxnode, rules, keep, topmost, replacements, backupfile = data
237
237
238 self.parentctxnode = parentctxnode
238 self.parentctxnode = parentctxnode
239 self.rules = rules
239 self.rules = rules
240 self.keep = keep
240 self.keep = keep
241 self.topmost = topmost
241 self.topmost = topmost
242 self.replacements = replacements
242 self.replacements = replacements
243 self.backupfile = backupfile
243 self.backupfile = backupfile
244
244
245 def write(self):
245 def write(self):
246 fp = self.repo.vfs('histedit-state', 'w')
246 fp = self.repo.vfs('histedit-state', 'w')
247 fp.write('v1\n')
247 fp.write('v1\n')
248 fp.write('%s\n' % node.hex(self.parentctxnode))
248 fp.write('%s\n' % node.hex(self.parentctxnode))
249 fp.write('%s\n' % node.hex(self.topmost))
249 fp.write('%s\n' % node.hex(self.topmost))
250 fp.write('%s\n' % self.keep)
250 fp.write('%s\n' % self.keep)
251 fp.write('%d\n' % len(self.rules))
251 fp.write('%d\n' % len(self.rules))
252 for rule in self.rules:
252 for rule in self.rules:
253 fp.write('%s\n' % rule[0]) # action
253 fp.write('%s\n' % rule[0]) # action
254 fp.write('%s\n' % rule[1]) # remainder
254 fp.write('%s\n' % rule[1]) # remainder
255 fp.write('%d\n' % len(self.replacements))
255 fp.write('%d\n' % len(self.replacements))
256 for replacement in self.replacements:
256 for replacement in self.replacements:
257 fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
257 fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
258 for r in replacement[1])))
258 for r in replacement[1])))
259 backupfile = self.backupfile
259 backupfile = self.backupfile
260 if not backupfile:
260 if not backupfile:
261 backupfile = ''
261 backupfile = ''
262 fp.write('%s\n' % backupfile)
262 fp.write('%s\n' % backupfile)
263 fp.close()
263 fp.close()
264
264
265 def _load(self):
265 def _load(self):
266 fp = self.repo.vfs('histedit-state', 'r')
266 fp = self.repo.vfs('histedit-state', 'r')
267 lines = [l[:-1] for l in fp.readlines()]
267 lines = [l[:-1] for l in fp.readlines()]
268
268
269 index = 0
269 index = 0
270 lines[index] # version number
270 lines[index] # version number
271 index += 1
271 index += 1
272
272
273 parentctxnode = node.bin(lines[index])
273 parentctxnode = node.bin(lines[index])
274 index += 1
274 index += 1
275
275
276 topmost = node.bin(lines[index])
276 topmost = node.bin(lines[index])
277 index += 1
277 index += 1
278
278
279 keep = lines[index] == 'True'
279 keep = lines[index] == 'True'
280 index += 1
280 index += 1
281
281
282 # Rules
282 # Rules
283 rules = []
283 rules = []
284 rulelen = int(lines[index])
284 rulelen = int(lines[index])
285 index += 1
285 index += 1
286 for i in xrange(rulelen):
286 for i in xrange(rulelen):
287 ruleaction = lines[index]
287 ruleaction = lines[index]
288 index += 1
288 index += 1
289 rule = lines[index]
289 rule = lines[index]
290 index += 1
290 index += 1
291 rules.append((ruleaction, rule))
291 rules.append((ruleaction, rule))
292
292
293 # Replacements
293 # Replacements
294 replacements = []
294 replacements = []
295 replacementlen = int(lines[index])
295 replacementlen = int(lines[index])
296 index += 1
296 index += 1
297 for i in xrange(replacementlen):
297 for i in xrange(replacementlen):
298 replacement = lines[index]
298 replacement = lines[index]
299 original = node.bin(replacement[:40])
299 original = node.bin(replacement[:40])
300 succ = [node.bin(replacement[i:i + 40]) for i in
300 succ = [node.bin(replacement[i:i + 40]) for i in
301 range(40, len(replacement), 40)]
301 range(40, len(replacement), 40)]
302 replacements.append((original, succ))
302 replacements.append((original, succ))
303 index += 1
303 index += 1
304
304
305 backupfile = lines[index]
305 backupfile = lines[index]
306 index += 1
306 index += 1
307
307
308 fp.close()
308 fp.close()
309
309
310 return parentctxnode, rules, keep, topmost, replacements, backupfile
310 return parentctxnode, rules, keep, topmost, replacements, backupfile
311
311
312 def clear(self):
312 def clear(self):
313 self.repo.vfs.unlink('histedit-state')
313 self.repo.vfs.unlink('histedit-state')
314
314
315 class histeditaction(object):
315 class histeditaction(object):
316 def __init__(self, state, node):
316 def __init__(self, state, node):
317 self.state = state
317 self.state = state
318 self.repo = state.repo
318 self.repo = state.repo
319 self.node = node
319 self.node = node
320
320
321 @classmethod
321 @classmethod
322 def fromrule(cls, state, rule):
322 def fromrule(cls, state, rule):
323 """Parses the given rule, returning an instance of the histeditaction.
323 """Parses the given rule, returning an instance of the histeditaction.
324 """
324 """
325 repo = state.repo
325 repo = state.repo
326 rulehash = rule.strip().split(' ', 1)[0]
326 rulehash = rule.strip().split(' ', 1)[0]
327 try:
327 try:
328 node = repo[rulehash].node()
328 node = repo[rulehash].node()
329 except error.RepoError:
329 except error.RepoError:
330 raise util.Abort(_('unknown changeset %s listed') % rulehash[:12])
330 raise util.Abort(_('unknown changeset %s listed') % rulehash[:12])
331 return cls(state, node)
331 return cls(state, node)
332
332
333 def run(self):
333 def run(self):
334 """Runs the action. The default behavior is simply apply the action's
334 """Runs the action. The default behavior is simply apply the action's
335 rulectx onto the current parentctx."""
335 rulectx onto the current parentctx."""
336 self.applychange()
336 self.applychange()
337 self.continuedirty()
337 self.continuedirty()
338 return self.continueclean()
338 return self.continueclean()
339
339
340 def applychange(self):
340 def applychange(self):
341 """Applies the changes from this action's rulectx onto the current
341 """Applies the changes from this action's rulectx onto the current
342 parentctx, but does not commit them."""
342 parentctx, but does not commit them."""
343 repo = self.repo
343 repo = self.repo
344 rulectx = repo[self.node]
344 rulectx = repo[self.node]
345 hg.update(repo, self.state.parentctxnode)
345 hg.update(repo, self.state.parentctxnode)
346 stats = applychanges(repo.ui, repo, rulectx, {})
346 stats = applychanges(repo.ui, repo, rulectx, {})
347 if stats and stats[3] > 0:
347 if stats and stats[3] > 0:
348 raise error.InterventionRequired(_('Fix up the change and run '
348 raise error.InterventionRequired(_('Fix up the change and run '
349 'hg histedit --continue'))
349 'hg histedit --continue'))
350
350
351 def continuedirty(self):
351 def continuedirty(self):
352 """Continues the action when changes have been applied to the working
352 """Continues the action when changes have been applied to the working
353 copy. The default behavior is to commit the dirty changes."""
353 copy. The default behavior is to commit the dirty changes."""
354 repo = self.repo
354 repo = self.repo
355 rulectx = repo[self.node]
355 rulectx = repo[self.node]
356
356
357 editor = self.commiteditor()
357 editor = self.commiteditor()
358 commit = commitfuncfor(repo, rulectx)
358 commit = commitfuncfor(repo, rulectx)
359
359
360 commit(text=rulectx.description(), user=rulectx.user(),
360 commit(text=rulectx.description(), user=rulectx.user(),
361 date=rulectx.date(), extra=rulectx.extra(), editor=editor)
361 date=rulectx.date(), extra=rulectx.extra(), editor=editor)
362
362
363 def commiteditor(self):
363 def commiteditor(self):
364 """The editor to be used to edit the commit message."""
364 """The editor to be used to edit the commit message."""
365 return False
365 return False
366
366
367 def continueclean(self):
367 def continueclean(self):
368 """Continues the action when the working copy is clean. The default
368 """Continues the action when the working copy is clean. The default
369 behavior is to accept the current commit as the new version of the
369 behavior is to accept the current commit as the new version of the
370 rulectx."""
370 rulectx."""
371 ctx = self.repo['.']
371 ctx = self.repo['.']
372 if ctx.node() == self.state.parentctxnode:
372 if ctx.node() == self.state.parentctxnode:
373 self.repo.ui.warn(_('%s: empty changeset\n') %
373 self.repo.ui.warn(_('%s: empty changeset\n') %
374 node.short(self.node))
374 node.short(self.node))
375 return ctx, [(self.node, tuple())]
375 return ctx, [(self.node, tuple())]
376 if ctx.node() == self.node:
376 if ctx.node() == self.node:
377 # Nothing changed
377 # Nothing changed
378 return ctx, []
378 return ctx, []
379 return ctx, [(self.node, (ctx.node(),))]
379 return ctx, [(self.node, (ctx.node(),))]
380
380
381 def commitfuncfor(repo, src):
381 def commitfuncfor(repo, src):
382 """Build a commit function for the replacement of <src>
382 """Build a commit function for the replacement of <src>
383
383
384 This function ensure we apply the same treatment to all changesets.
384 This function ensure we apply the same treatment to all changesets.
385
385
386 - Add a 'histedit_source' entry in extra.
386 - Add a 'histedit_source' entry in extra.
387
387
388 Note that fold has its own separated logic because its handling is a bit
388 Note that fold has its own separated logic because its handling is a bit
389 different and not easily factored out of the fold method.
389 different and not easily factored out of the fold method.
390 """
390 """
391 phasemin = src.phase()
391 phasemin = src.phase()
392 def commitfunc(**kwargs):
392 def commitfunc(**kwargs):
393 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
393 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
394 try:
394 try:
395 repo.ui.setconfig('phases', 'new-commit', phasemin,
395 repo.ui.setconfig('phases', 'new-commit', phasemin,
396 'histedit')
396 'histedit')
397 extra = kwargs.get('extra', {}).copy()
397 extra = kwargs.get('extra', {}).copy()
398 extra['histedit_source'] = src.hex()
398 extra['histedit_source'] = src.hex()
399 kwargs['extra'] = extra
399 kwargs['extra'] = extra
400 return repo.commit(**kwargs)
400 return repo.commit(**kwargs)
401 finally:
401 finally:
402 repo.ui.restoreconfig(phasebackup)
402 repo.ui.restoreconfig(phasebackup)
403 return commitfunc
403 return commitfunc
404
404
405 def applychanges(ui, repo, ctx, opts):
405 def applychanges(ui, repo, ctx, opts):
406 """Merge changeset from ctx (only) in the current working directory"""
406 """Merge changeset from ctx (only) in the current working directory"""
407 wcpar = repo.dirstate.parents()[0]
407 wcpar = repo.dirstate.parents()[0]
408 if ctx.p1().node() == wcpar:
408 if ctx.p1().node() == wcpar:
409 # edition ar "in place" we do not need to make any merge,
409 # edition ar "in place" we do not need to make any merge,
410 # just applies changes on parent for edition
410 # just applies changes on parent for edition
411 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
411 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
412 stats = None
412 stats = None
413 else:
413 else:
414 try:
414 try:
415 # ui.forcemerge is an internal variable, do not document
415 # ui.forcemerge is an internal variable, do not document
416 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
416 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
417 'histedit')
417 'histedit')
418 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'histedit'])
418 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'histedit'])
419 finally:
419 finally:
420 repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
420 repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
421 return stats
421 return stats
422
422
423 def collapse(repo, first, last, commitopts, skipprompt=False):
423 def collapse(repo, first, last, commitopts, skipprompt=False):
424 """collapse the set of revisions from first to last as new one.
424 """collapse the set of revisions from first to last as new one.
425
425
426 Expected commit options are:
426 Expected commit options are:
427 - message
427 - message
428 - date
428 - date
429 - username
429 - username
430 Commit message is edited in all cases.
430 Commit message is edited in all cases.
431
431
432 This function works in memory."""
432 This function works in memory."""
433 ctxs = list(repo.set('%d::%d', first, last))
433 ctxs = list(repo.set('%d::%d', first, last))
434 if not ctxs:
434 if not ctxs:
435 return None
435 return None
436 for c in ctxs:
436 for c in ctxs:
437 if not c.mutable():
437 if not c.mutable():
438 raise util.Abort(
438 raise util.Abort(
439 _("cannot fold into public change %s") % node.short(c.node()))
439 _("cannot fold into public change %s") % node.short(c.node()))
440 base = first.parents()[0]
440 base = first.parents()[0]
441
441
442 # commit a new version of the old changeset, including the update
442 # commit a new version of the old changeset, including the update
443 # collect all files which might be affected
443 # collect all files which might be affected
444 files = set()
444 files = set()
445 for ctx in ctxs:
445 for ctx in ctxs:
446 files.update(ctx.files())
446 files.update(ctx.files())
447
447
448 # Recompute copies (avoid recording a -> b -> a)
448 # Recompute copies (avoid recording a -> b -> a)
449 copied = copies.pathcopies(base, last)
449 copied = copies.pathcopies(base, last)
450
450
451 # prune files which were reverted by the updates
451 # prune files which were reverted by the updates
452 def samefile(f):
452 def samefile(f):
453 if f in last.manifest():
453 if f in last.manifest():
454 a = last.filectx(f)
454 a = last.filectx(f)
455 if f in base.manifest():
455 if f in base.manifest():
456 b = base.filectx(f)
456 b = base.filectx(f)
457 return (a.data() == b.data()
457 return (a.data() == b.data()
458 and a.flags() == b.flags())
458 and a.flags() == b.flags())
459 else:
459 else:
460 return False
460 return False
461 else:
461 else:
462 return f not in base.manifest()
462 return f not in base.manifest()
463 files = [f for f in files if not samefile(f)]
463 files = [f for f in files if not samefile(f)]
464 # commit version of these files as defined by head
464 # commit version of these files as defined by head
465 headmf = last.manifest()
465 headmf = last.manifest()
466 def filectxfn(repo, ctx, path):
466 def filectxfn(repo, ctx, path):
467 if path in headmf:
467 if path in headmf:
468 fctx = last[path]
468 fctx = last[path]
469 flags = fctx.flags()
469 flags = fctx.flags()
470 mctx = context.memfilectx(repo,
470 mctx = context.memfilectx(repo,
471 fctx.path(), fctx.data(),
471 fctx.path(), fctx.data(),
472 islink='l' in flags,
472 islink='l' in flags,
473 isexec='x' in flags,
473 isexec='x' in flags,
474 copied=copied.get(path))
474 copied=copied.get(path))
475 return mctx
475 return mctx
476 return None
476 return None
477
477
478 if commitopts.get('message'):
478 if commitopts.get('message'):
479 message = commitopts['message']
479 message = commitopts['message']
480 else:
480 else:
481 message = first.description()
481 message = first.description()
482 user = commitopts.get('user')
482 user = commitopts.get('user')
483 date = commitopts.get('date')
483 date = commitopts.get('date')
484 extra = commitopts.get('extra')
484 extra = commitopts.get('extra')
485
485
486 parents = (first.p1().node(), first.p2().node())
486 parents = (first.p1().node(), first.p2().node())
487 editor = None
487 editor = None
488 if not skipprompt:
488 if not skipprompt:
489 editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold')
489 editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold')
490 new = context.memctx(repo,
490 new = context.memctx(repo,
491 parents=parents,
491 parents=parents,
492 text=message,
492 text=message,
493 files=files,
493 files=files,
494 filectxfn=filectxfn,
494 filectxfn=filectxfn,
495 user=user,
495 user=user,
496 date=date,
496 date=date,
497 extra=extra,
497 extra=extra,
498 editor=editor)
498 editor=editor)
499 return repo.commitctx(new)
499 return repo.commitctx(new)
500
500
501 class pick(histeditaction):
501 class pick(histeditaction):
502 def run(self):
502 def run(self):
503 rulectx = self.repo[self.node]
503 rulectx = self.repo[self.node]
504 if rulectx.parents()[0].node() == self.state.parentctxnode:
504 if rulectx.parents()[0].node() == self.state.parentctxnode:
505 self.repo.ui.debug('node %s unchanged\n' % node.short(self.node))
505 self.repo.ui.debug('node %s unchanged\n' % node.short(self.node))
506 return rulectx, []
506 return rulectx, []
507
507
508 return super(pick, self).run()
508 return super(pick, self).run()
509
509
510 class edit(histeditaction):
510 class edit(histeditaction):
511 def run(self):
511 def run(self):
512 repo = self.repo
512 repo = self.repo
513 rulectx = repo[self.node]
513 rulectx = repo[self.node]
514 hg.update(repo, self.state.parentctxnode)
514 hg.update(repo, self.state.parentctxnode)
515 applychanges(repo.ui, repo, rulectx, {})
515 applychanges(repo.ui, repo, rulectx, {})
516 raise error.InterventionRequired(
516 raise error.InterventionRequired(
517 _('Make changes as needed, you may commit or record as needed '
517 _('Make changes as needed, you may commit or record as needed '
518 'now.\nWhen you are finished, run hg histedit --continue to '
518 'now.\nWhen you are finished, run hg histedit --continue to '
519 'resume.'))
519 'resume.'))
520
520
521 def commiteditor(self):
521 def commiteditor(self):
522 return cmdutil.getcommiteditor(edit=True, editform='histedit.edit')
522 return cmdutil.getcommiteditor(edit=True, editform='histedit.edit')
523
523
524 class fold(histeditaction):
524 class fold(histeditaction):
525 def continuedirty(self):
525 def continuedirty(self):
526 repo = self.repo
526 repo = self.repo
527 rulectx = repo[self.node]
527 rulectx = repo[self.node]
528
528
529 commit = commitfuncfor(repo, rulectx)
529 commit = commitfuncfor(repo, rulectx)
530 commit(text='fold-temp-revision %s' % node.short(self.node),
530 commit(text='fold-temp-revision %s' % node.short(self.node),
531 user=rulectx.user(), date=rulectx.date(),
531 user=rulectx.user(), date=rulectx.date(),
532 extra=rulectx.extra())
532 extra=rulectx.extra())
533
533
534 def continueclean(self):
534 def continueclean(self):
535 repo = self.repo
535 repo = self.repo
536 ctx = repo['.']
536 ctx = repo['.']
537 rulectx = repo[self.node]
537 rulectx = repo[self.node]
538 parentctxnode = self.state.parentctxnode
538 parentctxnode = self.state.parentctxnode
539 if ctx.node() == parentctxnode:
539 if ctx.node() == parentctxnode:
540 repo.ui.warn(_('%s: empty changeset\n') %
540 repo.ui.warn(_('%s: empty changeset\n') %
541 node.short(self.node))
541 node.short(self.node))
542 return ctx, [(self.node, (parentctxnode,))]
542 return ctx, [(self.node, (parentctxnode,))]
543
543
544 parentctx = repo[parentctxnode]
544 parentctx = repo[parentctxnode]
545 newcommits = set(c.node() for c in repo.set('(%d::. - %d)', parentctx,
545 newcommits = set(c.node() for c in repo.set('(%d::. - %d)', parentctx,
546 parentctx))
546 parentctx))
547 if not newcommits:
547 if not newcommits:
548 repo.ui.warn(_('%s: cannot fold - working copy is not a '
548 repo.ui.warn(_('%s: cannot fold - working copy is not a '
549 'descendant of previous commit %s\n') %
549 'descendant of previous commit %s\n') %
550 (node.short(self.node), node.short(parentctxnode)))
550 (node.short(self.node), node.short(parentctxnode)))
551 return ctx, [(self.node, (ctx.node(),))]
551 return ctx, [(self.node, (ctx.node(),))]
552
552
553 middlecommits = newcommits.copy()
553 middlecommits = newcommits.copy()
554 middlecommits.discard(ctx.node())
554 middlecommits.discard(ctx.node())
555
555
556 return self.finishfold(repo.ui, repo, parentctx, rulectx, ctx.node(),
556 return self.finishfold(repo.ui, repo, parentctx, rulectx, ctx.node(),
557 middlecommits)
557 middlecommits)
558
558
559 def skipprompt(self):
559 def skipprompt(self):
560 return False
560 return False
561
561
562 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
562 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
563 parent = ctx.parents()[0].node()
563 parent = ctx.parents()[0].node()
564 hg.update(repo, parent)
564 hg.update(repo, parent)
565 ### prepare new commit data
565 ### prepare new commit data
566 commitopts = {}
566 commitopts = {}
567 commitopts['user'] = ctx.user()
567 commitopts['user'] = ctx.user()
568 # commit message
568 # commit message
569 if self.skipprompt():
569 if self.skipprompt():
570 newmessage = ctx.description()
570 newmessage = ctx.description()
571 else:
571 else:
572 newmessage = '\n***\n'.join(
572 newmessage = '\n***\n'.join(
573 [ctx.description()] +
573 [ctx.description()] +
574 [repo[r].description() for r in internalchanges] +
574 [repo[r].description() for r in internalchanges] +
575 [oldctx.description()]) + '\n'
575 [oldctx.description()]) + '\n'
576 commitopts['message'] = newmessage
576 commitopts['message'] = newmessage
577 # date
577 # date
578 commitopts['date'] = max(ctx.date(), oldctx.date())
578 commitopts['date'] = max(ctx.date(), oldctx.date())
579 extra = ctx.extra().copy()
579 extra = ctx.extra().copy()
580 # histedit_source
580 # histedit_source
581 # note: ctx is likely a temporary commit but that the best we can do
581 # note: ctx is likely a temporary commit but that the best we can do
582 # here. This is sufficient to solve issue3681 anyway.
582 # here. This is sufficient to solve issue3681 anyway.
583 extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex())
583 extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex())
584 commitopts['extra'] = extra
584 commitopts['extra'] = extra
585 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
585 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
586 try:
586 try:
587 phasemin = max(ctx.phase(), oldctx.phase())
587 phasemin = max(ctx.phase(), oldctx.phase())
588 repo.ui.setconfig('phases', 'new-commit', phasemin, 'histedit')
588 repo.ui.setconfig('phases', 'new-commit', phasemin, 'histedit')
589 n = collapse(repo, ctx, repo[newnode], commitopts,
589 n = collapse(repo, ctx, repo[newnode], commitopts,
590 skipprompt=self.skipprompt())
590 skipprompt=self.skipprompt())
591 finally:
591 finally:
592 repo.ui.restoreconfig(phasebackup)
592 repo.ui.restoreconfig(phasebackup)
593 if n is None:
593 if n is None:
594 return ctx, []
594 return ctx, []
595 hg.update(repo, n)
595 hg.update(repo, n)
596 replacements = [(oldctx.node(), (newnode,)),
596 replacements = [(oldctx.node(), (newnode,)),
597 (ctx.node(), (n,)),
597 (ctx.node(), (n,)),
598 (newnode, (n,)),
598 (newnode, (n,)),
599 ]
599 ]
600 for ich in internalchanges:
600 for ich in internalchanges:
601 replacements.append((ich, (n,)))
601 replacements.append((ich, (n,)))
602 return repo[n], replacements
602 return repo[n], replacements
603
603
604 class rollup(fold):
604 class rollup(fold):
605 def skipprompt(self):
605 def skipprompt(self):
606 return True
606 return True
607
607
608 class drop(histeditaction):
608 class drop(histeditaction):
609 def run(self):
609 def run(self):
610 parentctx = self.repo[self.state.parentctxnode]
610 parentctx = self.repo[self.state.parentctxnode]
611 return parentctx, [(self.node, tuple())]
611 return parentctx, [(self.node, tuple())]
612
612
613 class message(histeditaction):
613 class message(histeditaction):
614 def commiteditor(self):
614 def commiteditor(self):
615 return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
615 return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
616
616
617 def findoutgoing(ui, repo, remote=None, force=False, opts={}):
617 def findoutgoing(ui, repo, remote=None, force=False, opts={}):
618 """utility function to find the first outgoing changeset
618 """utility function to find the first outgoing changeset
619
619
620 Used by initialisation code"""
620 Used by initialisation code"""
621 dest = ui.expandpath(remote or 'default-push', remote or 'default')
621 dest = ui.expandpath(remote or 'default-push', remote or 'default')
622 dest, revs = hg.parseurl(dest, None)[:2]
622 dest, revs = hg.parseurl(dest, None)[:2]
623 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
623 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
624
624
625 revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
625 revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
626 other = hg.peer(repo, opts, dest)
626 other = hg.peer(repo, opts, dest)
627
627
628 if revs:
628 if revs:
629 revs = [repo.lookup(rev) for rev in revs]
629 revs = [repo.lookup(rev) for rev in revs]
630
630
631 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
631 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
632 if not outgoing.missing:
632 if not outgoing.missing:
633 raise util.Abort(_('no outgoing ancestors'))
633 raise util.Abort(_('no outgoing ancestors'))
634 roots = list(repo.revs("roots(%ln)", outgoing.missing))
634 roots = list(repo.revs("roots(%ln)", outgoing.missing))
635 if 1 < len(roots):
635 if 1 < len(roots):
636 msg = _('there are ambiguous outgoing revisions')
636 msg = _('there are ambiguous outgoing revisions')
637 hint = _('see "hg help histedit" for more detail')
637 hint = _('see "hg help histedit" for more detail')
638 raise util.Abort(msg, hint=hint)
638 raise util.Abort(msg, hint=hint)
639 return repo.lookup(roots[0])
639 return repo.lookup(roots[0])
640
640
641 actiontable = {'p': pick,
641 actiontable = {'p': pick,
642 'pick': pick,
642 'pick': pick,
643 'e': edit,
643 'e': edit,
644 'edit': edit,
644 'edit': edit,
645 'f': fold,
645 'f': fold,
646 'fold': fold,
646 'fold': fold,
647 'r': rollup,
647 'r': rollup,
648 'roll': rollup,
648 'roll': rollup,
649 'd': drop,
649 'd': drop,
650 'drop': drop,
650 'drop': drop,
651 'm': message,
651 'm': message,
652 'mess': message,
652 'mess': message,
653 }
653 }
654
654
655 @command('histedit',
655 @command('histedit',
656 [('', 'commands', '',
656 [('', 'commands', '',
657 _('read history edits from the specified file'), _('FILE')),
657 _('read history edits from the specified file'), _('FILE')),
658 ('c', 'continue', False, _('continue an edit already in progress')),
658 ('c', 'continue', False, _('continue an edit already in progress')),
659 ('', 'edit-plan', False, _('edit remaining actions list')),
659 ('', 'edit-plan', False, _('edit remaining actions list')),
660 ('k', 'keep', False,
660 ('k', 'keep', False,
661 _("don't strip old nodes after edit is complete")),
661 _("don't strip old nodes after edit is complete")),
662 ('', 'abort', False, _('abort an edit in progress')),
662 ('', 'abort', False, _('abort an edit in progress')),
663 ('o', 'outgoing', False, _('changesets not found in destination')),
663 ('o', 'outgoing', False, _('changesets not found in destination')),
664 ('f', 'force', False,
664 ('f', 'force', False,
665 _('force outgoing even for unrelated repositories')),
665 _('force outgoing even for unrelated repositories')),
666 ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
666 ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
667 _("ANCESTOR | --outgoing [URL]"))
667 _("ANCESTOR | --outgoing [URL]"))
668 def histedit(ui, repo, *freeargs, **opts):
668 def histedit(ui, repo, *freeargs, **opts):
669 """interactively edit changeset history
669 """interactively edit changeset history
670
670
671 This command edits changesets between ANCESTOR and the parent of
671 This command edits changesets between ANCESTOR and the parent of
672 the working directory.
672 the working directory.
673
673
674 With --outgoing, this edits changesets not found in the
674 With --outgoing, this edits changesets not found in the
675 destination repository. If URL of the destination is omitted, the
675 destination repository. If URL of the destination is omitted, the
676 'default-push' (or 'default') path will be used.
676 'default-push' (or 'default') path will be used.
677
677
678 For safety, this command is also aborted if there are ambiguous
678 For safety, this command is also aborted if there are ambiguous
679 outgoing revisions which may confuse users: for example, if there
679 outgoing revisions which may confuse users: for example, if there
680 are multiple branches containing outgoing revisions.
680 are multiple branches containing outgoing revisions.
681
681
682 Use "min(outgoing() and ::.)" or similar revset specification
682 Use "min(outgoing() and ::.)" or similar revset specification
683 instead of --outgoing to specify edit target revision exactly in
683 instead of --outgoing to specify edit target revision exactly in
684 such ambiguous situation. See :hg:`help revsets` for detail about
684 such ambiguous situation. See :hg:`help revsets` for detail about
685 selecting revisions.
685 selecting revisions.
686
686
687 Returns 0 on success, 1 if user intervention is required (not only
687 Returns 0 on success, 1 if user intervention is required (not only
688 for intentional "edit" command, but also for resolving unexpected
688 for intentional "edit" command, but also for resolving unexpected
689 conflicts).
689 conflicts).
690 """
690 """
691 state = histeditstate(repo)
691 state = histeditstate(repo)
692 try:
692 try:
693 state.wlock = repo.wlock()
693 state.wlock = repo.wlock()
694 state.lock = repo.lock()
694 state.lock = repo.lock()
695 _histedit(ui, repo, state, *freeargs, **opts)
695 _histedit(ui, repo, state, *freeargs, **opts)
696 finally:
696 finally:
697 release(state.lock, state.wlock)
697 release(state.lock, state.wlock)
698
698
699 def _histedit(ui, repo, state, *freeargs, **opts):
699 def _histedit(ui, repo, state, *freeargs, **opts):
700 # TODO only abort if we try and histedit mq patches, not just
700 # TODO only abort if we try and histedit mq patches, not just
701 # blanket if mq patches are applied somewhere
701 # blanket if mq patches are applied somewhere
702 mq = getattr(repo, 'mq', None)
702 mq = getattr(repo, 'mq', None)
703 if mq and mq.applied:
703 if mq and mq.applied:
704 raise util.Abort(_('source has mq patches applied'))
704 raise util.Abort(_('source has mq patches applied'))
705
705
706 # basic argument incompatibility processing
706 # basic argument incompatibility processing
707 outg = opts.get('outgoing')
707 outg = opts.get('outgoing')
708 cont = opts.get('continue')
708 cont = opts.get('continue')
709 editplan = opts.get('edit_plan')
709 editplan = opts.get('edit_plan')
710 abort = opts.get('abort')
710 abort = opts.get('abort')
711 force = opts.get('force')
711 force = opts.get('force')
712 rules = opts.get('commands', '')
712 rules = opts.get('commands', '')
713 revs = opts.get('rev', [])
713 revs = opts.get('rev', [])
714 goal = 'new' # This invocation goal, in new, continue, abort
714 goal = 'new' # This invocation goal, in new, continue, abort
715 if force and not outg:
715 if force and not outg:
716 raise util.Abort(_('--force only allowed with --outgoing'))
716 raise util.Abort(_('--force only allowed with --outgoing'))
717 if cont:
717 if cont:
718 if any((outg, abort, revs, freeargs, rules, editplan)):
718 if any((outg, abort, revs, freeargs, rules, editplan)):
719 raise util.Abort(_('no arguments allowed with --continue'))
719 raise util.Abort(_('no arguments allowed with --continue'))
720 goal = 'continue'
720 goal = 'continue'
721 elif abort:
721 elif abort:
722 if any((outg, revs, freeargs, rules, editplan)):
722 if any((outg, revs, freeargs, rules, editplan)):
723 raise util.Abort(_('no arguments allowed with --abort'))
723 raise util.Abort(_('no arguments allowed with --abort'))
724 goal = 'abort'
724 goal = 'abort'
725 elif editplan:
725 elif editplan:
726 if any((outg, revs, freeargs)):
726 if any((outg, revs, freeargs)):
727 raise util.Abort(_('only --commands argument allowed with '
727 raise util.Abort(_('only --commands argument allowed with '
728 '--edit-plan'))
728 '--edit-plan'))
729 goal = 'edit-plan'
729 goal = 'edit-plan'
730 else:
730 else:
731 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
731 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
732 raise util.Abort(_('history edit already in progress, try '
732 raise util.Abort(_('history edit already in progress, try '
733 '--continue or --abort'))
733 '--continue or --abort'))
734 if outg:
734 if outg:
735 if revs:
735 if revs:
736 raise util.Abort(_('no revisions allowed with --outgoing'))
736 raise util.Abort(_('no revisions allowed with --outgoing'))
737 if len(freeargs) > 1:
737 if len(freeargs) > 1:
738 raise util.Abort(
738 raise util.Abort(
739 _('only one repo argument allowed with --outgoing'))
739 _('only one repo argument allowed with --outgoing'))
740 else:
740 else:
741 revs.extend(freeargs)
741 revs.extend(freeargs)
742 if len(revs) == 0:
742 if len(revs) == 0:
743 # experimental config: histedit.defaultrev
743 # experimental config: histedit.defaultrev
744 histeditdefault = ui.config('histedit', 'defaultrev')
744 histeditdefault = ui.config('histedit', 'defaultrev')
745 if histeditdefault:
745 if histeditdefault:
746 revs.append(histeditdefault)
746 revs.append(histeditdefault)
747 if len(revs) != 1:
747 if len(revs) != 1:
748 raise util.Abort(
748 raise util.Abort(
749 _('histedit requires exactly one ancestor revision'))
749 _('histedit requires exactly one ancestor revision'))
750
750
751
751
752 replacements = []
752 replacements = []
753 state.keep = opts.get('keep', False)
753 state.keep = opts.get('keep', False)
754 supportsmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
754 supportsmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
755
755
756 # rebuild state
756 # rebuild state
757 if goal == 'continue':
757 if goal == 'continue':
758 state.read()
758 state.read()
759 state = bootstrapcontinue(ui, state, opts)
759 state = bootstrapcontinue(ui, state, opts)
760 elif goal == 'edit-plan':
760 elif goal == 'edit-plan':
761 state.read()
761 state.read()
762 if not rules:
762 if not rules:
763 comment = editcomment % (node.short(state.parentctxnode),
763 comment = editcomment % (node.short(state.parentctxnode),
764 node.short(state.topmost))
764 node.short(state.topmost))
765 rules = ruleeditor(repo, ui, state.rules, comment)
765 rules = ruleeditor(repo, ui, state.rules, comment)
766 else:
766 else:
767 if rules == '-':
767 if rules == '-':
768 f = sys.stdin
768 f = sys.stdin
769 else:
769 else:
770 f = open(rules)
770 f = open(rules)
771 rules = f.read()
771 rules = f.read()
772 f.close()
772 f.close()
773 rules = [l for l in (r.strip() for r in rules.splitlines())
773 rules = [l for l in (r.strip() for r in rules.splitlines())
774 if l and not l.startswith('#')]
774 if l and not l.startswith('#')]
775 rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules])
775 rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules])
776 state.rules = rules
776 state.rules = rules
777 state.write()
777 state.write()
778 return
778 return
779 elif goal == 'abort':
779 elif goal == 'abort':
780 state.read()
780 state.read()
781 tmpnodes, leafs = newnodestoabort(state)
781 tmpnodes, leafs = newnodestoabort(state)
782 ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))
782 ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))
783
783
784 # Recover our old commits if necessary
784 # Recover our old commits if necessary
785 if not state.topmost in repo and state.backupfile:
785 if not state.topmost in repo and state.backupfile:
786 backupfile = repo.join(state.backupfile)
786 backupfile = repo.join(state.backupfile)
787 f = hg.openpath(ui, backupfile)
787 f = hg.openpath(ui, backupfile)
788 gen = exchange.readbundle(ui, f, backupfile)
788 gen = exchange.readbundle(ui, f, backupfile)
789 changegroup.addchangegroup(repo, gen, 'histedit',
789 changegroup.addchangegroup(repo, gen, 'histedit',
790 'bundle:' + backupfile)
790 'bundle:' + backupfile)
791 os.remove(backupfile)
791 os.remove(backupfile)
792
792
793 # check whether we should update away
793 # check whether we should update away
794 if repo.unfiltered().revs('parents() and (%n or %ln::)',
794 if repo.unfiltered().revs('parents() and (%n or %ln::)',
795 state.parentctxnode, leafs | tmpnodes):
795 state.parentctxnode, leafs | tmpnodes):
796 hg.clean(repo, state.topmost)
796 hg.clean(repo, state.topmost)
797 cleanupnode(ui, repo, 'created', tmpnodes)
797 cleanupnode(ui, repo, 'created', tmpnodes)
798 cleanupnode(ui, repo, 'temp', leafs)
798 cleanupnode(ui, repo, 'temp', leafs)
799 state.clear()
799 state.clear()
800 return
800 return
801 else:
801 else:
802 cmdutil.checkunfinished(repo)
802 cmdutil.checkunfinished(repo)
803 cmdutil.bailifchanged(repo)
803 cmdutil.bailifchanged(repo)
804
804
805 topmost, empty = repo.dirstate.parents()
805 topmost, empty = repo.dirstate.parents()
806 if outg:
806 if outg:
807 if freeargs:
807 if freeargs:
808 remote = freeargs[0]
808 remote = freeargs[0]
809 else:
809 else:
810 remote = None
810 remote = None
811 root = findoutgoing(ui, repo, remote, force, opts)
811 root = findoutgoing(ui, repo, remote, force, opts)
812 else:
812 else:
813 rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
813 rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
814 if len(rr) != 1:
814 if len(rr) != 1:
815 raise util.Abort(_('The specified revisions must have '
815 raise util.Abort(_('The specified revisions must have '
816 'exactly one common root'))
816 'exactly one common root'))
817 root = rr[0].node()
817 root = rr[0].node()
818
818
819 revs = between(repo, root, topmost, state.keep)
819 revs = between(repo, root, topmost, state.keep)
820 if not revs:
820 if not revs:
821 raise util.Abort(_('%s is not an ancestor of working directory') %
821 raise util.Abort(_('%s is not an ancestor of working directory') %
822 node.short(root))
822 node.short(root))
823
823
824 ctxs = [repo[r] for r in revs]
824 ctxs = [repo[r] for r in revs]
825 if not rules:
825 if not rules:
826 comment = editcomment % (node.short(root), node.short(topmost))
826 comment = editcomment % (node.short(root), node.short(topmost))
827 rules = ruleeditor(repo, ui, [['pick', c] for c in ctxs], comment)
827 rules = ruleeditor(repo, ui, [['pick', c] for c in ctxs], comment)
828 else:
828 else:
829 if rules == '-':
829 if rules == '-':
830 f = sys.stdin
830 f = sys.stdin
831 else:
831 else:
832 f = open(rules)
832 f = open(rules)
833 rules = f.read()
833 rules = f.read()
834 f.close()
834 f.close()
835 rules = [l for l in (r.strip() for r in rules.splitlines())
835 rules = [l for l in (r.strip() for r in rules.splitlines())
836 if l and not l.startswith('#')]
836 if l and not l.startswith('#')]
837 rules = verifyrules(rules, repo, ctxs)
837 rules = verifyrules(rules, repo, ctxs)
838
838
839 parentctxnode = repo[root].parents()[0].node()
839 parentctxnode = repo[root].parents()[0].node()
840
840
841 state.parentctxnode = parentctxnode
841 state.parentctxnode = parentctxnode
842 state.rules = rules
842 state.rules = rules
843 state.topmost = topmost
843 state.topmost = topmost
844 state.replacements = replacements
844 state.replacements = replacements
845
845
846 # Create a backup so we can always abort completely.
846 # Create a backup so we can always abort completely.
847 backupfile = None
847 backupfile = None
848 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
848 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
849 backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
849 backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
850 'histedit')
850 'histedit')
851 state.backupfile = backupfile
851 state.backupfile = backupfile
852
852
853 while state.rules:
853 while state.rules:
854 state.write()
854 state.write()
855 action, ha = state.rules.pop(0)
855 action, ha = state.rules.pop(0)
856 ui.debug('histedit: processing %s %s\n' % (action, ha[:12]))
856 ui.debug('histedit: processing %s %s\n' % (action, ha[:12]))
857 actobj = actiontable[action].fromrule(state, ha)
857 actobj = actiontable[action].fromrule(state, ha)
858 parentctx, replacement_ = actobj.run()
858 parentctx, replacement_ = actobj.run()
859 state.parentctxnode = parentctx.node()
859 state.parentctxnode = parentctx.node()
860 state.replacements.extend(replacement_)
860 state.replacements.extend(replacement_)
861 state.write()
861 state.write()
862
862
863 hg.update(repo, state.parentctxnode)
863 hg.update(repo, state.parentctxnode)
864
864
865 mapping, tmpnodes, created, ntm = processreplacement(state)
865 mapping, tmpnodes, created, ntm = processreplacement(state)
866 if mapping:
866 if mapping:
867 for prec, succs in mapping.iteritems():
867 for prec, succs in mapping.iteritems():
868 if not succs:
868 if not succs:
869 ui.debug('histedit: %s is dropped\n' % node.short(prec))
869 ui.debug('histedit: %s is dropped\n' % node.short(prec))
870 else:
870 else:
871 ui.debug('histedit: %s is replaced by %s\n' % (
871 ui.debug('histedit: %s is replaced by %s\n' % (
872 node.short(prec), node.short(succs[0])))
872 node.short(prec), node.short(succs[0])))
873 if len(succs) > 1:
873 if len(succs) > 1:
874 m = 'histedit: %s'
874 m = 'histedit: %s'
875 for n in succs[1:]:
875 for n in succs[1:]:
876 ui.debug(m % node.short(n))
876 ui.debug(m % node.short(n))
877
877
878 if not state.keep:
878 if not state.keep:
879 if mapping:
879 if mapping:
880 movebookmarks(ui, repo, mapping, state.topmost, ntm)
880 movebookmarks(ui, repo, mapping, state.topmost, ntm)
881 # TODO update mq state
881 # TODO update mq state
882 if supportsmarkers:
882 if supportsmarkers:
883 markers = []
883 markers = []
884 # sort by revision number because it sound "right"
884 # sort by revision number because it sound "right"
885 for prec in sorted(mapping, key=repo.changelog.rev):
885 for prec in sorted(mapping, key=repo.changelog.rev):
886 succs = mapping[prec]
886 succs = mapping[prec]
887 markers.append((repo[prec],
887 markers.append((repo[prec],
888 tuple(repo[s] for s in succs)))
888 tuple(repo[s] for s in succs)))
889 if markers:
889 if markers:
890 obsolete.createmarkers(repo, markers)
890 obsolete.createmarkers(repo, markers)
891 else:
891 else:
892 cleanupnode(ui, repo, 'replaced', mapping)
892 cleanupnode(ui, repo, 'replaced', mapping)
893
893
894 cleanupnode(ui, repo, 'temp', tmpnodes)
894 cleanupnode(ui, repo, 'temp', tmpnodes)
895 state.clear()
895 state.clear()
896 if os.path.exists(repo.sjoin('undo')):
896 if os.path.exists(repo.sjoin('undo')):
897 os.unlink(repo.sjoin('undo'))
897 os.unlink(repo.sjoin('undo'))
898
898
899 def bootstrapcontinue(ui, state, opts):
899 def bootstrapcontinue(ui, state, opts):
900 repo = state.repo
900 repo = state.repo
901 if state.rules:
901 if state.rules:
902 action, currentnode = state.rules.pop(0)
902 action, currentnode = state.rules.pop(0)
903
903
904 actobj = actiontable[action].fromrule(state, currentnode)
904 actobj = actiontable[action].fromrule(state, currentnode)
905
905
906 s = repo.status()
906 s = repo.status()
907 if s.modified or s.added or s.removed or s.deleted:
907 if s.modified or s.added or s.removed or s.deleted:
908 actobj.continuedirty()
908 actobj.continuedirty()
909 s = repo.status()
909 s = repo.status()
910 if s.modified or s.added or s.removed or s.deleted:
910 if s.modified or s.added or s.removed or s.deleted:
911 raise util.Abort(_("working copy still dirty"))
911 raise util.Abort(_("working copy still dirty"))
912
912
913 parentctx, replacements = actobj.continueclean()
913 parentctx, replacements = actobj.continueclean()
914
914
915 state.parentctxnode = parentctx.node()
915 state.parentctxnode = parentctx.node()
916 state.replacements.extend(replacements)
916 state.replacements.extend(replacements)
917
917
918 return state
918 return state
919
919
920 def between(repo, old, new, keep):
920 def between(repo, old, new, keep):
921 """select and validate the set of revision to edit
921 """select and validate the set of revision to edit
922
922
923 When keep is false, the specified set can't have children."""
923 When keep is false, the specified set can't have children."""
924 ctxs = list(repo.set('%n::%n', old, new))
924 ctxs = list(repo.set('%n::%n', old, new))
925 if ctxs and not keep:
925 if ctxs and not keep:
926 if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
926 if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
927 repo.revs('(%ld::) - (%ld)', ctxs, ctxs)):
927 repo.revs('(%ld::) - (%ld)', ctxs, ctxs)):
928 raise util.Abort(_('cannot edit history that would orphan nodes'))
928 raise util.Abort(_('cannot edit history that would orphan nodes'))
929 if repo.revs('(%ld) and merge()', ctxs):
929 if repo.revs('(%ld) and merge()', ctxs):
930 raise util.Abort(_('cannot edit history that contains merges'))
930 raise util.Abort(_('cannot edit history that contains merges'))
931 root = ctxs[0] # list is already sorted by repo.set
931 root = ctxs[0] # list is already sorted by repo.set
932 if not root.mutable():
932 if not root.mutable():
933 raise util.Abort(_('cannot edit public changeset: %s') % root,
933 raise util.Abort(_('cannot edit public changeset: %s') % root,
934 hint=_('see "hg help phases" for details'))
934 hint=_('see "hg help phases" for details'))
935 return [c.node() for c in ctxs]
935 return [c.node() for c in ctxs]
936
936
937 def makedesc(repo, action, rev):
937 def makedesc(repo, action, rev):
938 """build a initial action line for a ctx
938 """build a initial action line for a ctx
939
939
940 line are in the form:
940 line are in the form:
941
941
942 <action> <hash> <rev> <summary>
942 <action> <hash> <rev> <summary>
943 """
943 """
944 ctx = repo[rev]
944 ctx = repo[rev]
945 summary = ''
945 summary = ''
946 if ctx.description():
946 if ctx.description():
947 summary = ctx.description().splitlines()[0]
947 summary = ctx.description().splitlines()[0]
948 line = '%s %s %d %s' % (action, ctx, ctx.rev(), summary)
948 line = '%s %s %d %s' % (action, ctx, ctx.rev(), summary)
949 # trim to 80 columns so it's not stupidly wide in my editor
949 # trim to 80 columns so it's not stupidly wide in my editor
950 maxlen = repo.ui.configint('histedit', 'linelen', default=80)
950 maxlen = repo.ui.configint('histedit', 'linelen', default=80)
951 maxlen = max(maxlen, 22) # avoid truncating hash
951 maxlen = max(maxlen, 22) # avoid truncating hash
952 return util.ellipsis(line, maxlen)
952 return util.ellipsis(line, maxlen)
953
953
954 def ruleeditor(repo, ui, rules, editcomment=""):
954 def ruleeditor(repo, ui, rules, editcomment=""):
955 """open an editor to edit rules
955 """open an editor to edit rules
956
956
957 rules are in the format [ [act, ctx], ...] like in state.rules
957 rules are in the format [ [act, ctx], ...] like in state.rules
958 """
958 """
959 rules = '\n'.join([makedesc(repo, act, rev) for [act, rev] in rules])
959 rules = '\n'.join([makedesc(repo, act, rev) for [act, rev] in rules])
960 rules += '\n\n'
960 rules += '\n\n'
961 rules += editcomment
961 rules += editcomment
962 rules = ui.edit(rules, ui.username())
962 rules = ui.edit(rules, ui.username())
963
963
964 # Save edit rules in .hg/histedit-last-edit.txt in case
964 # Save edit rules in .hg/histedit-last-edit.txt in case
965 # the user needs to ask for help after something
965 # the user needs to ask for help after something
966 # surprising happens.
966 # surprising happens.
967 f = open(repo.join('histedit-last-edit.txt'), 'w')
967 f = open(repo.join('histedit-last-edit.txt'), 'w')
968 f.write(rules)
968 f.write(rules)
969 f.close()
969 f.close()
970
970
971 return rules
971 return rules
972
972
973 def verifyrules(rules, repo, ctxs):
973 def verifyrules(rules, repo, ctxs):
974 """Verify that there exists exactly one edit rule per given changeset.
974 """Verify that there exists exactly one edit rule per given changeset.
975
975
976 Will abort if there are to many or too few rules, a malformed rule,
976 Will abort if there are to many or too few rules, a malformed rule,
977 or a rule on a changeset outside of the user-given range.
977 or a rule on a changeset outside of the user-given range.
978 """
978 """
979 parsed = []
979 parsed = []
980 expected = set(c.hex() for c in ctxs)
980 expected = set(c.hex() for c in ctxs)
981 seen = set()
981 seen = set()
982 for r in rules:
982 for r in rules:
983 if ' ' not in r:
983 if ' ' not in r:
984 raise util.Abort(_('malformed line "%s"') % r)
984 raise util.Abort(_('malformed line "%s"') % r)
985 action, rest = r.split(' ', 1)
985 action, rest = r.split(' ', 1)
986 ha = rest.strip().split(' ', 1)[0]
986 ha = rest.strip().split(' ', 1)[0]
987 try:
987 try:
988 ha = repo[ha].hex()
988 ha = repo[ha].hex()
989 except error.RepoError:
989 except error.RepoError:
990 raise util.Abort(_('unknown changeset %s listed') % ha[:12])
990 raise util.Abort(_('unknown changeset %s listed') % ha[:12])
991 if ha not in expected:
991 if ha not in expected:
992 raise util.Abort(
992 raise util.Abort(
993 _('may not use changesets other than the ones listed'))
993 _('may not use changesets other than the ones listed'))
994 if ha in seen:
994 if ha in seen:
995 raise util.Abort(_('duplicated command for changeset %s') %
995 raise util.Abort(_('duplicated command for changeset %s') %
996 ha[:12])
996 ha[:12])
997 seen.add(ha)
997 seen.add(ha)
998 if action not in actiontable:
998 if action not in actiontable:
999 raise util.Abort(_('unknown action "%s"') % action)
999 raise util.Abort(_('unknown action "%s"') % action)
1000 parsed.append([action, ha])
1000 parsed.append([action, ha])
1001 missing = sorted(expected - seen) # sort to stabilize output
1001 missing = sorted(expected - seen) # sort to stabilize output
1002 if missing:
1002 if missing:
1003 raise util.Abort(_('missing rules for changeset %s') %
1003 raise util.Abort(_('missing rules for changeset %s') %
1004 missing[0][:12],
1004 missing[0][:12],
1005 hint=_('do you want to use the drop action?'))
1005 hint=_('do you want to use the drop action?'))
1006 return parsed
1006 return parsed
1007
1007
1008 def newnodestoabort(state):
1008 def newnodestoabort(state):
1009 """process the list of replacements to return
1009 """process the list of replacements to return
1010
1010
1011 1) the list of final node
1011 1) the list of final node
1012 2) the list of temporary node
1012 2) the list of temporary node
1013
1013
1014 This meant to be used on abort as less data are required in this case.
1014 This meant to be used on abort as less data are required in this case.
1015 """
1015 """
1016 replacements = state.replacements
1016 replacements = state.replacements
1017 allsuccs = set()
1017 allsuccs = set()
1018 replaced = set()
1018 replaced = set()
1019 for rep in replacements:
1019 for rep in replacements:
1020 allsuccs.update(rep[1])
1020 allsuccs.update(rep[1])
1021 replaced.add(rep[0])
1021 replaced.add(rep[0])
1022 newnodes = allsuccs - replaced
1022 newnodes = allsuccs - replaced
1023 tmpnodes = allsuccs & replaced
1023 tmpnodes = allsuccs & replaced
1024 return newnodes, tmpnodes
1024 return newnodes, tmpnodes
1025
1025
1026
1026
1027 def processreplacement(state):
1027 def processreplacement(state):
1028 """process the list of replacements to return
1028 """process the list of replacements to return
1029
1029
1030 1) the final mapping between original and created nodes
1030 1) the final mapping between original and created nodes
1031 2) the list of temporary node created by histedit
1031 2) the list of temporary node created by histedit
1032 3) the list of new commit created by histedit"""
1032 3) the list of new commit created by histedit"""
1033 replacements = state.replacements
1033 replacements = state.replacements
1034 allsuccs = set()
1034 allsuccs = set()
1035 replaced = set()
1035 replaced = set()
1036 fullmapping = {}
1036 fullmapping = {}
1037 # initialize basic set
1037 # initialize basic set
1038 # fullmapping records all operations recorded in replacement
1038 # fullmapping records all operations recorded in replacement
1039 for rep in replacements:
1039 for rep in replacements:
1040 allsuccs.update(rep[1])
1040 allsuccs.update(rep[1])
1041 replaced.add(rep[0])
1041 replaced.add(rep[0])
1042 fullmapping.setdefault(rep[0], set()).update(rep[1])
1042 fullmapping.setdefault(rep[0], set()).update(rep[1])
1043 new = allsuccs - replaced
1043 new = allsuccs - replaced
1044 tmpnodes = allsuccs & replaced
1044 tmpnodes = allsuccs & replaced
1045 # Reduce content fullmapping into direct relation between original nodes
1045 # Reduce content fullmapping into direct relation between original nodes
1046 # and final node created during history edition
1046 # and final node created during history edition
1047 # Dropped changeset are replaced by an empty list
1047 # Dropped changeset are replaced by an empty list
1048 toproceed = set(fullmapping)
1048 toproceed = set(fullmapping)
1049 final = {}
1049 final = {}
1050 while toproceed:
1050 while toproceed:
1051 for x in list(toproceed):
1051 for x in list(toproceed):
1052 succs = fullmapping[x]
1052 succs = fullmapping[x]
1053 for s in list(succs):
1053 for s in list(succs):
1054 if s in toproceed:
1054 if s in toproceed:
1055 # non final node with unknown closure
1055 # non final node with unknown closure
1056 # We can't process this now
1056 # We can't process this now
1057 break
1057 break
1058 elif s in final:
1058 elif s in final:
1059 # non final node, replace with closure
1059 # non final node, replace with closure
1060 succs.remove(s)
1060 succs.remove(s)
1061 succs.update(final[s])
1061 succs.update(final[s])
1062 else:
1062 else:
1063 final[x] = succs
1063 final[x] = succs
1064 toproceed.remove(x)
1064 toproceed.remove(x)
1065 # remove tmpnodes from final mapping
1065 # remove tmpnodes from final mapping
1066 for n in tmpnodes:
1066 for n in tmpnodes:
1067 del final[n]
1067 del final[n]
1068 # we expect all changes involved in final to exist in the repo
1068 # we expect all changes involved in final to exist in the repo
1069 # turn `final` into list (topologically sorted)
1069 # turn `final` into list (topologically sorted)
1070 nm = state.repo.changelog.nodemap
1070 nm = state.repo.changelog.nodemap
1071 for prec, succs in final.items():
1071 for prec, succs in final.items():
1072 final[prec] = sorted(succs, key=nm.get)
1072 final[prec] = sorted(succs, key=nm.get)
1073
1073
1074 # computed topmost element (necessary for bookmark)
1074 # computed topmost element (necessary for bookmark)
1075 if new:
1075 if new:
1076 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
1076 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
1077 elif not final:
1077 elif not final:
1078 # Nothing rewritten at all. we won't need `newtopmost`
1078 # Nothing rewritten at all. we won't need `newtopmost`
1079 # It is the same as `oldtopmost` and `processreplacement` know it
1079 # It is the same as `oldtopmost` and `processreplacement` know it
1080 newtopmost = None
1080 newtopmost = None
1081 else:
1081 else:
1082 # every body died. The newtopmost is the parent of the root.
1082 # every body died. The newtopmost is the parent of the root.
1083 r = state.repo.changelog.rev
1083 r = state.repo.changelog.rev
1084 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
1084 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
1085
1085
1086 return final, tmpnodes, new, newtopmost
1086 return final, tmpnodes, new, newtopmost
1087
1087
1088 def movebookmarks(ui, repo, mapping, oldtopmost, newtopmost):
1088 def movebookmarks(ui, repo, mapping, oldtopmost, newtopmost):
1089 """Move bookmark from old to newly created node"""
1089 """Move bookmark from old to newly created node"""
1090 if not mapping:
1090 if not mapping:
1091 # if nothing got rewritten there is not purpose for this function
1091 # if nothing got rewritten there is not purpose for this function
1092 return
1092 return
1093 moves = []
1093 moves = []
1094 for bk, old in sorted(repo._bookmarks.iteritems()):
1094 for bk, old in sorted(repo._bookmarks.iteritems()):
1095 if old == oldtopmost:
1095 if old == oldtopmost:
1096 # special case ensure bookmark stay on tip.
1096 # special case ensure bookmark stay on tip.
1097 #
1097 #
1098 # This is arguably a feature and we may only want that for the
1098 # This is arguably a feature and we may only want that for the
1099 # active bookmark. But the behavior is kept compatible with the old
1099 # active bookmark. But the behavior is kept compatible with the old
1100 # version for now.
1100 # version for now.
1101 moves.append((bk, newtopmost))
1101 moves.append((bk, newtopmost))
1102 continue
1102 continue
1103 base = old
1103 base = old
1104 new = mapping.get(base, None)
1104 new = mapping.get(base, None)
1105 if new is None:
1105 if new is None:
1106 continue
1106 continue
1107 while not new:
1107 while not new:
1108 # base is killed, trying with parent
1108 # base is killed, trying with parent
1109 base = repo[base].p1().node()
1109 base = repo[base].p1().node()
1110 new = mapping.get(base, (base,))
1110 new = mapping.get(base, (base,))
1111 # nothing to move
1111 # nothing to move
1112 moves.append((bk, new[-1]))
1112 moves.append((bk, new[-1]))
1113 if moves:
1113 if moves:
1114 marks = repo._bookmarks
1114 marks = repo._bookmarks
1115 for mark, new in moves:
1115 for mark, new in moves:
1116 old = marks[mark]
1116 old = marks[mark]
1117 ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
1117 ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
1118 % (mark, node.short(old), node.short(new)))
1118 % (mark, node.short(old), node.short(new)))
1119 marks[mark] = new
1119 marks[mark] = new
1120 marks.write()
1120 marks.write()
1121
1121
1122 def cleanupnode(ui, repo, name, nodes):
1122 def cleanupnode(ui, repo, name, nodes):
1123 """strip a group of nodes from the repository
1123 """strip a group of nodes from the repository
1124
1124
1125 The set of node to strip may contains unknown nodes."""
1125 The set of node to strip may contains unknown nodes."""
1126 ui.debug('should strip %s nodes %s\n' %
1126 ui.debug('should strip %s nodes %s\n' %
1127 (name, ', '.join([node.short(n) for n in nodes])))
1127 (name, ', '.join([node.short(n) for n in nodes])))
1128 lock = None
1128 lock = None
1129 try:
1129 try:
1130 lock = repo.lock()
1130 lock = repo.lock()
1131 # do not let filtering get in the way of the cleanse
1131 # do not let filtering get in the way of the cleanse
1132 # we should probably get ride of obsolescence marker created during the
1132 # we should probably get ride of obsolescence marker created during the
1133 # histedit, but we currently do not have such information.
1133 # histedit, but we currently do not have such information.
1134 repo = repo.unfiltered()
1134 repo = repo.unfiltered()
1135 # Find all node that need to be stripped
1135 # Find all node that need to be stripped
1136 # (we hg %lr instead of %ln to silently ignore unknown item
1136 # (we hg %lr instead of %ln to silently ignore unknown item
1137 nm = repo.changelog.nodemap
1137 nm = repo.changelog.nodemap
1138 nodes = sorted(n for n in nodes if n in nm)
1138 nodes = sorted(n for n in nodes if n in nm)
1139 roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
1139 roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
1140 for c in roots:
1140 for c in roots:
1141 # We should process node in reverse order to strip tip most first.
1141 # We should process node in reverse order to strip tip most first.
1142 # but this trigger a bug in changegroup hook.
1142 # but this trigger a bug in changegroup hook.
1143 # This would reduce bundle overhead
1143 # This would reduce bundle overhead
1144 repair.strip(ui, repo, c)
1144 repair.strip(ui, repo, c)
1145 finally:
1145 finally:
1146 release(lock)
1146 release(lock)
1147
1147
1148 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
1148 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
1149 if isinstance(nodelist, str):
1149 if isinstance(nodelist, str):
1150 nodelist = [nodelist]
1150 nodelist = [nodelist]
1151 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1151 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1152 state = histeditstate(repo)
1152 state = histeditstate(repo)
1153 state.read()
1153 state.read()
1154 histedit_nodes = set([repo[rulehash].node() for (action, rulehash)
1154 histedit_nodes = set([repo[rulehash].node() for (action, rulehash)
1155 in state.rules if rulehash in repo])
1155 in state.rules if rulehash in repo])
1156 strip_nodes = set([repo[n].node() for n in nodelist])
1156 strip_nodes = set([repo[n].node() for n in nodelist])
1157 common_nodes = histedit_nodes & strip_nodes
1157 common_nodes = histedit_nodes & strip_nodes
1158 if common_nodes:
1158 if common_nodes:
1159 raise util.Abort(_("histedit in progress, can't strip %s")
1159 raise util.Abort(_("histedit in progress, can't strip %s")
1160 % ', '.join(node.short(x) for x in common_nodes))
1160 % ', '.join(node.short(x) for x in common_nodes))
1161 return orig(ui, repo, nodelist, *args, **kwargs)
1161 return orig(ui, repo, nodelist, *args, **kwargs)
1162
1162
1163 extensions.wrapfunction(repair, 'strip', stripwrapper)
1163 extensions.wrapfunction(repair, 'strip', stripwrapper)
1164
1164
1165 def summaryhook(ui, repo):
1165 def summaryhook(ui, repo):
1166 if not os.path.exists(repo.join('histedit-state')):
1166 if not os.path.exists(repo.join('histedit-state')):
1167 return
1167 return
1168 state = histeditstate(repo)
1168 state = histeditstate(repo)
1169 state.read()
1169 state.read()
1170 if state.rules:
1170 if state.rules:
1171 # i18n: column positioning for "hg summary"
1171 # i18n: column positioning for "hg summary"
1172 ui.write(_('hist: %s (histedit --continue)\n') %
1172 ui.write(_('hist: %s (histedit --continue)\n') %
1173 (ui.label(_('%d remaining'), 'histedit.remaining') %
1173 (ui.label(_('%d remaining'), 'histedit.remaining') %
1174 len(state.rules)))
1174 len(state.rules)))
1175
1175
1176 def extsetup(ui):
1176 def extsetup(ui):
1177 cmdutil.summaryhooks.add('histedit', summaryhook)
1177 cmdutil.summaryhooks.add('histedit', summaryhook)
1178 cmdutil.unfinishedstates.append(
1178 cmdutil.unfinishedstates.append(
1179 ['histedit-state', False, True, _('histedit in progress'),
1179 ['histedit-state', False, True, _('histedit in progress'),
1180 _("use 'hg histedit --continue' or 'hg histedit --abort'")])
1180 _("use 'hg histedit --continue' or 'hg histedit --abort'")])
@@ -1,326 +1,326 b''
1 Test argument handling and various data parsing
1 Test argument handling and various data parsing
2 ==================================================
2 ==================================================
3
3
4
4
5 Enable extensions used by this test.
5 Enable extensions used by this test.
6 $ cat >>$HGRCPATH <<EOF
6 $ cat >>$HGRCPATH <<EOF
7 > [extensions]
7 > [extensions]
8 > histedit=
8 > histedit=
9 > EOF
9 > EOF
10
10
11 Repo setup.
11 Repo setup.
12 $ hg init foo
12 $ hg init foo
13 $ cd foo
13 $ cd foo
14 $ echo alpha >> alpha
14 $ echo alpha >> alpha
15 $ hg addr
15 $ hg addr
16 adding alpha
16 adding alpha
17 $ hg ci -m one
17 $ hg ci -m one
18 $ echo alpha >> alpha
18 $ echo alpha >> alpha
19 $ hg ci -m two
19 $ hg ci -m two
20 $ echo alpha >> alpha
20 $ echo alpha >> alpha
21 $ hg ci -m three
21 $ hg ci -m three
22 $ echo alpha >> alpha
22 $ echo alpha >> alpha
23 $ hg ci -m four
23 $ hg ci -m four
24 $ echo alpha >> alpha
24 $ echo alpha >> alpha
25 $ hg ci -m five
25 $ hg ci -m five
26
26
27 $ hg log --style compact --graph
27 $ hg log --style compact --graph
28 @ 4[tip] 08d98a8350f3 1970-01-01 00:00 +0000 test
28 @ 4[tip] 08d98a8350f3 1970-01-01 00:00 +0000 test
29 | five
29 | five
30 |
30 |
31 o 3 c8e68270e35a 1970-01-01 00:00 +0000 test
31 o 3 c8e68270e35a 1970-01-01 00:00 +0000 test
32 | four
32 | four
33 |
33 |
34 o 2 eb57da33312f 1970-01-01 00:00 +0000 test
34 o 2 eb57da33312f 1970-01-01 00:00 +0000 test
35 | three
35 | three
36 |
36 |
37 o 1 579e40513370 1970-01-01 00:00 +0000 test
37 o 1 579e40513370 1970-01-01 00:00 +0000 test
38 | two
38 | two
39 |
39 |
40 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
40 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
41 one
41 one
42
42
43
43
44 histedit --continue/--abort with no existing state
44 histedit --continue/--abort with no existing state
45 --------------------------------------------------
45 --------------------------------------------------
46
46
47 $ hg histedit --continue
47 $ hg histedit --continue
48 abort: no histedit in progress
48 abort: no histedit in progress
49 [255]
49 [255]
50 $ hg histedit --abort
50 $ hg histedit --abort
51 abort: no histedit in progress
51 abort: no histedit in progress
52 [255]
52 [255]
53
53
54 Run a dummy edit to make sure we get tip^^ correctly via revsingle.
54 Run a dummy edit to make sure we get tip^^ correctly via revsingle.
55 --------------------------------------------------------------------
55 --------------------------------------------------------------------
56
56
57 $ HGEDITOR=cat hg histedit "tip^^"
57 $ HGEDITOR=cat hg histedit "tip^^"
58 pick eb57da33312f 2 three
58 pick eb57da33312f 2 three
59 pick c8e68270e35a 3 four
59 pick c8e68270e35a 3 four
60 pick 08d98a8350f3 4 five
60 pick 08d98a8350f3 4 five
61
61
62 # Edit history between eb57da33312f and 08d98a8350f3
62 # Edit history between eb57da33312f and 08d98a8350f3
63 #
63 #
64 # Commits are listed from least to most recent
64 # Commits are listed from least to most recent
65 #
65 #
66 # Commands:
66 # Commands:
67 # p, pick = use commit
67 # p, pick = use commit
68 # e, edit = use commit, but stop for amending
68 # e, edit = use commit, but stop for amending
69 # f, fold = use commit, but combine it with the one above
69 # f, fold = use commit, but combine it with the one above
70 # r, roll = like fold, but discard this commit's description
70 # r, roll = like fold, but discard this commit's description
71 # d, drop = remove commit from history
71 # d, drop = remove commit from history
72 # m, mess = edit message without changing commit content
72 # m, mess = edit commit message without changing commit content
73 #
73 #
74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
75
75
76 Run on a revision not ancestors of the current working directory.
76 Run on a revision not ancestors of the current working directory.
77 --------------------------------------------------------------------
77 --------------------------------------------------------------------
78
78
79 $ hg up 2
79 $ hg up 2
80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 $ hg histedit -r 4
81 $ hg histedit -r 4
82 abort: 08d98a8350f3 is not an ancestor of working directory
82 abort: 08d98a8350f3 is not an ancestor of working directory
83 [255]
83 [255]
84 $ hg up --quiet
84 $ hg up --quiet
85
85
86
86
87 Test that we pick the minimum of a revrange
87 Test that we pick the minimum of a revrange
88 ---------------------------------------
88 ---------------------------------------
89
89
90 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
90 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
91 > pick eb57da33312f 2 three
91 > pick eb57da33312f 2 three
92 > pick c8e68270e35a 3 four
92 > pick c8e68270e35a 3 four
93 > pick 08d98a8350f3 4 five
93 > pick 08d98a8350f3 4 five
94 > EOF
94 > EOF
95 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 $ hg up --quiet
96 $ hg up --quiet
97
97
98 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
98 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
99 > pick eb57da33312f 2 three
99 > pick eb57da33312f 2 three
100 > pick c8e68270e35a 3 four
100 > pick c8e68270e35a 3 four
101 > pick 08d98a8350f3 4 five
101 > pick 08d98a8350f3 4 five
102 > EOF
102 > EOF
103 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
104 $ hg up --quiet
104 $ hg up --quiet
105
105
106 Test config specified default
106 Test config specified default
107 -----------------------------
107 -----------------------------
108
108
109 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
109 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
110 > pick c8e68270e35a 3 four
110 > pick c8e68270e35a 3 four
111 > pick 08d98a8350f3 4 five
111 > pick 08d98a8350f3 4 five
112 > EOF
112 > EOF
113 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
114
114
115 Run on a revision not descendants of the initial parent
115 Run on a revision not descendants of the initial parent
116 --------------------------------------------------------------------
116 --------------------------------------------------------------------
117
117
118 Test the message shown for inconsistent histedit state, which may be
118 Test the message shown for inconsistent histedit state, which may be
119 created (and forgotten) by Mercurial earlier than 2.7. This emulates
119 created (and forgotten) by Mercurial earlier than 2.7. This emulates
120 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
120 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
121 temporarily.
121 temporarily.
122
122
123 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
123 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
124 @ 4 08d9 five
124 @ 4 08d9 five
125 |
125 |
126 o 3 c8e6 four
126 o 3 c8e6 four
127 |
127 |
128 o 2 eb57 three
128 o 2 eb57 three
129 |
129 |
130 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
130 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
131 > edit 08d98a8350f3 4 five
131 > edit 08d98a8350f3 4 five
132 > EOF
132 > EOF
133 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 reverting alpha
134 reverting alpha
135 Make changes as needed, you may commit or record as needed now.
135 Make changes as needed, you may commit or record as needed now.
136 When you are finished, run hg histedit --continue to resume.
136 When you are finished, run hg histedit --continue to resume.
137 [1]
137 [1]
138
138
139 $ mv .hg/histedit-state .hg/histedit-state.back
139 $ mv .hg/histedit-state .hg/histedit-state.back
140 $ hg update --quiet --clean 2
140 $ hg update --quiet --clean 2
141 $ echo alpha >> alpha
141 $ echo alpha >> alpha
142 $ mv .hg/histedit-state.back .hg/histedit-state
142 $ mv .hg/histedit-state.back .hg/histedit-state
143
143
144 $ hg histedit --continue
144 $ hg histedit --continue
145 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg (glob)
146 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg (glob)
147 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
147 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
148 @ 4 f5ed five
148 @ 4 f5ed five
149 |
149 |
150 | o 3 c8e6 four
150 | o 3 c8e6 four
151 |/
151 |/
152 o 2 eb57 three
152 o 2 eb57 three
153 |
153 |
154
154
155 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg
155 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg
156 $ hg strip -q -r f5ed --config extensions.strip=
156 $ hg strip -q -r f5ed --config extensions.strip=
157 $ hg up -q 08d98a8350f3
157 $ hg up -q 08d98a8350f3
158
158
159 Test that missing revisions are detected
159 Test that missing revisions are detected
160 ---------------------------------------
160 ---------------------------------------
161
161
162 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
162 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
163 > pick eb57da33312f 2 three
163 > pick eb57da33312f 2 three
164 > pick 08d98a8350f3 4 five
164 > pick 08d98a8350f3 4 five
165 > EOF
165 > EOF
166 abort: missing rules for changeset c8e68270e35a
166 abort: missing rules for changeset c8e68270e35a
167 (do you want to use the drop action?)
167 (do you want to use the drop action?)
168 [255]
168 [255]
169
169
170 Test that extra revisions are detected
170 Test that extra revisions are detected
171 ---------------------------------------
171 ---------------------------------------
172
172
173 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
173 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
174 > pick 6058cbb6cfd7 0 one
174 > pick 6058cbb6cfd7 0 one
175 > pick c8e68270e35a 3 four
175 > pick c8e68270e35a 3 four
176 > pick 08d98a8350f3 4 five
176 > pick 08d98a8350f3 4 five
177 > EOF
177 > EOF
178 abort: may not use changesets other than the ones listed
178 abort: may not use changesets other than the ones listed
179 [255]
179 [255]
180
180
181 Test malformed line
181 Test malformed line
182 ---------------------------------------
182 ---------------------------------------
183
183
184 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
184 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
185 > pickeb57da33312f2three
185 > pickeb57da33312f2three
186 > pick c8e68270e35a 3 four
186 > pick c8e68270e35a 3 four
187 > pick 08d98a8350f3 4 five
187 > pick 08d98a8350f3 4 five
188 > EOF
188 > EOF
189 abort: malformed line "pickeb57da33312f2three"
189 abort: malformed line "pickeb57da33312f2three"
190 [255]
190 [255]
191
191
192 Test unknown changeset
192 Test unknown changeset
193 ---------------------------------------
193 ---------------------------------------
194
194
195 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
195 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
196 > pick 0123456789ab 2 three
196 > pick 0123456789ab 2 three
197 > pick c8e68270e35a 3 four
197 > pick c8e68270e35a 3 four
198 > pick 08d98a8350f3 4 five
198 > pick 08d98a8350f3 4 five
199 > EOF
199 > EOF
200 abort: unknown changeset 0123456789ab listed
200 abort: unknown changeset 0123456789ab listed
201 [255]
201 [255]
202
202
203 Test unknown command
203 Test unknown command
204 ---------------------------------------
204 ---------------------------------------
205
205
206 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
206 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
207 > coin eb57da33312f 2 three
207 > coin eb57da33312f 2 three
208 > pick c8e68270e35a 3 four
208 > pick c8e68270e35a 3 four
209 > pick 08d98a8350f3 4 five
209 > pick 08d98a8350f3 4 five
210 > EOF
210 > EOF
211 abort: unknown action "coin"
211 abort: unknown action "coin"
212 [255]
212 [255]
213
213
214 Test duplicated changeset
214 Test duplicated changeset
215 ---------------------------------------
215 ---------------------------------------
216
216
217 So one is missing and one appear twice.
217 So one is missing and one appear twice.
218
218
219 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
219 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
220 > pick eb57da33312f 2 three
220 > pick eb57da33312f 2 three
221 > pick eb57da33312f 2 three
221 > pick eb57da33312f 2 three
222 > pick 08d98a8350f3 4 five
222 > pick 08d98a8350f3 4 five
223 > EOF
223 > EOF
224 abort: duplicated command for changeset eb57da33312f
224 abort: duplicated command for changeset eb57da33312f
225 [255]
225 [255]
226
226
227 Test short version of command
227 Test short version of command
228 ---------------------------------------
228 ---------------------------------------
229
229
230 Note: we use varying amounts of white space between command name and changeset
230 Note: we use varying amounts of white space between command name and changeset
231 short hash. This tests issue3893.
231 short hash. This tests issue3893.
232
232
233 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
233 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
234 > pick eb57da33312f 2 three
234 > pick eb57da33312f 2 three
235 > p c8e68270e35a 3 four
235 > p c8e68270e35a 3 four
236 > f 08d98a8350f3 4 five
236 > f 08d98a8350f3 4 five
237 > EOF
237 > EOF
238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 reverting alpha
239 reverting alpha
240 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
240 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 four
241 four
242 ***
242 ***
243 five
243 five
244
244
245
245
246
246
247 HG: Enter commit message. Lines beginning with 'HG:' are removed.
247 HG: Enter commit message. Lines beginning with 'HG:' are removed.
248 HG: Leave message empty to abort commit.
248 HG: Leave message empty to abort commit.
249 HG: --
249 HG: --
250 HG: user: test
250 HG: user: test
251 HG: branch 'default'
251 HG: branch 'default'
252 HG: changed alpha
252 HG: changed alpha
253 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
255 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/*-backup.hg (glob)
255 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/*-backup.hg (glob)
256
256
257 $ hg update -q 2
257 $ hg update -q 2
258 $ echo x > x
258 $ echo x > x
259 $ hg add x
259 $ hg add x
260 $ hg commit -m'x' x
260 $ hg commit -m'x' x
261 created new head
261 created new head
262 $ hg histedit -r 'heads(all())'
262 $ hg histedit -r 'heads(all())'
263 abort: The specified revisions must have exactly one common root
263 abort: The specified revisions must have exactly one common root
264 [255]
264 [255]
265
265
266 Test that trimming description using multi-byte characters
266 Test that trimming description using multi-byte characters
267 --------------------------------------------------------------------
267 --------------------------------------------------------------------
268
268
269 $ python <<EOF
269 $ python <<EOF
270 > fp = open('logfile', 'w')
270 > fp = open('logfile', 'w')
271 > fp.write('12345678901234567890123456789012345678901234567890' +
271 > fp.write('12345678901234567890123456789012345678901234567890' +
272 > '12345') # there are 5 more columns for 80 columns
272 > '12345') # there are 5 more columns for 80 columns
273 >
273 >
274 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
274 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
275 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
275 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
276 >
276 >
277 > fp.close()
277 > fp.close()
278 > EOF
278 > EOF
279 $ echo xx >> x
279 $ echo xx >> x
280 $ hg --encoding utf-8 commit --logfile logfile
280 $ hg --encoding utf-8 commit --logfile logfile
281
281
282 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
282 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
283 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
283 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
284
284
285 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
285 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
286 #
286 #
287 # Commits are listed from least to most recent
287 # Commits are listed from least to most recent
288 #
288 #
289 # Commands:
289 # Commands:
290 # p, pick = use commit
290 # p, pick = use commit
291 # e, edit = use commit, but stop for amending
291 # e, edit = use commit, but stop for amending
292 # f, fold = use commit, but combine it with the one above
292 # f, fold = use commit, but combine it with the one above
293 # r, roll = like fold, but discard this commit's description
293 # r, roll = like fold, but discard this commit's description
294 # d, drop = remove commit from history
294 # d, drop = remove commit from history
295 # m, mess = edit message without changing commit content
295 # m, mess = edit commit message without changing commit content
296 #
296 #
297 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
298
298
299 Test --continue with --keep
299 Test --continue with --keep
300
300
301 $ hg strip -q -r . --config extensions.strip=
301 $ hg strip -q -r . --config extensions.strip=
302 $ hg histedit '.^' -q --keep --commands - << EOF
302 $ hg histedit '.^' -q --keep --commands - << EOF
303 > edit eb57da33312f 2 three
303 > edit eb57da33312f 2 three
304 > pick f3cfcca30c44 4 x
304 > pick f3cfcca30c44 4 x
305 > EOF
305 > EOF
306 Make changes as needed, you may commit or record as needed now.
306 Make changes as needed, you may commit or record as needed now.
307 When you are finished, run hg histedit --continue to resume.
307 When you are finished, run hg histedit --continue to resume.
308 [1]
308 [1]
309 $ echo edit >> alpha
309 $ echo edit >> alpha
310 $ hg histedit -q --continue
310 $ hg histedit -q --continue
311 $ hg log -G -T '{rev}:{node|short} {desc}'
311 $ hg log -G -T '{rev}:{node|short} {desc}'
312 @ 6:8fda0c726bf2 x
312 @ 6:8fda0c726bf2 x
313 |
313 |
314 o 5:63379946892c three
314 o 5:63379946892c three
315 |
315 |
316 | o 4:f3cfcca30c44 x
316 | o 4:f3cfcca30c44 x
317 | |
317 | |
318 | | o 3:2a30f3cfee78 four
318 | | o 3:2a30f3cfee78 four
319 | |/ ***
319 | |/ ***
320 | | five
320 | | five
321 | o 2:eb57da33312f three
321 | o 2:eb57da33312f three
322 |/
322 |/
323 o 1:579e40513370 two
323 o 1:579e40513370 two
324 |
324 |
325 o 0:6058cbb6cfd7 one
325 o 0:6058cbb6cfd7 one
326
326
@@ -1,182 +1,182 b''
1 $ . "$TESTDIR/histedit-helpers.sh"
1 $ . "$TESTDIR/histedit-helpers.sh"
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
4 > [extensions]
5 > histedit=
5 > histedit=
6 > EOF
6 > EOF
7
7
8 $ hg init r
8 $ hg init r
9 $ cd r
9 $ cd r
10
10
11 $ for x in a b c d e f ; do
11 $ for x in a b c d e f ; do
12 > echo $x > $x
12 > echo $x > $x
13 > hg add $x
13 > hg add $x
14 > hg ci -m $x
14 > hg ci -m $x
15 > done
15 > done
16
16
17 $ hg book -r 1 will-move-backwards
17 $ hg book -r 1 will-move-backwards
18 $ hg book -r 2 two
18 $ hg book -r 2 two
19 $ hg book -r 2 also-two
19 $ hg book -r 2 also-two
20 $ hg book -r 3 three
20 $ hg book -r 3 three
21 $ hg book -r 4 four
21 $ hg book -r 4 four
22 $ hg book -r tip five
22 $ hg book -r tip five
23 $ hg log --graph
23 $ hg log --graph
24 @ changeset: 5:652413bf663e
24 @ changeset: 5:652413bf663e
25 | bookmark: five
25 | bookmark: five
26 | tag: tip
26 | tag: tip
27 | user: test
27 | user: test
28 | date: Thu Jan 01 00:00:00 1970 +0000
28 | date: Thu Jan 01 00:00:00 1970 +0000
29 | summary: f
29 | summary: f
30 |
30 |
31 o changeset: 4:e860deea161a
31 o changeset: 4:e860deea161a
32 | bookmark: four
32 | bookmark: four
33 | user: test
33 | user: test
34 | date: Thu Jan 01 00:00:00 1970 +0000
34 | date: Thu Jan 01 00:00:00 1970 +0000
35 | summary: e
35 | summary: e
36 |
36 |
37 o changeset: 3:055a42cdd887
37 o changeset: 3:055a42cdd887
38 | bookmark: three
38 | bookmark: three
39 | user: test
39 | user: test
40 | date: Thu Jan 01 00:00:00 1970 +0000
40 | date: Thu Jan 01 00:00:00 1970 +0000
41 | summary: d
41 | summary: d
42 |
42 |
43 o changeset: 2:177f92b77385
43 o changeset: 2:177f92b77385
44 | bookmark: also-two
44 | bookmark: also-two
45 | bookmark: two
45 | bookmark: two
46 | user: test
46 | user: test
47 | date: Thu Jan 01 00:00:00 1970 +0000
47 | date: Thu Jan 01 00:00:00 1970 +0000
48 | summary: c
48 | summary: c
49 |
49 |
50 o changeset: 1:d2ae7f538514
50 o changeset: 1:d2ae7f538514
51 | bookmark: will-move-backwards
51 | bookmark: will-move-backwards
52 | user: test
52 | user: test
53 | date: Thu Jan 01 00:00:00 1970 +0000
53 | date: Thu Jan 01 00:00:00 1970 +0000
54 | summary: b
54 | summary: b
55 |
55 |
56 o changeset: 0:cb9a9f314b8b
56 o changeset: 0:cb9a9f314b8b
57 user: test
57 user: test
58 date: Thu Jan 01 00:00:00 1970 +0000
58 date: Thu Jan 01 00:00:00 1970 +0000
59 summary: a
59 summary: a
60
60
61 $ HGEDITOR=cat hg histedit 1
61 $ HGEDITOR=cat hg histedit 1
62 pick d2ae7f538514 1 b
62 pick d2ae7f538514 1 b
63 pick 177f92b77385 2 c
63 pick 177f92b77385 2 c
64 pick 055a42cdd887 3 d
64 pick 055a42cdd887 3 d
65 pick e860deea161a 4 e
65 pick e860deea161a 4 e
66 pick 652413bf663e 5 f
66 pick 652413bf663e 5 f
67
67
68 # Edit history between d2ae7f538514 and 652413bf663e
68 # Edit history between d2ae7f538514 and 652413bf663e
69 #
69 #
70 # Commits are listed from least to most recent
70 # Commits are listed from least to most recent
71 #
71 #
72 # Commands:
72 # Commands:
73 # p, pick = use commit
73 # p, pick = use commit
74 # e, edit = use commit, but stop for amending
74 # e, edit = use commit, but stop for amending
75 # f, fold = use commit, but combine it with the one above
75 # f, fold = use commit, but combine it with the one above
76 # r, roll = like fold, but discard this commit's description
76 # r, roll = like fold, but discard this commit's description
77 # d, drop = remove commit from history
77 # d, drop = remove commit from history
78 # m, mess = edit message without changing commit content
78 # m, mess = edit commit message without changing commit content
79 #
79 #
80 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
81 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
82 > pick 177f92b77385 2 c
82 > pick 177f92b77385 2 c
83 > drop d2ae7f538514 1 b
83 > drop d2ae7f538514 1 b
84 > pick 055a42cdd887 3 d
84 > pick 055a42cdd887 3 d
85 > fold e860deea161a 4 e
85 > fold e860deea161a 4 e
86 > pick 652413bf663e 5 f
86 > pick 652413bf663e 5 f
87 > EOF
87 > EOF
88 histedit: moving bookmarks also-two from 177f92b77385 to b346ab9a313d
88 histedit: moving bookmarks also-two from 177f92b77385 to b346ab9a313d
89 histedit: moving bookmarks five from 652413bf663e to cacdfd884a93
89 histedit: moving bookmarks five from 652413bf663e to cacdfd884a93
90 histedit: moving bookmarks four from e860deea161a to 59d9f330561f
90 histedit: moving bookmarks four from e860deea161a to 59d9f330561f
91 histedit: moving bookmarks three from 055a42cdd887 to 59d9f330561f
91 histedit: moving bookmarks three from 055a42cdd887 to 59d9f330561f
92 histedit: moving bookmarks two from 177f92b77385 to b346ab9a313d
92 histedit: moving bookmarks two from 177f92b77385 to b346ab9a313d
93 histedit: moving bookmarks will-move-backwards from d2ae7f538514 to cb9a9f314b8b
93 histedit: moving bookmarks will-move-backwards from d2ae7f538514 to cb9a9f314b8b
94 saved backup bundle to $TESTTMP/r/.hg/strip-backup/d2ae7f538514-48787b8d-backup.hg (glob)
94 saved backup bundle to $TESTTMP/r/.hg/strip-backup/d2ae7f538514-48787b8d-backup.hg (glob)
95 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
95 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
96 $ hg log --graph
96 $ hg log --graph
97 @ changeset: 3:cacdfd884a93
97 @ changeset: 3:cacdfd884a93
98 | bookmark: five
98 | bookmark: five
99 | tag: tip
99 | tag: tip
100 | user: test
100 | user: test
101 | date: Thu Jan 01 00:00:00 1970 +0000
101 | date: Thu Jan 01 00:00:00 1970 +0000
102 | summary: f
102 | summary: f
103 |
103 |
104 o changeset: 2:59d9f330561f
104 o changeset: 2:59d9f330561f
105 | bookmark: four
105 | bookmark: four
106 | bookmark: three
106 | bookmark: three
107 | user: test
107 | user: test
108 | date: Thu Jan 01 00:00:00 1970 +0000
108 | date: Thu Jan 01 00:00:00 1970 +0000
109 | summary: d
109 | summary: d
110 |
110 |
111 o changeset: 1:b346ab9a313d
111 o changeset: 1:b346ab9a313d
112 | bookmark: also-two
112 | bookmark: also-two
113 | bookmark: two
113 | bookmark: two
114 | user: test
114 | user: test
115 | date: Thu Jan 01 00:00:00 1970 +0000
115 | date: Thu Jan 01 00:00:00 1970 +0000
116 | summary: c
116 | summary: c
117 |
117 |
118 o changeset: 0:cb9a9f314b8b
118 o changeset: 0:cb9a9f314b8b
119 bookmark: will-move-backwards
119 bookmark: will-move-backwards
120 user: test
120 user: test
121 date: Thu Jan 01 00:00:00 1970 +0000
121 date: Thu Jan 01 00:00:00 1970 +0000
122 summary: a
122 summary: a
123
123
124 $ HGEDITOR=cat hg histedit 1
124 $ HGEDITOR=cat hg histedit 1
125 pick b346ab9a313d 1 c
125 pick b346ab9a313d 1 c
126 pick 59d9f330561f 2 d
126 pick 59d9f330561f 2 d
127 pick cacdfd884a93 3 f
127 pick cacdfd884a93 3 f
128
128
129 # Edit history between b346ab9a313d and cacdfd884a93
129 # Edit history between b346ab9a313d and cacdfd884a93
130 #
130 #
131 # Commits are listed from least to most recent
131 # Commits are listed from least to most recent
132 #
132 #
133 # Commands:
133 # Commands:
134 # p, pick = use commit
134 # p, pick = use commit
135 # e, edit = use commit, but stop for amending
135 # e, edit = use commit, but stop for amending
136 # f, fold = use commit, but combine it with the one above
136 # f, fold = use commit, but combine it with the one above
137 # r, roll = like fold, but discard this commit's description
137 # r, roll = like fold, but discard this commit's description
138 # d, drop = remove commit from history
138 # d, drop = remove commit from history
139 # m, mess = edit message without changing commit content
139 # m, mess = edit commit message without changing commit content
140 #
140 #
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
142 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
143 > pick b346ab9a313d 1 c
143 > pick b346ab9a313d 1 c
144 > pick cacdfd884a93 3 f
144 > pick cacdfd884a93 3 f
145 > pick 59d9f330561f 2 d
145 > pick 59d9f330561f 2 d
146 > EOF
146 > EOF
147 histedit: moving bookmarks five from cacdfd884a93 to c04e50810e4b
147 histedit: moving bookmarks five from cacdfd884a93 to c04e50810e4b
148 histedit: moving bookmarks four from 59d9f330561f to c04e50810e4b
148 histedit: moving bookmarks four from 59d9f330561f to c04e50810e4b
149 histedit: moving bookmarks three from 59d9f330561f to c04e50810e4b
149 histedit: moving bookmarks three from 59d9f330561f to c04e50810e4b
150 saved backup bundle to $TESTTMP/r/.hg/strip-backup/59d9f330561f-073008af-backup.hg (glob)
150 saved backup bundle to $TESTTMP/r/.hg/strip-backup/59d9f330561f-073008af-backup.hg (glob)
151
151
152 We expect 'five' to stay at tip, since the tipmost bookmark is most
152 We expect 'five' to stay at tip, since the tipmost bookmark is most
153 likely the useful signal.
153 likely the useful signal.
154
154
155 $ hg log --graph
155 $ hg log --graph
156 @ changeset: 3:c04e50810e4b
156 @ changeset: 3:c04e50810e4b
157 | bookmark: five
157 | bookmark: five
158 | bookmark: four
158 | bookmark: four
159 | bookmark: three
159 | bookmark: three
160 | tag: tip
160 | tag: tip
161 | user: test
161 | user: test
162 | date: Thu Jan 01 00:00:00 1970 +0000
162 | date: Thu Jan 01 00:00:00 1970 +0000
163 | summary: d
163 | summary: d
164 |
164 |
165 o changeset: 2:c13eb81022ca
165 o changeset: 2:c13eb81022ca
166 | user: test
166 | user: test
167 | date: Thu Jan 01 00:00:00 1970 +0000
167 | date: Thu Jan 01 00:00:00 1970 +0000
168 | summary: f
168 | summary: f
169 |
169 |
170 o changeset: 1:b346ab9a313d
170 o changeset: 1:b346ab9a313d
171 | bookmark: also-two
171 | bookmark: also-two
172 | bookmark: two
172 | bookmark: two
173 | user: test
173 | user: test
174 | date: Thu Jan 01 00:00:00 1970 +0000
174 | date: Thu Jan 01 00:00:00 1970 +0000
175 | summary: c
175 | summary: c
176 |
176 |
177 o changeset: 0:cb9a9f314b8b
177 o changeset: 0:cb9a9f314b8b
178 bookmark: will-move-backwards
178 bookmark: will-move-backwards
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:00 1970 +0000
180 date: Thu Jan 01 00:00:00 1970 +0000
181 summary: a
181 summary: a
182
182
@@ -1,459 +1,459 b''
1 $ . "$TESTDIR/histedit-helpers.sh"
1 $ . "$TESTDIR/histedit-helpers.sh"
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
4 > [extensions]
5 > histedit=
5 > histedit=
6 > EOF
6 > EOF
7
7
8 $ initrepo ()
8 $ initrepo ()
9 > {
9 > {
10 > hg init r
10 > hg init r
11 > cd r
11 > cd r
12 > for x in a b c d e f ; do
12 > for x in a b c d e f ; do
13 > echo $x > $x
13 > echo $x > $x
14 > hg add $x
14 > hg add $x
15 > hg ci -m $x
15 > hg ci -m $x
16 > done
16 > done
17 > }
17 > }
18
18
19 $ initrepo
19 $ initrepo
20
20
21 log before edit
21 log before edit
22 $ hg log --graph
22 $ hg log --graph
23 @ changeset: 5:652413bf663e
23 @ changeset: 5:652413bf663e
24 | tag: tip
24 | tag: tip
25 | user: test
25 | user: test
26 | date: Thu Jan 01 00:00:00 1970 +0000
26 | date: Thu Jan 01 00:00:00 1970 +0000
27 | summary: f
27 | summary: f
28 |
28 |
29 o changeset: 4:e860deea161a
29 o changeset: 4:e860deea161a
30 | user: test
30 | user: test
31 | date: Thu Jan 01 00:00:00 1970 +0000
31 | date: Thu Jan 01 00:00:00 1970 +0000
32 | summary: e
32 | summary: e
33 |
33 |
34 o changeset: 3:055a42cdd887
34 o changeset: 3:055a42cdd887
35 | user: test
35 | user: test
36 | date: Thu Jan 01 00:00:00 1970 +0000
36 | date: Thu Jan 01 00:00:00 1970 +0000
37 | summary: d
37 | summary: d
38 |
38 |
39 o changeset: 2:177f92b77385
39 o changeset: 2:177f92b77385
40 | user: test
40 | user: test
41 | date: Thu Jan 01 00:00:00 1970 +0000
41 | date: Thu Jan 01 00:00:00 1970 +0000
42 | summary: c
42 | summary: c
43 |
43 |
44 o changeset: 1:d2ae7f538514
44 o changeset: 1:d2ae7f538514
45 | user: test
45 | user: test
46 | date: Thu Jan 01 00:00:00 1970 +0000
46 | date: Thu Jan 01 00:00:00 1970 +0000
47 | summary: b
47 | summary: b
48 |
48 |
49 o changeset: 0:cb9a9f314b8b
49 o changeset: 0:cb9a9f314b8b
50 user: test
50 user: test
51 date: Thu Jan 01 00:00:00 1970 +0000
51 date: Thu Jan 01 00:00:00 1970 +0000
52 summary: a
52 summary: a
53
53
54
54
55 show the edit commands offered
55 show the edit commands offered
56 $ HGEDITOR=cat hg histedit 177f92b77385
56 $ HGEDITOR=cat hg histedit 177f92b77385
57 pick 177f92b77385 2 c
57 pick 177f92b77385 2 c
58 pick 055a42cdd887 3 d
58 pick 055a42cdd887 3 d
59 pick e860deea161a 4 e
59 pick e860deea161a 4 e
60 pick 652413bf663e 5 f
60 pick 652413bf663e 5 f
61
61
62 # Edit history between 177f92b77385 and 652413bf663e
62 # Edit history between 177f92b77385 and 652413bf663e
63 #
63 #
64 # Commits are listed from least to most recent
64 # Commits are listed from least to most recent
65 #
65 #
66 # Commands:
66 # Commands:
67 # p, pick = use commit
67 # p, pick = use commit
68 # e, edit = use commit, but stop for amending
68 # e, edit = use commit, but stop for amending
69 # f, fold = use commit, but combine it with the one above
69 # f, fold = use commit, but combine it with the one above
70 # r, roll = like fold, but discard this commit's description
70 # r, roll = like fold, but discard this commit's description
71 # d, drop = remove commit from history
71 # d, drop = remove commit from history
72 # m, mess = edit message without changing commit content
72 # m, mess = edit commit message without changing commit content
73 #
73 #
74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
75
75
76 edit the history
76 edit the history
77 (use a hacky editor to check histedit-last-edit.txt backup)
77 (use a hacky editor to check histedit-last-edit.txt backup)
78
78
79 $ EDITED="$TESTTMP/editedhistory"
79 $ EDITED="$TESTTMP/editedhistory"
80 $ cat > $EDITED <<EOF
80 $ cat > $EDITED <<EOF
81 > pick 177f92b77385 c
81 > pick 177f92b77385 c
82 > pick e860deea161a e
82 > pick e860deea161a e
83 > pick 652413bf663e f
83 > pick 652413bf663e f
84 > pick 055a42cdd887 d
84 > pick 055a42cdd887 d
85 > EOF
85 > EOF
86 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
86 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
87 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
87 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
91
91
92 rules should end up in .hg/histedit-last-edit.txt:
92 rules should end up in .hg/histedit-last-edit.txt:
93 $ cat .hg/histedit-last-edit.txt
93 $ cat .hg/histedit-last-edit.txt
94 pick 177f92b77385 c
94 pick 177f92b77385 c
95 pick e860deea161a e
95 pick e860deea161a e
96 pick 652413bf663e f
96 pick 652413bf663e f
97 pick 055a42cdd887 d
97 pick 055a42cdd887 d
98
98
99 log after edit
99 log after edit
100 $ hg log --graph
100 $ hg log --graph
101 @ changeset: 5:07114f51870f
101 @ changeset: 5:07114f51870f
102 | tag: tip
102 | tag: tip
103 | user: test
103 | user: test
104 | date: Thu Jan 01 00:00:00 1970 +0000
104 | date: Thu Jan 01 00:00:00 1970 +0000
105 | summary: d
105 | summary: d
106 |
106 |
107 o changeset: 4:8ade9693061e
107 o changeset: 4:8ade9693061e
108 | user: test
108 | user: test
109 | date: Thu Jan 01 00:00:00 1970 +0000
109 | date: Thu Jan 01 00:00:00 1970 +0000
110 | summary: f
110 | summary: f
111 |
111 |
112 o changeset: 3:d8249471110a
112 o changeset: 3:d8249471110a
113 | user: test
113 | user: test
114 | date: Thu Jan 01 00:00:00 1970 +0000
114 | date: Thu Jan 01 00:00:00 1970 +0000
115 | summary: e
115 | summary: e
116 |
116 |
117 o changeset: 2:177f92b77385
117 o changeset: 2:177f92b77385
118 | user: test
118 | user: test
119 | date: Thu Jan 01 00:00:00 1970 +0000
119 | date: Thu Jan 01 00:00:00 1970 +0000
120 | summary: c
120 | summary: c
121 |
121 |
122 o changeset: 1:d2ae7f538514
122 o changeset: 1:d2ae7f538514
123 | user: test
123 | user: test
124 | date: Thu Jan 01 00:00:00 1970 +0000
124 | date: Thu Jan 01 00:00:00 1970 +0000
125 | summary: b
125 | summary: b
126 |
126 |
127 o changeset: 0:cb9a9f314b8b
127 o changeset: 0:cb9a9f314b8b
128 user: test
128 user: test
129 date: Thu Jan 01 00:00:00 1970 +0000
129 date: Thu Jan 01 00:00:00 1970 +0000
130 summary: a
130 summary: a
131
131
132
132
133 put things back
133 put things back
134
134
135 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
135 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
136 > pick 177f92b77385 c
136 > pick 177f92b77385 c
137 > pick 07114f51870f d
137 > pick 07114f51870f d
138 > pick d8249471110a e
138 > pick d8249471110a e
139 > pick 8ade9693061e f
139 > pick 8ade9693061e f
140 > EOF
140 > EOF
141 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
141 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
142 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145
145
146 $ hg log --graph
146 $ hg log --graph
147 @ changeset: 5:7eca9b5b1148
147 @ changeset: 5:7eca9b5b1148
148 | tag: tip
148 | tag: tip
149 | user: test
149 | user: test
150 | date: Thu Jan 01 00:00:00 1970 +0000
150 | date: Thu Jan 01 00:00:00 1970 +0000
151 | summary: f
151 | summary: f
152 |
152 |
153 o changeset: 4:915da888f2de
153 o changeset: 4:915da888f2de
154 | user: test
154 | user: test
155 | date: Thu Jan 01 00:00:00 1970 +0000
155 | date: Thu Jan 01 00:00:00 1970 +0000
156 | summary: e
156 | summary: e
157 |
157 |
158 o changeset: 3:10517e47bbbb
158 o changeset: 3:10517e47bbbb
159 | user: test
159 | user: test
160 | date: Thu Jan 01 00:00:00 1970 +0000
160 | date: Thu Jan 01 00:00:00 1970 +0000
161 | summary: d
161 | summary: d
162 |
162 |
163 o changeset: 2:177f92b77385
163 o changeset: 2:177f92b77385
164 | user: test
164 | user: test
165 | date: Thu Jan 01 00:00:00 1970 +0000
165 | date: Thu Jan 01 00:00:00 1970 +0000
166 | summary: c
166 | summary: c
167 |
167 |
168 o changeset: 1:d2ae7f538514
168 o changeset: 1:d2ae7f538514
169 | user: test
169 | user: test
170 | date: Thu Jan 01 00:00:00 1970 +0000
170 | date: Thu Jan 01 00:00:00 1970 +0000
171 | summary: b
171 | summary: b
172 |
172 |
173 o changeset: 0:cb9a9f314b8b
173 o changeset: 0:cb9a9f314b8b
174 user: test
174 user: test
175 date: Thu Jan 01 00:00:00 1970 +0000
175 date: Thu Jan 01 00:00:00 1970 +0000
176 summary: a
176 summary: a
177
177
178
178
179 slightly different this time
179 slightly different this time
180
180
181 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
181 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
182 > pick 10517e47bbbb d
182 > pick 10517e47bbbb d
183 > pick 7eca9b5b1148 f
183 > pick 7eca9b5b1148 f
184 > pick 915da888f2de e
184 > pick 915da888f2de e
185 > pick 177f92b77385 c
185 > pick 177f92b77385 c
186 > EOF
186 > EOF
187 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
187 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
188 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
188 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 $ hg log --graph
192 $ hg log --graph
193 @ changeset: 5:38b92f448761
193 @ changeset: 5:38b92f448761
194 | tag: tip
194 | tag: tip
195 | user: test
195 | user: test
196 | date: Thu Jan 01 00:00:00 1970 +0000
196 | date: Thu Jan 01 00:00:00 1970 +0000
197 | summary: c
197 | summary: c
198 |
198 |
199 o changeset: 4:de71b079d9ce
199 o changeset: 4:de71b079d9ce
200 | user: test
200 | user: test
201 | date: Thu Jan 01 00:00:00 1970 +0000
201 | date: Thu Jan 01 00:00:00 1970 +0000
202 | summary: e
202 | summary: e
203 |
203 |
204 o changeset: 3:be9ae3a309c6
204 o changeset: 3:be9ae3a309c6
205 | user: test
205 | user: test
206 | date: Thu Jan 01 00:00:00 1970 +0000
206 | date: Thu Jan 01 00:00:00 1970 +0000
207 | summary: f
207 | summary: f
208 |
208 |
209 o changeset: 2:799205341b6b
209 o changeset: 2:799205341b6b
210 | user: test
210 | user: test
211 | date: Thu Jan 01 00:00:00 1970 +0000
211 | date: Thu Jan 01 00:00:00 1970 +0000
212 | summary: d
212 | summary: d
213 |
213 |
214 o changeset: 1:d2ae7f538514
214 o changeset: 1:d2ae7f538514
215 | user: test
215 | user: test
216 | date: Thu Jan 01 00:00:00 1970 +0000
216 | date: Thu Jan 01 00:00:00 1970 +0000
217 | summary: b
217 | summary: b
218 |
218 |
219 o changeset: 0:cb9a9f314b8b
219 o changeset: 0:cb9a9f314b8b
220 user: test
220 user: test
221 date: Thu Jan 01 00:00:00 1970 +0000
221 date: Thu Jan 01 00:00:00 1970 +0000
222 summary: a
222 summary: a
223
223
224
224
225 keep prevents stripping dead revs
225 keep prevents stripping dead revs
226 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
226 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
227 > pick 799205341b6b d
227 > pick 799205341b6b d
228 > pick be9ae3a309c6 f
228 > pick be9ae3a309c6 f
229 > pick 38b92f448761 c
229 > pick 38b92f448761 c
230 > pick de71b079d9ce e
230 > pick de71b079d9ce e
231 > EOF
231 > EOF
232 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
232 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
233 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 $ hg log --graph
235 $ hg log --graph
236 @ changeset: 7:803ef1c6fcfd
236 @ changeset: 7:803ef1c6fcfd
237 | tag: tip
237 | tag: tip
238 | user: test
238 | user: test
239 | date: Thu Jan 01 00:00:00 1970 +0000
239 | date: Thu Jan 01 00:00:00 1970 +0000
240 | summary: e
240 | summary: e
241 |
241 |
242 o changeset: 6:ece0b8d93dda
242 o changeset: 6:ece0b8d93dda
243 | parent: 3:be9ae3a309c6
243 | parent: 3:be9ae3a309c6
244 | user: test
244 | user: test
245 | date: Thu Jan 01 00:00:00 1970 +0000
245 | date: Thu Jan 01 00:00:00 1970 +0000
246 | summary: c
246 | summary: c
247 |
247 |
248 | o changeset: 5:38b92f448761
248 | o changeset: 5:38b92f448761
249 | | user: test
249 | | user: test
250 | | date: Thu Jan 01 00:00:00 1970 +0000
250 | | date: Thu Jan 01 00:00:00 1970 +0000
251 | | summary: c
251 | | summary: c
252 | |
252 | |
253 | o changeset: 4:de71b079d9ce
253 | o changeset: 4:de71b079d9ce
254 |/ user: test
254 |/ user: test
255 | date: Thu Jan 01 00:00:00 1970 +0000
255 | date: Thu Jan 01 00:00:00 1970 +0000
256 | summary: e
256 | summary: e
257 |
257 |
258 o changeset: 3:be9ae3a309c6
258 o changeset: 3:be9ae3a309c6
259 | user: test
259 | user: test
260 | date: Thu Jan 01 00:00:00 1970 +0000
260 | date: Thu Jan 01 00:00:00 1970 +0000
261 | summary: f
261 | summary: f
262 |
262 |
263 o changeset: 2:799205341b6b
263 o changeset: 2:799205341b6b
264 | user: test
264 | user: test
265 | date: Thu Jan 01 00:00:00 1970 +0000
265 | date: Thu Jan 01 00:00:00 1970 +0000
266 | summary: d
266 | summary: d
267 |
267 |
268 o changeset: 1:d2ae7f538514
268 o changeset: 1:d2ae7f538514
269 | user: test
269 | user: test
270 | date: Thu Jan 01 00:00:00 1970 +0000
270 | date: Thu Jan 01 00:00:00 1970 +0000
271 | summary: b
271 | summary: b
272 |
272 |
273 o changeset: 0:cb9a9f314b8b
273 o changeset: 0:cb9a9f314b8b
274 user: test
274 user: test
275 date: Thu Jan 01 00:00:00 1970 +0000
275 date: Thu Jan 01 00:00:00 1970 +0000
276 summary: a
276 summary: a
277
277
278
278
279 try with --rev
279 try with --rev
280 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
280 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
281 > pick de71b079d9ce e
281 > pick de71b079d9ce e
282 > pick 38b92f448761 c
282 > pick 38b92f448761 c
283 > EOF
283 > EOF
284 abort: may not use changesets other than the ones listed
284 abort: may not use changesets other than the ones listed
285 $ hg log --graph
285 $ hg log --graph
286 @ changeset: 7:803ef1c6fcfd
286 @ changeset: 7:803ef1c6fcfd
287 | tag: tip
287 | tag: tip
288 | user: test
288 | user: test
289 | date: Thu Jan 01 00:00:00 1970 +0000
289 | date: Thu Jan 01 00:00:00 1970 +0000
290 | summary: e
290 | summary: e
291 |
291 |
292 o changeset: 6:ece0b8d93dda
292 o changeset: 6:ece0b8d93dda
293 | parent: 3:be9ae3a309c6
293 | parent: 3:be9ae3a309c6
294 | user: test
294 | user: test
295 | date: Thu Jan 01 00:00:00 1970 +0000
295 | date: Thu Jan 01 00:00:00 1970 +0000
296 | summary: c
296 | summary: c
297 |
297 |
298 | o changeset: 5:38b92f448761
298 | o changeset: 5:38b92f448761
299 | | user: test
299 | | user: test
300 | | date: Thu Jan 01 00:00:00 1970 +0000
300 | | date: Thu Jan 01 00:00:00 1970 +0000
301 | | summary: c
301 | | summary: c
302 | |
302 | |
303 | o changeset: 4:de71b079d9ce
303 | o changeset: 4:de71b079d9ce
304 |/ user: test
304 |/ user: test
305 | date: Thu Jan 01 00:00:00 1970 +0000
305 | date: Thu Jan 01 00:00:00 1970 +0000
306 | summary: e
306 | summary: e
307 |
307 |
308 o changeset: 3:be9ae3a309c6
308 o changeset: 3:be9ae3a309c6
309 | user: test
309 | user: test
310 | date: Thu Jan 01 00:00:00 1970 +0000
310 | date: Thu Jan 01 00:00:00 1970 +0000
311 | summary: f
311 | summary: f
312 |
312 |
313 o changeset: 2:799205341b6b
313 o changeset: 2:799205341b6b
314 | user: test
314 | user: test
315 | date: Thu Jan 01 00:00:00 1970 +0000
315 | date: Thu Jan 01 00:00:00 1970 +0000
316 | summary: d
316 | summary: d
317 |
317 |
318 o changeset: 1:d2ae7f538514
318 o changeset: 1:d2ae7f538514
319 | user: test
319 | user: test
320 | date: Thu Jan 01 00:00:00 1970 +0000
320 | date: Thu Jan 01 00:00:00 1970 +0000
321 | summary: b
321 | summary: b
322 |
322 |
323 o changeset: 0:cb9a9f314b8b
323 o changeset: 0:cb9a9f314b8b
324 user: test
324 user: test
325 date: Thu Jan 01 00:00:00 1970 +0000
325 date: Thu Jan 01 00:00:00 1970 +0000
326 summary: a
326 summary: a
327
327
328 Verify that revsetalias entries work with histedit:
328 Verify that revsetalias entries work with histedit:
329 $ cat >> $HGRCPATH <<EOF
329 $ cat >> $HGRCPATH <<EOF
330 > [revsetalias]
330 > [revsetalias]
331 > grandparent(ARG) = p1(p1(ARG))
331 > grandparent(ARG) = p1(p1(ARG))
332 > EOF
332 > EOF
333 $ echo extra commit >> c
333 $ echo extra commit >> c
334 $ hg ci -m 'extra commit to c'
334 $ hg ci -m 'extra commit to c'
335 $ HGEDITOR=cat hg histedit 'grandparent(.)'
335 $ HGEDITOR=cat hg histedit 'grandparent(.)'
336 pick ece0b8d93dda 6 c
336 pick ece0b8d93dda 6 c
337 pick 803ef1c6fcfd 7 e
337 pick 803ef1c6fcfd 7 e
338 pick 9c863c565126 8 extra commit to c
338 pick 9c863c565126 8 extra commit to c
339
339
340 # Edit history between ece0b8d93dda and 9c863c565126
340 # Edit history between ece0b8d93dda and 9c863c565126
341 #
341 #
342 # Commits are listed from least to most recent
342 # Commits are listed from least to most recent
343 #
343 #
344 # Commands:
344 # Commands:
345 # p, pick = use commit
345 # p, pick = use commit
346 # e, edit = use commit, but stop for amending
346 # e, edit = use commit, but stop for amending
347 # f, fold = use commit, but combine it with the one above
347 # f, fold = use commit, but combine it with the one above
348 # r, roll = like fold, but discard this commit's description
348 # r, roll = like fold, but discard this commit's description
349 # d, drop = remove commit from history
349 # d, drop = remove commit from history
350 # m, mess = edit message without changing commit content
350 # m, mess = edit commit message without changing commit content
351 #
351 #
352 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
353
353
354 should also work if a commit message is missing
354 should also work if a commit message is missing
355 $ BUNDLE="$TESTDIR/missing-comment.hg"
355 $ BUNDLE="$TESTDIR/missing-comment.hg"
356 $ hg init missing
356 $ hg init missing
357 $ cd missing
357 $ cd missing
358 $ hg unbundle $BUNDLE
358 $ hg unbundle $BUNDLE
359 adding changesets
359 adding changesets
360 adding manifests
360 adding manifests
361 adding file changes
361 adding file changes
362 added 3 changesets with 3 changes to 1 files
362 added 3 changesets with 3 changes to 1 files
363 (run 'hg update' to get a working copy)
363 (run 'hg update' to get a working copy)
364 $ hg co tip
364 $ hg co tip
365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 $ hg log --graph
366 $ hg log --graph
367 @ changeset: 2:bd22688093b3
367 @ changeset: 2:bd22688093b3
368 | tag: tip
368 | tag: tip
369 | user: Robert Altman <robert.altman@telventDTN.com>
369 | user: Robert Altman <robert.altman@telventDTN.com>
370 | date: Mon Nov 28 16:40:04 2011 +0000
370 | date: Mon Nov 28 16:40:04 2011 +0000
371 | summary: Update file.
371 | summary: Update file.
372 |
372 |
373 o changeset: 1:3b3e956f9171
373 o changeset: 1:3b3e956f9171
374 | user: Robert Altman <robert.altman@telventDTN.com>
374 | user: Robert Altman <robert.altman@telventDTN.com>
375 | date: Mon Nov 28 16:37:57 2011 +0000
375 | date: Mon Nov 28 16:37:57 2011 +0000
376 |
376 |
377 o changeset: 0:141947992243
377 o changeset: 0:141947992243
378 user: Robert Altman <robert.altman@telventDTN.com>
378 user: Robert Altman <robert.altman@telventDTN.com>
379 date: Mon Nov 28 16:35:28 2011 +0000
379 date: Mon Nov 28 16:35:28 2011 +0000
380 summary: Checked in text file
380 summary: Checked in text file
381
381
382 $ hg histedit 0
382 $ hg histedit 0
383 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
383 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 $ cd ..
384 $ cd ..
385
385
386 $ cd ..
386 $ cd ..
387
387
388
388
389 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
389 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
390 $ hg init issue4251
390 $ hg init issue4251
391 $ cd issue4251
391 $ cd issue4251
392
392
393 $ mkdir initial-dir
393 $ mkdir initial-dir
394 $ echo foo > initial-dir/initial-file
394 $ echo foo > initial-dir/initial-file
395 $ hg add initial-dir/initial-file
395 $ hg add initial-dir/initial-file
396 $ hg commit -m "initial commit"
396 $ hg commit -m "initial commit"
397
397
398 Move the file to a new directory, and in the same commit, change its content:
398 Move the file to a new directory, and in the same commit, change its content:
399 $ mkdir another-dir
399 $ mkdir another-dir
400 $ hg mv initial-dir/initial-file another-dir/
400 $ hg mv initial-dir/initial-file another-dir/
401 $ echo changed > another-dir/initial-file
401 $ echo changed > another-dir/initial-file
402 $ hg commit -m "moved and changed"
402 $ hg commit -m "moved and changed"
403
403
404 Rename the file:
404 Rename the file:
405 $ hg mv another-dir/initial-file another-dir/renamed-file
405 $ hg mv another-dir/initial-file another-dir/renamed-file
406 $ hg commit -m "renamed"
406 $ hg commit -m "renamed"
407
407
408 Now, let's try to fold the second commit into the first:
408 Now, let's try to fold the second commit into the first:
409 $ cat > editor.sh <<EOF
409 $ cat > editor.sh <<EOF
410 > #!/bin/sh
410 > #!/bin/sh
411 > cat > \$1 <<ENDOF
411 > cat > \$1 <<ENDOF
412 > pick b0f4233702ca 0 initial commit
412 > pick b0f4233702ca 0 initial commit
413 > fold 5e8704a8f2d2 1 moved and changed
413 > fold 5e8704a8f2d2 1 moved and changed
414 > pick 40e7299e8fa7 2 renamed
414 > pick 40e7299e8fa7 2 renamed
415 > ENDOF
415 > ENDOF
416 > EOF
416 > EOF
417
417
418 $ HGEDITOR="sh ./editor.sh" hg histedit 0
418 $ HGEDITOR="sh ./editor.sh" hg histedit 0
419 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 adding another-dir/initial-file (glob)
420 adding another-dir/initial-file (glob)
421 removing initial-dir/initial-file (glob)
421 removing initial-dir/initial-file (glob)
422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
426 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
427
427
428 $ hg --config diff.git=yes export 0
428 $ hg --config diff.git=yes export 0
429 # HG changeset patch
429 # HG changeset patch
430 # User test
430 # User test
431 # Date 0 0
431 # Date 0 0
432 # Thu Jan 01 00:00:00 1970 +0000
432 # Thu Jan 01 00:00:00 1970 +0000
433 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
433 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
434 # Parent 0000000000000000000000000000000000000000
434 # Parent 0000000000000000000000000000000000000000
435 pick b0f4233702ca 0 initial commit
435 pick b0f4233702ca 0 initial commit
436 fold 5e8704a8f2d2 1 moved and changed
436 fold 5e8704a8f2d2 1 moved and changed
437 pick 40e7299e8fa7 2 renamed
437 pick 40e7299e8fa7 2 renamed
438
438
439 diff --git a/another-dir/initial-file b/another-dir/initial-file
439 diff --git a/another-dir/initial-file b/another-dir/initial-file
440 new file mode 100644
440 new file mode 100644
441 --- /dev/null
441 --- /dev/null
442 +++ b/another-dir/initial-file
442 +++ b/another-dir/initial-file
443 @@ -0,0 +1,1 @@
443 @@ -0,0 +1,1 @@
444 +changed
444 +changed
445
445
446 $ hg --config diff.git=yes export 1
446 $ hg --config diff.git=yes export 1
447 # HG changeset patch
447 # HG changeset patch
448 # User test
448 # User test
449 # Date 0 0
449 # Date 0 0
450 # Thu Jan 01 00:00:00 1970 +0000
450 # Thu Jan 01 00:00:00 1970 +0000
451 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
451 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
452 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
452 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
453 renamed
453 renamed
454
454
455 diff --git a/another-dir/initial-file b/another-dir/renamed-file
455 diff --git a/another-dir/initial-file b/another-dir/renamed-file
456 rename from another-dir/initial-file
456 rename from another-dir/initial-file
457 rename to another-dir/renamed-file
457 rename to another-dir/renamed-file
458
458
459 $ cd ..
459 $ cd ..
@@ -1,460 +1,460 b''
1 $ . "$TESTDIR/histedit-helpers.sh"
1 $ . "$TESTDIR/histedit-helpers.sh"
2
2
3 Enable obsolete
3 Enable obsolete
4
4
5 $ cat >> $HGRCPATH << EOF
5 $ cat >> $HGRCPATH << EOF
6 > [ui]
6 > [ui]
7 > logtemplate= {rev}:{node|short} {desc|firstline}
7 > logtemplate= {rev}:{node|short} {desc|firstline}
8 > [phases]
8 > [phases]
9 > publish=False
9 > publish=False
10 > [experimental]
10 > [experimental]
11 > evolution=createmarkers,allowunstable
11 > evolution=createmarkers,allowunstable
12 > [extensions]
12 > [extensions]
13 > histedit=
13 > histedit=
14 > rebase=
14 > rebase=
15 > EOF
15 > EOF
16
16
17 $ hg init base
17 $ hg init base
18 $ cd base
18 $ cd base
19
19
20 $ for x in a b c d e f ; do
20 $ for x in a b c d e f ; do
21 > echo $x > $x
21 > echo $x > $x
22 > hg add $x
22 > hg add $x
23 > hg ci -m $x
23 > hg ci -m $x
24 > done
24 > done
25
25
26 $ hg log --graph
26 $ hg log --graph
27 @ 5:652413bf663e f
27 @ 5:652413bf663e f
28 |
28 |
29 o 4:e860deea161a e
29 o 4:e860deea161a e
30 |
30 |
31 o 3:055a42cdd887 d
31 o 3:055a42cdd887 d
32 |
32 |
33 o 2:177f92b77385 c
33 o 2:177f92b77385 c
34 |
34 |
35 o 1:d2ae7f538514 b
35 o 1:d2ae7f538514 b
36 |
36 |
37 o 0:cb9a9f314b8b a
37 o 0:cb9a9f314b8b a
38
38
39
39
40 $ HGEDITOR=cat hg histedit 1
40 $ HGEDITOR=cat hg histedit 1
41 pick d2ae7f538514 1 b
41 pick d2ae7f538514 1 b
42 pick 177f92b77385 2 c
42 pick 177f92b77385 2 c
43 pick 055a42cdd887 3 d
43 pick 055a42cdd887 3 d
44 pick e860deea161a 4 e
44 pick e860deea161a 4 e
45 pick 652413bf663e 5 f
45 pick 652413bf663e 5 f
46
46
47 # Edit history between d2ae7f538514 and 652413bf663e
47 # Edit history between d2ae7f538514 and 652413bf663e
48 #
48 #
49 # Commits are listed from least to most recent
49 # Commits are listed from least to most recent
50 #
50 #
51 # Commands:
51 # Commands:
52 # p, pick = use commit
52 # p, pick = use commit
53 # e, edit = use commit, but stop for amending
53 # e, edit = use commit, but stop for amending
54 # f, fold = use commit, but combine it with the one above
54 # f, fold = use commit, but combine it with the one above
55 # r, roll = like fold, but discard this commit's description
55 # r, roll = like fold, but discard this commit's description
56 # d, drop = remove commit from history
56 # d, drop = remove commit from history
57 # m, mess = edit message without changing commit content
57 # m, mess = edit commit message without changing commit content
58 #
58 #
59 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
60 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
61 > pick 177f92b77385 2 c
61 > pick 177f92b77385 2 c
62 > drop d2ae7f538514 1 b
62 > drop d2ae7f538514 1 b
63 > pick 055a42cdd887 3 d
63 > pick 055a42cdd887 3 d
64 > fold e860deea161a 4 e
64 > fold e860deea161a 4 e
65 > pick 652413bf663e 5 f
65 > pick 652413bf663e 5 f
66 > EOF
66 > EOF
67 saved backup bundle to $TESTTMP/base/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
67 saved backup bundle to $TESTTMP/base/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
68 $ hg log --graph --hidden
68 $ hg log --graph --hidden
69 @ 8:cacdfd884a93 f
69 @ 8:cacdfd884a93 f
70 |
70 |
71 o 7:59d9f330561f d
71 o 7:59d9f330561f d
72 |
72 |
73 o 6:b346ab9a313d c
73 o 6:b346ab9a313d c
74 |
74 |
75 | x 5:652413bf663e f
75 | x 5:652413bf663e f
76 | |
76 | |
77 | x 4:e860deea161a e
77 | x 4:e860deea161a e
78 | |
78 | |
79 | x 3:055a42cdd887 d
79 | x 3:055a42cdd887 d
80 | |
80 | |
81 | x 2:177f92b77385 c
81 | x 2:177f92b77385 c
82 | |
82 | |
83 | x 1:d2ae7f538514 b
83 | x 1:d2ae7f538514 b
84 |/
84 |/
85 o 0:cb9a9f314b8b a
85 o 0:cb9a9f314b8b a
86
86
87 $ hg debugobsolete
87 $ hg debugobsolete
88 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob)
88 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob)
89 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob)
89 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob)
90 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
90 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
91 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
91 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
92 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob)
92 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob)
93
93
94
94
95 Ensure hidden revision does not prevent histedit
95 Ensure hidden revision does not prevent histedit
96 -------------------------------------------------
96 -------------------------------------------------
97
97
98 create an hidden revision
98 create an hidden revision
99
99
100 $ hg histedit 6 --commands - << EOF
100 $ hg histedit 6 --commands - << EOF
101 > pick b346ab9a313d 6 c
101 > pick b346ab9a313d 6 c
102 > drop 59d9f330561f 7 d
102 > drop 59d9f330561f 7 d
103 > pick cacdfd884a93 8 f
103 > pick cacdfd884a93 8 f
104 > EOF
104 > EOF
105 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
105 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
106 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 $ hg log --graph
107 $ hg log --graph
108 @ 9:c13eb81022ca f
108 @ 9:c13eb81022ca f
109 |
109 |
110 o 6:b346ab9a313d c
110 o 6:b346ab9a313d c
111 |
111 |
112 o 0:cb9a9f314b8b a
112 o 0:cb9a9f314b8b a
113
113
114 check hidden revision are ignored (6 have hidden children 7 and 8)
114 check hidden revision are ignored (6 have hidden children 7 and 8)
115
115
116 $ hg histedit 6 --commands - << EOF
116 $ hg histedit 6 --commands - << EOF
117 > pick b346ab9a313d 6 c
117 > pick b346ab9a313d 6 c
118 > pick c13eb81022ca 8 f
118 > pick c13eb81022ca 8 f
119 > EOF
119 > EOF
120 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
121
121
122
122
123
123
124 Test that rewriting leaving instability behind is allowed
124 Test that rewriting leaving instability behind is allowed
125 ---------------------------------------------------------------------
125 ---------------------------------------------------------------------
126
126
127 $ hg up '.^'
127 $ hg up '.^'
128 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
128 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
129 $ hg log -r 'children(.)'
129 $ hg log -r 'children(.)'
130 9:c13eb81022ca f (no-eol)
130 9:c13eb81022ca f (no-eol)
131 $ hg histedit -r '.' --commands - <<EOF
131 $ hg histedit -r '.' --commands - <<EOF
132 > edit b346ab9a313d 6 c
132 > edit b346ab9a313d 6 c
133 > EOF
133 > EOF
134 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
134 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
135 adding c
135 adding c
136 Make changes as needed, you may commit or record as needed now.
136 Make changes as needed, you may commit or record as needed now.
137 When you are finished, run hg histedit --continue to resume.
137 When you are finished, run hg histedit --continue to resume.
138 [1]
138 [1]
139 $ echo c >> c
139 $ echo c >> c
140 $ hg histedit --continue
140 $ hg histedit --continue
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142
142
143 $ hg log -r 'unstable()'
143 $ hg log -r 'unstable()'
144 9:c13eb81022ca f (no-eol)
144 9:c13eb81022ca f (no-eol)
145
145
146 stabilise
146 stabilise
147
147
148 $ hg rebase -r 'unstable()' -d .
148 $ hg rebase -r 'unstable()' -d .
149 rebasing 9:c13eb81022ca "f"
149 rebasing 9:c13eb81022ca "f"
150 $ hg up tip -q
150 $ hg up tip -q
151
151
152 Test dropping of changeset on the top of the stack
152 Test dropping of changeset on the top of the stack
153 -------------------------------------------------------
153 -------------------------------------------------------
154
154
155 Nothing is rewritten below, the working directory parent must be change for the
155 Nothing is rewritten below, the working directory parent must be change for the
156 dropped changeset to be hidden.
156 dropped changeset to be hidden.
157
157
158 $ cd ..
158 $ cd ..
159 $ hg clone base droplast
159 $ hg clone base droplast
160 updating to branch default
160 updating to branch default
161 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 $ cd droplast
162 $ cd droplast
163 $ hg histedit -r '40db8afa467b' --commands - << EOF
163 $ hg histedit -r '40db8afa467b' --commands - << EOF
164 > pick 40db8afa467b 10 c
164 > pick 40db8afa467b 10 c
165 > drop b449568bf7fc 11 f
165 > drop b449568bf7fc 11 f
166 > EOF
166 > EOF
167 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
167 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
168 $ hg log -G
168 $ hg log -G
169 @ 10:40db8afa467b c
169 @ 10:40db8afa467b c
170 |
170 |
171 o 0:cb9a9f314b8b a
171 o 0:cb9a9f314b8b a
172
172
173
173
174 With rewritten ancestors
174 With rewritten ancestors
175
175
176 $ echo e > e
176 $ echo e > e
177 $ hg add e
177 $ hg add e
178 $ hg commit -m g
178 $ hg commit -m g
179 $ echo f > f
179 $ echo f > f
180 $ hg add f
180 $ hg add f
181 $ hg commit -m h
181 $ hg commit -m h
182 $ hg histedit -r '40db8afa467b' --commands - << EOF
182 $ hg histedit -r '40db8afa467b' --commands - << EOF
183 > pick 47a8561c0449 12 g
183 > pick 47a8561c0449 12 g
184 > pick 40db8afa467b 10 c
184 > pick 40db8afa467b 10 c
185 > drop 1b3b05f35ff0 13 h
185 > drop 1b3b05f35ff0 13 h
186 > EOF
186 > EOF
187 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
187 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
188 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
188 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 $ hg log -G
190 $ hg log -G
191 @ 15:ee6544123ab8 c
191 @ 15:ee6544123ab8 c
192 |
192 |
193 o 14:269e713e9eae g
193 o 14:269e713e9eae g
194 |
194 |
195 o 0:cb9a9f314b8b a
195 o 0:cb9a9f314b8b a
196
196
197 $ cd ../base
197 $ cd ../base
198
198
199
199
200
200
201 Test phases support
201 Test phases support
202 ===========================================
202 ===========================================
203
203
204 Check that histedit respect immutability
204 Check that histedit respect immutability
205 -------------------------------------------
205 -------------------------------------------
206
206
207 $ cat >> $HGRCPATH << EOF
207 $ cat >> $HGRCPATH << EOF
208 > [ui]
208 > [ui]
209 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
209 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
210 > EOF
210 > EOF
211
211
212 $ hg ph -pv '.^'
212 $ hg ph -pv '.^'
213 phase changed for 2 changesets
213 phase changed for 2 changesets
214 $ hg log -G
214 $ hg log -G
215 @ 11:b449568bf7fc (draft) f
215 @ 11:b449568bf7fc (draft) f
216 |
216 |
217 o 10:40db8afa467b (public) c
217 o 10:40db8afa467b (public) c
218 |
218 |
219 o 0:cb9a9f314b8b (public) a
219 o 0:cb9a9f314b8b (public) a
220
220
221 $ hg histedit -r '.~2'
221 $ hg histedit -r '.~2'
222 abort: cannot edit public changeset: cb9a9f314b8b
222 abort: cannot edit public changeset: cb9a9f314b8b
223 (see "hg help phases" for details)
223 (see "hg help phases" for details)
224 [255]
224 [255]
225
225
226
226
227 Prepare further testing
227 Prepare further testing
228 -------------------------------------------
228 -------------------------------------------
229
229
230 $ for x in g h i j k ; do
230 $ for x in g h i j k ; do
231 > echo $x > $x
231 > echo $x > $x
232 > hg add $x
232 > hg add $x
233 > hg ci -m $x
233 > hg ci -m $x
234 > done
234 > done
235 $ hg phase --force --secret .~2
235 $ hg phase --force --secret .~2
236 $ hg log -G
236 $ hg log -G
237 @ 16:ee118ab9fa44 (secret) k
237 @ 16:ee118ab9fa44 (secret) k
238 |
238 |
239 o 15:3a6c53ee7f3d (secret) j
239 o 15:3a6c53ee7f3d (secret) j
240 |
240 |
241 o 14:b605fb7503f2 (secret) i
241 o 14:b605fb7503f2 (secret) i
242 |
242 |
243 o 13:7395e1ff83bd (draft) h
243 o 13:7395e1ff83bd (draft) h
244 |
244 |
245 o 12:6b70183d2492 (draft) g
245 o 12:6b70183d2492 (draft) g
246 |
246 |
247 o 11:b449568bf7fc (draft) f
247 o 11:b449568bf7fc (draft) f
248 |
248 |
249 o 10:40db8afa467b (public) c
249 o 10:40db8afa467b (public) c
250 |
250 |
251 o 0:cb9a9f314b8b (public) a
251 o 0:cb9a9f314b8b (public) a
252
252
253 $ cd ..
253 $ cd ..
254
254
255 simple phase conservation
255 simple phase conservation
256 -------------------------------------------
256 -------------------------------------------
257
257
258 Resulting changeset should conserve the phase of the original one whatever the
258 Resulting changeset should conserve the phase of the original one whatever the
259 phases.new-commit option is.
259 phases.new-commit option is.
260
260
261 New-commit as draft (default)
261 New-commit as draft (default)
262
262
263 $ cp -r base simple-draft
263 $ cp -r base simple-draft
264 $ cd simple-draft
264 $ cd simple-draft
265 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
265 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
266 > edit b449568bf7fc 11 f
266 > edit b449568bf7fc 11 f
267 > pick 6b70183d2492 12 g
267 > pick 6b70183d2492 12 g
268 > pick 7395e1ff83bd 13 h
268 > pick 7395e1ff83bd 13 h
269 > pick b605fb7503f2 14 i
269 > pick b605fb7503f2 14 i
270 > pick 3a6c53ee7f3d 15 j
270 > pick 3a6c53ee7f3d 15 j
271 > pick ee118ab9fa44 16 k
271 > pick ee118ab9fa44 16 k
272 > EOF
272 > EOF
273 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
273 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
274 adding f
274 adding f
275 Make changes as needed, you may commit or record as needed now.
275 Make changes as needed, you may commit or record as needed now.
276 When you are finished, run hg histedit --continue to resume.
276 When you are finished, run hg histedit --continue to resume.
277 [1]
277 [1]
278 $ echo f >> f
278 $ echo f >> f
279 $ hg histedit --continue
279 $ hg histedit --continue
280 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
282 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
282 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
283 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
283 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
285 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
285 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 $ hg log -G
286 $ hg log -G
287 @ 22:12e89af74238 (secret) k
287 @ 22:12e89af74238 (secret) k
288 |
288 |
289 o 21:636a8687b22e (secret) j
289 o 21:636a8687b22e (secret) j
290 |
290 |
291 o 20:ccaf0a38653f (secret) i
291 o 20:ccaf0a38653f (secret) i
292 |
292 |
293 o 19:11a89d1c2613 (draft) h
293 o 19:11a89d1c2613 (draft) h
294 |
294 |
295 o 18:c1dec7ca82ea (draft) g
295 o 18:c1dec7ca82ea (draft) g
296 |
296 |
297 o 17:087281e68428 (draft) f
297 o 17:087281e68428 (draft) f
298 |
298 |
299 o 10:40db8afa467b (public) c
299 o 10:40db8afa467b (public) c
300 |
300 |
301 o 0:cb9a9f314b8b (public) a
301 o 0:cb9a9f314b8b (public) a
302
302
303 $ cd ..
303 $ cd ..
304
304
305
305
306 New-commit as draft (default)
306 New-commit as draft (default)
307
307
308 $ cp -r base simple-secret
308 $ cp -r base simple-secret
309 $ cd simple-secret
309 $ cd simple-secret
310 $ cat >> .hg/hgrc << EOF
310 $ cat >> .hg/hgrc << EOF
311 > [phases]
311 > [phases]
312 > new-commit=secret
312 > new-commit=secret
313 > EOF
313 > EOF
314 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
314 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
315 > edit b449568bf7fc 11 f
315 > edit b449568bf7fc 11 f
316 > pick 6b70183d2492 12 g
316 > pick 6b70183d2492 12 g
317 > pick 7395e1ff83bd 13 h
317 > pick 7395e1ff83bd 13 h
318 > pick b605fb7503f2 14 i
318 > pick b605fb7503f2 14 i
319 > pick 3a6c53ee7f3d 15 j
319 > pick 3a6c53ee7f3d 15 j
320 > pick ee118ab9fa44 16 k
320 > pick ee118ab9fa44 16 k
321 > EOF
321 > EOF
322 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
322 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
323 adding f
323 adding f
324 Make changes as needed, you may commit or record as needed now.
324 Make changes as needed, you may commit or record as needed now.
325 When you are finished, run hg histedit --continue to resume.
325 When you are finished, run hg histedit --continue to resume.
326 [1]
326 [1]
327 $ echo f >> f
327 $ echo f >> f
328 $ hg histedit --continue
328 $ hg histedit --continue
329 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
331 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
331 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
332 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
332 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ hg log -G
335 $ hg log -G
336 @ 22:12e89af74238 (secret) k
336 @ 22:12e89af74238 (secret) k
337 |
337 |
338 o 21:636a8687b22e (secret) j
338 o 21:636a8687b22e (secret) j
339 |
339 |
340 o 20:ccaf0a38653f (secret) i
340 o 20:ccaf0a38653f (secret) i
341 |
341 |
342 o 19:11a89d1c2613 (draft) h
342 o 19:11a89d1c2613 (draft) h
343 |
343 |
344 o 18:c1dec7ca82ea (draft) g
344 o 18:c1dec7ca82ea (draft) g
345 |
345 |
346 o 17:087281e68428 (draft) f
346 o 17:087281e68428 (draft) f
347 |
347 |
348 o 10:40db8afa467b (public) c
348 o 10:40db8afa467b (public) c
349 |
349 |
350 o 0:cb9a9f314b8b (public) a
350 o 0:cb9a9f314b8b (public) a
351
351
352 $ cd ..
352 $ cd ..
353
353
354
354
355 Changeset reordering
355 Changeset reordering
356 -------------------------------------------
356 -------------------------------------------
357
357
358 If a secret changeset is put before a draft one, all descendant should be secret.
358 If a secret changeset is put before a draft one, all descendant should be secret.
359 It seems more important to present the secret phase.
359 It seems more important to present the secret phase.
360
360
361 $ cp -r base reorder
361 $ cp -r base reorder
362 $ cd reorder
362 $ cd reorder
363 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
363 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
364 > pick b449568bf7fc 11 f
364 > pick b449568bf7fc 11 f
365 > pick 3a6c53ee7f3d 15 j
365 > pick 3a6c53ee7f3d 15 j
366 > pick 6b70183d2492 12 g
366 > pick 6b70183d2492 12 g
367 > pick b605fb7503f2 14 i
367 > pick b605fb7503f2 14 i
368 > pick 7395e1ff83bd 13 h
368 > pick 7395e1ff83bd 13 h
369 > pick ee118ab9fa44 16 k
369 > pick ee118ab9fa44 16 k
370 > EOF
370 > EOF
371 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
371 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
372 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 $ hg log -G
377 $ hg log -G
378 @ 21:558246857888 (secret) k
378 @ 21:558246857888 (secret) k
379 |
379 |
380 o 20:28bd44768535 (secret) h
380 o 20:28bd44768535 (secret) h
381 |
381 |
382 o 19:d5395202aeb9 (secret) i
382 o 19:d5395202aeb9 (secret) i
383 |
383 |
384 o 18:21edda8e341b (secret) g
384 o 18:21edda8e341b (secret) g
385 |
385 |
386 o 17:5ab64f3a4832 (secret) j
386 o 17:5ab64f3a4832 (secret) j
387 |
387 |
388 o 11:b449568bf7fc (draft) f
388 o 11:b449568bf7fc (draft) f
389 |
389 |
390 o 10:40db8afa467b (public) c
390 o 10:40db8afa467b (public) c
391 |
391 |
392 o 0:cb9a9f314b8b (public) a
392 o 0:cb9a9f314b8b (public) a
393
393
394 $ cd ..
394 $ cd ..
395
395
396 Changeset folding
396 Changeset folding
397 -------------------------------------------
397 -------------------------------------------
398
398
399 Folding a secret changeset with a draft one turn the result secret (again,
399 Folding a secret changeset with a draft one turn the result secret (again,
400 better safe than sorry). Folding between same phase changeset still works
400 better safe than sorry). Folding between same phase changeset still works
401
401
402 Note that there is a few reordering in this series for more extensive test
402 Note that there is a few reordering in this series for more extensive test
403
403
404 $ cp -r base folding
404 $ cp -r base folding
405 $ cd folding
405 $ cd folding
406 $ cat >> .hg/hgrc << EOF
406 $ cat >> .hg/hgrc << EOF
407 > [phases]
407 > [phases]
408 > new-commit=secret
408 > new-commit=secret
409 > EOF
409 > EOF
410 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
410 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
411 > pick 7395e1ff83bd 13 h
411 > pick 7395e1ff83bd 13 h
412 > fold b449568bf7fc 11 f
412 > fold b449568bf7fc 11 f
413 > pick 6b70183d2492 12 g
413 > pick 6b70183d2492 12 g
414 > fold 3a6c53ee7f3d 15 j
414 > fold 3a6c53ee7f3d 15 j
415 > pick b605fb7503f2 14 i
415 > pick b605fb7503f2 14 i
416 > fold ee118ab9fa44 16 k
416 > fold ee118ab9fa44 16 k
417 > EOF
417 > EOF
418 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
418 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
419 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
420 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
421 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
424 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
425 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
428 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
429 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
429 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/58019c66f35f-96092fce-backup.hg (glob)
431 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/58019c66f35f-96092fce-backup.hg (glob)
432 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/83d1858e070b-f3469cf8-backup.hg (glob)
432 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/83d1858e070b-f3469cf8-backup.hg (glob)
433 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/859969f5ed7e-d89a19d7-backup.hg (glob)
433 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/859969f5ed7e-d89a19d7-backup.hg (glob)
434 $ hg log -G
434 $ hg log -G
435 @ 19:f9daec13fb98 (secret) i
435 @ 19:f9daec13fb98 (secret) i
436 |
436 |
437 o 18:49807617f46a (secret) g
437 o 18:49807617f46a (secret) g
438 |
438 |
439 o 17:050280826e04 (draft) h
439 o 17:050280826e04 (draft) h
440 |
440 |
441 o 10:40db8afa467b (public) c
441 o 10:40db8afa467b (public) c
442 |
442 |
443 o 0:cb9a9f314b8b (public) a
443 o 0:cb9a9f314b8b (public) a
444
444
445 $ hg co 18
445 $ hg co 18
446 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
446 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
447 $ echo wat >> wat
447 $ echo wat >> wat
448 $ hg add wat
448 $ hg add wat
449 $ hg ci -m 'add wat'
449 $ hg ci -m 'add wat'
450 created new head
450 created new head
451 $ hg merge 19
451 $ hg merge 19
452 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 (branch merge, don't forget to commit)
453 (branch merge, don't forget to commit)
454 $ hg ci -m 'merge'
454 $ hg ci -m 'merge'
455 $ echo not wat > wat
455 $ echo not wat > wat
456 $ hg ci -m 'modify wat'
456 $ hg ci -m 'modify wat'
457 $ hg histedit 17
457 $ hg histedit 17
458 abort: cannot edit history that contains merges
458 abort: cannot edit history that contains merges
459 [255]
459 [255]
460 $ cd ..
460 $ cd ..
@@ -1,147 +1,147 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > histedit=
3 > histedit=
4 > EOF
4 > EOF
5
5
6 $ initrepos ()
6 $ initrepos ()
7 > {
7 > {
8 > hg init r
8 > hg init r
9 > cd r
9 > cd r
10 > for x in a b c ; do
10 > for x in a b c ; do
11 > echo $x > $x
11 > echo $x > $x
12 > hg add $x
12 > hg add $x
13 > hg ci -m $x
13 > hg ci -m $x
14 > done
14 > done
15 > cd ..
15 > cd ..
16 > hg clone r r2 | grep -v updating
16 > hg clone r r2 | grep -v updating
17 > cd r2
17 > cd r2
18 > for x in d e f ; do
18 > for x in d e f ; do
19 > echo $x > $x
19 > echo $x > $x
20 > hg add $x
20 > hg add $x
21 > hg ci -m $x
21 > hg ci -m $x
22 > done
22 > done
23 > cd ..
23 > cd ..
24 > hg init r3
24 > hg init r3
25 > cd r3
25 > cd r3
26 > for x in g h i ; do
26 > for x in g h i ; do
27 > echo $x > $x
27 > echo $x > $x
28 > hg add $x
28 > hg add $x
29 > hg ci -m $x
29 > hg ci -m $x
30 > done
30 > done
31 > cd ..
31 > cd ..
32 > }
32 > }
33
33
34 $ initrepos
34 $ initrepos
35 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
35 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
36
36
37 show the edit commands offered by outgoing
37 show the edit commands offered by outgoing
38 $ cd r2
38 $ cd r2
39 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
39 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
40 pick 055a42cdd887 3 d
40 pick 055a42cdd887 3 d
41 pick e860deea161a 4 e
41 pick e860deea161a 4 e
42 pick 652413bf663e 5 f
42 pick 652413bf663e 5 f
43
43
44 # Edit history between 055a42cdd887 and 652413bf663e
44 # Edit history between 055a42cdd887 and 652413bf663e
45 #
45 #
46 # Commits are listed from least to most recent
46 # Commits are listed from least to most recent
47 #
47 #
48 # Commands:
48 # Commands:
49 # p, pick = use commit
49 # p, pick = use commit
50 # e, edit = use commit, but stop for amending
50 # e, edit = use commit, but stop for amending
51 # f, fold = use commit, but combine it with the one above
51 # f, fold = use commit, but combine it with the one above
52 # r, roll = like fold, but discard this commit's description
52 # r, roll = like fold, but discard this commit's description
53 # d, drop = remove commit from history
53 # d, drop = remove commit from history
54 # m, mess = edit message without changing commit content
54 # m, mess = edit commit message without changing commit content
55 #
55 #
56 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 $ cd ..
57 $ cd ..
58
58
59 show the error from unrelated repos
59 show the error from unrelated repos
60 $ cd r3
60 $ cd r3
61 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
61 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
62 abort: repository is unrelated
62 abort: repository is unrelated
63 [1]
63 [1]
64 $ cd ..
64 $ cd ..
65
65
66 show the error from unrelated repos
66 show the error from unrelated repos
67 $ cd r3
67 $ cd r3
68 $ HGEDITOR=cat hg histedit --force --outgoing ../r
68 $ HGEDITOR=cat hg histedit --force --outgoing ../r
69 comparing with ../r
69 comparing with ../r
70 searching for changes
70 searching for changes
71 warning: repository is unrelated
71 warning: repository is unrelated
72 pick 2a4042b45417 0 g
72 pick 2a4042b45417 0 g
73 pick 68c46b4927ce 1 h
73 pick 68c46b4927ce 1 h
74 pick 51281e65ba79 2 i
74 pick 51281e65ba79 2 i
75
75
76 # Edit history between 2a4042b45417 and 51281e65ba79
76 # Edit history between 2a4042b45417 and 51281e65ba79
77 #
77 #
78 # Commits are listed from least to most recent
78 # Commits are listed from least to most recent
79 #
79 #
80 # Commands:
80 # Commands:
81 # p, pick = use commit
81 # p, pick = use commit
82 # e, edit = use commit, but stop for amending
82 # e, edit = use commit, but stop for amending
83 # f, fold = use commit, but combine it with the one above
83 # f, fold = use commit, but combine it with the one above
84 # r, roll = like fold, but discard this commit's description
84 # r, roll = like fold, but discard this commit's description
85 # d, drop = remove commit from history
85 # d, drop = remove commit from history
86 # m, mess = edit message without changing commit content
86 # m, mess = edit commit message without changing commit content
87 #
87 #
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 $ cd ..
89 $ cd ..
90
90
91 test sensitivity to branch in URL:
91 test sensitivity to branch in URL:
92
92
93 $ cd r2
93 $ cd r2
94 $ hg -q update 2
94 $ hg -q update 2
95 $ hg -q branch foo
95 $ hg -q branch foo
96 $ hg commit -m 'create foo branch'
96 $ hg commit -m 'create foo branch'
97 $ HGEDITOR=cat hg histedit --outgoing '../r#foo' | grep -v comparing | grep -v searching
97 $ HGEDITOR=cat hg histedit --outgoing '../r#foo' | grep -v comparing | grep -v searching
98 pick f26599ee3441 6 create foo branch
98 pick f26599ee3441 6 create foo branch
99
99
100 # Edit history between f26599ee3441 and f26599ee3441
100 # Edit history between f26599ee3441 and f26599ee3441
101 #
101 #
102 # Commits are listed from least to most recent
102 # Commits are listed from least to most recent
103 #
103 #
104 # Commands:
104 # Commands:
105 # p, pick = use commit
105 # p, pick = use commit
106 # e, edit = use commit, but stop for amending
106 # e, edit = use commit, but stop for amending
107 # f, fold = use commit, but combine it with the one above
107 # f, fold = use commit, but combine it with the one above
108 # r, roll = like fold, but discard this commit's description
108 # r, roll = like fold, but discard this commit's description
109 # d, drop = remove commit from history
109 # d, drop = remove commit from history
110 # m, mess = edit message without changing commit content
110 # m, mess = edit commit message without changing commit content
111 #
111 #
112 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
113
113
114 test to check number of roots in outgoing revisions
114 test to check number of roots in outgoing revisions
115
115
116 $ hg -q outgoing -G --template '{node|short}({branch})' '../r'
116 $ hg -q outgoing -G --template '{node|short}({branch})' '../r'
117 @ f26599ee3441(foo)
117 @ f26599ee3441(foo)
118
118
119 o 652413bf663e(default)
119 o 652413bf663e(default)
120 |
120 |
121 o e860deea161a(default)
121 o e860deea161a(default)
122 |
122 |
123 o 055a42cdd887(default)
123 o 055a42cdd887(default)
124
124
125 $ HGEDITOR=cat hg -q histedit --outgoing '../r'
125 $ HGEDITOR=cat hg -q histedit --outgoing '../r'
126 abort: there are ambiguous outgoing revisions
126 abort: there are ambiguous outgoing revisions
127 (see "hg help histedit" for more detail)
127 (see "hg help histedit" for more detail)
128 [255]
128 [255]
129
129
130 $ hg -q update -C 2
130 $ hg -q update -C 2
131 $ echo aa >> a
131 $ echo aa >> a
132 $ hg -q commit -m 'another head on default'
132 $ hg -q commit -m 'another head on default'
133 $ hg -q outgoing -G --template '{node|short}({branch})' '../r#default'
133 $ hg -q outgoing -G --template '{node|short}({branch})' '../r#default'
134 @ 3879dc049647(default)
134 @ 3879dc049647(default)
135
135
136 o 652413bf663e(default)
136 o 652413bf663e(default)
137 |
137 |
138 o e860deea161a(default)
138 o e860deea161a(default)
139 |
139 |
140 o 055a42cdd887(default)
140 o 055a42cdd887(default)
141
141
142 $ HGEDITOR=cat hg -q histedit --outgoing '../r#default'
142 $ HGEDITOR=cat hg -q histedit --outgoing '../r#default'
143 abort: there are ambiguous outgoing revisions
143 abort: there are ambiguous outgoing revisions
144 (see "hg help histedit" for more detail)
144 (see "hg help histedit" for more detail)
145 [255]
145 [255]
146
146
147 $ cd ..
147 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now