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