##// END OF EJS Templates
histedit: removing the experimental config 'histeditng'...
Saurabh Singh -
r34490:270e344a default
parent child Browse files
Show More
@@ -1,1637 +1,1638 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 and date
39 # r, roll = like fold, but discard this commit's description and date
40 # d, drop = remove commit from history
40 # d, drop = remove commit from history
41 # m, mess = edit commit message without changing commit content
41 # m, mess = edit commit message without changing commit content
42 # b, base = checkout changeset and apply further changesets from there
42 #
43 #
43
44
44 In this file, lines beginning with ``#`` are ignored. You must specify a rule
45 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
46 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
47 before beta, and then wanted to add delta in the same revision as beta, you
47 would reorganize the file to look like this::
48 would reorganize the file to look like this::
48
49
49 pick 030b686bedc4 Add gamma
50 pick 030b686bedc4 Add gamma
50 pick c561b4e977df Add beta
51 pick c561b4e977df Add beta
51 fold 7c2fd3b9020c Add delta
52 fold 7c2fd3b9020c Add delta
52
53
53 # Edit history between c561b4e977df and 7c2fd3b9020c
54 # Edit history between c561b4e977df and 7c2fd3b9020c
54 #
55 #
55 # Commits are listed from least to most recent
56 # Commits are listed from least to most recent
56 #
57 #
57 # Commands:
58 # Commands:
58 # p, pick = use commit
59 # p, pick = use commit
59 # e, edit = use commit, but stop for amending
60 # e, edit = use commit, but stop for amending
60 # f, fold = use commit, but combine it with the one above
61 # f, fold = use commit, but combine it with the one above
61 # r, roll = like fold, but discard this commit's description and date
62 # r, roll = like fold, but discard this commit's description and date
62 # d, drop = remove commit from history
63 # d, drop = remove commit from history
63 # m, mess = edit commit message without changing commit content
64 # m, mess = edit commit message without changing commit content
65 # b, base = checkout changeset and apply further changesets from there
64 #
66 #
65
67
66 At which point you close the editor and ``histedit`` starts working. When you
68 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
69 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::
70 those revisions together, offering you a chance to clean up the commit message::
69
71
70 Add beta
72 Add beta
71 ***
73 ***
72 Add delta
74 Add delta
73
75
74 Edit the commit message to your liking, then close the editor. The date used
76 Edit the commit message to your liking, then close the editor. The date used
75 for the commit will be the later of the two commits' dates. For this example,
77 for the commit will be the later of the two commits' dates. For this example,
76 let's assume that the commit message was changed to ``Add beta and delta.``
78 let's assume that the commit message was changed to ``Add beta and delta.``
77 After histedit has run and had a chance to remove any old or temporary
79 After histedit has run and had a chance to remove any old or temporary
78 revisions it needed, the history looks like this::
80 revisions it needed, the history looks like this::
79
81
80 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
82 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
81 | Add beta and delta.
83 | Add beta and delta.
82 |
84 |
83 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
85 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
84 | Add gamma
86 | Add gamma
85 |
87 |
86 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
88 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
87 Add alpha
89 Add alpha
88
90
89 Note that ``histedit`` does *not* remove any revisions (even its own temporary
91 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
92 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,
93 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,
94 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
95 so you might need to be a little patient. You can choose to keep the original
94 revisions by passing the ``--keep`` flag.
96 revisions by passing the ``--keep`` flag.
95
97
96 The ``edit`` operation will drop you back to a command prompt,
98 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
99 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
100 some changes as a separate commit. When you're done, any remaining
99 uncommitted changes will be committed as well. When done, run ``hg
101 uncommitted changes will be committed as well. When done, run ``hg
100 histedit --continue`` to finish this step. If there are uncommitted
102 histedit --continue`` to finish this step. If there are uncommitted
101 changes, you'll be prompted for a new commit message, but the default
103 changes, you'll be prompted for a new commit message, but the default
102 commit message will be the original message for the ``edit`` ed
104 commit message will be the original message for the ``edit`` ed
103 revision, and the date of the original commit will be preserved.
105 revision, and the date of the original commit will be preserved.
104
106
105 The ``message`` operation will give you a chance to revise a commit
107 The ``message`` operation will give you a chance to revise a commit
106 message without changing the contents. It's a shortcut for doing
108 message without changing the contents. It's a shortcut for doing
107 ``edit`` immediately followed by `hg histedit --continue``.
109 ``edit`` immediately followed by `hg histedit --continue``.
108
110
109 If ``histedit`` encounters a conflict when moving a revision (while
111 If ``histedit`` encounters a conflict when moving a revision (while
110 handling ``pick`` or ``fold``), it'll stop in a similar manner to
112 handling ``pick`` or ``fold``), it'll stop in a similar manner to
111 ``edit`` with the difference that it won't prompt you for a commit
113 ``edit`` with the difference that it won't prompt you for a commit
112 message when done. If you decide at this point that you don't like how
114 message when done. If you decide at this point that you don't like how
113 much work it will be to rearrange history, or that you made a mistake,
115 much work it will be to rearrange history, or that you made a mistake,
114 you can use ``hg histedit --abort`` to abandon the new changes you
116 you can use ``hg histedit --abort`` to abandon the new changes you
115 have made and return to the state before you attempted to edit your
117 have made and return to the state before you attempted to edit your
116 history.
118 history.
117
119
118 If we clone the histedit-ed example repository above and add four more
120 If we clone the histedit-ed example repository above and add four more
119 changes, such that we have the following history::
121 changes, such that we have the following history::
120
122
121 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
123 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
122 | Add theta
124 | Add theta
123 |
125 |
124 o 5 140988835471 2009-04-27 18:04 -0500 stefan
126 o 5 140988835471 2009-04-27 18:04 -0500 stefan
125 | Add eta
127 | Add eta
126 |
128 |
127 o 4 122930637314 2009-04-27 18:04 -0500 stefan
129 o 4 122930637314 2009-04-27 18:04 -0500 stefan
128 | Add zeta
130 | Add zeta
129 |
131 |
130 o 3 836302820282 2009-04-27 18:04 -0500 stefan
132 o 3 836302820282 2009-04-27 18:04 -0500 stefan
131 | Add epsilon
133 | Add epsilon
132 |
134 |
133 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
135 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
134 | Add beta and delta.
136 | Add beta and delta.
135 |
137 |
136 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
138 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
137 | Add gamma
139 | Add gamma
138 |
140 |
139 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
141 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
140 Add alpha
142 Add alpha
141
143
142 If you run ``hg histedit --outgoing`` on the clone then it is the same
144 If you run ``hg histedit --outgoing`` on the clone then it is the same
143 as running ``hg histedit 836302820282``. If you need plan to push to a
145 as running ``hg histedit 836302820282``. If you need plan to push to a
144 repository that Mercurial does not detect to be related to the source
146 repository that Mercurial does not detect to be related to the source
145 repo, you can add a ``--force`` option.
147 repo, you can add a ``--force`` option.
146
148
147 Config
149 Config
148 ------
150 ------
149
151
150 Histedit rule lines are truncated to 80 characters by default. You
152 Histedit rule lines are truncated to 80 characters by default. You
151 can customize this behavior by setting a different length in your
153 can customize this behavior by setting a different length in your
152 configuration file::
154 configuration file::
153
155
154 [histedit]
156 [histedit]
155 linelen = 120 # truncate rule lines at 120 characters
157 linelen = 120 # truncate rule lines at 120 characters
156
158
157 ``hg histedit`` attempts to automatically choose an appropriate base
159 ``hg histedit`` attempts to automatically choose an appropriate base
158 revision to use. To change which base revision is used, define a
160 revision to use. To change which base revision is used, define a
159 revset in your configuration file::
161 revset in your configuration file::
160
162
161 [histedit]
163 [histedit]
162 defaultrev = only(.) & draft()
164 defaultrev = only(.) & draft()
163
165
164 By default each edited revision needs to be present in histedit commands.
166 By default each edited revision needs to be present in histedit commands.
165 To remove revision you need to use ``drop`` operation. You can configure
167 To remove revision you need to use ``drop`` operation. You can configure
166 the drop to be implicit for missing commits by adding::
168 the drop to be implicit for missing commits by adding::
167
169
168 [histedit]
170 [histedit]
169 dropmissing = True
171 dropmissing = True
170
172
171 By default, histedit will close the transaction after each action. For
173 By default, histedit will close the transaction after each action. For
172 performance purposes, you can configure histedit to use a single transaction
174 performance purposes, you can configure histedit to use a single transaction
173 across the entire histedit. WARNING: This setting introduces a significant risk
175 across the entire histedit. WARNING: This setting introduces a significant risk
174 of losing the work you've done in a histedit if the histedit aborts
176 of losing the work you've done in a histedit if the histedit aborts
175 unexpectedly::
177 unexpectedly::
176
178
177 [histedit]
179 [histedit]
178 singletransaction = True
180 singletransaction = True
179
181
180 """
182 """
181
183
182 from __future__ import absolute_import
184 from __future__ import absolute_import
183
185
184 import errno
186 import errno
185 import os
187 import os
186
188
187 from mercurial.i18n import _
189 from mercurial.i18n import _
188 from mercurial import (
190 from mercurial import (
189 bundle2,
191 bundle2,
190 cmdutil,
192 cmdutil,
191 configitems,
193 configitems,
192 context,
194 context,
193 copies,
195 copies,
194 destutil,
196 destutil,
195 discovery,
197 discovery,
196 error,
198 error,
197 exchange,
199 exchange,
198 extensions,
200 extensions,
199 hg,
201 hg,
200 lock,
202 lock,
201 merge as mergemod,
203 merge as mergemod,
202 mergeutil,
204 mergeutil,
203 node,
205 node,
204 obsolete,
206 obsolete,
205 registrar,
207 registrar,
206 repair,
208 repair,
207 scmutil,
209 scmutil,
208 util,
210 util,
209 )
211 )
210
212
211 pickle = util.pickle
213 pickle = util.pickle
212 release = lock.release
214 release = lock.release
213 cmdtable = {}
215 cmdtable = {}
214 command = registrar.command(cmdtable)
216 command = registrar.command(cmdtable)
215
217
216 configtable = {}
218 configtable = {}
217 configitem = registrar.configitem(configtable)
219 configitem = registrar.configitem(configtable)
218 configitem('experimental', 'histedit.autoverb',
220 configitem('experimental', 'histedit.autoverb',
219 default=False,
221 default=False,
220 )
222 )
221 configitem('experimental', 'histeditng',
223 configitem('experimental', 'histeditng',
222 default=False,
224 default=False,
223 )
225 )
224 configitem('histedit', 'defaultrev',
226 configitem('histedit', 'defaultrev',
225 default=configitems.dynamicdefault,
227 default=configitems.dynamicdefault,
226 )
228 )
227 configitem('histedit', 'dropmissing',
229 configitem('histedit', 'dropmissing',
228 default=False,
230 default=False,
229 )
231 )
230 configitem('histedit', 'linelen',
232 configitem('histedit', 'linelen',
231 default=80,
233 default=80,
232 )
234 )
233 configitem('histedit', 'singletransaction',
235 configitem('histedit', 'singletransaction',
234 default=False,
236 default=False,
235 )
237 )
236
238
237 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
239 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
238 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
240 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
239 # be specifying the version(s) of Mercurial they are tested with, or
241 # be specifying the version(s) of Mercurial they are tested with, or
240 # leave the attribute unspecified.
242 # leave the attribute unspecified.
241 testedwith = 'ships-with-hg-core'
243 testedwith = 'ships-with-hg-core'
242
244
243 actiontable = {}
245 actiontable = {}
244 primaryactions = set()
246 primaryactions = set()
245 secondaryactions = set()
247 secondaryactions = set()
246 tertiaryactions = set()
248 tertiaryactions = set()
247 internalactions = set()
249 internalactions = set()
248
250
249 def geteditcomment(ui, first, last):
251 def geteditcomment(ui, first, last):
250 """ construct the editor comment
252 """ construct the editor comment
251 The comment includes::
253 The comment includes::
252 - an intro
254 - an intro
253 - sorted primary commands
255 - sorted primary commands
254 - sorted short commands
256 - sorted short commands
255 - sorted long commands
257 - sorted long commands
256 - additional hints
258 - additional hints
257
259
258 Commands are only included once.
260 Commands are only included once.
259 """
261 """
260 intro = _("""Edit history between %s and %s
262 intro = _("""Edit history between %s and %s
261
263
262 Commits are listed from least to most recent
264 Commits are listed from least to most recent
263
265
264 You can reorder changesets by reordering the lines
266 You can reorder changesets by reordering the lines
265
267
266 Commands:
268 Commands:
267 """)
269 """)
268 actions = []
270 actions = []
269 def addverb(v):
271 def addverb(v):
270 a = actiontable[v]
272 a = actiontable[v]
271 lines = a.message.split("\n")
273 lines = a.message.split("\n")
272 if len(a.verbs):
274 if len(a.verbs):
273 v = ', '.join(sorted(a.verbs, key=lambda v: len(v)))
275 v = ', '.join(sorted(a.verbs, key=lambda v: len(v)))
274 actions.append(" %s = %s" % (v, lines[0]))
276 actions.append(" %s = %s" % (v, lines[0]))
275 actions.extend([' %s' for l in lines[1:]])
277 actions.extend([' %s' for l in lines[1:]])
276
278
277 for v in (
279 for v in (
278 sorted(primaryactions) +
280 sorted(primaryactions) +
279 sorted(secondaryactions) +
281 sorted(secondaryactions) +
280 sorted(tertiaryactions)
282 sorted(tertiaryactions)
281 ):
283 ):
282 addverb(v)
284 addverb(v)
283 actions.append('')
285 actions.append('')
284
286
285 hints = []
287 hints = []
286 if ui.configbool('histedit', 'dropmissing'):
288 if ui.configbool('histedit', 'dropmissing'):
287 hints.append("Deleting a changeset from the list "
289 hints.append("Deleting a changeset from the list "
288 "will DISCARD it from the edited history!")
290 "will DISCARD it from the edited history!")
289
291
290 lines = (intro % (first, last)).split('\n') + actions + hints
292 lines = (intro % (first, last)).split('\n') + actions + hints
291
293
292 return ''.join(['# %s\n' % l if l else '#\n' for l in lines])
294 return ''.join(['# %s\n' % l if l else '#\n' for l in lines])
293
295
294 class histeditstate(object):
296 class histeditstate(object):
295 def __init__(self, repo, parentctxnode=None, actions=None, keep=None,
297 def __init__(self, repo, parentctxnode=None, actions=None, keep=None,
296 topmost=None, replacements=None, lock=None, wlock=None):
298 topmost=None, replacements=None, lock=None, wlock=None):
297 self.repo = repo
299 self.repo = repo
298 self.actions = actions
300 self.actions = actions
299 self.keep = keep
301 self.keep = keep
300 self.topmost = topmost
302 self.topmost = topmost
301 self.parentctxnode = parentctxnode
303 self.parentctxnode = parentctxnode
302 self.lock = lock
304 self.lock = lock
303 self.wlock = wlock
305 self.wlock = wlock
304 self.backupfile = None
306 self.backupfile = None
305 if replacements is None:
307 if replacements is None:
306 self.replacements = []
308 self.replacements = []
307 else:
309 else:
308 self.replacements = replacements
310 self.replacements = replacements
309
311
310 def read(self):
312 def read(self):
311 """Load histedit state from disk and set fields appropriately."""
313 """Load histedit state from disk and set fields appropriately."""
312 try:
314 try:
313 state = self.repo.vfs.read('histedit-state')
315 state = self.repo.vfs.read('histedit-state')
314 except IOError as err:
316 except IOError as err:
315 if err.errno != errno.ENOENT:
317 if err.errno != errno.ENOENT:
316 raise
318 raise
317 cmdutil.wrongtooltocontinue(self.repo, _('histedit'))
319 cmdutil.wrongtooltocontinue(self.repo, _('histedit'))
318
320
319 if state.startswith('v1\n'):
321 if state.startswith('v1\n'):
320 data = self._load()
322 data = self._load()
321 parentctxnode, rules, keep, topmost, replacements, backupfile = data
323 parentctxnode, rules, keep, topmost, replacements, backupfile = data
322 else:
324 else:
323 data = pickle.loads(state)
325 data = pickle.loads(state)
324 parentctxnode, rules, keep, topmost, replacements = data
326 parentctxnode, rules, keep, topmost, replacements = data
325 backupfile = None
327 backupfile = None
326
328
327 self.parentctxnode = parentctxnode
329 self.parentctxnode = parentctxnode
328 rules = "\n".join(["%s %s" % (verb, rest) for [verb, rest] in rules])
330 rules = "\n".join(["%s %s" % (verb, rest) for [verb, rest] in rules])
329 actions = parserules(rules, self)
331 actions = parserules(rules, self)
330 self.actions = actions
332 self.actions = actions
331 self.keep = keep
333 self.keep = keep
332 self.topmost = topmost
334 self.topmost = topmost
333 self.replacements = replacements
335 self.replacements = replacements
334 self.backupfile = backupfile
336 self.backupfile = backupfile
335
337
336 def write(self, tr=None):
338 def write(self, tr=None):
337 if tr:
339 if tr:
338 tr.addfilegenerator('histedit-state', ('histedit-state',),
340 tr.addfilegenerator('histedit-state', ('histedit-state',),
339 self._write, location='plain')
341 self._write, location='plain')
340 else:
342 else:
341 with self.repo.vfs("histedit-state", "w") as f:
343 with self.repo.vfs("histedit-state", "w") as f:
342 self._write(f)
344 self._write(f)
343
345
344 def _write(self, fp):
346 def _write(self, fp):
345 fp.write('v1\n')
347 fp.write('v1\n')
346 fp.write('%s\n' % node.hex(self.parentctxnode))
348 fp.write('%s\n' % node.hex(self.parentctxnode))
347 fp.write('%s\n' % node.hex(self.topmost))
349 fp.write('%s\n' % node.hex(self.topmost))
348 fp.write('%s\n' % self.keep)
350 fp.write('%s\n' % self.keep)
349 fp.write('%d\n' % len(self.actions))
351 fp.write('%d\n' % len(self.actions))
350 for action in self.actions:
352 for action in self.actions:
351 fp.write('%s\n' % action.tostate())
353 fp.write('%s\n' % action.tostate())
352 fp.write('%d\n' % len(self.replacements))
354 fp.write('%d\n' % len(self.replacements))
353 for replacement in self.replacements:
355 for replacement in self.replacements:
354 fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
356 fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
355 for r in replacement[1])))
357 for r in replacement[1])))
356 backupfile = self.backupfile
358 backupfile = self.backupfile
357 if not backupfile:
359 if not backupfile:
358 backupfile = ''
360 backupfile = ''
359 fp.write('%s\n' % backupfile)
361 fp.write('%s\n' % backupfile)
360
362
361 def _load(self):
363 def _load(self):
362 fp = self.repo.vfs('histedit-state', 'r')
364 fp = self.repo.vfs('histedit-state', 'r')
363 lines = [l[:-1] for l in fp.readlines()]
365 lines = [l[:-1] for l in fp.readlines()]
364
366
365 index = 0
367 index = 0
366 lines[index] # version number
368 lines[index] # version number
367 index += 1
369 index += 1
368
370
369 parentctxnode = node.bin(lines[index])
371 parentctxnode = node.bin(lines[index])
370 index += 1
372 index += 1
371
373
372 topmost = node.bin(lines[index])
374 topmost = node.bin(lines[index])
373 index += 1
375 index += 1
374
376
375 keep = lines[index] == 'True'
377 keep = lines[index] == 'True'
376 index += 1
378 index += 1
377
379
378 # Rules
380 # Rules
379 rules = []
381 rules = []
380 rulelen = int(lines[index])
382 rulelen = int(lines[index])
381 index += 1
383 index += 1
382 for i in xrange(rulelen):
384 for i in xrange(rulelen):
383 ruleaction = lines[index]
385 ruleaction = lines[index]
384 index += 1
386 index += 1
385 rule = lines[index]
387 rule = lines[index]
386 index += 1
388 index += 1
387 rules.append((ruleaction, rule))
389 rules.append((ruleaction, rule))
388
390
389 # Replacements
391 # Replacements
390 replacements = []
392 replacements = []
391 replacementlen = int(lines[index])
393 replacementlen = int(lines[index])
392 index += 1
394 index += 1
393 for i in xrange(replacementlen):
395 for i in xrange(replacementlen):
394 replacement = lines[index]
396 replacement = lines[index]
395 original = node.bin(replacement[:40])
397 original = node.bin(replacement[:40])
396 succ = [node.bin(replacement[i:i + 40]) for i in
398 succ = [node.bin(replacement[i:i + 40]) for i in
397 range(40, len(replacement), 40)]
399 range(40, len(replacement), 40)]
398 replacements.append((original, succ))
400 replacements.append((original, succ))
399 index += 1
401 index += 1
400
402
401 backupfile = lines[index]
403 backupfile = lines[index]
402 index += 1
404 index += 1
403
405
404 fp.close()
406 fp.close()
405
407
406 return parentctxnode, rules, keep, topmost, replacements, backupfile
408 return parentctxnode, rules, keep, topmost, replacements, backupfile
407
409
408 def clear(self):
410 def clear(self):
409 if self.inprogress():
411 if self.inprogress():
410 self.repo.vfs.unlink('histedit-state')
412 self.repo.vfs.unlink('histedit-state')
411
413
412 def inprogress(self):
414 def inprogress(self):
413 return self.repo.vfs.exists('histedit-state')
415 return self.repo.vfs.exists('histedit-state')
414
416
415
417
416 class histeditaction(object):
418 class histeditaction(object):
417 def __init__(self, state, node):
419 def __init__(self, state, node):
418 self.state = state
420 self.state = state
419 self.repo = state.repo
421 self.repo = state.repo
420 self.node = node
422 self.node = node
421
423
422 @classmethod
424 @classmethod
423 def fromrule(cls, state, rule):
425 def fromrule(cls, state, rule):
424 """Parses the given rule, returning an instance of the histeditaction.
426 """Parses the given rule, returning an instance of the histeditaction.
425 """
427 """
426 rulehash = rule.strip().split(' ', 1)[0]
428 rulehash = rule.strip().split(' ', 1)[0]
427 try:
429 try:
428 rev = node.bin(rulehash)
430 rev = node.bin(rulehash)
429 except TypeError:
431 except TypeError:
430 raise error.ParseError("invalid changeset %s" % rulehash)
432 raise error.ParseError("invalid changeset %s" % rulehash)
431 return cls(state, rev)
433 return cls(state, rev)
432
434
433 def verify(self, prev, expected, seen):
435 def verify(self, prev, expected, seen):
434 """ Verifies semantic correctness of the rule"""
436 """ Verifies semantic correctness of the rule"""
435 repo = self.repo
437 repo = self.repo
436 ha = node.hex(self.node)
438 ha = node.hex(self.node)
437 try:
439 try:
438 self.node = repo[ha].node()
440 self.node = repo[ha].node()
439 except error.RepoError:
441 except error.RepoError:
440 raise error.ParseError(_('unknown changeset %s listed')
442 raise error.ParseError(_('unknown changeset %s listed')
441 % ha[:12])
443 % ha[:12])
442 if self.node is not None:
444 if self.node is not None:
443 self._verifynodeconstraints(prev, expected, seen)
445 self._verifynodeconstraints(prev, expected, seen)
444
446
445 def _verifynodeconstraints(self, prev, expected, seen):
447 def _verifynodeconstraints(self, prev, expected, seen):
446 # by default command need a node in the edited list
448 # by default command need a node in the edited list
447 if self.node not in expected:
449 if self.node not in expected:
448 raise error.ParseError(_('%s "%s" changeset was not a candidate')
450 raise error.ParseError(_('%s "%s" changeset was not a candidate')
449 % (self.verb, node.short(self.node)),
451 % (self.verb, node.short(self.node)),
450 hint=_('only use listed changesets'))
452 hint=_('only use listed changesets'))
451 # and only one command per node
453 # and only one command per node
452 if self.node in seen:
454 if self.node in seen:
453 raise error.ParseError(_('duplicated command for changeset %s') %
455 raise error.ParseError(_('duplicated command for changeset %s') %
454 node.short(self.node))
456 node.short(self.node))
455
457
456 def torule(self):
458 def torule(self):
457 """build a histedit rule line for an action
459 """build a histedit rule line for an action
458
460
459 by default lines are in the form:
461 by default lines are in the form:
460 <hash> <rev> <summary>
462 <hash> <rev> <summary>
461 """
463 """
462 ctx = self.repo[self.node]
464 ctx = self.repo[self.node]
463 summary = _getsummary(ctx)
465 summary = _getsummary(ctx)
464 line = '%s %s %d %s' % (self.verb, ctx, ctx.rev(), summary)
466 line = '%s %s %d %s' % (self.verb, ctx, ctx.rev(), summary)
465 # trim to 75 columns by default so it's not stupidly wide in my editor
467 # trim to 75 columns by default so it's not stupidly wide in my editor
466 # (the 5 more are left for verb)
468 # (the 5 more are left for verb)
467 maxlen = self.repo.ui.configint('histedit', 'linelen')
469 maxlen = self.repo.ui.configint('histedit', 'linelen')
468 maxlen = max(maxlen, 22) # avoid truncating hash
470 maxlen = max(maxlen, 22) # avoid truncating hash
469 return util.ellipsis(line, maxlen)
471 return util.ellipsis(line, maxlen)
470
472
471 def tostate(self):
473 def tostate(self):
472 """Print an action in format used by histedit state files
474 """Print an action in format used by histedit state files
473 (the first line is a verb, the remainder is the second)
475 (the first line is a verb, the remainder is the second)
474 """
476 """
475 return "%s\n%s" % (self.verb, node.hex(self.node))
477 return "%s\n%s" % (self.verb, node.hex(self.node))
476
478
477 def run(self):
479 def run(self):
478 """Runs the action. The default behavior is simply apply the action's
480 """Runs the action. The default behavior is simply apply the action's
479 rulectx onto the current parentctx."""
481 rulectx onto the current parentctx."""
480 self.applychange()
482 self.applychange()
481 self.continuedirty()
483 self.continuedirty()
482 return self.continueclean()
484 return self.continueclean()
483
485
484 def applychange(self):
486 def applychange(self):
485 """Applies the changes from this action's rulectx onto the current
487 """Applies the changes from this action's rulectx onto the current
486 parentctx, but does not commit them."""
488 parentctx, but does not commit them."""
487 repo = self.repo
489 repo = self.repo
488 rulectx = repo[self.node]
490 rulectx = repo[self.node]
489 repo.ui.pushbuffer(error=True, labeled=True)
491 repo.ui.pushbuffer(error=True, labeled=True)
490 hg.update(repo, self.state.parentctxnode, quietempty=True)
492 hg.update(repo, self.state.parentctxnode, quietempty=True)
491 stats = applychanges(repo.ui, repo, rulectx, {})
493 stats = applychanges(repo.ui, repo, rulectx, {})
492 if stats and stats[3] > 0:
494 if stats and stats[3] > 0:
493 buf = repo.ui.popbuffer()
495 buf = repo.ui.popbuffer()
494 repo.ui.write(*buf)
496 repo.ui.write(*buf)
495 raise error.InterventionRequired(
497 raise error.InterventionRequired(
496 _('Fix up the change (%s %s)') %
498 _('Fix up the change (%s %s)') %
497 (self.verb, node.short(self.node)),
499 (self.verb, node.short(self.node)),
498 hint=_('hg histedit --continue to resume'))
500 hint=_('hg histedit --continue to resume'))
499 else:
501 else:
500 repo.ui.popbuffer()
502 repo.ui.popbuffer()
501
503
502 def continuedirty(self):
504 def continuedirty(self):
503 """Continues the action when changes have been applied to the working
505 """Continues the action when changes have been applied to the working
504 copy. The default behavior is to commit the dirty changes."""
506 copy. The default behavior is to commit the dirty changes."""
505 repo = self.repo
507 repo = self.repo
506 rulectx = repo[self.node]
508 rulectx = repo[self.node]
507
509
508 editor = self.commiteditor()
510 editor = self.commiteditor()
509 commit = commitfuncfor(repo, rulectx)
511 commit = commitfuncfor(repo, rulectx)
510
512
511 commit(text=rulectx.description(), user=rulectx.user(),
513 commit(text=rulectx.description(), user=rulectx.user(),
512 date=rulectx.date(), extra=rulectx.extra(), editor=editor)
514 date=rulectx.date(), extra=rulectx.extra(), editor=editor)
513
515
514 def commiteditor(self):
516 def commiteditor(self):
515 """The editor to be used to edit the commit message."""
517 """The editor to be used to edit the commit message."""
516 return False
518 return False
517
519
518 def continueclean(self):
520 def continueclean(self):
519 """Continues the action when the working copy is clean. The default
521 """Continues the action when the working copy is clean. The default
520 behavior is to accept the current commit as the new version of the
522 behavior is to accept the current commit as the new version of the
521 rulectx."""
523 rulectx."""
522 ctx = self.repo['.']
524 ctx = self.repo['.']
523 if ctx.node() == self.state.parentctxnode:
525 if ctx.node() == self.state.parentctxnode:
524 self.repo.ui.warn(_('%s: skipping changeset (no changes)\n') %
526 self.repo.ui.warn(_('%s: skipping changeset (no changes)\n') %
525 node.short(self.node))
527 node.short(self.node))
526 return ctx, [(self.node, tuple())]
528 return ctx, [(self.node, tuple())]
527 if ctx.node() == self.node:
529 if ctx.node() == self.node:
528 # Nothing changed
530 # Nothing changed
529 return ctx, []
531 return ctx, []
530 return ctx, [(self.node, (ctx.node(),))]
532 return ctx, [(self.node, (ctx.node(),))]
531
533
532 def commitfuncfor(repo, src):
534 def commitfuncfor(repo, src):
533 """Build a commit function for the replacement of <src>
535 """Build a commit function for the replacement of <src>
534
536
535 This function ensure we apply the same treatment to all changesets.
537 This function ensure we apply the same treatment to all changesets.
536
538
537 - Add a 'histedit_source' entry in extra.
539 - Add a 'histedit_source' entry in extra.
538
540
539 Note that fold has its own separated logic because its handling is a bit
541 Note that fold has its own separated logic because its handling is a bit
540 different and not easily factored out of the fold method.
542 different and not easily factored out of the fold method.
541 """
543 """
542 phasemin = src.phase()
544 phasemin = src.phase()
543 def commitfunc(**kwargs):
545 def commitfunc(**kwargs):
544 overrides = {('phases', 'new-commit'): phasemin}
546 overrides = {('phases', 'new-commit'): phasemin}
545 with repo.ui.configoverride(overrides, 'histedit'):
547 with repo.ui.configoverride(overrides, 'histedit'):
546 extra = kwargs.get('extra', {}).copy()
548 extra = kwargs.get('extra', {}).copy()
547 extra['histedit_source'] = src.hex()
549 extra['histedit_source'] = src.hex()
548 kwargs['extra'] = extra
550 kwargs['extra'] = extra
549 return repo.commit(**kwargs)
551 return repo.commit(**kwargs)
550 return commitfunc
552 return commitfunc
551
553
552 def applychanges(ui, repo, ctx, opts):
554 def applychanges(ui, repo, ctx, opts):
553 """Merge changeset from ctx (only) in the current working directory"""
555 """Merge changeset from ctx (only) in the current working directory"""
554 wcpar = repo.dirstate.parents()[0]
556 wcpar = repo.dirstate.parents()[0]
555 if ctx.p1().node() == wcpar:
557 if ctx.p1().node() == wcpar:
556 # edits are "in place" we do not need to make any merge,
558 # edits are "in place" we do not need to make any merge,
557 # just applies changes on parent for editing
559 # just applies changes on parent for editing
558 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
560 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
559 stats = None
561 stats = None
560 else:
562 else:
561 try:
563 try:
562 # ui.forcemerge is an internal variable, do not document
564 # ui.forcemerge is an internal variable, do not document
563 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
565 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
564 'histedit')
566 'histedit')
565 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'histedit'])
567 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'histedit'])
566 finally:
568 finally:
567 repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
569 repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
568 return stats
570 return stats
569
571
570 def collapse(repo, first, last, commitopts, skipprompt=False):
572 def collapse(repo, first, last, commitopts, skipprompt=False):
571 """collapse the set of revisions from first to last as new one.
573 """collapse the set of revisions from first to last as new one.
572
574
573 Expected commit options are:
575 Expected commit options are:
574 - message
576 - message
575 - date
577 - date
576 - username
578 - username
577 Commit message is edited in all cases.
579 Commit message is edited in all cases.
578
580
579 This function works in memory."""
581 This function works in memory."""
580 ctxs = list(repo.set('%d::%d', first, last))
582 ctxs = list(repo.set('%d::%d', first, last))
581 if not ctxs:
583 if not ctxs:
582 return None
584 return None
583 for c in ctxs:
585 for c in ctxs:
584 if not c.mutable():
586 if not c.mutable():
585 raise error.ParseError(
587 raise error.ParseError(
586 _("cannot fold into public change %s") % node.short(c.node()))
588 _("cannot fold into public change %s") % node.short(c.node()))
587 base = first.parents()[0]
589 base = first.parents()[0]
588
590
589 # commit a new version of the old changeset, including the update
591 # commit a new version of the old changeset, including the update
590 # collect all files which might be affected
592 # collect all files which might be affected
591 files = set()
593 files = set()
592 for ctx in ctxs:
594 for ctx in ctxs:
593 files.update(ctx.files())
595 files.update(ctx.files())
594
596
595 # Recompute copies (avoid recording a -> b -> a)
597 # Recompute copies (avoid recording a -> b -> a)
596 copied = copies.pathcopies(base, last)
598 copied = copies.pathcopies(base, last)
597
599
598 # prune files which were reverted by the updates
600 # prune files which were reverted by the updates
599 files = [f for f in files if not cmdutil.samefile(f, last, base)]
601 files = [f for f in files if not cmdutil.samefile(f, last, base)]
600 # commit version of these files as defined by head
602 # commit version of these files as defined by head
601 headmf = last.manifest()
603 headmf = last.manifest()
602 def filectxfn(repo, ctx, path):
604 def filectxfn(repo, ctx, path):
603 if path in headmf:
605 if path in headmf:
604 fctx = last[path]
606 fctx = last[path]
605 flags = fctx.flags()
607 flags = fctx.flags()
606 mctx = context.memfilectx(repo,
608 mctx = context.memfilectx(repo,
607 fctx.path(), fctx.data(),
609 fctx.path(), fctx.data(),
608 islink='l' in flags,
610 islink='l' in flags,
609 isexec='x' in flags,
611 isexec='x' in flags,
610 copied=copied.get(path))
612 copied=copied.get(path))
611 return mctx
613 return mctx
612 return None
614 return None
613
615
614 if commitopts.get('message'):
616 if commitopts.get('message'):
615 message = commitopts['message']
617 message = commitopts['message']
616 else:
618 else:
617 message = first.description()
619 message = first.description()
618 user = commitopts.get('user')
620 user = commitopts.get('user')
619 date = commitopts.get('date')
621 date = commitopts.get('date')
620 extra = commitopts.get('extra')
622 extra = commitopts.get('extra')
621
623
622 parents = (first.p1().node(), first.p2().node())
624 parents = (first.p1().node(), first.p2().node())
623 editor = None
625 editor = None
624 if not skipprompt:
626 if not skipprompt:
625 editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold')
627 editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold')
626 new = context.memctx(repo,
628 new = context.memctx(repo,
627 parents=parents,
629 parents=parents,
628 text=message,
630 text=message,
629 files=files,
631 files=files,
630 filectxfn=filectxfn,
632 filectxfn=filectxfn,
631 user=user,
633 user=user,
632 date=date,
634 date=date,
633 extra=extra,
635 extra=extra,
634 editor=editor)
636 editor=editor)
635 return repo.commitctx(new)
637 return repo.commitctx(new)
636
638
637 def _isdirtywc(repo):
639 def _isdirtywc(repo):
638 return repo[None].dirty(missing=True)
640 return repo[None].dirty(missing=True)
639
641
640 def abortdirty():
642 def abortdirty():
641 raise error.Abort(_('working copy has pending changes'),
643 raise error.Abort(_('working copy has pending changes'),
642 hint=_('amend, commit, or revert them and run histedit '
644 hint=_('amend, commit, or revert them and run histedit '
643 '--continue, or abort with histedit --abort'))
645 '--continue, or abort with histedit --abort'))
644
646
645 def action(verbs, message, priority=False, internal=False):
647 def action(verbs, message, priority=False, internal=False):
646 def wrap(cls):
648 def wrap(cls):
647 assert not priority or not internal
649 assert not priority or not internal
648 verb = verbs[0]
650 verb = verbs[0]
649 if priority:
651 if priority:
650 primaryactions.add(verb)
652 primaryactions.add(verb)
651 elif internal:
653 elif internal:
652 internalactions.add(verb)
654 internalactions.add(verb)
653 elif len(verbs) > 1:
655 elif len(verbs) > 1:
654 secondaryactions.add(verb)
656 secondaryactions.add(verb)
655 else:
657 else:
656 tertiaryactions.add(verb)
658 tertiaryactions.add(verb)
657
659
658 cls.verb = verb
660 cls.verb = verb
659 cls.verbs = verbs
661 cls.verbs = verbs
660 cls.message = message
662 cls.message = message
661 for verb in verbs:
663 for verb in verbs:
662 actiontable[verb] = cls
664 actiontable[verb] = cls
663 return cls
665 return cls
664 return wrap
666 return wrap
665
667
666 @action(['pick', 'p'],
668 @action(['pick', 'p'],
667 _('use commit'),
669 _('use commit'),
668 priority=True)
670 priority=True)
669 class pick(histeditaction):
671 class pick(histeditaction):
670 def run(self):
672 def run(self):
671 rulectx = self.repo[self.node]
673 rulectx = self.repo[self.node]
672 if rulectx.parents()[0].node() == self.state.parentctxnode:
674 if rulectx.parents()[0].node() == self.state.parentctxnode:
673 self.repo.ui.debug('node %s unchanged\n' % node.short(self.node))
675 self.repo.ui.debug('node %s unchanged\n' % node.short(self.node))
674 return rulectx, []
676 return rulectx, []
675
677
676 return super(pick, self).run()
678 return super(pick, self).run()
677
679
678 @action(['edit', 'e'],
680 @action(['edit', 'e'],
679 _('use commit, but stop for amending'),
681 _('use commit, but stop for amending'),
680 priority=True)
682 priority=True)
681 class edit(histeditaction):
683 class edit(histeditaction):
682 def run(self):
684 def run(self):
683 repo = self.repo
685 repo = self.repo
684 rulectx = repo[self.node]
686 rulectx = repo[self.node]
685 hg.update(repo, self.state.parentctxnode, quietempty=True)
687 hg.update(repo, self.state.parentctxnode, quietempty=True)
686 applychanges(repo.ui, repo, rulectx, {})
688 applychanges(repo.ui, repo, rulectx, {})
687 raise error.InterventionRequired(
689 raise error.InterventionRequired(
688 _('Editing (%s), you may commit or record as needed now.')
690 _('Editing (%s), you may commit or record as needed now.')
689 % node.short(self.node),
691 % node.short(self.node),
690 hint=_('hg histedit --continue to resume'))
692 hint=_('hg histedit --continue to resume'))
691
693
692 def commiteditor(self):
694 def commiteditor(self):
693 return cmdutil.getcommiteditor(edit=True, editform='histedit.edit')
695 return cmdutil.getcommiteditor(edit=True, editform='histedit.edit')
694
696
695 @action(['fold', 'f'],
697 @action(['fold', 'f'],
696 _('use commit, but combine it with the one above'))
698 _('use commit, but combine it with the one above'))
697 class fold(histeditaction):
699 class fold(histeditaction):
698 def verify(self, prev, expected, seen):
700 def verify(self, prev, expected, seen):
699 """ Verifies semantic correctness of the fold rule"""
701 """ Verifies semantic correctness of the fold rule"""
700 super(fold, self).verify(prev, expected, seen)
702 super(fold, self).verify(prev, expected, seen)
701 repo = self.repo
703 repo = self.repo
702 if not prev:
704 if not prev:
703 c = repo[self.node].parents()[0]
705 c = repo[self.node].parents()[0]
704 elif not prev.verb in ('pick', 'base'):
706 elif not prev.verb in ('pick', 'base'):
705 return
707 return
706 else:
708 else:
707 c = repo[prev.node]
709 c = repo[prev.node]
708 if not c.mutable():
710 if not c.mutable():
709 raise error.ParseError(
711 raise error.ParseError(
710 _("cannot fold into public change %s") % node.short(c.node()))
712 _("cannot fold into public change %s") % node.short(c.node()))
711
713
712
714
713 def continuedirty(self):
715 def continuedirty(self):
714 repo = self.repo
716 repo = self.repo
715 rulectx = repo[self.node]
717 rulectx = repo[self.node]
716
718
717 commit = commitfuncfor(repo, rulectx)
719 commit = commitfuncfor(repo, rulectx)
718 commit(text='fold-temp-revision %s' % node.short(self.node),
720 commit(text='fold-temp-revision %s' % node.short(self.node),
719 user=rulectx.user(), date=rulectx.date(),
721 user=rulectx.user(), date=rulectx.date(),
720 extra=rulectx.extra())
722 extra=rulectx.extra())
721
723
722 def continueclean(self):
724 def continueclean(self):
723 repo = self.repo
725 repo = self.repo
724 ctx = repo['.']
726 ctx = repo['.']
725 rulectx = repo[self.node]
727 rulectx = repo[self.node]
726 parentctxnode = self.state.parentctxnode
728 parentctxnode = self.state.parentctxnode
727 if ctx.node() == parentctxnode:
729 if ctx.node() == parentctxnode:
728 repo.ui.warn(_('%s: empty changeset\n') %
730 repo.ui.warn(_('%s: empty changeset\n') %
729 node.short(self.node))
731 node.short(self.node))
730 return ctx, [(self.node, (parentctxnode,))]
732 return ctx, [(self.node, (parentctxnode,))]
731
733
732 parentctx = repo[parentctxnode]
734 parentctx = repo[parentctxnode]
733 newcommits = set(c.node() for c in repo.set('(%d::. - %d)', parentctx,
735 newcommits = set(c.node() for c in repo.set('(%d::. - %d)', parentctx,
734 parentctx))
736 parentctx))
735 if not newcommits:
737 if not newcommits:
736 repo.ui.warn(_('%s: cannot fold - working copy is not a '
738 repo.ui.warn(_('%s: cannot fold - working copy is not a '
737 'descendant of previous commit %s\n') %
739 'descendant of previous commit %s\n') %
738 (node.short(self.node), node.short(parentctxnode)))
740 (node.short(self.node), node.short(parentctxnode)))
739 return ctx, [(self.node, (ctx.node(),))]
741 return ctx, [(self.node, (ctx.node(),))]
740
742
741 middlecommits = newcommits.copy()
743 middlecommits = newcommits.copy()
742 middlecommits.discard(ctx.node())
744 middlecommits.discard(ctx.node())
743
745
744 return self.finishfold(repo.ui, repo, parentctx, rulectx, ctx.node(),
746 return self.finishfold(repo.ui, repo, parentctx, rulectx, ctx.node(),
745 middlecommits)
747 middlecommits)
746
748
747 def skipprompt(self):
749 def skipprompt(self):
748 """Returns true if the rule should skip the message editor.
750 """Returns true if the rule should skip the message editor.
749
751
750 For example, 'fold' wants to show an editor, but 'rollup'
752 For example, 'fold' wants to show an editor, but 'rollup'
751 doesn't want to.
753 doesn't want to.
752 """
754 """
753 return False
755 return False
754
756
755 def mergedescs(self):
757 def mergedescs(self):
756 """Returns true if the rule should merge messages of multiple changes.
758 """Returns true if the rule should merge messages of multiple changes.
757
759
758 This exists mainly so that 'rollup' rules can be a subclass of
760 This exists mainly so that 'rollup' rules can be a subclass of
759 'fold'.
761 'fold'.
760 """
762 """
761 return True
763 return True
762
764
763 def firstdate(self):
765 def firstdate(self):
764 """Returns true if the rule should preserve the date of the first
766 """Returns true if the rule should preserve the date of the first
765 change.
767 change.
766
768
767 This exists mainly so that 'rollup' rules can be a subclass of
769 This exists mainly so that 'rollup' rules can be a subclass of
768 'fold'.
770 'fold'.
769 """
771 """
770 return False
772 return False
771
773
772 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
774 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
773 parent = ctx.parents()[0].node()
775 parent = ctx.parents()[0].node()
774 repo.ui.pushbuffer()
776 repo.ui.pushbuffer()
775 hg.update(repo, parent)
777 hg.update(repo, parent)
776 repo.ui.popbuffer()
778 repo.ui.popbuffer()
777 ### prepare new commit data
779 ### prepare new commit data
778 commitopts = {}
780 commitopts = {}
779 commitopts['user'] = ctx.user()
781 commitopts['user'] = ctx.user()
780 # commit message
782 # commit message
781 if not self.mergedescs():
783 if not self.mergedescs():
782 newmessage = ctx.description()
784 newmessage = ctx.description()
783 else:
785 else:
784 newmessage = '\n***\n'.join(
786 newmessage = '\n***\n'.join(
785 [ctx.description()] +
787 [ctx.description()] +
786 [repo[r].description() for r in internalchanges] +
788 [repo[r].description() for r in internalchanges] +
787 [oldctx.description()]) + '\n'
789 [oldctx.description()]) + '\n'
788 commitopts['message'] = newmessage
790 commitopts['message'] = newmessage
789 # date
791 # date
790 if self.firstdate():
792 if self.firstdate():
791 commitopts['date'] = ctx.date()
793 commitopts['date'] = ctx.date()
792 else:
794 else:
793 commitopts['date'] = max(ctx.date(), oldctx.date())
795 commitopts['date'] = max(ctx.date(), oldctx.date())
794 extra = ctx.extra().copy()
796 extra = ctx.extra().copy()
795 # histedit_source
797 # histedit_source
796 # note: ctx is likely a temporary commit but that the best we can do
798 # note: ctx is likely a temporary commit but that the best we can do
797 # here. This is sufficient to solve issue3681 anyway.
799 # here. This is sufficient to solve issue3681 anyway.
798 extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex())
800 extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex())
799 commitopts['extra'] = extra
801 commitopts['extra'] = extra
800 phasemin = max(ctx.phase(), oldctx.phase())
802 phasemin = max(ctx.phase(), oldctx.phase())
801 overrides = {('phases', 'new-commit'): phasemin}
803 overrides = {('phases', 'new-commit'): phasemin}
802 with repo.ui.configoverride(overrides, 'histedit'):
804 with repo.ui.configoverride(overrides, 'histedit'):
803 n = collapse(repo, ctx, repo[newnode], commitopts,
805 n = collapse(repo, ctx, repo[newnode], commitopts,
804 skipprompt=self.skipprompt())
806 skipprompt=self.skipprompt())
805 if n is None:
807 if n is None:
806 return ctx, []
808 return ctx, []
807 repo.ui.pushbuffer()
809 repo.ui.pushbuffer()
808 hg.update(repo, n)
810 hg.update(repo, n)
809 repo.ui.popbuffer()
811 repo.ui.popbuffer()
810 replacements = [(oldctx.node(), (newnode,)),
812 replacements = [(oldctx.node(), (newnode,)),
811 (ctx.node(), (n,)),
813 (ctx.node(), (n,)),
812 (newnode, (n,)),
814 (newnode, (n,)),
813 ]
815 ]
814 for ich in internalchanges:
816 for ich in internalchanges:
815 replacements.append((ich, (n,)))
817 replacements.append((ich, (n,)))
816 return repo[n], replacements
818 return repo[n], replacements
817
819
820 @action(['base', 'b'],
821 _('checkout changeset and apply further changesets from there'))
818 class base(histeditaction):
822 class base(histeditaction):
819
823
820 def run(self):
824 def run(self):
821 if self.repo['.'].node() != self.node:
825 if self.repo['.'].node() != self.node:
822 mergemod.update(self.repo, self.node, False, True)
826 mergemod.update(self.repo, self.node, False, True)
823 # branchmerge, force)
827 # branchmerge, force)
824 return self.continueclean()
828 return self.continueclean()
825
829
826 def continuedirty(self):
830 def continuedirty(self):
827 abortdirty()
831 abortdirty()
828
832
829 def continueclean(self):
833 def continueclean(self):
830 basectx = self.repo['.']
834 basectx = self.repo['.']
831 return basectx, []
835 return basectx, []
832
836
833 def _verifynodeconstraints(self, prev, expected, seen):
837 def _verifynodeconstraints(self, prev, expected, seen):
834 # base can only be use with a node not in the edited set
838 # base can only be use with a node not in the edited set
835 if self.node in expected:
839 if self.node in expected:
836 msg = _('%s "%s" changeset was an edited list candidate')
840 msg = _('%s "%s" changeset was an edited list candidate')
837 raise error.ParseError(
841 raise error.ParseError(
838 msg % (self.verb, node.short(self.node)),
842 msg % (self.verb, node.short(self.node)),
839 hint=_('base must only use unlisted changesets'))
843 hint=_('base must only use unlisted changesets'))
840
844
841 @action(['_multifold'],
845 @action(['_multifold'],
842 _(
846 _(
843 """fold subclass used for when multiple folds happen in a row
847 """fold subclass used for when multiple folds happen in a row
844
848
845 We only want to fire the editor for the folded message once when
849 We only want to fire the editor for the folded message once when
846 (say) four changes are folded down into a single change. This is
850 (say) four changes are folded down into a single change. This is
847 similar to rollup, but we should preserve both messages so that
851 similar to rollup, but we should preserve both messages so that
848 when the last fold operation runs we can show the user all the
852 when the last fold operation runs we can show the user all the
849 commit messages in their editor.
853 commit messages in their editor.
850 """),
854 """),
851 internal=True)
855 internal=True)
852 class _multifold(fold):
856 class _multifold(fold):
853 def skipprompt(self):
857 def skipprompt(self):
854 return True
858 return True
855
859
856 @action(["roll", "r"],
860 @action(["roll", "r"],
857 _("like fold, but discard this commit's description and date"))
861 _("like fold, but discard this commit's description and date"))
858 class rollup(fold):
862 class rollup(fold):
859 def mergedescs(self):
863 def mergedescs(self):
860 return False
864 return False
861
865
862 def skipprompt(self):
866 def skipprompt(self):
863 return True
867 return True
864
868
865 def firstdate(self):
869 def firstdate(self):
866 return True
870 return True
867
871
868 @action(["drop", "d"],
872 @action(["drop", "d"],
869 _('remove commit from history'))
873 _('remove commit from history'))
870 class drop(histeditaction):
874 class drop(histeditaction):
871 def run(self):
875 def run(self):
872 parentctx = self.repo[self.state.parentctxnode]
876 parentctx = self.repo[self.state.parentctxnode]
873 return parentctx, [(self.node, tuple())]
877 return parentctx, [(self.node, tuple())]
874
878
875 @action(["mess", "m"],
879 @action(["mess", "m"],
876 _('edit commit message without changing commit content'),
880 _('edit commit message without changing commit content'),
877 priority=True)
881 priority=True)
878 class message(histeditaction):
882 class message(histeditaction):
879 def commiteditor(self):
883 def commiteditor(self):
880 return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
884 return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
881
885
882 def findoutgoing(ui, repo, remote=None, force=False, opts=None):
886 def findoutgoing(ui, repo, remote=None, force=False, opts=None):
883 """utility function to find the first outgoing changeset
887 """utility function to find the first outgoing changeset
884
888
885 Used by initialization code"""
889 Used by initialization code"""
886 if opts is None:
890 if opts is None:
887 opts = {}
891 opts = {}
888 dest = ui.expandpath(remote or 'default-push', remote or 'default')
892 dest = ui.expandpath(remote or 'default-push', remote or 'default')
889 dest, revs = hg.parseurl(dest, None)[:2]
893 dest, revs = hg.parseurl(dest, None)[:2]
890 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
894 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
891
895
892 revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
896 revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
893 other = hg.peer(repo, opts, dest)
897 other = hg.peer(repo, opts, dest)
894
898
895 if revs:
899 if revs:
896 revs = [repo.lookup(rev) for rev in revs]
900 revs = [repo.lookup(rev) for rev in revs]
897
901
898 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
902 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
899 if not outgoing.missing:
903 if not outgoing.missing:
900 raise error.Abort(_('no outgoing ancestors'))
904 raise error.Abort(_('no outgoing ancestors'))
901 roots = list(repo.revs("roots(%ln)", outgoing.missing))
905 roots = list(repo.revs("roots(%ln)", outgoing.missing))
902 if 1 < len(roots):
906 if 1 < len(roots):
903 msg = _('there are ambiguous outgoing revisions')
907 msg = _('there are ambiguous outgoing revisions')
904 hint = _("see 'hg help histedit' for more detail")
908 hint = _("see 'hg help histedit' for more detail")
905 raise error.Abort(msg, hint=hint)
909 raise error.Abort(msg, hint=hint)
906 return repo.lookup(roots[0])
910 return repo.lookup(roots[0])
907
911
908
909 @command('histedit',
912 @command('histedit',
910 [('', 'commands', '',
913 [('', 'commands', '',
911 _('read history edits from the specified file'), _('FILE')),
914 _('read history edits from the specified file'), _('FILE')),
912 ('c', 'continue', False, _('continue an edit already in progress')),
915 ('c', 'continue', False, _('continue an edit already in progress')),
913 ('', 'edit-plan', False, _('edit remaining actions list')),
916 ('', 'edit-plan', False, _('edit remaining actions list')),
914 ('k', 'keep', False,
917 ('k', 'keep', False,
915 _("don't strip old nodes after edit is complete")),
918 _("don't strip old nodes after edit is complete")),
916 ('', 'abort', False, _('abort an edit in progress')),
919 ('', 'abort', False, _('abort an edit in progress')),
917 ('o', 'outgoing', False, _('changesets not found in destination')),
920 ('o', 'outgoing', False, _('changesets not found in destination')),
918 ('f', 'force', False,
921 ('f', 'force', False,
919 _('force outgoing even for unrelated repositories')),
922 _('force outgoing even for unrelated repositories')),
920 ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
923 ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
921 _("[OPTIONS] ([ANCESTOR] | --outgoing [URL])"))
924 _("[OPTIONS] ([ANCESTOR] | --outgoing [URL])"))
922 def histedit(ui, repo, *freeargs, **opts):
925 def histedit(ui, repo, *freeargs, **opts):
923 """interactively edit changeset history
926 """interactively edit changeset history
924
927
925 This command lets you edit a linear series of changesets (up to
928 This command lets you edit a linear series of changesets (up to
926 and including the working directory, which should be clean).
929 and including the working directory, which should be clean).
927 You can:
930 You can:
928
931
929 - `pick` to [re]order a changeset
932 - `pick` to [re]order a changeset
930
933
931 - `drop` to omit changeset
934 - `drop` to omit changeset
932
935
933 - `mess` to reword the changeset commit message
936 - `mess` to reword the changeset commit message
934
937
935 - `fold` to combine it with the preceding changeset (using the later date)
938 - `fold` to combine it with the preceding changeset (using the later date)
936
939
937 - `roll` like fold, but discarding this commit's description and date
940 - `roll` like fold, but discarding this commit's description and date
938
941
939 - `edit` to edit this changeset (preserving date)
942 - `edit` to edit this changeset (preserving date)
940
943
944 - `base` to checkout changeset and apply further changesets from there
945
941 There are a number of ways to select the root changeset:
946 There are a number of ways to select the root changeset:
942
947
943 - Specify ANCESTOR directly
948 - Specify ANCESTOR directly
944
949
945 - Use --outgoing -- it will be the first linear changeset not
950 - Use --outgoing -- it will be the first linear changeset not
946 included in destination. (See :hg:`help config.paths.default-push`)
951 included in destination. (See :hg:`help config.paths.default-push`)
947
952
948 - Otherwise, the value from the "histedit.defaultrev" config option
953 - Otherwise, the value from the "histedit.defaultrev" config option
949 is used as a revset to select the base revision when ANCESTOR is not
954 is used as a revset to select the base revision when ANCESTOR is not
950 specified. The first revision returned by the revset is used. By
955 specified. The first revision returned by the revset is used. By
951 default, this selects the editable history that is unique to the
956 default, this selects the editable history that is unique to the
952 ancestry of the working directory.
957 ancestry of the working directory.
953
958
954 .. container:: verbose
959 .. container:: verbose
955
960
956 If you use --outgoing, this command will abort if there are ambiguous
961 If you use --outgoing, this command will abort if there are ambiguous
957 outgoing revisions. For example, if there are multiple branches
962 outgoing revisions. For example, if there are multiple branches
958 containing outgoing revisions.
963 containing outgoing revisions.
959
964
960 Use "min(outgoing() and ::.)" or similar revset specification
965 Use "min(outgoing() and ::.)" or similar revset specification
961 instead of --outgoing to specify edit target revision exactly in
966 instead of --outgoing to specify edit target revision exactly in
962 such ambiguous situation. See :hg:`help revsets` for detail about
967 such ambiguous situation. See :hg:`help revsets` for detail about
963 selecting revisions.
968 selecting revisions.
964
969
965 .. container:: verbose
970 .. container:: verbose
966
971
967 Examples:
972 Examples:
968
973
969 - A number of changes have been made.
974 - A number of changes have been made.
970 Revision 3 is no longer needed.
975 Revision 3 is no longer needed.
971
976
972 Start history editing from revision 3::
977 Start history editing from revision 3::
973
978
974 hg histedit -r 3
979 hg histedit -r 3
975
980
976 An editor opens, containing the list of revisions,
981 An editor opens, containing the list of revisions,
977 with specific actions specified::
982 with specific actions specified::
978
983
979 pick 5339bf82f0ca 3 Zworgle the foobar
984 pick 5339bf82f0ca 3 Zworgle the foobar
980 pick 8ef592ce7cc4 4 Bedazzle the zerlog
985 pick 8ef592ce7cc4 4 Bedazzle the zerlog
981 pick 0a9639fcda9d 5 Morgify the cromulancy
986 pick 0a9639fcda9d 5 Morgify the cromulancy
982
987
983 Additional information about the possible actions
988 Additional information about the possible actions
984 to take appears below the list of revisions.
989 to take appears below the list of revisions.
985
990
986 To remove revision 3 from the history,
991 To remove revision 3 from the history,
987 its action (at the beginning of the relevant line)
992 its action (at the beginning of the relevant line)
988 is changed to 'drop'::
993 is changed to 'drop'::
989
994
990 drop 5339bf82f0ca 3 Zworgle the foobar
995 drop 5339bf82f0ca 3 Zworgle the foobar
991 pick 8ef592ce7cc4 4 Bedazzle the zerlog
996 pick 8ef592ce7cc4 4 Bedazzle the zerlog
992 pick 0a9639fcda9d 5 Morgify the cromulancy
997 pick 0a9639fcda9d 5 Morgify the cromulancy
993
998
994 - A number of changes have been made.
999 - A number of changes have been made.
995 Revision 2 and 4 need to be swapped.
1000 Revision 2 and 4 need to be swapped.
996
1001
997 Start history editing from revision 2::
1002 Start history editing from revision 2::
998
1003
999 hg histedit -r 2
1004 hg histedit -r 2
1000
1005
1001 An editor opens, containing the list of revisions,
1006 An editor opens, containing the list of revisions,
1002 with specific actions specified::
1007 with specific actions specified::
1003
1008
1004 pick 252a1af424ad 2 Blorb a morgwazzle
1009 pick 252a1af424ad 2 Blorb a morgwazzle
1005 pick 5339bf82f0ca 3 Zworgle the foobar
1010 pick 5339bf82f0ca 3 Zworgle the foobar
1006 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1011 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1007
1012
1008 To swap revision 2 and 4, its lines are swapped
1013 To swap revision 2 and 4, its lines are swapped
1009 in the editor::
1014 in the editor::
1010
1015
1011 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1016 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1012 pick 5339bf82f0ca 3 Zworgle the foobar
1017 pick 5339bf82f0ca 3 Zworgle the foobar
1013 pick 252a1af424ad 2 Blorb a morgwazzle
1018 pick 252a1af424ad 2 Blorb a morgwazzle
1014
1019
1015 Returns 0 on success, 1 if user intervention is required (not only
1020 Returns 0 on success, 1 if user intervention is required (not only
1016 for intentional "edit" command, but also for resolving unexpected
1021 for intentional "edit" command, but also for resolving unexpected
1017 conflicts).
1022 conflicts).
1018 """
1023 """
1019 state = histeditstate(repo)
1024 state = histeditstate(repo)
1020 try:
1025 try:
1021 state.wlock = repo.wlock()
1026 state.wlock = repo.wlock()
1022 state.lock = repo.lock()
1027 state.lock = repo.lock()
1023 _histedit(ui, repo, state, *freeargs, **opts)
1028 _histedit(ui, repo, state, *freeargs, **opts)
1024 finally:
1029 finally:
1025 release(state.lock, state.wlock)
1030 release(state.lock, state.wlock)
1026
1031
1027 goalcontinue = 'continue'
1032 goalcontinue = 'continue'
1028 goalabort = 'abort'
1033 goalabort = 'abort'
1029 goaleditplan = 'edit-plan'
1034 goaleditplan = 'edit-plan'
1030 goalnew = 'new'
1035 goalnew = 'new'
1031
1036
1032 def _getgoal(opts):
1037 def _getgoal(opts):
1033 if opts.get('continue'):
1038 if opts.get('continue'):
1034 return goalcontinue
1039 return goalcontinue
1035 if opts.get('abort'):
1040 if opts.get('abort'):
1036 return goalabort
1041 return goalabort
1037 if opts.get('edit_plan'):
1042 if opts.get('edit_plan'):
1038 return goaleditplan
1043 return goaleditplan
1039 return goalnew
1044 return goalnew
1040
1045
1041 def _readfile(ui, path):
1046 def _readfile(ui, path):
1042 if path == '-':
1047 if path == '-':
1043 with ui.timeblockedsection('histedit'):
1048 with ui.timeblockedsection('histedit'):
1044 return ui.fin.read()
1049 return ui.fin.read()
1045 else:
1050 else:
1046 with open(path, 'rb') as f:
1051 with open(path, 'rb') as f:
1047 return f.read()
1052 return f.read()
1048
1053
1049 def _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs):
1054 def _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs):
1050 # TODO only abort if we try to histedit mq patches, not just
1055 # TODO only abort if we try to histedit mq patches, not just
1051 # blanket if mq patches are applied somewhere
1056 # blanket if mq patches are applied somewhere
1052 mq = getattr(repo, 'mq', None)
1057 mq = getattr(repo, 'mq', None)
1053 if mq and mq.applied:
1058 if mq and mq.applied:
1054 raise error.Abort(_('source has mq patches applied'))
1059 raise error.Abort(_('source has mq patches applied'))
1055
1060
1056 # basic argument incompatibility processing
1061 # basic argument incompatibility processing
1057 outg = opts.get('outgoing')
1062 outg = opts.get('outgoing')
1058 editplan = opts.get('edit_plan')
1063 editplan = opts.get('edit_plan')
1059 abort = opts.get('abort')
1064 abort = opts.get('abort')
1060 force = opts.get('force')
1065 force = opts.get('force')
1061 if force and not outg:
1066 if force and not outg:
1062 raise error.Abort(_('--force only allowed with --outgoing'))
1067 raise error.Abort(_('--force only allowed with --outgoing'))
1063 if goal == 'continue':
1068 if goal == 'continue':
1064 if any((outg, abort, revs, freeargs, rules, editplan)):
1069 if any((outg, abort, revs, freeargs, rules, editplan)):
1065 raise error.Abort(_('no arguments allowed with --continue'))
1070 raise error.Abort(_('no arguments allowed with --continue'))
1066 elif goal == 'abort':
1071 elif goal == 'abort':
1067 if any((outg, revs, freeargs, rules, editplan)):
1072 if any((outg, revs, freeargs, rules, editplan)):
1068 raise error.Abort(_('no arguments allowed with --abort'))
1073 raise error.Abort(_('no arguments allowed with --abort'))
1069 elif goal == 'edit-plan':
1074 elif goal == 'edit-plan':
1070 if any((outg, revs, freeargs)):
1075 if any((outg, revs, freeargs)):
1071 raise error.Abort(_('only --commands argument allowed with '
1076 raise error.Abort(_('only --commands argument allowed with '
1072 '--edit-plan'))
1077 '--edit-plan'))
1073 else:
1078 else:
1074 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1079 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1075 raise error.Abort(_('history edit already in progress, try '
1080 raise error.Abort(_('history edit already in progress, try '
1076 '--continue or --abort'))
1081 '--continue or --abort'))
1077 if outg:
1082 if outg:
1078 if revs:
1083 if revs:
1079 raise error.Abort(_('no revisions allowed with --outgoing'))
1084 raise error.Abort(_('no revisions allowed with --outgoing'))
1080 if len(freeargs) > 1:
1085 if len(freeargs) > 1:
1081 raise error.Abort(
1086 raise error.Abort(
1082 _('only one repo argument allowed with --outgoing'))
1087 _('only one repo argument allowed with --outgoing'))
1083 else:
1088 else:
1084 revs.extend(freeargs)
1089 revs.extend(freeargs)
1085 if len(revs) == 0:
1090 if len(revs) == 0:
1086 defaultrev = destutil.desthistedit(ui, repo)
1091 defaultrev = destutil.desthistedit(ui, repo)
1087 if defaultrev is not None:
1092 if defaultrev is not None:
1088 revs.append(defaultrev)
1093 revs.append(defaultrev)
1089
1094
1090 if len(revs) != 1:
1095 if len(revs) != 1:
1091 raise error.Abort(
1096 raise error.Abort(
1092 _('histedit requires exactly one ancestor revision'))
1097 _('histedit requires exactly one ancestor revision'))
1093
1098
1094 def _histedit(ui, repo, state, *freeargs, **opts):
1099 def _histedit(ui, repo, state, *freeargs, **opts):
1095 goal = _getgoal(opts)
1100 goal = _getgoal(opts)
1096 revs = opts.get('rev', [])
1101 revs = opts.get('rev', [])
1097 rules = opts.get('commands', '')
1102 rules = opts.get('commands', '')
1098 state.keep = opts.get('keep', False)
1103 state.keep = opts.get('keep', False)
1099
1104
1100 _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs)
1105 _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs)
1101
1106
1102 # rebuild state
1107 # rebuild state
1103 if goal == goalcontinue:
1108 if goal == goalcontinue:
1104 state.read()
1109 state.read()
1105 state = bootstrapcontinue(ui, state, opts)
1110 state = bootstrapcontinue(ui, state, opts)
1106 elif goal == goaleditplan:
1111 elif goal == goaleditplan:
1107 _edithisteditplan(ui, repo, state, rules)
1112 _edithisteditplan(ui, repo, state, rules)
1108 return
1113 return
1109 elif goal == goalabort:
1114 elif goal == goalabort:
1110 _aborthistedit(ui, repo, state)
1115 _aborthistedit(ui, repo, state)
1111 return
1116 return
1112 else:
1117 else:
1113 # goal == goalnew
1118 # goal == goalnew
1114 _newhistedit(ui, repo, state, revs, freeargs, opts)
1119 _newhistedit(ui, repo, state, revs, freeargs, opts)
1115
1120
1116 _continuehistedit(ui, repo, state)
1121 _continuehistedit(ui, repo, state)
1117 _finishhistedit(ui, repo, state)
1122 _finishhistedit(ui, repo, state)
1118
1123
1119 def _continuehistedit(ui, repo, state):
1124 def _continuehistedit(ui, repo, state):
1120 """This function runs after either:
1125 """This function runs after either:
1121 - bootstrapcontinue (if the goal is 'continue')
1126 - bootstrapcontinue (if the goal is 'continue')
1122 - _newhistedit (if the goal is 'new')
1127 - _newhistedit (if the goal is 'new')
1123 """
1128 """
1124 # preprocess rules so that we can hide inner folds from the user
1129 # preprocess rules so that we can hide inner folds from the user
1125 # and only show one editor
1130 # and only show one editor
1126 actions = state.actions[:]
1131 actions = state.actions[:]
1127 for idx, (action, nextact) in enumerate(
1132 for idx, (action, nextact) in enumerate(
1128 zip(actions, actions[1:] + [None])):
1133 zip(actions, actions[1:] + [None])):
1129 if action.verb == 'fold' and nextact and nextact.verb == 'fold':
1134 if action.verb == 'fold' and nextact and nextact.verb == 'fold':
1130 state.actions[idx].__class__ = _multifold
1135 state.actions[idx].__class__ = _multifold
1131
1136
1132 # Force an initial state file write, so the user can run --abort/continue
1137 # Force an initial state file write, so the user can run --abort/continue
1133 # even if there's an exception before the first transaction serialize.
1138 # even if there's an exception before the first transaction serialize.
1134 state.write()
1139 state.write()
1135
1140
1136 total = len(state.actions)
1141 total = len(state.actions)
1137 pos = 0
1142 pos = 0
1138 tr = None
1143 tr = None
1139 # Don't use singletransaction by default since it rolls the entire
1144 # Don't use singletransaction by default since it rolls the entire
1140 # transaction back if an unexpected exception happens (like a
1145 # transaction back if an unexpected exception happens (like a
1141 # pretxncommit hook throws, or the user aborts the commit msg editor).
1146 # pretxncommit hook throws, or the user aborts the commit msg editor).
1142 if ui.configbool("histedit", "singletransaction"):
1147 if ui.configbool("histedit", "singletransaction"):
1143 # Don't use a 'with' for the transaction, since actions may close
1148 # Don't use a 'with' for the transaction, since actions may close
1144 # and reopen a transaction. For example, if the action executes an
1149 # and reopen a transaction. For example, if the action executes an
1145 # external process it may choose to commit the transaction first.
1150 # external process it may choose to commit the transaction first.
1146 tr = repo.transaction('histedit')
1151 tr = repo.transaction('histedit')
1147 with util.acceptintervention(tr):
1152 with util.acceptintervention(tr):
1148 while state.actions:
1153 while state.actions:
1149 state.write(tr=tr)
1154 state.write(tr=tr)
1150 actobj = state.actions[0]
1155 actobj = state.actions[0]
1151 pos += 1
1156 pos += 1
1152 ui.progress(_("editing"), pos, actobj.torule(),
1157 ui.progress(_("editing"), pos, actobj.torule(),
1153 _('changes'), total)
1158 _('changes'), total)
1154 ui.debug('histedit: processing %s %s\n' % (actobj.verb,\
1159 ui.debug('histedit: processing %s %s\n' % (actobj.verb,\
1155 actobj.torule()))
1160 actobj.torule()))
1156 parentctx, replacement_ = actobj.run()
1161 parentctx, replacement_ = actobj.run()
1157 state.parentctxnode = parentctx.node()
1162 state.parentctxnode = parentctx.node()
1158 state.replacements.extend(replacement_)
1163 state.replacements.extend(replacement_)
1159 state.actions.pop(0)
1164 state.actions.pop(0)
1160
1165
1161 state.write()
1166 state.write()
1162 ui.progress(_("editing"), None)
1167 ui.progress(_("editing"), None)
1163
1168
1164 def _finishhistedit(ui, repo, state):
1169 def _finishhistedit(ui, repo, state):
1165 """This action runs when histedit is finishing its session"""
1170 """This action runs when histedit is finishing its session"""
1166 repo.ui.pushbuffer()
1171 repo.ui.pushbuffer()
1167 hg.update(repo, state.parentctxnode, quietempty=True)
1172 hg.update(repo, state.parentctxnode, quietempty=True)
1168 repo.ui.popbuffer()
1173 repo.ui.popbuffer()
1169
1174
1170 mapping, tmpnodes, created, ntm = processreplacement(state)
1175 mapping, tmpnodes, created, ntm = processreplacement(state)
1171 if mapping:
1176 if mapping:
1172 for prec, succs in mapping.iteritems():
1177 for prec, succs in mapping.iteritems():
1173 if not succs:
1178 if not succs:
1174 ui.debug('histedit: %s is dropped\n' % node.short(prec))
1179 ui.debug('histedit: %s is dropped\n' % node.short(prec))
1175 else:
1180 else:
1176 ui.debug('histedit: %s is replaced by %s\n' % (
1181 ui.debug('histedit: %s is replaced by %s\n' % (
1177 node.short(prec), node.short(succs[0])))
1182 node.short(prec), node.short(succs[0])))
1178 if len(succs) > 1:
1183 if len(succs) > 1:
1179 m = 'histedit: %s'
1184 m = 'histedit: %s'
1180 for n in succs[1:]:
1185 for n in succs[1:]:
1181 ui.debug(m % node.short(n))
1186 ui.debug(m % node.short(n))
1182
1187
1183 if not state.keep:
1188 if not state.keep:
1184 if mapping:
1189 if mapping:
1185 movetopmostbookmarks(repo, state.topmost, ntm)
1190 movetopmostbookmarks(repo, state.topmost, ntm)
1186 # TODO update mq state
1191 # TODO update mq state
1187 else:
1192 else:
1188 mapping = {}
1193 mapping = {}
1189
1194
1190 for n in tmpnodes:
1195 for n in tmpnodes:
1191 mapping[n] = ()
1196 mapping[n] = ()
1192
1197
1193 # remove entries about unknown nodes
1198 # remove entries about unknown nodes
1194 nodemap = repo.unfiltered().changelog.nodemap
1199 nodemap = repo.unfiltered().changelog.nodemap
1195 mapping = {k: v for k, v in mapping.items()
1200 mapping = {k: v for k, v in mapping.items()
1196 if k in nodemap and all(n in nodemap for n in v)}
1201 if k in nodemap and all(n in nodemap for n in v)}
1197 scmutil.cleanupnodes(repo, mapping, 'histedit')
1202 scmutil.cleanupnodes(repo, mapping, 'histedit')
1198
1203
1199 state.clear()
1204 state.clear()
1200 if os.path.exists(repo.sjoin('undo')):
1205 if os.path.exists(repo.sjoin('undo')):
1201 os.unlink(repo.sjoin('undo'))
1206 os.unlink(repo.sjoin('undo'))
1202 if repo.vfs.exists('histedit-last-edit.txt'):
1207 if repo.vfs.exists('histedit-last-edit.txt'):
1203 repo.vfs.unlink('histedit-last-edit.txt')
1208 repo.vfs.unlink('histedit-last-edit.txt')
1204
1209
1205 def _aborthistedit(ui, repo, state):
1210 def _aborthistedit(ui, repo, state):
1206 try:
1211 try:
1207 state.read()
1212 state.read()
1208 __, leafs, tmpnodes, __ = processreplacement(state)
1213 __, leafs, tmpnodes, __ = processreplacement(state)
1209 ui.debug('restore wc to old parent %s\n'
1214 ui.debug('restore wc to old parent %s\n'
1210 % node.short(state.topmost))
1215 % node.short(state.topmost))
1211
1216
1212 # Recover our old commits if necessary
1217 # Recover our old commits if necessary
1213 if not state.topmost in repo and state.backupfile:
1218 if not state.topmost in repo and state.backupfile:
1214 backupfile = repo.vfs.join(state.backupfile)
1219 backupfile = repo.vfs.join(state.backupfile)
1215 f = hg.openpath(ui, backupfile)
1220 f = hg.openpath(ui, backupfile)
1216 gen = exchange.readbundle(ui, f, backupfile)
1221 gen = exchange.readbundle(ui, f, backupfile)
1217 with repo.transaction('histedit.abort') as tr:
1222 with repo.transaction('histedit.abort') as tr:
1218 bundle2.applybundle(repo, gen, tr, source='histedit',
1223 bundle2.applybundle(repo, gen, tr, source='histedit',
1219 url='bundle:' + backupfile)
1224 url='bundle:' + backupfile)
1220
1225
1221 os.remove(backupfile)
1226 os.remove(backupfile)
1222
1227
1223 # check whether we should update away
1228 # check whether we should update away
1224 if repo.unfiltered().revs('parents() and (%n or %ln::)',
1229 if repo.unfiltered().revs('parents() and (%n or %ln::)',
1225 state.parentctxnode, leafs | tmpnodes):
1230 state.parentctxnode, leafs | tmpnodes):
1226 hg.clean(repo, state.topmost, show_stats=True, quietempty=True)
1231 hg.clean(repo, state.topmost, show_stats=True, quietempty=True)
1227 cleanupnode(ui, repo, tmpnodes)
1232 cleanupnode(ui, repo, tmpnodes)
1228 cleanupnode(ui, repo, leafs)
1233 cleanupnode(ui, repo, leafs)
1229 except Exception:
1234 except Exception:
1230 if state.inprogress():
1235 if state.inprogress():
1231 ui.warn(_('warning: encountered an exception during histedit '
1236 ui.warn(_('warning: encountered an exception during histedit '
1232 '--abort; the repository may not have been completely '
1237 '--abort; the repository may not have been completely '
1233 'cleaned up\n'))
1238 'cleaned up\n'))
1234 raise
1239 raise
1235 finally:
1240 finally:
1236 state.clear()
1241 state.clear()
1237
1242
1238 def _edithisteditplan(ui, repo, state, rules):
1243 def _edithisteditplan(ui, repo, state, rules):
1239 state.read()
1244 state.read()
1240 if not rules:
1245 if not rules:
1241 comment = geteditcomment(ui,
1246 comment = geteditcomment(ui,
1242 node.short(state.parentctxnode),
1247 node.short(state.parentctxnode),
1243 node.short(state.topmost))
1248 node.short(state.topmost))
1244 rules = ruleeditor(repo, ui, state.actions, comment)
1249 rules = ruleeditor(repo, ui, state.actions, comment)
1245 else:
1250 else:
1246 rules = _readfile(ui, rules)
1251 rules = _readfile(ui, rules)
1247 actions = parserules(rules, state)
1252 actions = parserules(rules, state)
1248 ctxs = [repo[act.node] \
1253 ctxs = [repo[act.node] \
1249 for act in state.actions if act.node]
1254 for act in state.actions if act.node]
1250 warnverifyactions(ui, repo, actions, state, ctxs)
1255 warnverifyactions(ui, repo, actions, state, ctxs)
1251 state.actions = actions
1256 state.actions = actions
1252 state.write()
1257 state.write()
1253
1258
1254 def _newhistedit(ui, repo, state, revs, freeargs, opts):
1259 def _newhistedit(ui, repo, state, revs, freeargs, opts):
1255 outg = opts.get('outgoing')
1260 outg = opts.get('outgoing')
1256 rules = opts.get('commands', '')
1261 rules = opts.get('commands', '')
1257 force = opts.get('force')
1262 force = opts.get('force')
1258
1263
1259 cmdutil.checkunfinished(repo)
1264 cmdutil.checkunfinished(repo)
1260 cmdutil.bailifchanged(repo)
1265 cmdutil.bailifchanged(repo)
1261
1266
1262 topmost, empty = repo.dirstate.parents()
1267 topmost, empty = repo.dirstate.parents()
1263 if outg:
1268 if outg:
1264 if freeargs:
1269 if freeargs:
1265 remote = freeargs[0]
1270 remote = freeargs[0]
1266 else:
1271 else:
1267 remote = None
1272 remote = None
1268 root = findoutgoing(ui, repo, remote, force, opts)
1273 root = findoutgoing(ui, repo, remote, force, opts)
1269 else:
1274 else:
1270 rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
1275 rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
1271 if len(rr) != 1:
1276 if len(rr) != 1:
1272 raise error.Abort(_('The specified revisions must have '
1277 raise error.Abort(_('The specified revisions must have '
1273 'exactly one common root'))
1278 'exactly one common root'))
1274 root = rr[0].node()
1279 root = rr[0].node()
1275
1280
1276 revs = between(repo, root, topmost, state.keep)
1281 revs = between(repo, root, topmost, state.keep)
1277 if not revs:
1282 if not revs:
1278 raise error.Abort(_('%s is not an ancestor of working directory') %
1283 raise error.Abort(_('%s is not an ancestor of working directory') %
1279 node.short(root))
1284 node.short(root))
1280
1285
1281 ctxs = [repo[r] for r in revs]
1286 ctxs = [repo[r] for r in revs]
1282 if not rules:
1287 if not rules:
1283 comment = geteditcomment(ui, node.short(root), node.short(topmost))
1288 comment = geteditcomment(ui, node.short(root), node.short(topmost))
1284 actions = [pick(state, r) for r in revs]
1289 actions = [pick(state, r) for r in revs]
1285 rules = ruleeditor(repo, ui, actions, comment)
1290 rules = ruleeditor(repo, ui, actions, comment)
1286 else:
1291 else:
1287 rules = _readfile(ui, rules)
1292 rules = _readfile(ui, rules)
1288 actions = parserules(rules, state)
1293 actions = parserules(rules, state)
1289 warnverifyactions(ui, repo, actions, state, ctxs)
1294 warnverifyactions(ui, repo, actions, state, ctxs)
1290
1295
1291 parentctxnode = repo[root].parents()[0].node()
1296 parentctxnode = repo[root].parents()[0].node()
1292
1297
1293 state.parentctxnode = parentctxnode
1298 state.parentctxnode = parentctxnode
1294 state.actions = actions
1299 state.actions = actions
1295 state.topmost = topmost
1300 state.topmost = topmost
1296 state.replacements = []
1301 state.replacements = []
1297
1302
1298 # Create a backup so we can always abort completely.
1303 # Create a backup so we can always abort completely.
1299 backupfile = None
1304 backupfile = None
1300 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1305 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1301 backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
1306 backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
1302 'histedit')
1307 'histedit')
1303 state.backupfile = backupfile
1308 state.backupfile = backupfile
1304
1309
1305 def _getsummary(ctx):
1310 def _getsummary(ctx):
1306 # a common pattern is to extract the summary but default to the empty
1311 # a common pattern is to extract the summary but default to the empty
1307 # string
1312 # string
1308 summary = ctx.description() or ''
1313 summary = ctx.description() or ''
1309 if summary:
1314 if summary:
1310 summary = summary.splitlines()[0]
1315 summary = summary.splitlines()[0]
1311 return summary
1316 return summary
1312
1317
1313 def bootstrapcontinue(ui, state, opts):
1318 def bootstrapcontinue(ui, state, opts):
1314 repo = state.repo
1319 repo = state.repo
1315
1320
1316 ms = mergemod.mergestate.read(repo)
1321 ms = mergemod.mergestate.read(repo)
1317 mergeutil.checkunresolved(ms)
1322 mergeutil.checkunresolved(ms)
1318
1323
1319 if state.actions:
1324 if state.actions:
1320 actobj = state.actions.pop(0)
1325 actobj = state.actions.pop(0)
1321
1326
1322 if _isdirtywc(repo):
1327 if _isdirtywc(repo):
1323 actobj.continuedirty()
1328 actobj.continuedirty()
1324 if _isdirtywc(repo):
1329 if _isdirtywc(repo):
1325 abortdirty()
1330 abortdirty()
1326
1331
1327 parentctx, replacements = actobj.continueclean()
1332 parentctx, replacements = actobj.continueclean()
1328
1333
1329 state.parentctxnode = parentctx.node()
1334 state.parentctxnode = parentctx.node()
1330 state.replacements.extend(replacements)
1335 state.replacements.extend(replacements)
1331
1336
1332 return state
1337 return state
1333
1338
1334 def between(repo, old, new, keep):
1339 def between(repo, old, new, keep):
1335 """select and validate the set of revision to edit
1340 """select and validate the set of revision to edit
1336
1341
1337 When keep is false, the specified set can't have children."""
1342 When keep is false, the specified set can't have children."""
1338 ctxs = list(repo.set('%n::%n', old, new))
1343 ctxs = list(repo.set('%n::%n', old, new))
1339 if ctxs and not keep:
1344 if ctxs and not keep:
1340 if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
1345 if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
1341 repo.revs('(%ld::) - (%ld)', ctxs, ctxs)):
1346 repo.revs('(%ld::) - (%ld)', ctxs, ctxs)):
1342 raise error.Abort(_('can only histedit a changeset together '
1347 raise error.Abort(_('can only histedit a changeset together '
1343 'with all its descendants'))
1348 'with all its descendants'))
1344 if repo.revs('(%ld) and merge()', ctxs):
1349 if repo.revs('(%ld) and merge()', ctxs):
1345 raise error.Abort(_('cannot edit history that contains merges'))
1350 raise error.Abort(_('cannot edit history that contains merges'))
1346 root = ctxs[0] # list is already sorted by repo.set
1351 root = ctxs[0] # list is already sorted by repo.set
1347 if not root.mutable():
1352 if not root.mutable():
1348 raise error.Abort(_('cannot edit public changeset: %s') % root,
1353 raise error.Abort(_('cannot edit public changeset: %s') % root,
1349 hint=_("see 'hg help phases' for details"))
1354 hint=_("see 'hg help phases' for details"))
1350 return [c.node() for c in ctxs]
1355 return [c.node() for c in ctxs]
1351
1356
1352 def ruleeditor(repo, ui, actions, editcomment=""):
1357 def ruleeditor(repo, ui, actions, editcomment=""):
1353 """open an editor to edit rules
1358 """open an editor to edit rules
1354
1359
1355 rules are in the format [ [act, ctx], ...] like in state.rules
1360 rules are in the format [ [act, ctx], ...] like in state.rules
1356 """
1361 """
1357 if repo.ui.configbool("experimental", "histedit.autoverb"):
1362 if repo.ui.configbool("experimental", "histedit.autoverb"):
1358 newact = util.sortdict()
1363 newact = util.sortdict()
1359 for act in actions:
1364 for act in actions:
1360 ctx = repo[act.node]
1365 ctx = repo[act.node]
1361 summary = _getsummary(ctx)
1366 summary = _getsummary(ctx)
1362 fword = summary.split(' ', 1)[0].lower()
1367 fword = summary.split(' ', 1)[0].lower()
1363 added = False
1368 added = False
1364
1369
1365 # if it doesn't end with the special character '!' just skip this
1370 # if it doesn't end with the special character '!' just skip this
1366 if fword.endswith('!'):
1371 if fword.endswith('!'):
1367 fword = fword[:-1]
1372 fword = fword[:-1]
1368 if fword in primaryactions | secondaryactions | tertiaryactions:
1373 if fword in primaryactions | secondaryactions | tertiaryactions:
1369 act.verb = fword
1374 act.verb = fword
1370 # get the target summary
1375 # get the target summary
1371 tsum = summary[len(fword) + 1:].lstrip()
1376 tsum = summary[len(fword) + 1:].lstrip()
1372 # safe but slow: reverse iterate over the actions so we
1377 # safe but slow: reverse iterate over the actions so we
1373 # don't clash on two commits having the same summary
1378 # don't clash on two commits having the same summary
1374 for na, l in reversed(list(newact.iteritems())):
1379 for na, l in reversed(list(newact.iteritems())):
1375 actx = repo[na.node]
1380 actx = repo[na.node]
1376 asum = _getsummary(actx)
1381 asum = _getsummary(actx)
1377 if asum == tsum:
1382 if asum == tsum:
1378 added = True
1383 added = True
1379 l.append(act)
1384 l.append(act)
1380 break
1385 break
1381
1386
1382 if not added:
1387 if not added:
1383 newact[act] = []
1388 newact[act] = []
1384
1389
1385 # copy over and flatten the new list
1390 # copy over and flatten the new list
1386 actions = []
1391 actions = []
1387 for na, l in newact.iteritems():
1392 for na, l in newact.iteritems():
1388 actions.append(na)
1393 actions.append(na)
1389 actions += l
1394 actions += l
1390
1395
1391 rules = '\n'.join([act.torule() for act in actions])
1396 rules = '\n'.join([act.torule() for act in actions])
1392 rules += '\n\n'
1397 rules += '\n\n'
1393 rules += editcomment
1398 rules += editcomment
1394 rules = ui.edit(rules, ui.username(), {'prefix': 'histedit'},
1399 rules = ui.edit(rules, ui.username(), {'prefix': 'histedit'},
1395 repopath=repo.path, action='histedit')
1400 repopath=repo.path, action='histedit')
1396
1401
1397 # Save edit rules in .hg/histedit-last-edit.txt in case
1402 # Save edit rules in .hg/histedit-last-edit.txt in case
1398 # the user needs to ask for help after something
1403 # the user needs to ask for help after something
1399 # surprising happens.
1404 # surprising happens.
1400 f = open(repo.vfs.join('histedit-last-edit.txt'), 'w')
1405 f = open(repo.vfs.join('histedit-last-edit.txt'), 'w')
1401 f.write(rules)
1406 f.write(rules)
1402 f.close()
1407 f.close()
1403
1408
1404 return rules
1409 return rules
1405
1410
1406 def parserules(rules, state):
1411 def parserules(rules, state):
1407 """Read the histedit rules string and return list of action objects """
1412 """Read the histedit rules string and return list of action objects """
1408 rules = [l for l in (r.strip() for r in rules.splitlines())
1413 rules = [l for l in (r.strip() for r in rules.splitlines())
1409 if l and not l.startswith('#')]
1414 if l and not l.startswith('#')]
1410 actions = []
1415 actions = []
1411 for r in rules:
1416 for r in rules:
1412 if ' ' not in r:
1417 if ' ' not in r:
1413 raise error.ParseError(_('malformed line "%s"') % r)
1418 raise error.ParseError(_('malformed line "%s"') % r)
1414 verb, rest = r.split(' ', 1)
1419 verb, rest = r.split(' ', 1)
1415
1420
1416 if verb not in actiontable:
1421 if verb not in actiontable:
1417 raise error.ParseError(_('unknown action "%s"') % verb)
1422 raise error.ParseError(_('unknown action "%s"') % verb)
1418
1423
1419 action = actiontable[verb].fromrule(state, rest)
1424 action = actiontable[verb].fromrule(state, rest)
1420 actions.append(action)
1425 actions.append(action)
1421 return actions
1426 return actions
1422
1427
1423 def warnverifyactions(ui, repo, actions, state, ctxs):
1428 def warnverifyactions(ui, repo, actions, state, ctxs):
1424 try:
1429 try:
1425 verifyactions(actions, state, ctxs)
1430 verifyactions(actions, state, ctxs)
1426 except error.ParseError:
1431 except error.ParseError:
1427 if repo.vfs.exists('histedit-last-edit.txt'):
1432 if repo.vfs.exists('histedit-last-edit.txt'):
1428 ui.warn(_('warning: histedit rules saved '
1433 ui.warn(_('warning: histedit rules saved '
1429 'to: .hg/histedit-last-edit.txt\n'))
1434 'to: .hg/histedit-last-edit.txt\n'))
1430 raise
1435 raise
1431
1436
1432 def verifyactions(actions, state, ctxs):
1437 def verifyactions(actions, state, ctxs):
1433 """Verify that there exists exactly one action per given changeset and
1438 """Verify that there exists exactly one action per given changeset and
1434 other constraints.
1439 other constraints.
1435
1440
1436 Will abort if there are to many or too few rules, a malformed rule,
1441 Will abort if there are to many or too few rules, a malformed rule,
1437 or a rule on a changeset outside of the user-given range.
1442 or a rule on a changeset outside of the user-given range.
1438 """
1443 """
1439 expected = set(c.node() for c in ctxs)
1444 expected = set(c.node() for c in ctxs)
1440 seen = set()
1445 seen = set()
1441 prev = None
1446 prev = None
1442
1447
1443 if actions and actions[0].verb in ['roll', 'fold']:
1448 if actions and actions[0].verb in ['roll', 'fold']:
1444 raise error.ParseError(_('first changeset cannot use verb "%s"') %
1449 raise error.ParseError(_('first changeset cannot use verb "%s"') %
1445 actions[0].verb)
1450 actions[0].verb)
1446
1451
1447 for action in actions:
1452 for action in actions:
1448 action.verify(prev, expected, seen)
1453 action.verify(prev, expected, seen)
1449 prev = action
1454 prev = action
1450 if action.node is not None:
1455 if action.node is not None:
1451 seen.add(action.node)
1456 seen.add(action.node)
1452 missing = sorted(expected - seen) # sort to stabilize output
1457 missing = sorted(expected - seen) # sort to stabilize output
1453
1458
1454 if state.repo.ui.configbool('histedit', 'dropmissing'):
1459 if state.repo.ui.configbool('histedit', 'dropmissing'):
1455 if len(actions) == 0:
1460 if len(actions) == 0:
1456 raise error.ParseError(_('no rules provided'),
1461 raise error.ParseError(_('no rules provided'),
1457 hint=_('use strip extension to remove commits'))
1462 hint=_('use strip extension to remove commits'))
1458
1463
1459 drops = [drop(state, n) for n in missing]
1464 drops = [drop(state, n) for n in missing]
1460 # put the in the beginning so they execute immediately and
1465 # put the in the beginning so they execute immediately and
1461 # don't show in the edit-plan in the future
1466 # don't show in the edit-plan in the future
1462 actions[:0] = drops
1467 actions[:0] = drops
1463 elif missing:
1468 elif missing:
1464 raise error.ParseError(_('missing rules for changeset %s') %
1469 raise error.ParseError(_('missing rules for changeset %s') %
1465 node.short(missing[0]),
1470 node.short(missing[0]),
1466 hint=_('use "drop %s" to discard, see also: '
1471 hint=_('use "drop %s" to discard, see also: '
1467 "'hg help -e histedit.config'")
1472 "'hg help -e histedit.config'")
1468 % node.short(missing[0]))
1473 % node.short(missing[0]))
1469
1474
1470 def adjustreplacementsfrommarkers(repo, oldreplacements):
1475 def adjustreplacementsfrommarkers(repo, oldreplacements):
1471 """Adjust replacements from obsolescence markers
1476 """Adjust replacements from obsolescence markers
1472
1477
1473 Replacements structure is originally generated based on
1478 Replacements structure is originally generated based on
1474 histedit's state and does not account for changes that are
1479 histedit's state and does not account for changes that are
1475 not recorded there. This function fixes that by adding
1480 not recorded there. This function fixes that by adding
1476 data read from obsolescence markers"""
1481 data read from obsolescence markers"""
1477 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1482 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1478 return oldreplacements
1483 return oldreplacements
1479
1484
1480 unfi = repo.unfiltered()
1485 unfi = repo.unfiltered()
1481 nm = unfi.changelog.nodemap
1486 nm = unfi.changelog.nodemap
1482 obsstore = repo.obsstore
1487 obsstore = repo.obsstore
1483 newreplacements = list(oldreplacements)
1488 newreplacements = list(oldreplacements)
1484 oldsuccs = [r[1] for r in oldreplacements]
1489 oldsuccs = [r[1] for r in oldreplacements]
1485 # successors that have already been added to succstocheck once
1490 # successors that have already been added to succstocheck once
1486 seensuccs = set().union(*oldsuccs) # create a set from an iterable of tuples
1491 seensuccs = set().union(*oldsuccs) # create a set from an iterable of tuples
1487 succstocheck = list(seensuccs)
1492 succstocheck = list(seensuccs)
1488 while succstocheck:
1493 while succstocheck:
1489 n = succstocheck.pop()
1494 n = succstocheck.pop()
1490 missing = nm.get(n) is None
1495 missing = nm.get(n) is None
1491 markers = obsstore.successors.get(n, ())
1496 markers = obsstore.successors.get(n, ())
1492 if missing and not markers:
1497 if missing and not markers:
1493 # dead end, mark it as such
1498 # dead end, mark it as such
1494 newreplacements.append((n, ()))
1499 newreplacements.append((n, ()))
1495 for marker in markers:
1500 for marker in markers:
1496 nsuccs = marker[1]
1501 nsuccs = marker[1]
1497 newreplacements.append((n, nsuccs))
1502 newreplacements.append((n, nsuccs))
1498 for nsucc in nsuccs:
1503 for nsucc in nsuccs:
1499 if nsucc not in seensuccs:
1504 if nsucc not in seensuccs:
1500 seensuccs.add(nsucc)
1505 seensuccs.add(nsucc)
1501 succstocheck.append(nsucc)
1506 succstocheck.append(nsucc)
1502
1507
1503 return newreplacements
1508 return newreplacements
1504
1509
1505 def processreplacement(state):
1510 def processreplacement(state):
1506 """process the list of replacements to return
1511 """process the list of replacements to return
1507
1512
1508 1) the final mapping between original and created nodes
1513 1) the final mapping between original and created nodes
1509 2) the list of temporary node created by histedit
1514 2) the list of temporary node created by histedit
1510 3) the list of new commit created by histedit"""
1515 3) the list of new commit created by histedit"""
1511 replacements = adjustreplacementsfrommarkers(state.repo, state.replacements)
1516 replacements = adjustreplacementsfrommarkers(state.repo, state.replacements)
1512 allsuccs = set()
1517 allsuccs = set()
1513 replaced = set()
1518 replaced = set()
1514 fullmapping = {}
1519 fullmapping = {}
1515 # initialize basic set
1520 # initialize basic set
1516 # fullmapping records all operations recorded in replacement
1521 # fullmapping records all operations recorded in replacement
1517 for rep in replacements:
1522 for rep in replacements:
1518 allsuccs.update(rep[1])
1523 allsuccs.update(rep[1])
1519 replaced.add(rep[0])
1524 replaced.add(rep[0])
1520 fullmapping.setdefault(rep[0], set()).update(rep[1])
1525 fullmapping.setdefault(rep[0], set()).update(rep[1])
1521 new = allsuccs - replaced
1526 new = allsuccs - replaced
1522 tmpnodes = allsuccs & replaced
1527 tmpnodes = allsuccs & replaced
1523 # Reduce content fullmapping into direct relation between original nodes
1528 # Reduce content fullmapping into direct relation between original nodes
1524 # and final node created during history edition
1529 # and final node created during history edition
1525 # Dropped changeset are replaced by an empty list
1530 # Dropped changeset are replaced by an empty list
1526 toproceed = set(fullmapping)
1531 toproceed = set(fullmapping)
1527 final = {}
1532 final = {}
1528 while toproceed:
1533 while toproceed:
1529 for x in list(toproceed):
1534 for x in list(toproceed):
1530 succs = fullmapping[x]
1535 succs = fullmapping[x]
1531 for s in list(succs):
1536 for s in list(succs):
1532 if s in toproceed:
1537 if s in toproceed:
1533 # non final node with unknown closure
1538 # non final node with unknown closure
1534 # We can't process this now
1539 # We can't process this now
1535 break
1540 break
1536 elif s in final:
1541 elif s in final:
1537 # non final node, replace with closure
1542 # non final node, replace with closure
1538 succs.remove(s)
1543 succs.remove(s)
1539 succs.update(final[s])
1544 succs.update(final[s])
1540 else:
1545 else:
1541 final[x] = succs
1546 final[x] = succs
1542 toproceed.remove(x)
1547 toproceed.remove(x)
1543 # remove tmpnodes from final mapping
1548 # remove tmpnodes from final mapping
1544 for n in tmpnodes:
1549 for n in tmpnodes:
1545 del final[n]
1550 del final[n]
1546 # we expect all changes involved in final to exist in the repo
1551 # we expect all changes involved in final to exist in the repo
1547 # turn `final` into list (topologically sorted)
1552 # turn `final` into list (topologically sorted)
1548 nm = state.repo.changelog.nodemap
1553 nm = state.repo.changelog.nodemap
1549 for prec, succs in final.items():
1554 for prec, succs in final.items():
1550 final[prec] = sorted(succs, key=nm.get)
1555 final[prec] = sorted(succs, key=nm.get)
1551
1556
1552 # computed topmost element (necessary for bookmark)
1557 # computed topmost element (necessary for bookmark)
1553 if new:
1558 if new:
1554 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
1559 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
1555 elif not final:
1560 elif not final:
1556 # Nothing rewritten at all. we won't need `newtopmost`
1561 # Nothing rewritten at all. we won't need `newtopmost`
1557 # It is the same as `oldtopmost` and `processreplacement` know it
1562 # It is the same as `oldtopmost` and `processreplacement` know it
1558 newtopmost = None
1563 newtopmost = None
1559 else:
1564 else:
1560 # every body died. The newtopmost is the parent of the root.
1565 # every body died. The newtopmost is the parent of the root.
1561 r = state.repo.changelog.rev
1566 r = state.repo.changelog.rev
1562 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
1567 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
1563
1568
1564 return final, tmpnodes, new, newtopmost
1569 return final, tmpnodes, new, newtopmost
1565
1570
1566 def movetopmostbookmarks(repo, oldtopmost, newtopmost):
1571 def movetopmostbookmarks(repo, oldtopmost, newtopmost):
1567 """Move bookmark from oldtopmost to newly created topmost
1572 """Move bookmark from oldtopmost to newly created topmost
1568
1573
1569 This is arguably a feature and we may only want that for the active
1574 This is arguably a feature and we may only want that for the active
1570 bookmark. But the behavior is kept compatible with the old version for now.
1575 bookmark. But the behavior is kept compatible with the old version for now.
1571 """
1576 """
1572 if not oldtopmost or not newtopmost:
1577 if not oldtopmost or not newtopmost:
1573 return
1578 return
1574 oldbmarks = repo.nodebookmarks(oldtopmost)
1579 oldbmarks = repo.nodebookmarks(oldtopmost)
1575 if oldbmarks:
1580 if oldbmarks:
1576 with repo.lock(), repo.transaction('histedit') as tr:
1581 with repo.lock(), repo.transaction('histedit') as tr:
1577 marks = repo._bookmarks
1582 marks = repo._bookmarks
1578 changes = []
1583 changes = []
1579 for name in oldbmarks:
1584 for name in oldbmarks:
1580 changes.append((name, newtopmost))
1585 changes.append((name, newtopmost))
1581 marks.applychanges(repo, tr, changes)
1586 marks.applychanges(repo, tr, changes)
1582
1587
1583 def cleanupnode(ui, repo, nodes):
1588 def cleanupnode(ui, repo, nodes):
1584 """strip a group of nodes from the repository
1589 """strip a group of nodes from the repository
1585
1590
1586 The set of node to strip may contains unknown nodes."""
1591 The set of node to strip may contains unknown nodes."""
1587 with repo.lock():
1592 with repo.lock():
1588 # do not let filtering get in the way of the cleanse
1593 # do not let filtering get in the way of the cleanse
1589 # we should probably get rid of obsolescence marker created during the
1594 # we should probably get rid of obsolescence marker created during the
1590 # histedit, but we currently do not have such information.
1595 # histedit, but we currently do not have such information.
1591 repo = repo.unfiltered()
1596 repo = repo.unfiltered()
1592 # Find all nodes that need to be stripped
1597 # Find all nodes that need to be stripped
1593 # (we use %lr instead of %ln to silently ignore unknown items)
1598 # (we use %lr instead of %ln to silently ignore unknown items)
1594 nm = repo.changelog.nodemap
1599 nm = repo.changelog.nodemap
1595 nodes = sorted(n for n in nodes if n in nm)
1600 nodes = sorted(n for n in nodes if n in nm)
1596 roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
1601 roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
1597 if roots:
1602 if roots:
1598 repair.strip(ui, repo, roots)
1603 repair.strip(ui, repo, roots)
1599
1604
1600 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
1605 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
1601 if isinstance(nodelist, str):
1606 if isinstance(nodelist, str):
1602 nodelist = [nodelist]
1607 nodelist = [nodelist]
1603 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1608 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1604 state = histeditstate(repo)
1609 state = histeditstate(repo)
1605 state.read()
1610 state.read()
1606 histedit_nodes = {action.node for action
1611 histedit_nodes = {action.node for action
1607 in state.actions if action.node}
1612 in state.actions if action.node}
1608 common_nodes = histedit_nodes & set(nodelist)
1613 common_nodes = histedit_nodes & set(nodelist)
1609 if common_nodes:
1614 if common_nodes:
1610 raise error.Abort(_("histedit in progress, can't strip %s")
1615 raise error.Abort(_("histedit in progress, can't strip %s")
1611 % ', '.join(node.short(x) for x in common_nodes))
1616 % ', '.join(node.short(x) for x in common_nodes))
1612 return orig(ui, repo, nodelist, *args, **kwargs)
1617 return orig(ui, repo, nodelist, *args, **kwargs)
1613
1618
1614 extensions.wrapfunction(repair, 'strip', stripwrapper)
1619 extensions.wrapfunction(repair, 'strip', stripwrapper)
1615
1620
1616 def summaryhook(ui, repo):
1621 def summaryhook(ui, repo):
1617 if not os.path.exists(repo.vfs.join('histedit-state')):
1622 if not os.path.exists(repo.vfs.join('histedit-state')):
1618 return
1623 return
1619 state = histeditstate(repo)
1624 state = histeditstate(repo)
1620 state.read()
1625 state.read()
1621 if state.actions:
1626 if state.actions:
1622 # i18n: column positioning for "hg summary"
1627 # i18n: column positioning for "hg summary"
1623 ui.write(_('hist: %s (histedit --continue)\n') %
1628 ui.write(_('hist: %s (histedit --continue)\n') %
1624 (ui.label(_('%d remaining'), 'histedit.remaining') %
1629 (ui.label(_('%d remaining'), 'histedit.remaining') %
1625 len(state.actions)))
1630 len(state.actions)))
1626
1631
1627 def extsetup(ui):
1632 def extsetup(ui):
1628 cmdutil.summaryhooks.add('histedit', summaryhook)
1633 cmdutil.summaryhooks.add('histedit', summaryhook)
1629 cmdutil.unfinishedstates.append(
1634 cmdutil.unfinishedstates.append(
1630 ['histedit-state', False, True, _('histedit in progress'),
1635 ['histedit-state', False, True, _('histedit in progress'),
1631 _("use 'hg histedit --continue' or 'hg histedit --abort'")])
1636 _("use 'hg histedit --continue' or 'hg histedit --abort'")])
1632 cmdutil.afterresolvedstates.append(
1637 cmdutil.afterresolvedstates.append(
1633 ['histedit-state', _('hg histedit --continue')])
1638 ['histedit-state', _('hg histedit --continue')])
1634 if ui.configbool("experimental", "histeditng"):
1635 globals()['base'] = action(['base', 'b'],
1636 _('checkout changeset and apply further changesets from there')
1637 )(base)
@@ -1,549 +1,552 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 # You can reorder changesets by reordering the lines
66 # You can reorder changesets by reordering the lines
67 #
67 #
68 # Commands:
68 # Commands:
69 #
69 #
70 # e, edit = use commit, but stop for amending
70 # e, edit = use commit, but stop for amending
71 # m, mess = edit commit message without changing commit content
71 # m, mess = edit commit message without changing commit content
72 # p, pick = use commit
72 # p, pick = use commit
73 # b, base = checkout changeset and apply further changesets from there
73 # d, drop = remove commit from history
74 # d, drop = remove commit from history
74 # f, fold = use commit, but combine it with the one above
75 # f, fold = use commit, but combine it with the one above
75 # r, roll = like fold, but discard this commit's description and date
76 # r, roll = like fold, but discard this commit's description and date
76 #
77 #
77
78
78 Run on a revision not ancestors of the current working directory.
79 Run on a revision not ancestors of the current working directory.
79 --------------------------------------------------------------------
80 --------------------------------------------------------------------
80
81
81 $ hg up 2
82 $ hg up 2
82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 $ hg histedit -r 4
84 $ hg histedit -r 4
84 abort: 08d98a8350f3 is not an ancestor of working directory
85 abort: 08d98a8350f3 is not an ancestor of working directory
85 [255]
86 [255]
86 $ hg up --quiet
87 $ hg up --quiet
87
88
88
89
89 Test that we pick the minimum of a revrange
90 Test that we pick the minimum of a revrange
90 ---------------------------------------
91 ---------------------------------------
91
92
92 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
93 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
93 > pick eb57da33312f 2 three
94 > pick eb57da33312f 2 three
94 > pick c8e68270e35a 3 four
95 > pick c8e68270e35a 3 four
95 > pick 08d98a8350f3 4 five
96 > pick 08d98a8350f3 4 five
96 > EOF
97 > EOF
97 $ hg up --quiet
98 $ hg up --quiet
98
99
99 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
100 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
100 > pick eb57da33312f 2 three
101 > pick eb57da33312f 2 three
101 > pick c8e68270e35a 3 four
102 > pick c8e68270e35a 3 four
102 > pick 08d98a8350f3 4 five
103 > pick 08d98a8350f3 4 five
103 > EOF
104 > EOF
104 $ hg up --quiet
105 $ hg up --quiet
105
106
106 Test config specified default
107 Test config specified default
107 -----------------------------
108 -----------------------------
108
109
109 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
110 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
110 > pick c8e68270e35a 3 four
111 > pick c8e68270e35a 3 four
111 > pick 08d98a8350f3 4 five
112 > pick 08d98a8350f3 4 five
112 > EOF
113 > EOF
113
114
114 Run on a revision not descendants of the initial parent
115 Run on a revision not descendants of the initial parent
115 --------------------------------------------------------------------
116 --------------------------------------------------------------------
116
117
117 Test the message shown for inconsistent histedit state, which may be
118 Test the message shown for inconsistent histedit state, which may be
118 created (and forgotten) by Mercurial earlier than 2.7. This emulates
119 created (and forgotten) by Mercurial earlier than 2.7. This emulates
119 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
120 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
120 temporarily.
121 temporarily.
121
122
122 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
123 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
123 @ 4 08d9 five
124 @ 4 08d9 five
124 |
125 |
125 o 3 c8e6 four
126 o 3 c8e6 four
126 |
127 |
127 o 2 eb57 three
128 o 2 eb57 three
128 |
129 |
129 ~
130 ~
130 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
131 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
131 > edit 08d98a8350f3 4 five
132 > edit 08d98a8350f3 4 five
132 > EOF
133 > EOF
133 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 reverting alpha
135 reverting alpha
135 Editing (08d98a8350f3), you may commit or record as needed now.
136 Editing (08d98a8350f3), you may commit or record as needed now.
136 (hg histedit --continue to resume)
137 (hg histedit --continue to resume)
137 [1]
138 [1]
138
139
139 $ hg graft --continue
140 $ hg graft --continue
140 abort: no graft in progress
141 abort: no graft in progress
141 (continue: hg histedit --continue)
142 (continue: hg histedit --continue)
142 [255]
143 [255]
143
144
144 $ mv .hg/histedit-state .hg/histedit-state.back
145 $ mv .hg/histedit-state .hg/histedit-state.back
145 $ hg update --quiet --clean 2
146 $ hg update --quiet --clean 2
146 $ echo alpha >> alpha
147 $ echo alpha >> alpha
147 $ mv .hg/histedit-state.back .hg/histedit-state
148 $ mv .hg/histedit-state.back .hg/histedit-state
148
149
149 $ hg histedit --continue
150 $ hg histedit --continue
150 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg (glob)
151 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg (glob)
151 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
152 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
152 @ 4 f5ed five
153 @ 4 f5ed five
153 |
154 |
154 | o 3 c8e6 four
155 | o 3 c8e6 four
155 |/
156 |/
156 o 2 eb57 three
157 o 2 eb57 three
157 |
158 |
158 ~
159 ~
159
160
160 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg
161 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg
161 $ hg strip -q -r f5ed --config extensions.strip=
162 $ hg strip -q -r f5ed --config extensions.strip=
162 $ hg up -q 08d98a8350f3
163 $ hg up -q 08d98a8350f3
163
164
164 Test that missing revisions are detected
165 Test that missing revisions are detected
165 ---------------------------------------
166 ---------------------------------------
166
167
167 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
168 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
168 > pick eb57da33312f 2 three
169 > pick eb57da33312f 2 three
169 > pick 08d98a8350f3 4 five
170 > pick 08d98a8350f3 4 five
170 > EOF
171 > EOF
171 hg: parse error: missing rules for changeset c8e68270e35a
172 hg: parse error: missing rules for changeset c8e68270e35a
172 (use "drop c8e68270e35a" to discard, see also: 'hg help -e histedit.config')
173 (use "drop c8e68270e35a" to discard, see also: 'hg help -e histedit.config')
173 [255]
174 [255]
174
175
175 Test that extra revisions are detected
176 Test that extra revisions are detected
176 ---------------------------------------
177 ---------------------------------------
177
178
178 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
179 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
179 > pick 6058cbb6cfd7 0 one
180 > pick 6058cbb6cfd7 0 one
180 > pick c8e68270e35a 3 four
181 > pick c8e68270e35a 3 four
181 > pick 08d98a8350f3 4 five
182 > pick 08d98a8350f3 4 five
182 > EOF
183 > EOF
183 hg: parse error: pick "6058cbb6cfd7" changeset was not a candidate
184 hg: parse error: pick "6058cbb6cfd7" changeset was not a candidate
184 (only use listed changesets)
185 (only use listed changesets)
185 [255]
186 [255]
186
187
187 Test malformed line
188 Test malformed line
188 ---------------------------------------
189 ---------------------------------------
189
190
190 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
191 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
191 > pickeb57da33312f2three
192 > pickeb57da33312f2three
192 > pick c8e68270e35a 3 four
193 > pick c8e68270e35a 3 four
193 > pick 08d98a8350f3 4 five
194 > pick 08d98a8350f3 4 five
194 > EOF
195 > EOF
195 hg: parse error: malformed line "pickeb57da33312f2three"
196 hg: parse error: malformed line "pickeb57da33312f2three"
196 [255]
197 [255]
197
198
198 Test unknown changeset
199 Test unknown changeset
199 ---------------------------------------
200 ---------------------------------------
200
201
201 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
202 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
202 > pick 0123456789ab 2 three
203 > pick 0123456789ab 2 three
203 > pick c8e68270e35a 3 four
204 > pick c8e68270e35a 3 four
204 > pick 08d98a8350f3 4 five
205 > pick 08d98a8350f3 4 five
205 > EOF
206 > EOF
206 hg: parse error: unknown changeset 0123456789ab listed
207 hg: parse error: unknown changeset 0123456789ab listed
207 [255]
208 [255]
208
209
209 Test unknown command
210 Test unknown command
210 ---------------------------------------
211 ---------------------------------------
211
212
212 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
213 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
213 > coin eb57da33312f 2 three
214 > coin eb57da33312f 2 three
214 > pick c8e68270e35a 3 four
215 > pick c8e68270e35a 3 four
215 > pick 08d98a8350f3 4 five
216 > pick 08d98a8350f3 4 five
216 > EOF
217 > EOF
217 hg: parse error: unknown action "coin"
218 hg: parse error: unknown action "coin"
218 [255]
219 [255]
219
220
220 Test duplicated changeset
221 Test duplicated changeset
221 ---------------------------------------
222 ---------------------------------------
222
223
223 So one is missing and one appear twice.
224 So one is missing and one appear twice.
224
225
225 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
226 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
226 > pick eb57da33312f 2 three
227 > pick eb57da33312f 2 three
227 > pick eb57da33312f 2 three
228 > pick eb57da33312f 2 three
228 > pick 08d98a8350f3 4 five
229 > pick 08d98a8350f3 4 five
229 > EOF
230 > EOF
230 hg: parse error: duplicated command for changeset eb57da33312f
231 hg: parse error: duplicated command for changeset eb57da33312f
231 [255]
232 [255]
232
233
233 Test bogus rev
234 Test bogus rev
234 ---------------------------------------
235 ---------------------------------------
235
236
236 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
237 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
237 > pick eb57da33312f 2 three
238 > pick eb57da33312f 2 three
238 > pick 0
239 > pick 0
239 > pick 08d98a8350f3 4 five
240 > pick 08d98a8350f3 4 five
240 > EOF
241 > EOF
241 hg: parse error: invalid changeset 0
242 hg: parse error: invalid changeset 0
242 [255]
243 [255]
243
244
244 Test short version of command
245 Test short version of command
245 ---------------------------------------
246 ---------------------------------------
246
247
247 Note: we use varying amounts of white space between command name and changeset
248 Note: we use varying amounts of white space between command name and changeset
248 short hash. This tests issue3893.
249 short hash. This tests issue3893.
249
250
250 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
251 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
251 > pick eb57da33312f 2 three
252 > pick eb57da33312f 2 three
252 > p c8e68270e35a 3 four
253 > p c8e68270e35a 3 four
253 > f 08d98a8350f3 4 five
254 > f 08d98a8350f3 4 five
254 > EOF
255 > EOF
255 four
256 four
256 ***
257 ***
257 five
258 five
258
259
259
260
260
261
261 HG: Enter commit message. Lines beginning with 'HG:' are removed.
262 HG: Enter commit message. Lines beginning with 'HG:' are removed.
262 HG: Leave message empty to abort commit.
263 HG: Leave message empty to abort commit.
263 HG: --
264 HG: --
264 HG: user: test
265 HG: user: test
265 HG: branch 'default'
266 HG: branch 'default'
266 HG: changed alpha
267 HG: changed alpha
267 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/c8e68270e35a-63d8b8d8-histedit.hg (glob)
268 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/c8e68270e35a-63d8b8d8-histedit.hg (glob)
268
269
269 $ hg update -q 2
270 $ hg update -q 2
270 $ echo x > x
271 $ echo x > x
271 $ hg add x
272 $ hg add x
272 $ hg commit -m'x' x
273 $ hg commit -m'x' x
273 created new head
274 created new head
274 $ hg histedit -r 'heads(all())'
275 $ hg histedit -r 'heads(all())'
275 abort: The specified revisions must have exactly one common root
276 abort: The specified revisions must have exactly one common root
276 [255]
277 [255]
277
278
278 Test that trimming description using multi-byte characters
279 Test that trimming description using multi-byte characters
279 --------------------------------------------------------------------
280 --------------------------------------------------------------------
280
281
281 $ $PYTHON <<EOF
282 $ $PYTHON <<EOF
282 > fp = open('logfile', 'w')
283 > fp = open('logfile', 'w')
283 > fp.write('12345678901234567890123456789012345678901234567890' +
284 > fp.write('12345678901234567890123456789012345678901234567890' +
284 > '12345') # there are 5 more columns for 80 columns
285 > '12345') # there are 5 more columns for 80 columns
285 >
286 >
286 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
287 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
287 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
288 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
288 >
289 >
289 > fp.close()
290 > fp.close()
290 > EOF
291 > EOF
291 $ echo xx >> x
292 $ echo xx >> x
292 $ hg --encoding utf-8 commit --logfile logfile
293 $ hg --encoding utf-8 commit --logfile logfile
293
294
294 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
295 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
295 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
296 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
296
297
297 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
298 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
298 #
299 #
299 # Commits are listed from least to most recent
300 # Commits are listed from least to most recent
300 #
301 #
301 # You can reorder changesets by reordering the lines
302 # You can reorder changesets by reordering the lines
302 #
303 #
303 # Commands:
304 # Commands:
304 #
305 #
305 # e, edit = use commit, but stop for amending
306 # e, edit = use commit, but stop for amending
306 # m, mess = edit commit message without changing commit content
307 # m, mess = edit commit message without changing commit content
307 # p, pick = use commit
308 # p, pick = use commit
309 # b, base = checkout changeset and apply further changesets from there
308 # d, drop = remove commit from history
310 # d, drop = remove commit from history
309 # f, fold = use commit, but combine it with the one above
311 # f, fold = use commit, but combine it with the one above
310 # r, roll = like fold, but discard this commit's description and date
312 # r, roll = like fold, but discard this commit's description and date
311 #
313 #
312
314
313 Test --continue with --keep
315 Test --continue with --keep
314
316
315 $ hg strip -q -r . --config extensions.strip=
317 $ hg strip -q -r . --config extensions.strip=
316 $ hg histedit '.^' -q --keep --commands - << EOF
318 $ hg histedit '.^' -q --keep --commands - << EOF
317 > edit eb57da33312f 2 three
319 > edit eb57da33312f 2 three
318 > pick f3cfcca30c44 4 x
320 > pick f3cfcca30c44 4 x
319 > EOF
321 > EOF
320 Editing (eb57da33312f), you may commit or record as needed now.
322 Editing (eb57da33312f), you may commit or record as needed now.
321 (hg histedit --continue to resume)
323 (hg histedit --continue to resume)
322 [1]
324 [1]
323 $ echo edit >> alpha
325 $ echo edit >> alpha
324 $ hg histedit -q --continue
326 $ hg histedit -q --continue
325 $ hg log -G -T '{rev}:{node|short} {desc}'
327 $ hg log -G -T '{rev}:{node|short} {desc}'
326 @ 6:8fda0c726bf2 x
328 @ 6:8fda0c726bf2 x
327 |
329 |
328 o 5:63379946892c three
330 o 5:63379946892c three
329 |
331 |
330 | o 4:f3cfcca30c44 x
332 | o 4:f3cfcca30c44 x
331 | |
333 | |
332 | | o 3:2a30f3cfee78 four
334 | | o 3:2a30f3cfee78 four
333 | |/ ***
335 | |/ ***
334 | | five
336 | | five
335 | o 2:eb57da33312f three
337 | o 2:eb57da33312f three
336 |/
338 |/
337 o 1:579e40513370 two
339 o 1:579e40513370 two
338 |
340 |
339 o 0:6058cbb6cfd7 one
341 o 0:6058cbb6cfd7 one
340
342
341
343
342 Test that abort fails gracefully on exception
344 Test that abort fails gracefully on exception
343 ----------------------------------------------
345 ----------------------------------------------
344 $ hg histedit . -q --commands - << EOF
346 $ hg histedit . -q --commands - << EOF
345 > edit 8fda0c726bf2 6 x
347 > edit 8fda0c726bf2 6 x
346 > EOF
348 > EOF
347 Editing (8fda0c726bf2), you may commit or record as needed now.
349 Editing (8fda0c726bf2), you may commit or record as needed now.
348 (hg histedit --continue to resume)
350 (hg histedit --continue to resume)
349 [1]
351 [1]
350 Corrupt histedit state file
352 Corrupt histedit state file
351 $ sed 's/8fda0c726bf2/123456789012/' .hg/histedit-state > ../corrupt-histedit
353 $ sed 's/8fda0c726bf2/123456789012/' .hg/histedit-state > ../corrupt-histedit
352 $ mv ../corrupt-histedit .hg/histedit-state
354 $ mv ../corrupt-histedit .hg/histedit-state
353 $ hg histedit --abort
355 $ hg histedit --abort
354 warning: encountered an exception during histedit --abort; the repository may not have been completely cleaned up
356 warning: encountered an exception during histedit --abort; the repository may not have been completely cleaned up
355 abort: .*(No such file or directory:|The system cannot find the file specified).* (re)
357 abort: .*(No such file or directory:|The system cannot find the file specified).* (re)
356 [255]
358 [255]
357 Histedit state has been exited
359 Histedit state has been exited
358 $ hg summary -q
360 $ hg summary -q
359 parent: 5:63379946892c
361 parent: 5:63379946892c
360 commit: 1 added, 1 unknown (new branch head)
362 commit: 1 added, 1 unknown (new branch head)
361 update: 4 new changesets (update)
363 update: 4 new changesets (update)
362
364
363 $ cd ..
365 $ cd ..
364
366
365 Set up default base revision tests
367 Set up default base revision tests
366
368
367 $ hg init defaultbase
369 $ hg init defaultbase
368 $ cd defaultbase
370 $ cd defaultbase
369 $ touch foo
371 $ touch foo
370 $ hg -q commit -A -m root
372 $ hg -q commit -A -m root
371 $ echo 1 > foo
373 $ echo 1 > foo
372 $ hg commit -m 'public 1'
374 $ hg commit -m 'public 1'
373 $ hg phase --force --public -r .
375 $ hg phase --force --public -r .
374 $ echo 2 > foo
376 $ echo 2 > foo
375 $ hg commit -m 'draft after public'
377 $ hg commit -m 'draft after public'
376 $ hg -q up -r 1
378 $ hg -q up -r 1
377 $ echo 3 > foo
379 $ echo 3 > foo
378 $ hg commit -m 'head 1 public'
380 $ hg commit -m 'head 1 public'
379 created new head
381 created new head
380 $ hg phase --force --public -r .
382 $ hg phase --force --public -r .
381 $ echo 4 > foo
383 $ echo 4 > foo
382 $ hg commit -m 'head 1 draft 1'
384 $ hg commit -m 'head 1 draft 1'
383 $ echo 5 > foo
385 $ echo 5 > foo
384 $ hg commit -m 'head 1 draft 2'
386 $ hg commit -m 'head 1 draft 2'
385 $ hg -q up -r 2
387 $ hg -q up -r 2
386 $ echo 6 > foo
388 $ echo 6 > foo
387 $ hg commit -m 'head 2 commit 1'
389 $ hg commit -m 'head 2 commit 1'
388 $ echo 7 > foo
390 $ echo 7 > foo
389 $ hg commit -m 'head 2 commit 2'
391 $ hg commit -m 'head 2 commit 2'
390 $ hg -q up -r 2
392 $ hg -q up -r 2
391 $ echo 8 > foo
393 $ echo 8 > foo
392 $ hg commit -m 'head 3'
394 $ hg commit -m 'head 3'
393 created new head
395 created new head
394 $ hg -q up -r 2
396 $ hg -q up -r 2
395 $ echo 9 > foo
397 $ echo 9 > foo
396 $ hg commit -m 'head 4'
398 $ hg commit -m 'head 4'
397 created new head
399 created new head
398 $ hg merge --tool :local -r 8
400 $ hg merge --tool :local -r 8
399 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
401 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
400 (branch merge, don't forget to commit)
402 (branch merge, don't forget to commit)
401 $ hg commit -m 'merge head 3 into head 4'
403 $ hg commit -m 'merge head 3 into head 4'
402 $ echo 11 > foo
404 $ echo 11 > foo
403 $ hg commit -m 'commit 1 after merge'
405 $ hg commit -m 'commit 1 after merge'
404 $ echo 12 > foo
406 $ echo 12 > foo
405 $ hg commit -m 'commit 2 after merge'
407 $ hg commit -m 'commit 2 after merge'
406
408
407 $ hg log -G -T '{rev}:{node|short} {phase} {desc}\n'
409 $ hg log -G -T '{rev}:{node|short} {phase} {desc}\n'
408 @ 12:8cde254db839 draft commit 2 after merge
410 @ 12:8cde254db839 draft commit 2 after merge
409 |
411 |
410 o 11:6f2f0241f119 draft commit 1 after merge
412 o 11:6f2f0241f119 draft commit 1 after merge
411 |
413 |
412 o 10:90506cc76b00 draft merge head 3 into head 4
414 o 10:90506cc76b00 draft merge head 3 into head 4
413 |\
415 |\
414 | o 9:f8607a373a97 draft head 4
416 | o 9:f8607a373a97 draft head 4
415 | |
417 | |
416 o | 8:0da92be05148 draft head 3
418 o | 8:0da92be05148 draft head 3
417 |/
419 |/
418 | o 7:4c35cdf97d5e draft head 2 commit 2
420 | o 7:4c35cdf97d5e draft head 2 commit 2
419 | |
421 | |
420 | o 6:931820154288 draft head 2 commit 1
422 | o 6:931820154288 draft head 2 commit 1
421 |/
423 |/
422 | o 5:8cdc02b9bc63 draft head 1 draft 2
424 | o 5:8cdc02b9bc63 draft head 1 draft 2
423 | |
425 | |
424 | o 4:463b8c0d2973 draft head 1 draft 1
426 | o 4:463b8c0d2973 draft head 1 draft 1
425 | |
427 | |
426 | o 3:23a0c4eefcbf public head 1 public
428 | o 3:23a0c4eefcbf public head 1 public
427 | |
429 | |
428 o | 2:4117331c3abb draft draft after public
430 o | 2:4117331c3abb draft draft after public
429 |/
431 |/
430 o 1:4426d359ea59 public public 1
432 o 1:4426d359ea59 public public 1
431 |
433 |
432 o 0:54136a8ddf32 public root
434 o 0:54136a8ddf32 public root
433
435
434
436
435 Default base revision should stop at public changesets
437 Default base revision should stop at public changesets
436
438
437 $ hg -q up 8cdc02b9bc63
439 $ hg -q up 8cdc02b9bc63
438 $ hg histedit --commands - <<EOF
440 $ hg histedit --commands - <<EOF
439 > pick 463b8c0d2973
441 > pick 463b8c0d2973
440 > pick 8cdc02b9bc63
442 > pick 8cdc02b9bc63
441 > EOF
443 > EOF
442
444
443 Default base revision should stop at branchpoint
445 Default base revision should stop at branchpoint
444
446
445 $ hg -q up 4c35cdf97d5e
447 $ hg -q up 4c35cdf97d5e
446 $ hg histedit --commands - <<EOF
448 $ hg histedit --commands - <<EOF
447 > pick 931820154288
449 > pick 931820154288
448 > pick 4c35cdf97d5e
450 > pick 4c35cdf97d5e
449 > EOF
451 > EOF
450
452
451 Default base revision should stop at merge commit
453 Default base revision should stop at merge commit
452
454
453 $ hg -q up 8cde254db839
455 $ hg -q up 8cde254db839
454 $ hg histedit --commands - <<EOF
456 $ hg histedit --commands - <<EOF
455 > pick 6f2f0241f119
457 > pick 6f2f0241f119
456 > pick 8cde254db839
458 > pick 8cde254db839
457 > EOF
459 > EOF
458
460
459 commit --amend should abort if histedit is in progress
461 commit --amend should abort if histedit is in progress
460 (issue4800) and markers are not being created.
462 (issue4800) and markers are not being created.
461 Eventually, histedit could perhaps look at `source` extra,
463 Eventually, histedit could perhaps look at `source` extra,
462 in which case this test should be revisited.
464 in which case this test should be revisited.
463
465
464 $ hg -q up 8cde254db839
466 $ hg -q up 8cde254db839
465 $ hg histedit 6f2f0241f119 --commands - <<EOF
467 $ hg histedit 6f2f0241f119 --commands - <<EOF
466 > pick 8cde254db839
468 > pick 8cde254db839
467 > edit 6f2f0241f119
469 > edit 6f2f0241f119
468 > EOF
470 > EOF
469 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 merging foo
472 merging foo
471 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
473 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
472 Fix up the change (pick 8cde254db839)
474 Fix up the change (pick 8cde254db839)
473 (hg histedit --continue to resume)
475 (hg histedit --continue to resume)
474 [1]
476 [1]
475 $ hg resolve -m --all
477 $ hg resolve -m --all
476 (no more unresolved files)
478 (no more unresolved files)
477 continue: hg histedit --continue
479 continue: hg histedit --continue
478 $ hg histedit --cont
480 $ hg histedit --cont
479 merging foo
481 merging foo
480 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
482 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
481 Editing (6f2f0241f119), you may commit or record as needed now.
483 Editing (6f2f0241f119), you may commit or record as needed now.
482 (hg histedit --continue to resume)
484 (hg histedit --continue to resume)
483 [1]
485 [1]
484 $ hg resolve -m --all
486 $ hg resolve -m --all
485 (no more unresolved files)
487 (no more unresolved files)
486 continue: hg histedit --continue
488 continue: hg histedit --continue
487 $ hg commit --amend -m 'reject this fold'
489 $ hg commit --amend -m 'reject this fold'
488 abort: histedit in progress
490 abort: histedit in progress
489 (use 'hg histedit --continue' or 'hg histedit --abort')
491 (use 'hg histedit --continue' or 'hg histedit --abort')
490 [255]
492 [255]
491
493
492 With markers enabled, histedit does not get confused, and
494 With markers enabled, histedit does not get confused, and
493 amend should not be blocked by the ongoing histedit.
495 amend should not be blocked by the ongoing histedit.
494
496
495 $ cat >>$HGRCPATH <<EOF
497 $ cat >>$HGRCPATH <<EOF
496 > [experimental]
498 > [experimental]
497 > stabilization=createmarkers,allowunstable
499 > stabilization=createmarkers,allowunstable
498 > EOF
500 > EOF
499 $ hg commit --amend -m 'allow this fold'
501 $ hg commit --amend -m 'allow this fold'
500 $ hg histedit --continue
502 $ hg histedit --continue
501
503
502 $ cd ..
504 $ cd ..
503
505
504 Test autoverb feature
506 Test autoverb feature
505
507
506 $ hg init autoverb
508 $ hg init autoverb
507 $ cd autoverb
509 $ cd autoverb
508 $ echo alpha >> alpha
510 $ echo alpha >> alpha
509 $ hg ci -qAm one
511 $ hg ci -qAm one
510 $ echo alpha >> alpha
512 $ echo alpha >> alpha
511 $ hg ci -qm two
513 $ hg ci -qm two
512 $ echo beta >> beta
514 $ echo beta >> beta
513 $ hg ci -qAm "roll! one"
515 $ hg ci -qAm "roll! one"
514
516
515 $ hg log --style compact --graph
517 $ hg log --style compact --graph
516 @ 2[tip] 4f34d0f8b5fa 1970-01-01 00:00 +0000 test
518 @ 2[tip] 4f34d0f8b5fa 1970-01-01 00:00 +0000 test
517 | roll! one
519 | roll! one
518 |
520 |
519 o 1 579e40513370 1970-01-01 00:00 +0000 test
521 o 1 579e40513370 1970-01-01 00:00 +0000 test
520 | two
522 | two
521 |
523 |
522 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
524 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
523 one
525 one
524
526
525
527
526 Check that 'roll' is selected by default
528 Check that 'roll' is selected by default
527
529
528 $ HGEDITOR=cat hg histedit 0 --config experimental.histedit.autoverb=True
530 $ HGEDITOR=cat hg histedit 0 --config experimental.histedit.autoverb=True
529 pick 6058cbb6cfd7 0 one
531 pick 6058cbb6cfd7 0 one
530 roll 4f34d0f8b5fa 2 roll! one
532 roll 4f34d0f8b5fa 2 roll! one
531 pick 579e40513370 1 two
533 pick 579e40513370 1 two
532
534
533 # Edit history between 6058cbb6cfd7 and 4f34d0f8b5fa
535 # Edit history between 6058cbb6cfd7 and 4f34d0f8b5fa
534 #
536 #
535 # Commits are listed from least to most recent
537 # Commits are listed from least to most recent
536 #
538 #
537 # You can reorder changesets by reordering the lines
539 # You can reorder changesets by reordering the lines
538 #
540 #
539 # Commands:
541 # Commands:
540 #
542 #
541 # e, edit = use commit, but stop for amending
543 # e, edit = use commit, but stop for amending
542 # m, mess = edit commit message without changing commit content
544 # m, mess = edit commit message without changing commit content
543 # p, pick = use commit
545 # p, pick = use commit
546 # b, base = checkout changeset and apply further changesets from there
544 # d, drop = remove commit from history
547 # d, drop = remove commit from history
545 # f, fold = use commit, but combine it with the one above
548 # f, fold = use commit, but combine it with the one above
546 # r, roll = like fold, but discard this commit's description and date
549 # r, roll = like fold, but discard this commit's description and date
547 #
550 #
548
551
549 $ cd ..
552 $ cd ..
@@ -1,268 +1,257 b''
1 $ . "$TESTDIR/histedit-helpers.sh"
1 $ . "$TESTDIR/histedit-helpers.sh"
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [alias]
4 > [alias]
5 > tglog = log -G --template "{rev}:{node}:{phase} '{desc}'\n"
5 > tglog = log -G --template "{rev}:{node}:{phase} '{desc}'\n"
6 > [extensions]
6 > [extensions]
7 > histedit=
7 > histedit=
8 > [experimental]
9 > histeditng=True
10 > EOF
8 > EOF
11
9
12 Create repo a:
10 Create repo a:
13
11
14 $ hg init a
12 $ hg init a
15 $ cd a
13 $ cd a
16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
14 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
17 adding changesets
15 adding changesets
18 adding manifests
16 adding manifests
19 adding file changes
17 adding file changes
20 added 8 changesets with 7 changes to 7 files (+2 heads)
18 added 8 changesets with 7 changes to 7 files (+2 heads)
21 (run 'hg heads' to see heads, 'hg merge' to merge)
19 (run 'hg heads' to see heads, 'hg merge' to merge)
22 $ hg up tip
20 $ hg up tip
23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
24
22
25 $ hg tglog
23 $ hg tglog
26 @ 7:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
24 @ 7:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
27 |
25 |
28 | o 6:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
26 | o 6:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
29 |/|
27 |/|
30 o | 5:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
28 o | 5:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
31 | |
29 | |
32 | o 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
30 | o 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
33 |/
31 |/
34 | o 3:32af7686d403cf45b5d95f2d70cebea587ac806a:draft 'D'
32 | o 3:32af7686d403cf45b5d95f2d70cebea587ac806a:draft 'D'
35 | |
33 | |
36 | o 2:5fddd98957c8a54a4d436dfe1da9d87f21a1b97b:draft 'C'
34 | o 2:5fddd98957c8a54a4d436dfe1da9d87f21a1b97b:draft 'C'
37 | |
35 | |
38 | o 1:42ccdea3bb16d28e1848c95fe2e44c000f3f21b1:draft 'B'
36 | o 1:42ccdea3bb16d28e1848c95fe2e44c000f3f21b1:draft 'B'
39 |/
37 |/
40 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
38 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
41
39
42 Verify that implicit base command and help are listed
40 Verify that implicit base command and help are listed
43
41
44 $ HGEDITOR=cat hg histedit |grep base
42 $ HGEDITOR=cat hg histedit |grep base
45 # b, base = checkout changeset and apply further changesets from there
43 # b, base = checkout changeset and apply further changesets from there
46
44
47 Go to D
45 Go to D
48 $ hg update 3
46 $ hg update 3
49 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
47 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
50 edit the history to rebase B onto H
48 edit the history to rebase B onto H
51
49
52
50
53 Rebase B onto H
51 Rebase B onto H
54 $ hg histedit 1 --commands - 2>&1 << EOF | fixbundle
52 $ hg histedit 1 --commands - 2>&1 << EOF | fixbundle
55 > base 02de42196ebe
53 > base 02de42196ebe
56 > pick 42ccdea3bb16 B
54 > pick 42ccdea3bb16 B
57 > pick 5fddd98957c8 C
55 > pick 5fddd98957c8 C
58 > pick 32af7686d403 D
56 > pick 32af7686d403 D
59 > EOF
57 > EOF
60
58
61 $ hg tglog
59 $ hg tglog
62 @ 7:0937e82309df47d14176ee15e45dbec5fbdef340:draft 'D'
60 @ 7:0937e82309df47d14176ee15e45dbec5fbdef340:draft 'D'
63 |
61 |
64 o 6:f778d1cbddac4ab679d9983c9bb92e4c5e09e7fa:draft 'C'
62 o 6:f778d1cbddac4ab679d9983c9bb92e4c5e09e7fa:draft 'C'
65 |
63 |
66 o 5:3d41b7cc708545206213a842f96d812d2e73d818:draft 'B'
64 o 5:3d41b7cc708545206213a842f96d812d2e73d818:draft 'B'
67 |
65 |
68 o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
66 o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
69 |
67 |
70 | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
68 | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
71 |/|
69 |/|
72 o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
70 o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
73 | |
71 | |
74 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
72 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
75 |/
73 |/
76 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
74 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
77
75
78 Rebase back and drop something
76 Rebase back and drop something
79 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
77 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
80 > base cd010b8cd998
78 > base cd010b8cd998
81 > pick 3d41b7cc7085 B
79 > pick 3d41b7cc7085 B
82 > drop f778d1cbddac C
80 > drop f778d1cbddac C
83 > pick 0937e82309df D
81 > pick 0937e82309df D
84 > EOF
82 > EOF
85
83
86 $ hg tglog
84 $ hg tglog
87 @ 6:476cc3e4168da2d036b141f7f7dcff7f8e3fe846:draft 'D'
85 @ 6:476cc3e4168da2d036b141f7f7dcff7f8e3fe846:draft 'D'
88 |
86 |
89 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
87 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
90 |
88 |
91 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
89 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
92 | |
90 | |
93 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
91 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
94 | |/|
92 | |/|
95 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
93 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
96 |/ /
94 |/ /
97 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
95 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
98 |/
96 |/
99 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
97 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
100
98
101 Split stack
99 Split stack
102 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
100 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
103 > base cd010b8cd998
101 > base cd010b8cd998
104 > pick d273e35dcdf2 B
102 > pick d273e35dcdf2 B
105 > base cd010b8cd998
103 > base cd010b8cd998
106 > pick 476cc3e4168d D
104 > pick 476cc3e4168d D
107 > EOF
105 > EOF
108
106
109 $ hg tglog
107 $ hg tglog
110 @ 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
108 @ 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
111 |
109 |
112 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
110 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
113 |/
111 |/
114 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
112 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
115 | |
113 | |
116 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
114 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
117 | |/|
115 | |/|
118 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
116 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
119 |/ /
117 |/ /
120 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
118 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
121 |/
119 |/
122 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
120 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
123
121
124 Abort
122 Abort
125 $ echo x > B
123 $ echo x > B
126 $ hg add B
124 $ hg add B
127 $ hg commit -m "X"
125 $ hg commit -m "X"
128 $ hg tglog
126 $ hg tglog
129 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
127 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
130 |
128 |
131 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
129 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
132 |
130 |
133 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
131 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
134 |/
132 |/
135 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
133 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
136 | |
134 | |
137 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
135 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
138 | |/|
136 | |/|
139 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
137 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
140 |/ /
138 |/ /
141 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
139 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
142 |/
140 |/
143 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
141 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
144
142
145 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
143 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
146 > base d273e35dcdf2 B
144 > base d273e35dcdf2 B
147 > drop d7a6f907a822 D
145 > drop d7a6f907a822 D
148 > pick 591369deedfd X
146 > pick 591369deedfd X
149 > EOF
147 > EOF
150 merging B
148 merging B
151 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
149 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
152 Fix up the change (pick 591369deedfd)
150 Fix up the change (pick 591369deedfd)
153 (hg histedit --continue to resume)
151 (hg histedit --continue to resume)
154 $ hg histedit --abort | fixbundle
152 $ hg histedit --abort | fixbundle
155 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 $ hg tglog
154 $ hg tglog
157 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
155 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
158 |
156 |
159 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
157 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
160 |
158 |
161 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
159 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
162 |/
160 |/
163 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
161 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
164 | |
162 | |
165 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
163 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
166 | |/|
164 | |/|
167 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
165 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
168 |/ /
166 |/ /
169 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
167 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
170 |/
168 |/
171 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
169 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
172
170
173 Continue
171 Continue
174 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
172 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
175 > base d273e35dcdf2 B
173 > base d273e35dcdf2 B
176 > drop d7a6f907a822 D
174 > drop d7a6f907a822 D
177 > pick 591369deedfd X
175 > pick 591369deedfd X
178 > EOF
176 > EOF
179 merging B
177 merging B
180 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
178 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
181 Fix up the change (pick 591369deedfd)
179 Fix up the change (pick 591369deedfd)
182 (hg histedit --continue to resume)
180 (hg histedit --continue to resume)
183 $ echo b2 > B
181 $ echo b2 > B
184 $ hg resolve --mark B
182 $ hg resolve --mark B
185 (no more unresolved files)
183 (no more unresolved files)
186 continue: hg histedit --continue
184 continue: hg histedit --continue
187 $ hg histedit --continue | fixbundle
185 $ hg histedit --continue | fixbundle
188 $ hg tglog
186 $ hg tglog
189 @ 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
187 @ 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
190 |
188 |
191 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
189 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
192 |
190 |
193 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
191 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
194 | |
192 | |
195 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
193 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
196 | |/|
194 | |/|
197 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
195 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
198 |/ /
196 |/ /
199 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
197 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
200 |/
198 |/
201 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
199 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
202
200
203
201
204 base on a previously picked changeset
202 base on a previously picked changeset
205 $ echo i > i
203 $ echo i > i
206 $ hg add i
204 $ hg add i
207 $ hg commit -m "I"
205 $ hg commit -m "I"
208 $ echo j > j
206 $ echo j > j
209 $ hg add j
207 $ hg add j
210 $ hg commit -m "J"
208 $ hg commit -m "J"
211 $ hg tglog
209 $ hg tglog
212 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
210 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
213 |
211 |
214 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
212 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
215 |
213 |
216 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
214 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
217 |
215 |
218 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
216 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
219 |
217 |
220 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
218 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
221 | |
219 | |
222 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
220 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
223 | |/|
221 | |/|
224 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
222 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
225 |/ /
223 |/ /
226 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
224 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
227 |/
225 |/
228 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
226 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
229
227
230 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
228 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
231 > pick d273e35dcdf2 B
229 > pick d273e35dcdf2 B
232 > pick 03772da75548 X
230 > pick 03772da75548 X
233 > base d273e35dcdf2 B
231 > base d273e35dcdf2 B
234 > pick e8c55b19d366 J
232 > pick e8c55b19d366 J
235 > base d273e35dcdf2 B
233 > base d273e35dcdf2 B
236 > pick b2f90fd8aa85 I
234 > pick b2f90fd8aa85 I
237 > EOF
235 > EOF
238 hg: parse error: base "d273e35dcdf2" changeset was an edited list candidate
236 hg: parse error: base "d273e35dcdf2" changeset was an edited list candidate
239 (base must only use unlisted changesets)
237 (base must only use unlisted changesets)
240
238
241 $ hg --config experimental.histeditng=False histedit 5 --commands - 2>&1 << EOF | fixbundle
242 > base cd010b8cd998 A
243 > pick d273e35dcdf2 B
244 > pick 03772da75548 X
245 > pick b2f90fd8aa85 I
246 > pick e8c55b19d366 J
247 > EOF
248 hg: parse error: unknown action "base"
249
250 $ hg tglog
239 $ hg tglog
251 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
240 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
252 |
241 |
253 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
242 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
254 |
243 |
255 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
244 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
256 |
245 |
257 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
246 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
258 |
247 |
259 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
248 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
260 | |
249 | |
261 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
250 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
262 | |/|
251 | |/|
263 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
252 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
264 |/ /
253 |/ /
265 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
254 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
266 |/
255 |/
267 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
256 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
268
257
@@ -1,176 +1,178 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 # You can reorder changesets by reordering the lines
72 # You can reorder changesets by reordering the lines
73 #
73 #
74 # Commands:
74 # Commands:
75 #
75 #
76 # e, edit = use commit, but stop for amending
76 # e, edit = use commit, but stop for amending
77 # m, mess = edit commit message without changing commit content
77 # m, mess = edit commit message without changing commit content
78 # p, pick = use commit
78 # p, pick = use commit
79 # b, base = checkout changeset and apply further changesets from there
79 # d, drop = remove commit from history
80 # d, drop = remove commit from history
80 # f, fold = use commit, but combine it with the one above
81 # f, fold = use commit, but combine it with the one above
81 # r, roll = like fold, but discard this commit's description and date
82 # r, roll = like fold, but discard this commit's description and date
82 #
83 #
83 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
84 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
84 > pick 177f92b77385 2 c
85 > pick 177f92b77385 2 c
85 > drop d2ae7f538514 1 b
86 > drop d2ae7f538514 1 b
86 > pick 055a42cdd887 3 d
87 > pick 055a42cdd887 3 d
87 > fold e860deea161a 4 e
88 > fold e860deea161a 4 e
88 > pick 652413bf663e 5 f
89 > pick 652413bf663e 5 f
89 > EOF
90 > EOF
90 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-45c027ab-histedit.hg (glob)
91 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-45c027ab-histedit.hg (glob)
91 $ hg log --graph
92 $ hg log --graph
92 @ changeset: 3:cacdfd884a93
93 @ changeset: 3:cacdfd884a93
93 | bookmark: five
94 | bookmark: five
94 | tag: tip
95 | tag: tip
95 | user: test
96 | user: test
96 | date: Thu Jan 01 00:00:00 1970 +0000
97 | date: Thu Jan 01 00:00:00 1970 +0000
97 | summary: f
98 | summary: f
98 |
99 |
99 o changeset: 2:59d9f330561f
100 o changeset: 2:59d9f330561f
100 | bookmark: four
101 | bookmark: four
101 | bookmark: three
102 | bookmark: three
102 | user: test
103 | user: test
103 | date: Thu Jan 01 00:00:00 1970 +0000
104 | date: Thu Jan 01 00:00:00 1970 +0000
104 | summary: d
105 | summary: d
105 |
106 |
106 o changeset: 1:b346ab9a313d
107 o changeset: 1:b346ab9a313d
107 | bookmark: also-two
108 | bookmark: also-two
108 | bookmark: two
109 | bookmark: two
109 | user: test
110 | user: test
110 | date: Thu Jan 01 00:00:00 1970 +0000
111 | date: Thu Jan 01 00:00:00 1970 +0000
111 | summary: c
112 | summary: c
112 |
113 |
113 o changeset: 0:cb9a9f314b8b
114 o changeset: 0:cb9a9f314b8b
114 bookmark: will-move-backwards
115 bookmark: will-move-backwards
115 user: test
116 user: test
116 date: Thu Jan 01 00:00:00 1970 +0000
117 date: Thu Jan 01 00:00:00 1970 +0000
117 summary: a
118 summary: a
118
119
119 $ HGEDITOR=cat hg histedit 1
120 $ HGEDITOR=cat hg histedit 1
120 pick b346ab9a313d 1 c
121 pick b346ab9a313d 1 c
121 pick 59d9f330561f 2 d
122 pick 59d9f330561f 2 d
122 pick cacdfd884a93 3 f
123 pick cacdfd884a93 3 f
123
124
124 # Edit history between b346ab9a313d and cacdfd884a93
125 # Edit history between b346ab9a313d and cacdfd884a93
125 #
126 #
126 # Commits are listed from least to most recent
127 # Commits are listed from least to most recent
127 #
128 #
128 # You can reorder changesets by reordering the lines
129 # You can reorder changesets by reordering the lines
129 #
130 #
130 # Commands:
131 # Commands:
131 #
132 #
132 # e, edit = use commit, but stop for amending
133 # e, edit = use commit, but stop for amending
133 # m, mess = edit commit message without changing commit content
134 # m, mess = edit commit message without changing commit content
134 # p, pick = use commit
135 # p, pick = use commit
136 # b, base = checkout changeset and apply further changesets from there
135 # d, drop = remove commit from history
137 # d, drop = remove commit from history
136 # f, fold = use commit, but combine it with the one above
138 # f, fold = use commit, but combine it with the one above
137 # r, roll = like fold, but discard this commit's description and date
139 # r, roll = like fold, but discard this commit's description and date
138 #
140 #
139 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
141 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
140 > pick b346ab9a313d 1 c
142 > pick b346ab9a313d 1 c
141 > pick cacdfd884a93 3 f
143 > pick cacdfd884a93 3 f
142 > pick 59d9f330561f 2 d
144 > pick 59d9f330561f 2 d
143 > EOF
145 > EOF
144 saved backup bundle to $TESTTMP/r/.hg/strip-backup/59d9f330561f-073008af-histedit.hg (glob)
146 saved backup bundle to $TESTTMP/r/.hg/strip-backup/59d9f330561f-073008af-histedit.hg (glob)
145
147
146 We expect 'five' to stay at tip, since the tipmost bookmark is most
148 We expect 'five' to stay at tip, since the tipmost bookmark is most
147 likely the useful signal.
149 likely the useful signal.
148
150
149 $ hg log --graph
151 $ hg log --graph
150 @ changeset: 3:c04e50810e4b
152 @ changeset: 3:c04e50810e4b
151 | bookmark: five
153 | bookmark: five
152 | bookmark: four
154 | bookmark: four
153 | bookmark: three
155 | bookmark: three
154 | tag: tip
156 | tag: tip
155 | user: test
157 | user: test
156 | date: Thu Jan 01 00:00:00 1970 +0000
158 | date: Thu Jan 01 00:00:00 1970 +0000
157 | summary: d
159 | summary: d
158 |
160 |
159 o changeset: 2:c13eb81022ca
161 o changeset: 2:c13eb81022ca
160 | user: test
162 | user: test
161 | date: Thu Jan 01 00:00:00 1970 +0000
163 | date: Thu Jan 01 00:00:00 1970 +0000
162 | summary: f
164 | summary: f
163 |
165 |
164 o changeset: 1:b346ab9a313d
166 o changeset: 1:b346ab9a313d
165 | bookmark: also-two
167 | bookmark: also-two
166 | bookmark: two
168 | bookmark: two
167 | user: test
169 | user: test
168 | date: Thu Jan 01 00:00:00 1970 +0000
170 | date: Thu Jan 01 00:00:00 1970 +0000
169 | summary: c
171 | summary: c
170 |
172 |
171 o changeset: 0:cb9a9f314b8b
173 o changeset: 0:cb9a9f314b8b
172 bookmark: will-move-backwards
174 bookmark: will-move-backwards
173 user: test
175 user: test
174 date: Thu Jan 01 00:00:00 1970 +0000
176 date: Thu Jan 01 00:00:00 1970 +0000
175 summary: a
177 summary: a
176
178
@@ -1,453 +1,455 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 # You can reorder changesets by reordering the lines
66 # You can reorder changesets by reordering the lines
67 #
67 #
68 # Commands:
68 # Commands:
69 #
69 #
70 # e, edit = use commit, but stop for amending
70 # e, edit = use commit, but stop for amending
71 # m, mess = edit commit message without changing commit content
71 # m, mess = edit commit message without changing commit content
72 # p, pick = use commit
72 # p, pick = use commit
73 # b, base = checkout changeset and apply further changesets from there
73 # d, drop = remove commit from history
74 # d, drop = remove commit from history
74 # f, fold = use commit, but combine it with the one above
75 # f, fold = use commit, but combine it with the one above
75 # r, roll = like fold, but discard this commit's description and date
76 # r, roll = like fold, but discard this commit's description and date
76 #
77 #
77
78
78 edit the history
79 edit the history
79 (use a hacky editor to check histedit-last-edit.txt backup)
80 (use a hacky editor to check histedit-last-edit.txt backup)
80
81
81 $ EDITED="$TESTTMP/editedhistory"
82 $ EDITED="$TESTTMP/editedhistory"
82 $ cat > $EDITED <<EOF
83 $ cat > $EDITED <<EOF
83 > edit 177f92b77385 c
84 > edit 177f92b77385 c
84 > pick e860deea161a e
85 > pick e860deea161a e
85 > pick 652413bf663e f
86 > pick 652413bf663e f
86 > pick 055a42cdd887 d
87 > pick 055a42cdd887 d
87 > EOF
88 > EOF
88 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
89 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
89 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
90 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
90 Editing (177f92b77385), you may commit or record as needed now.
91 Editing (177f92b77385), you may commit or record as needed now.
91 (hg histedit --continue to resume)
92 (hg histedit --continue to resume)
92
93
93 rules should end up in .hg/histedit-last-edit.txt:
94 rules should end up in .hg/histedit-last-edit.txt:
94 $ cat .hg/histedit-last-edit.txt
95 $ cat .hg/histedit-last-edit.txt
95 edit 177f92b77385 c
96 edit 177f92b77385 c
96 pick e860deea161a e
97 pick e860deea161a e
97 pick 652413bf663e f
98 pick 652413bf663e f
98 pick 055a42cdd887 d
99 pick 055a42cdd887 d
99
100
100 $ hg histedit --abort
101 $ hg histedit --abort
101 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 $ cat > $EDITED <<EOF
103 $ cat > $EDITED <<EOF
103 > pick 177f92b77385 c
104 > pick 177f92b77385 c
104 > pick e860deea161a e
105 > pick e860deea161a e
105 > pick 652413bf663e f
106 > pick 652413bf663e f
106 > pick 055a42cdd887 d
107 > pick 055a42cdd887 d
107 > EOF
108 > EOF
108 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
109 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
109
110
110 log after edit
111 log after edit
111 $ hg log --graph
112 $ hg log --graph
112 @ changeset: 5:07114f51870f
113 @ changeset: 5:07114f51870f
113 | tag: tip
114 | tag: tip
114 | user: test
115 | user: test
115 | date: Thu Jan 01 00:00:00 1970 +0000
116 | date: Thu Jan 01 00:00:00 1970 +0000
116 | summary: d
117 | summary: d
117 |
118 |
118 o changeset: 4:8ade9693061e
119 o changeset: 4:8ade9693061e
119 | user: test
120 | user: test
120 | date: Thu Jan 01 00:00:00 1970 +0000
121 | date: Thu Jan 01 00:00:00 1970 +0000
121 | summary: f
122 | summary: f
122 |
123 |
123 o changeset: 3:d8249471110a
124 o changeset: 3:d8249471110a
124 | user: test
125 | user: test
125 | date: Thu Jan 01 00:00:00 1970 +0000
126 | date: Thu Jan 01 00:00:00 1970 +0000
126 | summary: e
127 | summary: e
127 |
128 |
128 o changeset: 2:177f92b77385
129 o changeset: 2:177f92b77385
129 | user: test
130 | user: test
130 | date: Thu Jan 01 00:00:00 1970 +0000
131 | date: Thu Jan 01 00:00:00 1970 +0000
131 | summary: c
132 | summary: c
132 |
133 |
133 o changeset: 1:d2ae7f538514
134 o changeset: 1:d2ae7f538514
134 | user: test
135 | user: test
135 | date: Thu Jan 01 00:00:00 1970 +0000
136 | date: Thu Jan 01 00:00:00 1970 +0000
136 | summary: b
137 | summary: b
137 |
138 |
138 o changeset: 0:cb9a9f314b8b
139 o changeset: 0:cb9a9f314b8b
139 user: test
140 user: test
140 date: Thu Jan 01 00:00:00 1970 +0000
141 date: Thu Jan 01 00:00:00 1970 +0000
141 summary: a
142 summary: a
142
143
143
144
144 put things back
145 put things back
145
146
146 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
147 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
147 > pick 177f92b77385 c
148 > pick 177f92b77385 c
148 > pick 07114f51870f d
149 > pick 07114f51870f d
149 > pick d8249471110a e
150 > pick d8249471110a e
150 > pick 8ade9693061e f
151 > pick 8ade9693061e f
151 > EOF
152 > EOF
152
153
153 $ hg log --graph
154 $ hg log --graph
154 @ changeset: 5:7eca9b5b1148
155 @ changeset: 5:7eca9b5b1148
155 | tag: tip
156 | tag: tip
156 | user: test
157 | user: test
157 | date: Thu Jan 01 00:00:00 1970 +0000
158 | date: Thu Jan 01 00:00:00 1970 +0000
158 | summary: f
159 | summary: f
159 |
160 |
160 o changeset: 4:915da888f2de
161 o changeset: 4:915da888f2de
161 | user: test
162 | user: test
162 | date: Thu Jan 01 00:00:00 1970 +0000
163 | date: Thu Jan 01 00:00:00 1970 +0000
163 | summary: e
164 | summary: e
164 |
165 |
165 o changeset: 3:10517e47bbbb
166 o changeset: 3:10517e47bbbb
166 | user: test
167 | user: test
167 | date: Thu Jan 01 00:00:00 1970 +0000
168 | date: Thu Jan 01 00:00:00 1970 +0000
168 | summary: d
169 | summary: d
169 |
170 |
170 o changeset: 2:177f92b77385
171 o changeset: 2:177f92b77385
171 | user: test
172 | user: test
172 | date: Thu Jan 01 00:00:00 1970 +0000
173 | date: Thu Jan 01 00:00:00 1970 +0000
173 | summary: c
174 | summary: c
174 |
175 |
175 o changeset: 1:d2ae7f538514
176 o changeset: 1:d2ae7f538514
176 | user: test
177 | user: test
177 | date: Thu Jan 01 00:00:00 1970 +0000
178 | date: Thu Jan 01 00:00:00 1970 +0000
178 | summary: b
179 | summary: b
179 |
180 |
180 o changeset: 0:cb9a9f314b8b
181 o changeset: 0:cb9a9f314b8b
181 user: test
182 user: test
182 date: Thu Jan 01 00:00:00 1970 +0000
183 date: Thu Jan 01 00:00:00 1970 +0000
183 summary: a
184 summary: a
184
185
185
186
186 slightly different this time
187 slightly different this time
187
188
188 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
189 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
189 > pick 10517e47bbbb d
190 > pick 10517e47bbbb d
190 > pick 7eca9b5b1148 f
191 > pick 7eca9b5b1148 f
191 > pick 915da888f2de e
192 > pick 915da888f2de e
192 > pick 177f92b77385 c
193 > pick 177f92b77385 c
193 > EOF
194 > EOF
194 $ hg log --graph
195 $ hg log --graph
195 @ changeset: 5:38b92f448761
196 @ changeset: 5:38b92f448761
196 | tag: tip
197 | tag: tip
197 | user: test
198 | user: test
198 | date: Thu Jan 01 00:00:00 1970 +0000
199 | date: Thu Jan 01 00:00:00 1970 +0000
199 | summary: c
200 | summary: c
200 |
201 |
201 o changeset: 4:de71b079d9ce
202 o changeset: 4:de71b079d9ce
202 | user: test
203 | user: test
203 | date: Thu Jan 01 00:00:00 1970 +0000
204 | date: Thu Jan 01 00:00:00 1970 +0000
204 | summary: e
205 | summary: e
205 |
206 |
206 o changeset: 3:be9ae3a309c6
207 o changeset: 3:be9ae3a309c6
207 | user: test
208 | user: test
208 | date: Thu Jan 01 00:00:00 1970 +0000
209 | date: Thu Jan 01 00:00:00 1970 +0000
209 | summary: f
210 | summary: f
210 |
211 |
211 o changeset: 2:799205341b6b
212 o changeset: 2:799205341b6b
212 | user: test
213 | user: test
213 | date: Thu Jan 01 00:00:00 1970 +0000
214 | date: Thu Jan 01 00:00:00 1970 +0000
214 | summary: d
215 | summary: d
215 |
216 |
216 o changeset: 1:d2ae7f538514
217 o changeset: 1:d2ae7f538514
217 | user: test
218 | user: test
218 | date: Thu Jan 01 00:00:00 1970 +0000
219 | date: Thu Jan 01 00:00:00 1970 +0000
219 | summary: b
220 | summary: b
220 |
221 |
221 o changeset: 0:cb9a9f314b8b
222 o changeset: 0:cb9a9f314b8b
222 user: test
223 user: test
223 date: Thu Jan 01 00:00:00 1970 +0000
224 date: Thu Jan 01 00:00:00 1970 +0000
224 summary: a
225 summary: a
225
226
226
227
227 keep prevents stripping dead revs
228 keep prevents stripping dead revs
228 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
229 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
229 > pick 799205341b6b d
230 > pick 799205341b6b d
230 > pick be9ae3a309c6 f
231 > pick be9ae3a309c6 f
231 > pick 38b92f448761 c
232 > pick 38b92f448761 c
232 > pick de71b079d9ce e
233 > pick de71b079d9ce e
233 > EOF
234 > EOF
234 $ hg log --graph
235 $ hg log --graph
235 @ changeset: 7:803ef1c6fcfd
236 @ changeset: 7:803ef1c6fcfd
236 | tag: tip
237 | tag: tip
237 | user: test
238 | user: test
238 | date: Thu Jan 01 00:00:00 1970 +0000
239 | date: Thu Jan 01 00:00:00 1970 +0000
239 | summary: e
240 | summary: e
240 |
241 |
241 o changeset: 6:ece0b8d93dda
242 o changeset: 6:ece0b8d93dda
242 | parent: 3:be9ae3a309c6
243 | parent: 3:be9ae3a309c6
243 | user: test
244 | user: test
244 | date: Thu Jan 01 00:00:00 1970 +0000
245 | date: Thu Jan 01 00:00:00 1970 +0000
245 | summary: c
246 | summary: c
246 |
247 |
247 | o changeset: 5:38b92f448761
248 | o changeset: 5:38b92f448761
248 | | user: test
249 | | user: test
249 | | date: Thu Jan 01 00:00:00 1970 +0000
250 | | date: Thu Jan 01 00:00:00 1970 +0000
250 | | summary: c
251 | | summary: c
251 | |
252 | |
252 | o changeset: 4:de71b079d9ce
253 | o changeset: 4:de71b079d9ce
253 |/ user: test
254 |/ user: test
254 | date: Thu Jan 01 00:00:00 1970 +0000
255 | date: Thu Jan 01 00:00:00 1970 +0000
255 | summary: e
256 | summary: e
256 |
257 |
257 o changeset: 3:be9ae3a309c6
258 o changeset: 3:be9ae3a309c6
258 | user: test
259 | user: test
259 | date: Thu Jan 01 00:00:00 1970 +0000
260 | date: Thu Jan 01 00:00:00 1970 +0000
260 | summary: f
261 | summary: f
261 |
262 |
262 o changeset: 2:799205341b6b
263 o changeset: 2:799205341b6b
263 | user: test
264 | user: test
264 | date: Thu Jan 01 00:00:00 1970 +0000
265 | date: Thu Jan 01 00:00:00 1970 +0000
265 | summary: d
266 | summary: d
266 |
267 |
267 o changeset: 1:d2ae7f538514
268 o changeset: 1:d2ae7f538514
268 | user: test
269 | user: test
269 | date: Thu Jan 01 00:00:00 1970 +0000
270 | date: Thu Jan 01 00:00:00 1970 +0000
270 | summary: b
271 | summary: b
271 |
272 |
272 o changeset: 0:cb9a9f314b8b
273 o changeset: 0:cb9a9f314b8b
273 user: test
274 user: test
274 date: Thu Jan 01 00:00:00 1970 +0000
275 date: Thu Jan 01 00:00:00 1970 +0000
275 summary: a
276 summary: a
276
277
277
278
278 try with --rev
279 try with --rev
279 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
280 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
280 > pick de71b079d9ce e
281 > pick de71b079d9ce e
281 > pick 38b92f448761 c
282 > pick 38b92f448761 c
282 > EOF
283 > EOF
283 hg: parse error: pick "de71b079d9ce" changeset was not a candidate
284 hg: parse error: pick "de71b079d9ce" changeset was not a candidate
284 (only use listed changesets)
285 (only use listed changesets)
285 $ hg log --graph
286 $ hg log --graph
286 @ changeset: 7:803ef1c6fcfd
287 @ changeset: 7:803ef1c6fcfd
287 | tag: tip
288 | tag: tip
288 | user: test
289 | user: test
289 | date: Thu Jan 01 00:00:00 1970 +0000
290 | date: Thu Jan 01 00:00:00 1970 +0000
290 | summary: e
291 | summary: e
291 |
292 |
292 o changeset: 6:ece0b8d93dda
293 o changeset: 6:ece0b8d93dda
293 | parent: 3:be9ae3a309c6
294 | parent: 3:be9ae3a309c6
294 | user: test
295 | user: test
295 | date: Thu Jan 01 00:00:00 1970 +0000
296 | date: Thu Jan 01 00:00:00 1970 +0000
296 | summary: c
297 | summary: c
297 |
298 |
298 | o changeset: 5:38b92f448761
299 | o changeset: 5:38b92f448761
299 | | user: test
300 | | user: test
300 | | date: Thu Jan 01 00:00:00 1970 +0000
301 | | date: Thu Jan 01 00:00:00 1970 +0000
301 | | summary: c
302 | | summary: c
302 | |
303 | |
303 | o changeset: 4:de71b079d9ce
304 | o changeset: 4:de71b079d9ce
304 |/ user: test
305 |/ user: test
305 | date: Thu Jan 01 00:00:00 1970 +0000
306 | date: Thu Jan 01 00:00:00 1970 +0000
306 | summary: e
307 | summary: e
307 |
308 |
308 o changeset: 3:be9ae3a309c6
309 o changeset: 3:be9ae3a309c6
309 | user: test
310 | user: test
310 | date: Thu Jan 01 00:00:00 1970 +0000
311 | date: Thu Jan 01 00:00:00 1970 +0000
311 | summary: f
312 | summary: f
312 |
313 |
313 o changeset: 2:799205341b6b
314 o changeset: 2:799205341b6b
314 | user: test
315 | user: test
315 | date: Thu Jan 01 00:00:00 1970 +0000
316 | date: Thu Jan 01 00:00:00 1970 +0000
316 | summary: d
317 | summary: d
317 |
318 |
318 o changeset: 1:d2ae7f538514
319 o changeset: 1:d2ae7f538514
319 | user: test
320 | user: test
320 | date: Thu Jan 01 00:00:00 1970 +0000
321 | date: Thu Jan 01 00:00:00 1970 +0000
321 | summary: b
322 | summary: b
322 |
323 |
323 o changeset: 0:cb9a9f314b8b
324 o changeset: 0:cb9a9f314b8b
324 user: test
325 user: test
325 date: Thu Jan 01 00:00:00 1970 +0000
326 date: Thu Jan 01 00:00:00 1970 +0000
326 summary: a
327 summary: a
327
328
328 Verify that revsetalias entries work with histedit:
329 Verify that revsetalias entries work with histedit:
329 $ cat >> $HGRCPATH <<EOF
330 $ cat >> $HGRCPATH <<EOF
330 > [revsetalias]
331 > [revsetalias]
331 > grandparent(ARG) = p1(p1(ARG))
332 > grandparent(ARG) = p1(p1(ARG))
332 > EOF
333 > EOF
333 $ echo extra commit >> c
334 $ echo extra commit >> c
334 $ hg ci -m 'extra commit to c'
335 $ hg ci -m 'extra commit to c'
335 $ HGEDITOR=cat hg histedit 'grandparent(.)'
336 $ HGEDITOR=cat hg histedit 'grandparent(.)'
336 pick ece0b8d93dda 6 c
337 pick ece0b8d93dda 6 c
337 pick 803ef1c6fcfd 7 e
338 pick 803ef1c6fcfd 7 e
338 pick 9c863c565126 8 extra commit to c
339 pick 9c863c565126 8 extra commit to c
339
340
340 # Edit history between ece0b8d93dda and 9c863c565126
341 # Edit history between ece0b8d93dda and 9c863c565126
341 #
342 #
342 # Commits are listed from least to most recent
343 # Commits are listed from least to most recent
343 #
344 #
344 # You can reorder changesets by reordering the lines
345 # You can reorder changesets by reordering the lines
345 #
346 #
346 # Commands:
347 # Commands:
347 #
348 #
348 # e, edit = use commit, but stop for amending
349 # e, edit = use commit, but stop for amending
349 # m, mess = edit commit message without changing commit content
350 # m, mess = edit commit message without changing commit content
350 # p, pick = use commit
351 # p, pick = use commit
352 # b, base = checkout changeset and apply further changesets from there
351 # d, drop = remove commit from history
353 # d, drop = remove commit from history
352 # f, fold = use commit, but combine it with the one above
354 # f, fold = use commit, but combine it with the one above
353 # r, roll = like fold, but discard this commit's description and date
355 # r, roll = like fold, but discard this commit's description and date
354 #
356 #
355
357
356 should also work if a commit message is missing
358 should also work if a commit message is missing
357 $ BUNDLE="$TESTDIR/missing-comment.hg"
359 $ BUNDLE="$TESTDIR/missing-comment.hg"
358 $ hg init missing
360 $ hg init missing
359 $ cd missing
361 $ cd missing
360 $ hg unbundle $BUNDLE
362 $ hg unbundle $BUNDLE
361 adding changesets
363 adding changesets
362 adding manifests
364 adding manifests
363 adding file changes
365 adding file changes
364 added 3 changesets with 3 changes to 1 files
366 added 3 changesets with 3 changes to 1 files
365 (run 'hg update' to get a working copy)
367 (run 'hg update' to get a working copy)
366 $ hg co tip
368 $ hg co tip
367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 $ hg log --graph
370 $ hg log --graph
369 @ changeset: 2:bd22688093b3
371 @ changeset: 2:bd22688093b3
370 | tag: tip
372 | tag: tip
371 | user: Robert Altman <robert.altman@telventDTN.com>
373 | user: Robert Altman <robert.altman@telventDTN.com>
372 | date: Mon Nov 28 16:40:04 2011 +0000
374 | date: Mon Nov 28 16:40:04 2011 +0000
373 | summary: Update file.
375 | summary: Update file.
374 |
376 |
375 o changeset: 1:3b3e956f9171
377 o changeset: 1:3b3e956f9171
376 | user: Robert Altman <robert.altman@telventDTN.com>
378 | user: Robert Altman <robert.altman@telventDTN.com>
377 | date: Mon Nov 28 16:37:57 2011 +0000
379 | date: Mon Nov 28 16:37:57 2011 +0000
378 |
380 |
379 o changeset: 0:141947992243
381 o changeset: 0:141947992243
380 user: Robert Altman <robert.altman@telventDTN.com>
382 user: Robert Altman <robert.altman@telventDTN.com>
381 date: Mon Nov 28 16:35:28 2011 +0000
383 date: Mon Nov 28 16:35:28 2011 +0000
382 summary: Checked in text file
384 summary: Checked in text file
383
385
384 $ hg histedit 0
386 $ hg histedit 0
385 $ cd ..
387 $ cd ..
386
388
387 $ cd ..
389 $ cd ..
388
390
389
391
390 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
392 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
391 $ hg init issue4251
393 $ hg init issue4251
392 $ cd issue4251
394 $ cd issue4251
393
395
394 $ mkdir initial-dir
396 $ mkdir initial-dir
395 $ echo foo > initial-dir/initial-file
397 $ echo foo > initial-dir/initial-file
396 $ hg add initial-dir/initial-file
398 $ hg add initial-dir/initial-file
397 $ hg commit -m "initial commit"
399 $ hg commit -m "initial commit"
398
400
399 Move the file to a new directory, and in the same commit, change its content:
401 Move the file to a new directory, and in the same commit, change its content:
400 $ mkdir another-dir
402 $ mkdir another-dir
401 $ hg mv initial-dir/initial-file another-dir/
403 $ hg mv initial-dir/initial-file another-dir/
402 $ echo changed > another-dir/initial-file
404 $ echo changed > another-dir/initial-file
403 $ hg commit -m "moved and changed"
405 $ hg commit -m "moved and changed"
404
406
405 Rename the file:
407 Rename the file:
406 $ hg mv another-dir/initial-file another-dir/renamed-file
408 $ hg mv another-dir/initial-file another-dir/renamed-file
407 $ hg commit -m "renamed"
409 $ hg commit -m "renamed"
408
410
409 Now, let's try to fold the second commit into the first:
411 Now, let's try to fold the second commit into the first:
410 $ cat > editor.sh <<EOF
412 $ cat > editor.sh <<EOF
411 > #!/bin/sh
413 > #!/bin/sh
412 > cat > \$1 <<ENDOF
414 > cat > \$1 <<ENDOF
413 > pick b0f4233702ca 0 initial commit
415 > pick b0f4233702ca 0 initial commit
414 > fold 5e8704a8f2d2 1 moved and changed
416 > fold 5e8704a8f2d2 1 moved and changed
415 > pick 40e7299e8fa7 2 renamed
417 > pick 40e7299e8fa7 2 renamed
416 > ENDOF
418 > ENDOF
417 > EOF
419 > EOF
418
420
419 $ HGEDITOR="sh ./editor.sh" hg histedit 0
421 $ HGEDITOR="sh ./editor.sh" hg histedit 0
420 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/b0f4233702ca-4cf5af69-histedit.hg (glob)
422 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/b0f4233702ca-4cf5af69-histedit.hg (glob)
421
423
422 $ hg --config diff.git=yes export 0
424 $ hg --config diff.git=yes export 0
423 # HG changeset patch
425 # HG changeset patch
424 # User test
426 # User test
425 # Date 0 0
427 # Date 0 0
426 # Thu Jan 01 00:00:00 1970 +0000
428 # Thu Jan 01 00:00:00 1970 +0000
427 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
429 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
428 # Parent 0000000000000000000000000000000000000000
430 # Parent 0000000000000000000000000000000000000000
429 pick b0f4233702ca 0 initial commit
431 pick b0f4233702ca 0 initial commit
430 fold 5e8704a8f2d2 1 moved and changed
432 fold 5e8704a8f2d2 1 moved and changed
431 pick 40e7299e8fa7 2 renamed
433 pick 40e7299e8fa7 2 renamed
432
434
433 diff --git a/another-dir/initial-file b/another-dir/initial-file
435 diff --git a/another-dir/initial-file b/another-dir/initial-file
434 new file mode 100644
436 new file mode 100644
435 --- /dev/null
437 --- /dev/null
436 +++ b/another-dir/initial-file
438 +++ b/another-dir/initial-file
437 @@ -0,0 +1,1 @@
439 @@ -0,0 +1,1 @@
438 +changed
440 +changed
439
441
440 $ hg --config diff.git=yes export 1
442 $ hg --config diff.git=yes export 1
441 # HG changeset patch
443 # HG changeset patch
442 # User test
444 # User test
443 # Date 0 0
445 # Date 0 0
444 # Thu Jan 01 00:00:00 1970 +0000
446 # Thu Jan 01 00:00:00 1970 +0000
445 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
447 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
446 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
448 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
447 renamed
449 renamed
448
450
449 diff --git a/another-dir/initial-file b/another-dir/renamed-file
451 diff --git a/another-dir/initial-file b/another-dir/renamed-file
450 rename from another-dir/initial-file
452 rename from another-dir/initial-file
451 rename to another-dir/renamed-file
453 rename to another-dir/renamed-file
452
454
453 $ cd ..
455 $ cd ..
@@ -1,482 +1,483 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 > strip=
6 > strip=
7 > EOF
7 > EOF
8
8
9 $ initrepo ()
9 $ initrepo ()
10 > {
10 > {
11 > hg init r
11 > hg init r
12 > cd r
12 > cd r
13 > for x in a b c d e f g; do
13 > for x in a b c d e f g; do
14 > echo $x > $x
14 > echo $x > $x
15 > hg add $x
15 > hg add $x
16 > hg ci -m $x
16 > hg ci -m $x
17 > done
17 > done
18 > }
18 > }
19
19
20 $ initrepo
20 $ initrepo
21
21
22 log before edit
22 log before edit
23 $ hg log --graph
23 $ hg log --graph
24 @ changeset: 6:3c6a8ed2ebe8
24 @ changeset: 6:3c6a8ed2ebe8
25 | tag: tip
25 | tag: tip
26 | user: test
26 | user: test
27 | date: Thu Jan 01 00:00:00 1970 +0000
27 | date: Thu Jan 01 00:00:00 1970 +0000
28 | summary: g
28 | summary: g
29 |
29 |
30 o changeset: 5:652413bf663e
30 o changeset: 5:652413bf663e
31 | user: test
31 | user: test
32 | date: Thu Jan 01 00:00:00 1970 +0000
32 | date: Thu Jan 01 00:00:00 1970 +0000
33 | summary: f
33 | summary: f
34 |
34 |
35 o changeset: 4:e860deea161a
35 o changeset: 4:e860deea161a
36 | user: test
36 | user: test
37 | date: Thu Jan 01 00:00:00 1970 +0000
37 | date: Thu Jan 01 00:00:00 1970 +0000
38 | summary: e
38 | summary: e
39 |
39 |
40 o changeset: 3:055a42cdd887
40 o changeset: 3:055a42cdd887
41 | user: test
41 | user: test
42 | date: Thu Jan 01 00:00:00 1970 +0000
42 | date: Thu Jan 01 00:00:00 1970 +0000
43 | summary: d
43 | summary: d
44 |
44 |
45 o changeset: 2:177f92b77385
45 o changeset: 2:177f92b77385
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 | user: test
51 | user: test
52 | date: Thu Jan 01 00:00:00 1970 +0000
52 | date: Thu Jan 01 00:00:00 1970 +0000
53 | summary: b
53 | summary: b
54 |
54 |
55 o changeset: 0:cb9a9f314b8b
55 o changeset: 0:cb9a9f314b8b
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:00 1970 +0000
57 date: Thu Jan 01 00:00:00 1970 +0000
58 summary: a
58 summary: a
59
59
60 dirty a file
60 dirty a file
61 $ echo a > g
61 $ echo a > g
62 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF
62 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF
63 > EOF
63 > EOF
64 abort: uncommitted changes
64 abort: uncommitted changes
65 [255]
65 [255]
66 $ echo g > g
66 $ echo g > g
67
67
68 edit the history
68 edit the history
69 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
69 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
70 > pick 177f92b77385 c
70 > pick 177f92b77385 c
71 > pick 055a42cdd887 d
71 > pick 055a42cdd887 d
72 > edit e860deea161a e
72 > edit e860deea161a e
73 > pick 652413bf663e f
73 > pick 652413bf663e f
74 > pick 3c6a8ed2ebe8 g
74 > pick 3c6a8ed2ebe8 g
75 > EOF
75 > EOF
76 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
76 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
77 Editing (e860deea161a), you may commit or record as needed now.
77 Editing (e860deea161a), you may commit or record as needed now.
78 (hg histedit --continue to resume)
78 (hg histedit --continue to resume)
79
79
80 try to update and get an error
80 try to update and get an error
81 $ hg update tip
81 $ hg update tip
82 abort: histedit in progress
82 abort: histedit in progress
83 (use 'hg histedit --continue' or 'hg histedit --abort')
83 (use 'hg histedit --continue' or 'hg histedit --abort')
84 [255]
84 [255]
85
85
86 edit the plan via the editor
86 edit the plan via the editor
87 $ cat >> $TESTTMP/editplan.sh <<EOF
87 $ cat >> $TESTTMP/editplan.sh <<EOF
88 > cat > \$1 <<EOF2
88 > cat > \$1 <<EOF2
89 > drop e860deea161a e
89 > drop e860deea161a e
90 > drop 652413bf663e f
90 > drop 652413bf663e f
91 > drop 3c6a8ed2ebe8 g
91 > drop 3c6a8ed2ebe8 g
92 > EOF2
92 > EOF2
93 > EOF
93 > EOF
94 $ HGEDITOR="sh $TESTTMP/editplan.sh" hg histedit --edit-plan
94 $ HGEDITOR="sh $TESTTMP/editplan.sh" hg histedit --edit-plan
95 $ cat .hg/histedit-state
95 $ cat .hg/histedit-state
96 v1
96 v1
97 055a42cdd88768532f9cf79daa407fc8d138de9b
97 055a42cdd88768532f9cf79daa407fc8d138de9b
98 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
98 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
99 False
99 False
100 3
100 3
101 drop
101 drop
102 e860deea161a2f77de56603b340ebbb4536308ae
102 e860deea161a2f77de56603b340ebbb4536308ae
103 drop
103 drop
104 652413bf663ef2a641cab26574e46d5f5a64a55a
104 652413bf663ef2a641cab26574e46d5f5a64a55a
105 drop
105 drop
106 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
106 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
107 0
107 0
108 strip-backup/177f92b77385-0ebe6a8f-histedit.hg
108 strip-backup/177f92b77385-0ebe6a8f-histedit.hg
109
109
110 edit the plan via --commands
110 edit the plan via --commands
111 $ hg histedit --edit-plan --commands - 2>&1 << EOF
111 $ hg histedit --edit-plan --commands - 2>&1 << EOF
112 > edit e860deea161a e
112 > edit e860deea161a e
113 > pick 652413bf663e f
113 > pick 652413bf663e f
114 > drop 3c6a8ed2ebe8 g
114 > drop 3c6a8ed2ebe8 g
115 > EOF
115 > EOF
116 $ cat .hg/histedit-state
116 $ cat .hg/histedit-state
117 v1
117 v1
118 055a42cdd88768532f9cf79daa407fc8d138de9b
118 055a42cdd88768532f9cf79daa407fc8d138de9b
119 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
119 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
120 False
120 False
121 3
121 3
122 edit
122 edit
123 e860deea161a2f77de56603b340ebbb4536308ae
123 e860deea161a2f77de56603b340ebbb4536308ae
124 pick
124 pick
125 652413bf663ef2a641cab26574e46d5f5a64a55a
125 652413bf663ef2a641cab26574e46d5f5a64a55a
126 drop
126 drop
127 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
127 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
128 0
128 0
129 strip-backup/177f92b77385-0ebe6a8f-histedit.hg
129 strip-backup/177f92b77385-0ebe6a8f-histedit.hg
130
130
131 Go at a random point and try to continue
131 Go at a random point and try to continue
132
132
133 $ hg id -n
133 $ hg id -n
134 3+
134 3+
135 $ hg up 0
135 $ hg up 0
136 abort: histedit in progress
136 abort: histedit in progress
137 (use 'hg histedit --continue' or 'hg histedit --abort')
137 (use 'hg histedit --continue' or 'hg histedit --abort')
138 [255]
138 [255]
139
139
140 Try to delete necessary commit
140 Try to delete necessary commit
141 $ hg strip -r 652413b
141 $ hg strip -r 652413b
142 abort: histedit in progress, can't strip 652413bf663e
142 abort: histedit in progress, can't strip 652413bf663e
143 [255]
143 [255]
144
144
145 commit, then edit the revision
145 commit, then edit the revision
146 $ hg ci -m 'wat'
146 $ hg ci -m 'wat'
147 created new head
147 created new head
148 $ echo a > e
148 $ echo a > e
149
149
150 qnew should fail while we're in the middle of the edit step
150 qnew should fail while we're in the middle of the edit step
151
151
152 $ hg --config extensions.mq= qnew please-fail
152 $ hg --config extensions.mq= qnew please-fail
153 abort: histedit in progress
153 abort: histedit in progress
154 (use 'hg histedit --continue' or 'hg histedit --abort')
154 (use 'hg histedit --continue' or 'hg histedit --abort')
155 [255]
155 [255]
156 $ HGEDITOR='echo foobaz > ' hg histedit --continue 2>&1 | fixbundle
156 $ HGEDITOR='echo foobaz > ' hg histedit --continue 2>&1 | fixbundle
157
157
158 $ hg log --graph
158 $ hg log --graph
159 @ changeset: 6:b5f70786f9b0
159 @ changeset: 6:b5f70786f9b0
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: f
163 | summary: f
164 |
164 |
165 o changeset: 5:a5e1ba2f7afb
165 o changeset: 5:a5e1ba2f7afb
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: foobaz
168 | summary: foobaz
169 |
169 |
170 o changeset: 4:1a60820cd1f6
170 o changeset: 4:1a60820cd1f6
171 | user: test
171 | user: test
172 | date: Thu Jan 01 00:00:00 1970 +0000
172 | date: Thu Jan 01 00:00:00 1970 +0000
173 | summary: wat
173 | summary: wat
174 |
174 |
175 o changeset: 3:055a42cdd887
175 o changeset: 3:055a42cdd887
176 | user: test
176 | user: test
177 | date: Thu Jan 01 00:00:00 1970 +0000
177 | date: Thu Jan 01 00:00:00 1970 +0000
178 | summary: d
178 | summary: d
179 |
179 |
180 o changeset: 2:177f92b77385
180 o changeset: 2:177f92b77385
181 | user: test
181 | user: test
182 | date: Thu Jan 01 00:00:00 1970 +0000
182 | date: Thu Jan 01 00:00:00 1970 +0000
183 | summary: c
183 | summary: c
184 |
184 |
185 o changeset: 1:d2ae7f538514
185 o changeset: 1:d2ae7f538514
186 | user: test
186 | user: test
187 | date: Thu Jan 01 00:00:00 1970 +0000
187 | date: Thu Jan 01 00:00:00 1970 +0000
188 | summary: b
188 | summary: b
189 |
189 |
190 o changeset: 0:cb9a9f314b8b
190 o changeset: 0:cb9a9f314b8b
191 user: test
191 user: test
192 date: Thu Jan 01 00:00:00 1970 +0000
192 date: Thu Jan 01 00:00:00 1970 +0000
193 summary: a
193 summary: a
194
194
195
195
196 $ hg cat e
196 $ hg cat e
197 a
197 a
198
198
199 Stripping necessary commits should not break --abort
199 Stripping necessary commits should not break --abort
200
200
201 $ hg histedit 1a60820cd1f6 --commands - 2>&1 << EOF| fixbundle
201 $ hg histedit 1a60820cd1f6 --commands - 2>&1 << EOF| fixbundle
202 > edit 1a60820cd1f6 wat
202 > edit 1a60820cd1f6 wat
203 > pick a5e1ba2f7afb foobaz
203 > pick a5e1ba2f7afb foobaz
204 > pick b5f70786f9b0 g
204 > pick b5f70786f9b0 g
205 > EOF
205 > EOF
206 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
206 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
207 Editing (1a60820cd1f6), you may commit or record as needed now.
207 Editing (1a60820cd1f6), you may commit or record as needed now.
208 (hg histedit --continue to resume)
208 (hg histedit --continue to resume)
209
209
210 $ mv .hg/histedit-state .hg/histedit-state.bak
210 $ mv .hg/histedit-state .hg/histedit-state.bak
211 $ hg strip -q -r b5f70786f9b0
211 $ hg strip -q -r b5f70786f9b0
212 $ mv .hg/histedit-state.bak .hg/histedit-state
212 $ mv .hg/histedit-state.bak .hg/histedit-state
213 $ hg histedit --abort
213 $ hg histedit --abort
214 adding changesets
214 adding changesets
215 adding manifests
215 adding manifests
216 adding file changes
216 adding file changes
217 added 1 changesets with 1 changes to 3 files
217 added 1 changesets with 1 changes to 3 files
218 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 $ hg log -r .
219 $ hg log -r .
220 changeset: 6:b5f70786f9b0
220 changeset: 6:b5f70786f9b0
221 tag: tip
221 tag: tip
222 user: test
222 user: test
223 date: Thu Jan 01 00:00:00 1970 +0000
223 date: Thu Jan 01 00:00:00 1970 +0000
224 summary: f
224 summary: f
225
225
226
226
227 check histedit_source
227 check histedit_source
228
228
229 $ hg log --debug --rev 5
229 $ hg log --debug --rev 5
230 changeset: 5:a5e1ba2f7afb899ef1581cea528fd885d2fca70d
230 changeset: 5:a5e1ba2f7afb899ef1581cea528fd885d2fca70d
231 phase: draft
231 phase: draft
232 parent: 4:1a60820cd1f6004a362aa622ebc47d59bc48eb34
232 parent: 4:1a60820cd1f6004a362aa622ebc47d59bc48eb34
233 parent: -1:0000000000000000000000000000000000000000
233 parent: -1:0000000000000000000000000000000000000000
234 manifest: 5:5ad3be8791f39117565557781f5464363b918a45
234 manifest: 5:5ad3be8791f39117565557781f5464363b918a45
235 user: test
235 user: test
236 date: Thu Jan 01 00:00:00 1970 +0000
236 date: Thu Jan 01 00:00:00 1970 +0000
237 files: e
237 files: e
238 extra: branch=default
238 extra: branch=default
239 extra: histedit_source=e860deea161a2f77de56603b340ebbb4536308ae
239 extra: histedit_source=e860deea161a2f77de56603b340ebbb4536308ae
240 description:
240 description:
241 foobaz
241 foobaz
242
242
243
243
244
244
245 $ hg histedit tip --commands - 2>&1 <<EOF| fixbundle
245 $ hg histedit tip --commands - 2>&1 <<EOF| fixbundle
246 > edit b5f70786f9b0 f
246 > edit b5f70786f9b0 f
247 > EOF
247 > EOF
248 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
248 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
249 Editing (b5f70786f9b0), you may commit or record as needed now.
249 Editing (b5f70786f9b0), you may commit or record as needed now.
250 (hg histedit --continue to resume)
250 (hg histedit --continue to resume)
251 $ hg status
251 $ hg status
252 A f
252 A f
253
253
254 $ hg summary
254 $ hg summary
255 parent: 5:a5e1ba2f7afb
255 parent: 5:a5e1ba2f7afb
256 foobaz
256 foobaz
257 branch: default
257 branch: default
258 commit: 1 added (new branch head)
258 commit: 1 added (new branch head)
259 update: 1 new changesets (update)
259 update: 1 new changesets (update)
260 phases: 7 draft
260 phases: 7 draft
261 hist: 1 remaining (histedit --continue)
261 hist: 1 remaining (histedit --continue)
262
262
263 (test also that editor is invoked if histedit is continued for
263 (test also that editor is invoked if histedit is continued for
264 "edit" action)
264 "edit" action)
265
265
266 $ HGEDITOR='cat' hg histedit --continue
266 $ HGEDITOR='cat' hg histedit --continue
267 f
267 f
268
268
269
269
270 HG: Enter commit message. Lines beginning with 'HG:' are removed.
270 HG: Enter commit message. Lines beginning with 'HG:' are removed.
271 HG: Leave message empty to abort commit.
271 HG: Leave message empty to abort commit.
272 HG: --
272 HG: --
273 HG: user: test
273 HG: user: test
274 HG: branch 'default'
274 HG: branch 'default'
275 HG: added f
275 HG: added f
276 saved backup bundle to $TESTTMP/r/.hg/strip-backup/b5f70786f9b0-c28d9c86-histedit.hg (glob)
276 saved backup bundle to $TESTTMP/r/.hg/strip-backup/b5f70786f9b0-c28d9c86-histedit.hg (glob)
277
277
278 $ hg status
278 $ hg status
279
279
280 log after edit
280 log after edit
281 $ hg log --limit 1
281 $ hg log --limit 1
282 changeset: 6:a107ee126658
282 changeset: 6:a107ee126658
283 tag: tip
283 tag: tip
284 user: test
284 user: test
285 date: Thu Jan 01 00:00:00 1970 +0000
285 date: Thu Jan 01 00:00:00 1970 +0000
286 summary: f
286 summary: f
287
287
288
288
289 say we'll change the message, but don't.
289 say we'll change the message, but don't.
290 $ cat > ../edit.sh <<EOF
290 $ cat > ../edit.sh <<EOF
291 > cat "\$1" | sed s/pick/mess/ > tmp
291 > cat "\$1" | sed s/pick/mess/ > tmp
292 > mv tmp "\$1"
292 > mv tmp "\$1"
293 > EOF
293 > EOF
294 $ HGEDITOR="sh ../edit.sh" hg histedit tip 2>&1 | fixbundle
294 $ HGEDITOR="sh ../edit.sh" hg histedit tip 2>&1 | fixbundle
295 $ hg status
295 $ hg status
296 $ hg log --limit 1
296 $ hg log --limit 1
297 changeset: 6:1fd3b2fe7754
297 changeset: 6:1fd3b2fe7754
298 tag: tip
298 tag: tip
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: f
301 summary: f
302
302
303
303
304 modify the message
304 modify the message
305
305
306 check saving last-message.txt, at first
306 check saving last-message.txt, at first
307
307
308 $ cat > $TESTTMP/commitfailure.py <<EOF
308 $ cat > $TESTTMP/commitfailure.py <<EOF
309 > from mercurial import error
309 > from mercurial import error
310 > def reposetup(ui, repo):
310 > def reposetup(ui, repo):
311 > class commitfailure(repo.__class__):
311 > class commitfailure(repo.__class__):
312 > def commit(self, *args, **kwargs):
312 > def commit(self, *args, **kwargs):
313 > raise error.Abort('emulating unexpected abort')
313 > raise error.Abort('emulating unexpected abort')
314 > repo.__class__ = commitfailure
314 > repo.__class__ = commitfailure
315 > EOF
315 > EOF
316 $ cat >> .hg/hgrc <<EOF
316 $ cat >> .hg/hgrc <<EOF
317 > [extensions]
317 > [extensions]
318 > # this failure occurs before editor invocation
318 > # this failure occurs before editor invocation
319 > commitfailure = $TESTTMP/commitfailure.py
319 > commitfailure = $TESTTMP/commitfailure.py
320 > EOF
320 > EOF
321
321
322 $ cat > $TESTTMP/editor.sh <<EOF
322 $ cat > $TESTTMP/editor.sh <<EOF
323 > echo "==== before editing"
323 > echo "==== before editing"
324 > cat \$1
324 > cat \$1
325 > echo "===="
325 > echo "===="
326 > echo "check saving last-message.txt" >> \$1
326 > echo "check saving last-message.txt" >> \$1
327 > EOF
327 > EOF
328
328
329 (test that editor is not invoked before transaction starting)
329 (test that editor is not invoked before transaction starting)
330
330
331 $ rm -f .hg/last-message.txt
331 $ rm -f .hg/last-message.txt
332 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF | fixbundle
332 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF | fixbundle
333 > mess 1fd3b2fe7754 f
333 > mess 1fd3b2fe7754 f
334 > EOF
334 > EOF
335 abort: emulating unexpected abort
335 abort: emulating unexpected abort
336 $ test -f .hg/last-message.txt
336 $ test -f .hg/last-message.txt
337 [1]
337 [1]
338
338
339 $ cat >> .hg/hgrc <<EOF
339 $ cat >> .hg/hgrc <<EOF
340 > [extensions]
340 > [extensions]
341 > commitfailure = !
341 > commitfailure = !
342 > EOF
342 > EOF
343 $ hg histedit --abort -q
343 $ hg histedit --abort -q
344
344
345 (test that editor is invoked and commit message is saved into
345 (test that editor is invoked and commit message is saved into
346 "last-message.txt")
346 "last-message.txt")
347
347
348 $ cat >> .hg/hgrc <<EOF
348 $ cat >> .hg/hgrc <<EOF
349 > [hooks]
349 > [hooks]
350 > # this failure occurs after editor invocation
350 > # this failure occurs after editor invocation
351 > pretxncommit.unexpectedabort = false
351 > pretxncommit.unexpectedabort = false
352 > EOF
352 > EOF
353
353
354 $ hg status --rev '1fd3b2fe7754^1' --rev 1fd3b2fe7754
354 $ hg status --rev '1fd3b2fe7754^1' --rev 1fd3b2fe7754
355 A f
355 A f
356
356
357 $ rm -f .hg/last-message.txt
357 $ rm -f .hg/last-message.txt
358 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF
358 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF
359 > mess 1fd3b2fe7754 f
359 > mess 1fd3b2fe7754 f
360 > EOF
360 > EOF
361 ==== before editing
361 ==== before editing
362 f
362 f
363
363
364
364
365 HG: Enter commit message. Lines beginning with 'HG:' are removed.
365 HG: Enter commit message. Lines beginning with 'HG:' are removed.
366 HG: Leave message empty to abort commit.
366 HG: Leave message empty to abort commit.
367 HG: --
367 HG: --
368 HG: user: test
368 HG: user: test
369 HG: branch 'default'
369 HG: branch 'default'
370 HG: added f
370 HG: added f
371 ====
371 ====
372 note: commit message saved in .hg/last-message.txt
372 note: commit message saved in .hg/last-message.txt
373 transaction abort!
373 transaction abort!
374 rollback completed
374 rollback completed
375 abort: pretxncommit.unexpectedabort hook exited with status 1
375 abort: pretxncommit.unexpectedabort hook exited with status 1
376 [255]
376 [255]
377 $ cat .hg/last-message.txt
377 $ cat .hg/last-message.txt
378 f
378 f
379
379
380
380
381 check saving last-message.txt
381 check saving last-message.txt
382
382
383 (test also that editor is invoked if histedit is continued for "message"
383 (test also that editor is invoked if histedit is continued for "message"
384 action)
384 action)
385
385
386 $ HGEDITOR=cat hg histedit --continue
386 $ HGEDITOR=cat hg histedit --continue
387 f
387 f
388
388
389
389
390 HG: Enter commit message. Lines beginning with 'HG:' are removed.
390 HG: Enter commit message. Lines beginning with 'HG:' are removed.
391 HG: Leave message empty to abort commit.
391 HG: Leave message empty to abort commit.
392 HG: --
392 HG: --
393 HG: user: test
393 HG: user: test
394 HG: branch 'default'
394 HG: branch 'default'
395 HG: added f
395 HG: added f
396 note: commit message saved in .hg/last-message.txt
396 note: commit message saved in .hg/last-message.txt
397 transaction abort!
397 transaction abort!
398 rollback completed
398 rollback completed
399 abort: pretxncommit.unexpectedabort hook exited with status 1
399 abort: pretxncommit.unexpectedabort hook exited with status 1
400 [255]
400 [255]
401
401
402 $ cat >> .hg/hgrc <<EOF
402 $ cat >> .hg/hgrc <<EOF
403 > [hooks]
403 > [hooks]
404 > pretxncommit.unexpectedabort =
404 > pretxncommit.unexpectedabort =
405 > EOF
405 > EOF
406 $ hg histedit --abort -q
406 $ hg histedit --abort -q
407
407
408 then, check "modify the message" itself
408 then, check "modify the message" itself
409
409
410 $ hg histedit tip --commands - 2>&1 << EOF | fixbundle
410 $ hg histedit tip --commands - 2>&1 << EOF | fixbundle
411 > mess 1fd3b2fe7754 f
411 > mess 1fd3b2fe7754 f
412 > EOF
412 > EOF
413 $ hg status
413 $ hg status
414 $ hg log --limit 1
414 $ hg log --limit 1
415 changeset: 6:62feedb1200e
415 changeset: 6:62feedb1200e
416 tag: tip
416 tag: tip
417 user: test
417 user: test
418 date: Thu Jan 01 00:00:00 1970 +0000
418 date: Thu Jan 01 00:00:00 1970 +0000
419 summary: f
419 summary: f
420
420
421
421
422 rollback should not work after a histedit
422 rollback should not work after a histedit
423 $ hg rollback
423 $ hg rollback
424 no rollback information available
424 no rollback information available
425 [1]
425 [1]
426
426
427 $ cd ..
427 $ cd ..
428 $ hg clone -qr0 r r0
428 $ hg clone -qr0 r r0
429 $ cd r0
429 $ cd r0
430 $ hg phase -fdr0
430 $ hg phase -fdr0
431 $ hg histedit --commands - 0 2>&1 << EOF
431 $ hg histedit --commands - 0 2>&1 << EOF
432 > edit cb9a9f314b8b a > $EDITED
432 > edit cb9a9f314b8b a > $EDITED
433 > EOF
433 > EOF
434 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
434 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
435 adding a
435 adding a
436 Editing (cb9a9f314b8b), you may commit or record as needed now.
436 Editing (cb9a9f314b8b), you may commit or record as needed now.
437 (hg histedit --continue to resume)
437 (hg histedit --continue to resume)
438 [1]
438 [1]
439 $ HGEDITOR=true hg histedit --continue
439 $ HGEDITOR=true hg histedit --continue
440 saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-histedit.hg (glob)
440 saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-histedit.hg (glob)
441
441
442 $ hg log -G
442 $ hg log -G
443 @ changeset: 0:0efcea34f18a
443 @ changeset: 0:0efcea34f18a
444 tag: tip
444 tag: tip
445 user: test
445 user: test
446 date: Thu Jan 01 00:00:00 1970 +0000
446 date: Thu Jan 01 00:00:00 1970 +0000
447 summary: a
447 summary: a
448
448
449 $ echo foo >> b
449 $ echo foo >> b
450 $ hg addr
450 $ hg addr
451 adding b
451 adding b
452 $ hg ci -m 'add b'
452 $ hg ci -m 'add b'
453 $ echo foo >> a
453 $ echo foo >> a
454 $ hg ci -m 'extend a'
454 $ hg ci -m 'extend a'
455 $ hg phase --public 1
455 $ hg phase --public 1
456 Attempting to fold a change into a public change should not work:
456 Attempting to fold a change into a public change should not work:
457 $ cat > ../edit.sh <<EOF
457 $ cat > ../edit.sh <<EOF
458 > cat "\$1" | sed s/pick/fold/ > tmp
458 > cat "\$1" | sed s/pick/fold/ > tmp
459 > mv tmp "\$1"
459 > mv tmp "\$1"
460 > EOF
460 > EOF
461 $ HGEDITOR="sh ../edit.sh" hg histedit 2
461 $ HGEDITOR="sh ../edit.sh" hg histedit 2
462 warning: histedit rules saved to: .hg/histedit-last-edit.txt
462 warning: histedit rules saved to: .hg/histedit-last-edit.txt
463 hg: parse error: first changeset cannot use verb "fold"
463 hg: parse error: first changeset cannot use verb "fold"
464 [255]
464 [255]
465 $ cat .hg/histedit-last-edit.txt
465 $ cat .hg/histedit-last-edit.txt
466 fold 0012be4a27ea 2 extend a
466 fold 0012be4a27ea 2 extend a
467
467
468 # Edit history between 0012be4a27ea and 0012be4a27ea
468 # Edit history between 0012be4a27ea and 0012be4a27ea
469 #
469 #
470 # Commits are listed from least to most recent
470 # Commits are listed from least to most recent
471 #
471 #
472 # You can reorder changesets by reordering the lines
472 # You can reorder changesets by reordering the lines
473 #
473 #
474 # Commands:
474 # Commands:
475 #
475 #
476 # e, edit = use commit, but stop for amending
476 # e, edit = use commit, but stop for amending
477 # m, mess = edit commit message without changing commit content
477 # m, mess = edit commit message without changing commit content
478 # p, fold = use commit
478 # p, fold = use commit
479 # b, base = checkout changeset and apply further changesets from there
479 # d, drop = remove commit from history
480 # d, drop = remove commit from history
480 # f, fold = use commit, but combine it with the one above
481 # f, fold = use commit, but combine it with the one above
481 # r, roll = like fold, but discard this commit's description and date
482 # r, roll = like fold, but discard this commit's description and date
482 #
483 #
@@ -1,576 +1,577 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 > stabilization=createmarkers,allowunstable
11 > stabilization=createmarkers,allowunstable
12 > [extensions]
12 > [extensions]
13 > histedit=
13 > histedit=
14 > rebase=
14 > rebase=
15 > EOF
15 > EOF
16
16
17 Test that histedit learns about obsolescence not stored in histedit state
17 Test that histedit learns about obsolescence not stored in histedit state
18 $ hg init boo
18 $ hg init boo
19 $ cd boo
19 $ cd boo
20 $ echo a > a
20 $ echo a > a
21 $ hg ci -Am a
21 $ hg ci -Am a
22 adding a
22 adding a
23 $ echo a > b
23 $ echo a > b
24 $ echo a > c
24 $ echo a > c
25 $ echo a > c
25 $ echo a > c
26 $ hg ci -Am b
26 $ hg ci -Am b
27 adding b
27 adding b
28 adding c
28 adding c
29 $ echo a > d
29 $ echo a > d
30 $ hg ci -Am c
30 $ hg ci -Am c
31 adding d
31 adding d
32 $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
32 $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
33 $ echo "pick `hg log -r 2 -T '{node|short}'`" >> plan
33 $ echo "pick `hg log -r 2 -T '{node|short}'`" >> plan
34 $ echo "edit `hg log -r 1 -T '{node|short}'`" >> plan
34 $ echo "edit `hg log -r 1 -T '{node|short}'`" >> plan
35 $ hg histedit -r 'all()' --commands plan
35 $ hg histedit -r 'all()' --commands plan
36 Editing (1b2d564fad96), you may commit or record as needed now.
36 Editing (1b2d564fad96), you may commit or record as needed now.
37 (hg histedit --continue to resume)
37 (hg histedit --continue to resume)
38 [1]
38 [1]
39 $ hg st
39 $ hg st
40 A b
40 A b
41 A c
41 A c
42 ? plan
42 ? plan
43 $ hg commit --amend b
43 $ hg commit --amend b
44 $ hg histedit --continue
44 $ hg histedit --continue
45 $ hg log -G
45 $ hg log -G
46 @ 5:46abc7c4d873 b
46 @ 5:46abc7c4d873 b
47 |
47 |
48 o 4:49d44ab2be1b c
48 o 4:49d44ab2be1b c
49 |
49 |
50 o 0:cb9a9f314b8b a
50 o 0:cb9a9f314b8b a
51
51
52 $ hg debugobsolete
52 $ hg debugobsolete
53 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
53 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
54 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
54 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
55 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
55 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
56
56
57 With some node gone missing during the edit.
57 With some node gone missing during the edit.
58
58
59 $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
59 $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
60 $ echo "pick `hg log -r 5 -T '{node|short}'`" >> plan
60 $ echo "pick `hg log -r 5 -T '{node|short}'`" >> plan
61 $ echo "edit `hg log -r 4 -T '{node|short}'`" >> plan
61 $ echo "edit `hg log -r 4 -T '{node|short}'`" >> plan
62 $ hg histedit -r 'all()' --commands plan
62 $ hg histedit -r 'all()' --commands plan
63 Editing (49d44ab2be1b), you may commit or record as needed now.
63 Editing (49d44ab2be1b), you may commit or record as needed now.
64 (hg histedit --continue to resume)
64 (hg histedit --continue to resume)
65 [1]
65 [1]
66 $ hg st
66 $ hg st
67 A b
67 A b
68 A d
68 A d
69 ? plan
69 ? plan
70 $ hg commit --amend -X . -m XXXXXX
70 $ hg commit --amend -X . -m XXXXXX
71 $ hg commit --amend -X . -m b2
71 $ hg commit --amend -X . -m b2
72 $ hg --hidden --config extensions.strip= strip 'desc(XXXXXX)' --no-backup
72 $ hg --hidden --config extensions.strip= strip 'desc(XXXXXX)' --no-backup
73 $ hg histedit --continue
73 $ hg histedit --continue
74 $ hg log -G
74 $ hg log -G
75 @ 8:273c1f3b8626 c
75 @ 8:273c1f3b8626 c
76 |
76 |
77 o 7:aba7da937030 b2
77 o 7:aba7da937030 b2
78 |
78 |
79 o 0:cb9a9f314b8b a
79 o 0:cb9a9f314b8b a
80
80
81 $ hg debugobsolete
81 $ hg debugobsolete
82 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
82 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
83 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
83 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
84 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
84 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
85 76f72745eac0643d16530e56e2f86e36e40631f1 2ca853e48edbd6453a0674dc0fe28a0974c51b9c 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
85 76f72745eac0643d16530e56e2f86e36e40631f1 2ca853e48edbd6453a0674dc0fe28a0974c51b9c 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
86 2ca853e48edbd6453a0674dc0fe28a0974c51b9c aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
86 2ca853e48edbd6453a0674dc0fe28a0974c51b9c aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'amend', 'user': 'test'}
87 49d44ab2be1b67a79127568a67c9c99430633b48 273c1f3b86267ed3ec684bb13af1fa4d6ba56e02 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
87 49d44ab2be1b67a79127568a67c9c99430633b48 273c1f3b86267ed3ec684bb13af1fa4d6ba56e02 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
88 46abc7c4d8738e8563e577f7889e1b6db3da4199 aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
88 46abc7c4d8738e8563e577f7889e1b6db3da4199 aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
89 $ cd ..
89 $ cd ..
90
90
91 Base setup for the rest of the testing
91 Base setup for the rest of the testing
92 ======================================
92 ======================================
93
93
94 $ hg init base
94 $ hg init base
95 $ cd base
95 $ cd base
96
96
97 $ for x in a b c d e f ; do
97 $ for x in a b c d e f ; do
98 > echo $x > $x
98 > echo $x > $x
99 > hg add $x
99 > hg add $x
100 > hg ci -m $x
100 > hg ci -m $x
101 > done
101 > done
102
102
103 $ hg log --graph
103 $ hg log --graph
104 @ 5:652413bf663e f
104 @ 5:652413bf663e f
105 |
105 |
106 o 4:e860deea161a e
106 o 4:e860deea161a e
107 |
107 |
108 o 3:055a42cdd887 d
108 o 3:055a42cdd887 d
109 |
109 |
110 o 2:177f92b77385 c
110 o 2:177f92b77385 c
111 |
111 |
112 o 1:d2ae7f538514 b
112 o 1:d2ae7f538514 b
113 |
113 |
114 o 0:cb9a9f314b8b a
114 o 0:cb9a9f314b8b a
115
115
116
116
117 $ HGEDITOR=cat hg histedit 1
117 $ HGEDITOR=cat hg histedit 1
118 pick d2ae7f538514 1 b
118 pick d2ae7f538514 1 b
119 pick 177f92b77385 2 c
119 pick 177f92b77385 2 c
120 pick 055a42cdd887 3 d
120 pick 055a42cdd887 3 d
121 pick e860deea161a 4 e
121 pick e860deea161a 4 e
122 pick 652413bf663e 5 f
122 pick 652413bf663e 5 f
123
123
124 # Edit history between d2ae7f538514 and 652413bf663e
124 # Edit history between d2ae7f538514 and 652413bf663e
125 #
125 #
126 # Commits are listed from least to most recent
126 # Commits are listed from least to most recent
127 #
127 #
128 # You can reorder changesets by reordering the lines
128 # You can reorder changesets by reordering the lines
129 #
129 #
130 # Commands:
130 # Commands:
131 #
131 #
132 # e, edit = use commit, but stop for amending
132 # e, edit = use commit, but stop for amending
133 # m, mess = edit commit message without changing commit content
133 # m, mess = edit commit message without changing commit content
134 # p, pick = use commit
134 # p, pick = use commit
135 # b, base = checkout changeset and apply further changesets from there
135 # d, drop = remove commit from history
136 # d, drop = remove commit from history
136 # f, fold = use commit, but combine it with the one above
137 # f, fold = use commit, but combine it with the one above
137 # r, roll = like fold, but discard this commit's description and date
138 # r, roll = like fold, but discard this commit's description and date
138 #
139 #
139 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
140 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
140 > pick 177f92b77385 2 c
141 > pick 177f92b77385 2 c
141 > drop d2ae7f538514 1 b
142 > drop d2ae7f538514 1 b
142 > pick 055a42cdd887 3 d
143 > pick 055a42cdd887 3 d
143 > fold e860deea161a 4 e
144 > fold e860deea161a 4 e
144 > pick 652413bf663e 5 f
145 > pick 652413bf663e 5 f
145 > EOF
146 > EOF
146 [1]
147 [1]
147 $ hg log --graph --hidden
148 $ hg log --graph --hidden
148 @ 10:cacdfd884a93 f
149 @ 10:cacdfd884a93 f
149 |
150 |
150 o 9:59d9f330561f d
151 o 9:59d9f330561f d
151 |
152 |
152 | x 8:b558abc46d09 fold-temp-revision e860deea161a
153 | x 8:b558abc46d09 fold-temp-revision e860deea161a
153 | |
154 | |
154 | x 7:96e494a2d553 d
155 | x 7:96e494a2d553 d
155 |/
156 |/
156 o 6:b346ab9a313d c
157 o 6:b346ab9a313d c
157 |
158 |
158 | x 5:652413bf663e f
159 | x 5:652413bf663e f
159 | |
160 | |
160 | x 4:e860deea161a e
161 | x 4:e860deea161a e
161 | |
162 | |
162 | x 3:055a42cdd887 d
163 | x 3:055a42cdd887 d
163 | |
164 | |
164 | x 2:177f92b77385 c
165 | x 2:177f92b77385 c
165 | |
166 | |
166 | x 1:d2ae7f538514 b
167 | x 1:d2ae7f538514 b
167 |/
168 |/
168 o 0:cb9a9f314b8b a
169 o 0:cb9a9f314b8b a
169
170
170 $ hg debugobsolete
171 $ hg debugobsolete
171 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
172 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
172 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
173 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
173 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
174 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
174 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
175 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
175 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
176 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
176 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
177 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
177 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
178 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'histedit', 'user': 'test'}
178
179
179
180
180 Ensure hidden revision does not prevent histedit
181 Ensure hidden revision does not prevent histedit
181 -------------------------------------------------
182 -------------------------------------------------
182
183
183 create an hidden revision
184 create an hidden revision
184
185
185 $ hg histedit 6 --commands - << EOF
186 $ hg histedit 6 --commands - << EOF
186 > pick b346ab9a313d 6 c
187 > pick b346ab9a313d 6 c
187 > drop 59d9f330561f 7 d
188 > drop 59d9f330561f 7 d
188 > pick cacdfd884a93 8 f
189 > pick cacdfd884a93 8 f
189 > EOF
190 > EOF
190 $ hg log --graph
191 $ hg log --graph
191 @ 11:c13eb81022ca f
192 @ 11:c13eb81022ca f
192 |
193 |
193 o 6:b346ab9a313d c
194 o 6:b346ab9a313d c
194 |
195 |
195 o 0:cb9a9f314b8b a
196 o 0:cb9a9f314b8b a
196
197
197 check hidden revision are ignored (6 have hidden children 7 and 8)
198 check hidden revision are ignored (6 have hidden children 7 and 8)
198
199
199 $ hg histedit 6 --commands - << EOF
200 $ hg histedit 6 --commands - << EOF
200 > pick b346ab9a313d 6 c
201 > pick b346ab9a313d 6 c
201 > pick c13eb81022ca 8 f
202 > pick c13eb81022ca 8 f
202 > EOF
203 > EOF
203
204
204
205
205
206
206 Test that rewriting leaving instability behind is allowed
207 Test that rewriting leaving instability behind is allowed
207 ---------------------------------------------------------------------
208 ---------------------------------------------------------------------
208
209
209 $ hg up '.^'
210 $ hg up '.^'
210 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
211 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
211 $ hg log -r 'children(.)'
212 $ hg log -r 'children(.)'
212 11:c13eb81022ca f (no-eol)
213 11:c13eb81022ca f (no-eol)
213 $ hg histedit -r '.' --commands - <<EOF
214 $ hg histedit -r '.' --commands - <<EOF
214 > edit b346ab9a313d 6 c
215 > edit b346ab9a313d 6 c
215 > EOF
216 > EOF
216 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
217 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
217 adding c
218 adding c
218 Editing (b346ab9a313d), you may commit or record as needed now.
219 Editing (b346ab9a313d), you may commit or record as needed now.
219 (hg histedit --continue to resume)
220 (hg histedit --continue to resume)
220 [1]
221 [1]
221 $ echo c >> c
222 $ echo c >> c
222 $ hg histedit --continue
223 $ hg histedit --continue
223
224
224 $ hg log -r 'orphan()'
225 $ hg log -r 'orphan()'
225 11:c13eb81022ca f (no-eol)
226 11:c13eb81022ca f (no-eol)
226
227
227 stabilise
228 stabilise
228
229
229 $ hg rebase -r 'orphan()' -d .
230 $ hg rebase -r 'orphan()' -d .
230 rebasing 11:c13eb81022ca "f"
231 rebasing 11:c13eb81022ca "f"
231 $ hg up tip -q
232 $ hg up tip -q
232
233
233 Test dropping of changeset on the top of the stack
234 Test dropping of changeset on the top of the stack
234 -------------------------------------------------------
235 -------------------------------------------------------
235
236
236 Nothing is rewritten below, the working directory parent must be change for the
237 Nothing is rewritten below, the working directory parent must be change for the
237 dropped changeset to be hidden.
238 dropped changeset to be hidden.
238
239
239 $ cd ..
240 $ cd ..
240 $ hg clone base droplast
241 $ hg clone base droplast
241 updating to branch default
242 updating to branch default
242 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 $ cd droplast
244 $ cd droplast
244 $ hg histedit -r '40db8afa467b' --commands - << EOF
245 $ hg histedit -r '40db8afa467b' --commands - << EOF
245 > pick 40db8afa467b 10 c
246 > pick 40db8afa467b 10 c
246 > drop b449568bf7fc 11 f
247 > drop b449568bf7fc 11 f
247 > EOF
248 > EOF
248 $ hg log -G
249 $ hg log -G
249 @ 12:40db8afa467b c
250 @ 12:40db8afa467b c
250 |
251 |
251 o 0:cb9a9f314b8b a
252 o 0:cb9a9f314b8b a
252
253
253
254
254 With rewritten ancestors
255 With rewritten ancestors
255
256
256 $ echo e > e
257 $ echo e > e
257 $ hg add e
258 $ hg add e
258 $ hg commit -m g
259 $ hg commit -m g
259 $ echo f > f
260 $ echo f > f
260 $ hg add f
261 $ hg add f
261 $ hg commit -m h
262 $ hg commit -m h
262 $ hg histedit -r '40db8afa467b' --commands - << EOF
263 $ hg histedit -r '40db8afa467b' --commands - << EOF
263 > pick 47a8561c0449 12 g
264 > pick 47a8561c0449 12 g
264 > pick 40db8afa467b 10 c
265 > pick 40db8afa467b 10 c
265 > drop 1b3b05f35ff0 13 h
266 > drop 1b3b05f35ff0 13 h
266 > EOF
267 > EOF
267 $ hg log -G
268 $ hg log -G
268 @ 17:ee6544123ab8 c
269 @ 17:ee6544123ab8 c
269 |
270 |
270 o 16:269e713e9eae g
271 o 16:269e713e9eae g
271 |
272 |
272 o 0:cb9a9f314b8b a
273 o 0:cb9a9f314b8b a
273
274
274 $ cd ../base
275 $ cd ../base
275
276
276
277
277
278
278 Test phases support
279 Test phases support
279 ===========================================
280 ===========================================
280
281
281 Check that histedit respect immutability
282 Check that histedit respect immutability
282 -------------------------------------------
283 -------------------------------------------
283
284
284 $ cat >> $HGRCPATH << EOF
285 $ cat >> $HGRCPATH << EOF
285 > [ui]
286 > [ui]
286 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
287 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
287 > EOF
288 > EOF
288
289
289 $ hg ph -pv '.^'
290 $ hg ph -pv '.^'
290 phase changed for 2 changesets
291 phase changed for 2 changesets
291 $ hg log -G
292 $ hg log -G
292 @ 13:b449568bf7fc (draft) f
293 @ 13:b449568bf7fc (draft) f
293 |
294 |
294 o 12:40db8afa467b (public) c
295 o 12:40db8afa467b (public) c
295 |
296 |
296 o 0:cb9a9f314b8b (public) a
297 o 0:cb9a9f314b8b (public) a
297
298
298 $ hg histedit -r '.~2'
299 $ hg histedit -r '.~2'
299 abort: cannot edit public changeset: cb9a9f314b8b
300 abort: cannot edit public changeset: cb9a9f314b8b
300 (see 'hg help phases' for details)
301 (see 'hg help phases' for details)
301 [255]
302 [255]
302
303
303
304
304 Prepare further testing
305 Prepare further testing
305 -------------------------------------------
306 -------------------------------------------
306
307
307 $ for x in g h i j k ; do
308 $ for x in g h i j k ; do
308 > echo $x > $x
309 > echo $x > $x
309 > hg add $x
310 > hg add $x
310 > hg ci -m $x
311 > hg ci -m $x
311 > done
312 > done
312 $ hg phase --force --secret .~2
313 $ hg phase --force --secret .~2
313 $ hg log -G
314 $ hg log -G
314 @ 18:ee118ab9fa44 (secret) k
315 @ 18:ee118ab9fa44 (secret) k
315 |
316 |
316 o 17:3a6c53ee7f3d (secret) j
317 o 17:3a6c53ee7f3d (secret) j
317 |
318 |
318 o 16:b605fb7503f2 (secret) i
319 o 16:b605fb7503f2 (secret) i
319 |
320 |
320 o 15:7395e1ff83bd (draft) h
321 o 15:7395e1ff83bd (draft) h
321 |
322 |
322 o 14:6b70183d2492 (draft) g
323 o 14:6b70183d2492 (draft) g
323 |
324 |
324 o 13:b449568bf7fc (draft) f
325 o 13:b449568bf7fc (draft) f
325 |
326 |
326 o 12:40db8afa467b (public) c
327 o 12:40db8afa467b (public) c
327 |
328 |
328 o 0:cb9a9f314b8b (public) a
329 o 0:cb9a9f314b8b (public) a
329
330
330 $ cd ..
331 $ cd ..
331
332
332 simple phase conservation
333 simple phase conservation
333 -------------------------------------------
334 -------------------------------------------
334
335
335 Resulting changeset should conserve the phase of the original one whatever the
336 Resulting changeset should conserve the phase of the original one whatever the
336 phases.new-commit option is.
337 phases.new-commit option is.
337
338
338 New-commit as draft (default)
339 New-commit as draft (default)
339
340
340 $ cp -R base simple-draft
341 $ cp -R base simple-draft
341 $ cd simple-draft
342 $ cd simple-draft
342 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
343 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
343 > edit b449568bf7fc 11 f
344 > edit b449568bf7fc 11 f
344 > pick 6b70183d2492 12 g
345 > pick 6b70183d2492 12 g
345 > pick 7395e1ff83bd 13 h
346 > pick 7395e1ff83bd 13 h
346 > pick b605fb7503f2 14 i
347 > pick b605fb7503f2 14 i
347 > pick 3a6c53ee7f3d 15 j
348 > pick 3a6c53ee7f3d 15 j
348 > pick ee118ab9fa44 16 k
349 > pick ee118ab9fa44 16 k
349 > EOF
350 > EOF
350 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
351 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
351 adding f
352 adding f
352 Editing (b449568bf7fc), you may commit or record as needed now.
353 Editing (b449568bf7fc), you may commit or record as needed now.
353 (hg histedit --continue to resume)
354 (hg histedit --continue to resume)
354 [1]
355 [1]
355 $ echo f >> f
356 $ echo f >> f
356 $ hg histedit --continue
357 $ hg histedit --continue
357 $ hg log -G
358 $ hg log -G
358 @ 24:12e89af74238 (secret) k
359 @ 24:12e89af74238 (secret) k
359 |
360 |
360 o 23:636a8687b22e (secret) j
361 o 23:636a8687b22e (secret) j
361 |
362 |
362 o 22:ccaf0a38653f (secret) i
363 o 22:ccaf0a38653f (secret) i
363 |
364 |
364 o 21:11a89d1c2613 (draft) h
365 o 21:11a89d1c2613 (draft) h
365 |
366 |
366 o 20:c1dec7ca82ea (draft) g
367 o 20:c1dec7ca82ea (draft) g
367 |
368 |
368 o 19:087281e68428 (draft) f
369 o 19:087281e68428 (draft) f
369 |
370 |
370 o 12:40db8afa467b (public) c
371 o 12:40db8afa467b (public) c
371 |
372 |
372 o 0:cb9a9f314b8b (public) a
373 o 0:cb9a9f314b8b (public) a
373
374
374 $ cd ..
375 $ cd ..
375
376
376
377
377 New-commit as secret (config)
378 New-commit as secret (config)
378
379
379 $ cp -R base simple-secret
380 $ cp -R base simple-secret
380 $ cd simple-secret
381 $ cd simple-secret
381 $ cat >> .hg/hgrc << EOF
382 $ cat >> .hg/hgrc << EOF
382 > [phases]
383 > [phases]
383 > new-commit=secret
384 > new-commit=secret
384 > EOF
385 > EOF
385 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
386 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
386 > edit b449568bf7fc 11 f
387 > edit b449568bf7fc 11 f
387 > pick 6b70183d2492 12 g
388 > pick 6b70183d2492 12 g
388 > pick 7395e1ff83bd 13 h
389 > pick 7395e1ff83bd 13 h
389 > pick b605fb7503f2 14 i
390 > pick b605fb7503f2 14 i
390 > pick 3a6c53ee7f3d 15 j
391 > pick 3a6c53ee7f3d 15 j
391 > pick ee118ab9fa44 16 k
392 > pick ee118ab9fa44 16 k
392 > EOF
393 > EOF
393 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
394 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
394 adding f
395 adding f
395 Editing (b449568bf7fc), you may commit or record as needed now.
396 Editing (b449568bf7fc), you may commit or record as needed now.
396 (hg histedit --continue to resume)
397 (hg histedit --continue to resume)
397 [1]
398 [1]
398 $ echo f >> f
399 $ echo f >> f
399 $ hg histedit --continue
400 $ hg histedit --continue
400 $ hg log -G
401 $ hg log -G
401 @ 24:12e89af74238 (secret) k
402 @ 24:12e89af74238 (secret) k
402 |
403 |
403 o 23:636a8687b22e (secret) j
404 o 23:636a8687b22e (secret) j
404 |
405 |
405 o 22:ccaf0a38653f (secret) i
406 o 22:ccaf0a38653f (secret) i
406 |
407 |
407 o 21:11a89d1c2613 (draft) h
408 o 21:11a89d1c2613 (draft) h
408 |
409 |
409 o 20:c1dec7ca82ea (draft) g
410 o 20:c1dec7ca82ea (draft) g
410 |
411 |
411 o 19:087281e68428 (draft) f
412 o 19:087281e68428 (draft) f
412 |
413 |
413 o 12:40db8afa467b (public) c
414 o 12:40db8afa467b (public) c
414 |
415 |
415 o 0:cb9a9f314b8b (public) a
416 o 0:cb9a9f314b8b (public) a
416
417
417 $ cd ..
418 $ cd ..
418
419
419
420
420 Changeset reordering
421 Changeset reordering
421 -------------------------------------------
422 -------------------------------------------
422
423
423 If a secret changeset is put before a draft one, all descendant should be secret.
424 If a secret changeset is put before a draft one, all descendant should be secret.
424 It seems more important to present the secret phase.
425 It seems more important to present the secret phase.
425
426
426 $ cp -R base reorder
427 $ cp -R base reorder
427 $ cd reorder
428 $ cd reorder
428 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
429 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
429 > pick b449568bf7fc 11 f
430 > pick b449568bf7fc 11 f
430 > pick 3a6c53ee7f3d 15 j
431 > pick 3a6c53ee7f3d 15 j
431 > pick 6b70183d2492 12 g
432 > pick 6b70183d2492 12 g
432 > pick b605fb7503f2 14 i
433 > pick b605fb7503f2 14 i
433 > pick 7395e1ff83bd 13 h
434 > pick 7395e1ff83bd 13 h
434 > pick ee118ab9fa44 16 k
435 > pick ee118ab9fa44 16 k
435 > EOF
436 > EOF
436 $ hg log -G
437 $ hg log -G
437 @ 23:558246857888 (secret) k
438 @ 23:558246857888 (secret) k
438 |
439 |
439 o 22:28bd44768535 (secret) h
440 o 22:28bd44768535 (secret) h
440 |
441 |
441 o 21:d5395202aeb9 (secret) i
442 o 21:d5395202aeb9 (secret) i
442 |
443 |
443 o 20:21edda8e341b (secret) g
444 o 20:21edda8e341b (secret) g
444 |
445 |
445 o 19:5ab64f3a4832 (secret) j
446 o 19:5ab64f3a4832 (secret) j
446 |
447 |
447 o 13:b449568bf7fc (draft) f
448 o 13:b449568bf7fc (draft) f
448 |
449 |
449 o 12:40db8afa467b (public) c
450 o 12:40db8afa467b (public) c
450 |
451 |
451 o 0:cb9a9f314b8b (public) a
452 o 0:cb9a9f314b8b (public) a
452
453
453 $ cd ..
454 $ cd ..
454
455
455 Changeset folding
456 Changeset folding
456 -------------------------------------------
457 -------------------------------------------
457
458
458 Folding a secret changeset with a draft one turn the result secret (again,
459 Folding a secret changeset with a draft one turn the result secret (again,
459 better safe than sorry). Folding between same phase changeset still works
460 better safe than sorry). Folding between same phase changeset still works
460
461
461 Note that there is a few reordering in this series for more extensive test
462 Note that there is a few reordering in this series for more extensive test
462
463
463 $ cp -R base folding
464 $ cp -R base folding
464 $ cd folding
465 $ cd folding
465 $ cat >> .hg/hgrc << EOF
466 $ cat >> .hg/hgrc << EOF
466 > [phases]
467 > [phases]
467 > new-commit=secret
468 > new-commit=secret
468 > EOF
469 > EOF
469 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
470 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
470 > pick 7395e1ff83bd 13 h
471 > pick 7395e1ff83bd 13 h
471 > fold b449568bf7fc 11 f
472 > fold b449568bf7fc 11 f
472 > pick 6b70183d2492 12 g
473 > pick 6b70183d2492 12 g
473 > fold 3a6c53ee7f3d 15 j
474 > fold 3a6c53ee7f3d 15 j
474 > pick b605fb7503f2 14 i
475 > pick b605fb7503f2 14 i
475 > fold ee118ab9fa44 16 k
476 > fold ee118ab9fa44 16 k
476 > EOF
477 > EOF
477 $ hg log -G
478 $ hg log -G
478 @ 27:f9daec13fb98 (secret) i
479 @ 27:f9daec13fb98 (secret) i
479 |
480 |
480 o 24:49807617f46a (secret) g
481 o 24:49807617f46a (secret) g
481 |
482 |
482 o 21:050280826e04 (draft) h
483 o 21:050280826e04 (draft) h
483 |
484 |
484 o 12:40db8afa467b (public) c
485 o 12:40db8afa467b (public) c
485 |
486 |
486 o 0:cb9a9f314b8b (public) a
487 o 0:cb9a9f314b8b (public) a
487
488
488 $ hg co 49807617f46a
489 $ hg co 49807617f46a
489 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
490 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
490 $ echo wat >> wat
491 $ echo wat >> wat
491 $ hg add wat
492 $ hg add wat
492 $ hg ci -m 'add wat'
493 $ hg ci -m 'add wat'
493 created new head
494 created new head
494 $ hg merge f9daec13fb98
495 $ hg merge f9daec13fb98
495 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 (branch merge, don't forget to commit)
497 (branch merge, don't forget to commit)
497 $ hg ci -m 'merge'
498 $ hg ci -m 'merge'
498 $ echo not wat > wat
499 $ echo not wat > wat
499 $ hg ci -m 'modify wat'
500 $ hg ci -m 'modify wat'
500 $ hg histedit 050280826e04
501 $ hg histedit 050280826e04
501 abort: cannot edit history that contains merges
502 abort: cannot edit history that contains merges
502 [255]
503 [255]
503 $ cd ..
504 $ cd ..
504
505
505 Check abort behavior
506 Check abort behavior
506 -------------------------------------------
507 -------------------------------------------
507
508
508 We checks that abort properly clean the repository so the same histedit can be
509 We checks that abort properly clean the repository so the same histedit can be
509 attempted later.
510 attempted later.
510
511
511 $ cp -R base abort
512 $ cp -R base abort
512 $ cd abort
513 $ cd abort
513 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
514 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
514 > pick b449568bf7fc 13 f
515 > pick b449568bf7fc 13 f
515 > pick 7395e1ff83bd 15 h
516 > pick 7395e1ff83bd 15 h
516 > pick 6b70183d2492 14 g
517 > pick 6b70183d2492 14 g
517 > pick b605fb7503f2 16 i
518 > pick b605fb7503f2 16 i
518 > roll 3a6c53ee7f3d 17 j
519 > roll 3a6c53ee7f3d 17 j
519 > edit ee118ab9fa44 18 k
520 > edit ee118ab9fa44 18 k
520 > EOF
521 > EOF
521 Editing (ee118ab9fa44), you may commit or record as needed now.
522 Editing (ee118ab9fa44), you may commit or record as needed now.
522 (hg histedit --continue to resume)
523 (hg histedit --continue to resume)
523 [1]
524 [1]
524
525
525 $ hg histedit --abort
526 $ hg histedit --abort
526 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
527 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
527 saved backup bundle to $TESTTMP/abort/.hg/strip-backup/4dc06258baa6-dff4ef05-backup.hg (glob)
528 saved backup bundle to $TESTTMP/abort/.hg/strip-backup/4dc06258baa6-dff4ef05-backup.hg (glob)
528
529
529 $ hg log -G
530 $ hg log -G
530 @ 18:ee118ab9fa44 (secret) k
531 @ 18:ee118ab9fa44 (secret) k
531 |
532 |
532 o 17:3a6c53ee7f3d (secret) j
533 o 17:3a6c53ee7f3d (secret) j
533 |
534 |
534 o 16:b605fb7503f2 (secret) i
535 o 16:b605fb7503f2 (secret) i
535 |
536 |
536 o 15:7395e1ff83bd (draft) h
537 o 15:7395e1ff83bd (draft) h
537 |
538 |
538 o 14:6b70183d2492 (draft) g
539 o 14:6b70183d2492 (draft) g
539 |
540 |
540 o 13:b449568bf7fc (draft) f
541 o 13:b449568bf7fc (draft) f
541 |
542 |
542 o 12:40db8afa467b (public) c
543 o 12:40db8afa467b (public) c
543 |
544 |
544 o 0:cb9a9f314b8b (public) a
545 o 0:cb9a9f314b8b (public) a
545
546
546 $ hg histedit -r 'b449568bf7fc' --commands - << EOF --config experimental.stabilization.track-operation=1
547 $ hg histedit -r 'b449568bf7fc' --commands - << EOF --config experimental.stabilization.track-operation=1
547 > pick b449568bf7fc 13 f
548 > pick b449568bf7fc 13 f
548 > pick 7395e1ff83bd 15 h
549 > pick 7395e1ff83bd 15 h
549 > pick 6b70183d2492 14 g
550 > pick 6b70183d2492 14 g
550 > pick b605fb7503f2 16 i
551 > pick b605fb7503f2 16 i
551 > pick 3a6c53ee7f3d 17 j
552 > pick 3a6c53ee7f3d 17 j
552 > edit ee118ab9fa44 18 k
553 > edit ee118ab9fa44 18 k
553 > EOF
554 > EOF
554 Editing (ee118ab9fa44), you may commit or record as needed now.
555 Editing (ee118ab9fa44), you may commit or record as needed now.
555 (hg histedit --continue to resume)
556 (hg histedit --continue to resume)
556 [1]
557 [1]
557 $ hg histedit --continue --config experimental.stabilization.track-operation=1
558 $ hg histedit --continue --config experimental.stabilization.track-operation=1
558 $ hg log -G
559 $ hg log -G
559 @ 23:175d6b286a22 (secret) k
560 @ 23:175d6b286a22 (secret) k
560 |
561 |
561 o 22:44ca09d59ae4 (secret) j
562 o 22:44ca09d59ae4 (secret) j
562 |
563 |
563 o 21:31747692a644 (secret) i
564 o 21:31747692a644 (secret) i
564 |
565 |
565 o 20:9985cd4f21fa (draft) g
566 o 20:9985cd4f21fa (draft) g
566 |
567 |
567 o 19:4dc06258baa6 (draft) h
568 o 19:4dc06258baa6 (draft) h
568 |
569 |
569 o 13:b449568bf7fc (draft) f
570 o 13:b449568bf7fc (draft) f
570 |
571 |
571 o 12:40db8afa467b (public) c
572 o 12:40db8afa467b (public) c
572 |
573 |
573 o 0:cb9a9f314b8b (public) a
574 o 0:cb9a9f314b8b (public) a
574
575
575 $ hg debugobsolete --rev .
576 $ hg debugobsolete --rev .
576 ee118ab9fa44ebb86be85996548b5517a39e5093 175d6b286a224c23f192e79a581ce83131a53fa2 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
577 ee118ab9fa44ebb86be85996548b5517a39e5093 175d6b286a224c23f192e79a581ce83131a53fa2 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
@@ -1,153 +1,156 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 # You can reorder changesets by reordering the lines
48 # You can reorder changesets by reordering the lines
49 #
49 #
50 # Commands:
50 # Commands:
51 #
51 #
52 # e, edit = use commit, but stop for amending
52 # e, edit = use commit, but stop for amending
53 # m, mess = edit commit message without changing commit content
53 # m, mess = edit commit message without changing commit content
54 # p, pick = use commit
54 # p, pick = use commit
55 # b, base = checkout changeset and apply further changesets from there
55 # d, drop = remove commit from history
56 # d, drop = remove commit from history
56 # f, fold = use commit, but combine it with the one above
57 # f, fold = use commit, but combine it with the one above
57 # r, roll = like fold, but discard this commit's description and date
58 # r, roll = like fold, but discard this commit's description and date
58 #
59 #
59 $ cd ..
60 $ cd ..
60
61
61 show the error from unrelated repos
62 show the error from unrelated repos
62 $ cd r3
63 $ cd r3
63 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
64 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
64 abort: repository is unrelated
65 abort: repository is unrelated
65 [1]
66 [1]
66 $ cd ..
67 $ cd ..
67
68
68 show the error from unrelated repos
69 show the error from unrelated repos
69 $ cd r3
70 $ cd r3
70 $ HGEDITOR=cat hg histedit --force --outgoing ../r
71 $ HGEDITOR=cat hg histedit --force --outgoing ../r
71 comparing with ../r
72 comparing with ../r
72 searching for changes
73 searching for changes
73 warning: repository is unrelated
74 warning: repository is unrelated
74 pick 2a4042b45417 0 g
75 pick 2a4042b45417 0 g
75 pick 68c46b4927ce 1 h
76 pick 68c46b4927ce 1 h
76 pick 51281e65ba79 2 i
77 pick 51281e65ba79 2 i
77
78
78 # Edit history between 2a4042b45417 and 51281e65ba79
79 # Edit history between 2a4042b45417 and 51281e65ba79
79 #
80 #
80 # Commits are listed from least to most recent
81 # Commits are listed from least to most recent
81 #
82 #
82 # You can reorder changesets by reordering the lines
83 # You can reorder changesets by reordering the lines
83 #
84 #
84 # Commands:
85 # Commands:
85 #
86 #
86 # e, edit = use commit, but stop for amending
87 # e, edit = use commit, but stop for amending
87 # m, mess = edit commit message without changing commit content
88 # m, mess = edit commit message without changing commit content
88 # p, pick = use commit
89 # p, pick = use commit
90 # b, base = checkout changeset and apply further changesets from there
89 # d, drop = remove commit from history
91 # d, drop = remove commit from history
90 # f, fold = use commit, but combine it with the one above
92 # f, fold = use commit, but combine it with the one above
91 # r, roll = like fold, but discard this commit's description and date
93 # r, roll = like fold, but discard this commit's description and date
92 #
94 #
93 $ cd ..
95 $ cd ..
94
96
95 test sensitivity to branch in URL:
97 test sensitivity to branch in URL:
96
98
97 $ cd r2
99 $ cd r2
98 $ hg -q update 2
100 $ hg -q update 2
99 $ hg -q branch foo
101 $ hg -q branch foo
100 $ hg commit -m 'create foo branch'
102 $ hg commit -m 'create foo branch'
101 $ HGEDITOR=cat hg histedit --outgoing '../r#foo' | grep -v comparing | grep -v searching
103 $ HGEDITOR=cat hg histedit --outgoing '../r#foo' | grep -v comparing | grep -v searching
102 pick f26599ee3441 6 create foo branch
104 pick f26599ee3441 6 create foo branch
103
105
104 # Edit history between f26599ee3441 and f26599ee3441
106 # Edit history between f26599ee3441 and f26599ee3441
105 #
107 #
106 # Commits are listed from least to most recent
108 # Commits are listed from least to most recent
107 #
109 #
108 # You can reorder changesets by reordering the lines
110 # You can reorder changesets by reordering the lines
109 #
111 #
110 # Commands:
112 # Commands:
111 #
113 #
112 # e, edit = use commit, but stop for amending
114 # e, edit = use commit, but stop for amending
113 # m, mess = edit commit message without changing commit content
115 # m, mess = edit commit message without changing commit content
114 # p, pick = use commit
116 # p, pick = use commit
117 # b, base = checkout changeset and apply further changesets from there
115 # d, drop = remove commit from history
118 # d, drop = remove commit from history
116 # f, fold = use commit, but combine it with the one above
119 # f, fold = use commit, but combine it with the one above
117 # r, roll = like fold, but discard this commit's description and date
120 # r, roll = like fold, but discard this commit's description and date
118 #
121 #
119
122
120 test to check number of roots in outgoing revisions
123 test to check number of roots in outgoing revisions
121
124
122 $ hg -q outgoing -G --template '{node|short}({branch})' '../r'
125 $ hg -q outgoing -G --template '{node|short}({branch})' '../r'
123 @ f26599ee3441(foo)
126 @ f26599ee3441(foo)
124
127
125 o 652413bf663e(default)
128 o 652413bf663e(default)
126 |
129 |
127 o e860deea161a(default)
130 o e860deea161a(default)
128 |
131 |
129 o 055a42cdd887(default)
132 o 055a42cdd887(default)
130
133
131 $ HGEDITOR=cat hg -q histedit --outgoing '../r'
134 $ HGEDITOR=cat hg -q histedit --outgoing '../r'
132 abort: there are ambiguous outgoing revisions
135 abort: there are ambiguous outgoing revisions
133 (see 'hg help histedit' for more detail)
136 (see 'hg help histedit' for more detail)
134 [255]
137 [255]
135
138
136 $ hg -q update -C 2
139 $ hg -q update -C 2
137 $ echo aa >> a
140 $ echo aa >> a
138 $ hg -q commit -m 'another head on default'
141 $ hg -q commit -m 'another head on default'
139 $ hg -q outgoing -G --template '{node|short}({branch})' '../r#default'
142 $ hg -q outgoing -G --template '{node|short}({branch})' '../r#default'
140 @ 3879dc049647(default)
143 @ 3879dc049647(default)
141
144
142 o 652413bf663e(default)
145 o 652413bf663e(default)
143 |
146 |
144 o e860deea161a(default)
147 o e860deea161a(default)
145 |
148 |
146 o 055a42cdd887(default)
149 o 055a42cdd887(default)
147
150
148 $ HGEDITOR=cat hg -q histedit --outgoing '../r#default'
151 $ HGEDITOR=cat hg -q histedit --outgoing '../r#default'
149 abort: there are ambiguous outgoing revisions
152 abort: there are ambiguous outgoing revisions
150 (see 'hg help histedit' for more detail)
153 (see 'hg help histedit' for more detail)
151 [255]
154 [255]
152
155
153 $ cd ..
156 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now