##// END OF EJS Templates
unamend: abort if commit was not created by `hg [un]amend`...
Martin von Zweigbergk -
r49836:9120c0cd stable
parent child Browse files
Show More
@@ -1,318 +1,327 b''
1 # uncommit - undo the actions of a commit
1 # uncommit - undo the actions of a commit
2 #
2 #
3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
6 # Patrick Mezard <patrick@mezard.eu>
6 # Patrick Mezard <patrick@mezard.eu>
7 # Copyright 2016 Facebook, Inc.
7 # Copyright 2016 Facebook, Inc.
8 #
8 #
9 # This software may be used and distributed according to the terms of the
9 # This software may be used and distributed according to the terms of the
10 # GNU General Public License version 2 or any later version.
10 # GNU General Public License version 2 or any later version.
11
11
12 """uncommit part or all of a local changeset (EXPERIMENTAL)
12 """uncommit part or all of a local changeset (EXPERIMENTAL)
13
13
14 This command undoes the effect of a local commit, returning the affected
14 This command undoes the effect of a local commit, returning the affected
15 files to their uncommitted state. This means that files modified, added or
15 files to their uncommitted state. This means that files modified, added or
16 removed in the changeset will be left unchanged, and so will remain modified,
16 removed in the changeset will be left unchanged, and so will remain modified,
17 added and removed in the working directory.
17 added and removed in the working directory.
18 """
18 """
19
19
20 from __future__ import absolute_import
20 from __future__ import absolute_import
21
21
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23
23
24 from mercurial import (
24 from mercurial import (
25 cmdutil,
25 cmdutil,
26 commands,
26 commands,
27 context,
27 context,
28 copies as copiesmod,
28 copies as copiesmod,
29 error,
29 error,
30 obsutil,
30 obsutil,
31 pathutil,
31 pathutil,
32 pycompat,
32 pycompat,
33 registrar,
33 registrar,
34 rewriteutil,
34 rewriteutil,
35 scmutil,
35 scmutil,
36 )
36 )
37
37
38 cmdtable = {}
38 cmdtable = {}
39 command = registrar.command(cmdtable)
39 command = registrar.command(cmdtable)
40
40
41 configtable = {}
41 configtable = {}
42 configitem = registrar.configitem(configtable)
42 configitem = registrar.configitem(configtable)
43
43
44 configitem(
44 configitem(
45 b'experimental',
45 b'experimental',
46 b'uncommitondirtywdir',
46 b'uncommitondirtywdir',
47 default=False,
47 default=False,
48 )
48 )
49 configitem(
49 configitem(
50 b'experimental',
50 b'experimental',
51 b'uncommit.keep',
51 b'uncommit.keep',
52 default=False,
52 default=False,
53 )
53 )
54
54
55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
57 # be specifying the version(s) of Mercurial they are tested with, or
57 # be specifying the version(s) of Mercurial they are tested with, or
58 # leave the attribute unspecified.
58 # leave the attribute unspecified.
59 testedwith = b'ships-with-hg-core'
59 testedwith = b'ships-with-hg-core'
60
60
61
61
62 def _commitfiltered(
62 def _commitfiltered(
63 repo, ctx, match, keepcommit, message=None, user=None, date=None
63 repo, ctx, match, keepcommit, message=None, user=None, date=None
64 ):
64 ):
65 """Recommit ctx with changed files not in match. Return the new
65 """Recommit ctx with changed files not in match. Return the new
66 node identifier, or None if nothing changed.
66 node identifier, or None if nothing changed.
67 """
67 """
68 base = ctx.p1()
68 base = ctx.p1()
69 # ctx
69 # ctx
70 initialfiles = set(ctx.files())
70 initialfiles = set(ctx.files())
71 exclude = {f for f in initialfiles if match(f)}
71 exclude = {f for f in initialfiles if match(f)}
72
72
73 # No files matched commit, so nothing excluded
73 # No files matched commit, so nothing excluded
74 if not exclude:
74 if not exclude:
75 return None
75 return None
76
76
77 # return the p1 so that we don't create an obsmarker later
77 # return the p1 so that we don't create an obsmarker later
78 if not keepcommit:
78 if not keepcommit:
79 return ctx.p1().node()
79 return ctx.p1().node()
80
80
81 files = initialfiles - exclude
81 files = initialfiles - exclude
82 # Filter copies
82 # Filter copies
83 copied = copiesmod.pathcopies(base, ctx)
83 copied = copiesmod.pathcopies(base, ctx)
84 copied = {
84 copied = {
85 dst: src for dst, src in pycompat.iteritems(copied) if dst in files
85 dst: src for dst, src in pycompat.iteritems(copied) if dst in files
86 }
86 }
87
87
88 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
88 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
89 if path not in contentctx:
89 if path not in contentctx:
90 return None
90 return None
91 fctx = contentctx[path]
91 fctx = contentctx[path]
92 mctx = context.memfilectx(
92 mctx = context.memfilectx(
93 repo,
93 repo,
94 memctx,
94 memctx,
95 fctx.path(),
95 fctx.path(),
96 fctx.data(),
96 fctx.data(),
97 fctx.islink(),
97 fctx.islink(),
98 fctx.isexec(),
98 fctx.isexec(),
99 copysource=copied.get(path),
99 copysource=copied.get(path),
100 )
100 )
101 return mctx
101 return mctx
102
102
103 if not files:
103 if not files:
104 repo.ui.status(_(b"note: keeping empty commit\n"))
104 repo.ui.status(_(b"note: keeping empty commit\n"))
105
105
106 if message is None:
106 if message is None:
107 message = ctx.description()
107 message = ctx.description()
108 if not user:
108 if not user:
109 user = ctx.user()
109 user = ctx.user()
110 if not date:
110 if not date:
111 date = ctx.date()
111 date = ctx.date()
112
112
113 new = context.memctx(
113 new = context.memctx(
114 repo,
114 repo,
115 parents=[base.node(), repo.nullid],
115 parents=[base.node(), repo.nullid],
116 text=message,
116 text=message,
117 files=files,
117 files=files,
118 filectxfn=filectxfn,
118 filectxfn=filectxfn,
119 user=user,
119 user=user,
120 date=date,
120 date=date,
121 extra=ctx.extra(),
121 extra=ctx.extra(),
122 )
122 )
123 return repo.commitctx(new)
123 return repo.commitctx(new)
124
124
125
125
126 @command(
126 @command(
127 b'uncommit',
127 b'uncommit',
128 [
128 [
129 (b'', b'keep', None, _(b'allow an empty commit after uncommitting')),
129 (b'', b'keep', None, _(b'allow an empty commit after uncommitting')),
130 (
130 (
131 b'',
131 b'',
132 b'allow-dirty-working-copy',
132 b'allow-dirty-working-copy',
133 False,
133 False,
134 _(b'allow uncommit with outstanding changes'),
134 _(b'allow uncommit with outstanding changes'),
135 ),
135 ),
136 (b'n', b'note', b'', _(b'store a note on uncommit'), _(b'TEXT')),
136 (b'n', b'note', b'', _(b'store a note on uncommit'), _(b'TEXT')),
137 ]
137 ]
138 + commands.walkopts
138 + commands.walkopts
139 + commands.commitopts
139 + commands.commitopts
140 + commands.commitopts2
140 + commands.commitopts2
141 + commands.commitopts3,
141 + commands.commitopts3,
142 _(b'[OPTION]... [FILE]...'),
142 _(b'[OPTION]... [FILE]...'),
143 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
143 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
144 )
144 )
145 def uncommit(ui, repo, *pats, **opts):
145 def uncommit(ui, repo, *pats, **opts):
146 """uncommit part or all of a local changeset
146 """uncommit part or all of a local changeset
147
147
148 This command undoes the effect of a local commit, returning the affected
148 This command undoes the effect of a local commit, returning the affected
149 files to their uncommitted state. This means that files modified or
149 files to their uncommitted state. This means that files modified or
150 deleted in the changeset will be left unchanged, and so will remain
150 deleted in the changeset will be left unchanged, and so will remain
151 modified in the working directory.
151 modified in the working directory.
152
152
153 If no files are specified, the commit will be pruned, unless --keep is
153 If no files are specified, the commit will be pruned, unless --keep is
154 given.
154 given.
155 """
155 """
156 cmdutil.check_note_size(opts)
156 cmdutil.check_note_size(opts)
157 cmdutil.resolve_commit_options(ui, opts)
157 cmdutil.resolve_commit_options(ui, opts)
158 opts = pycompat.byteskwargs(opts)
158 opts = pycompat.byteskwargs(opts)
159
159
160 with repo.wlock(), repo.lock():
160 with repo.wlock(), repo.lock():
161
161
162 st = repo.status()
162 st = repo.status()
163 m, a, r, d = st.modified, st.added, st.removed, st.deleted
163 m, a, r, d = st.modified, st.added, st.removed, st.deleted
164 isdirtypath = any(set(m + a + r + d) & set(pats))
164 isdirtypath = any(set(m + a + r + d) & set(pats))
165 allowdirtywcopy = opts[
165 allowdirtywcopy = opts[
166 b'allow_dirty_working_copy'
166 b'allow_dirty_working_copy'
167 ] or repo.ui.configbool(b'experimental', b'uncommitondirtywdir')
167 ] or repo.ui.configbool(b'experimental', b'uncommitondirtywdir')
168 if not allowdirtywcopy and (not pats or isdirtypath):
168 if not allowdirtywcopy and (not pats or isdirtypath):
169 cmdutil.bailifchanged(
169 cmdutil.bailifchanged(
170 repo,
170 repo,
171 hint=_(b'requires --allow-dirty-working-copy to uncommit'),
171 hint=_(b'requires --allow-dirty-working-copy to uncommit'),
172 )
172 )
173 old = repo[b'.']
173 old = repo[b'.']
174 rewriteutil.precheck(repo, [old.rev()], b'uncommit')
174 rewriteutil.precheck(repo, [old.rev()], b'uncommit')
175 if len(old.parents()) > 1:
175 if len(old.parents()) > 1:
176 raise error.InputError(_(b"cannot uncommit merge changeset"))
176 raise error.InputError(_(b"cannot uncommit merge changeset"))
177
177
178 match = scmutil.match(old, pats, opts)
178 match = scmutil.match(old, pats, opts)
179
179
180 # Check all explicitly given files; abort if there's a problem.
180 # Check all explicitly given files; abort if there's a problem.
181 if match.files():
181 if match.files():
182 s = old.status(old.p1(), match, listclean=True)
182 s = old.status(old.p1(), match, listclean=True)
183 eligible = set(s.added) | set(s.modified) | set(s.removed)
183 eligible = set(s.added) | set(s.modified) | set(s.removed)
184
184
185 badfiles = set(match.files()) - eligible
185 badfiles = set(match.files()) - eligible
186
186
187 # Naming a parent directory of an eligible file is OK, even
187 # Naming a parent directory of an eligible file is OK, even
188 # if not everything tracked in that directory can be
188 # if not everything tracked in that directory can be
189 # uncommitted.
189 # uncommitted.
190 if badfiles:
190 if badfiles:
191 badfiles -= {f for f in pathutil.dirs(eligible)}
191 badfiles -= {f for f in pathutil.dirs(eligible)}
192
192
193 for f in sorted(badfiles):
193 for f in sorted(badfiles):
194 if f in s.clean:
194 if f in s.clean:
195 hint = _(
195 hint = _(
196 b"file was not changed in working directory parent"
196 b"file was not changed in working directory parent"
197 )
197 )
198 elif repo.wvfs.exists(f):
198 elif repo.wvfs.exists(f):
199 hint = _(b"file was untracked in working directory parent")
199 hint = _(b"file was untracked in working directory parent")
200 else:
200 else:
201 hint = _(b"file does not exist")
201 hint = _(b"file does not exist")
202
202
203 raise error.InputError(
203 raise error.InputError(
204 _(b'cannot uncommit "%s"') % scmutil.getuipathfn(repo)(f),
204 _(b'cannot uncommit "%s"') % scmutil.getuipathfn(repo)(f),
205 hint=hint,
205 hint=hint,
206 )
206 )
207
207
208 with repo.transaction(b'uncommit'):
208 with repo.transaction(b'uncommit'):
209 if not (opts[b'message'] or opts[b'logfile']):
209 if not (opts[b'message'] or opts[b'logfile']):
210 opts[b'message'] = old.description()
210 opts[b'message'] = old.description()
211 message = cmdutil.logmessage(ui, opts)
211 message = cmdutil.logmessage(ui, opts)
212
212
213 keepcommit = pats
213 keepcommit = pats
214 if not keepcommit:
214 if not keepcommit:
215 if opts.get(b'keep') is not None:
215 if opts.get(b'keep') is not None:
216 keepcommit = opts.get(b'keep')
216 keepcommit = opts.get(b'keep')
217 else:
217 else:
218 keepcommit = ui.configbool(
218 keepcommit = ui.configbool(
219 b'experimental', b'uncommit.keep'
219 b'experimental', b'uncommit.keep'
220 )
220 )
221 newid = _commitfiltered(
221 newid = _commitfiltered(
222 repo,
222 repo,
223 old,
223 old,
224 match,
224 match,
225 keepcommit,
225 keepcommit,
226 message=message,
226 message=message,
227 user=opts.get(b'user'),
227 user=opts.get(b'user'),
228 date=opts.get(b'date'),
228 date=opts.get(b'date'),
229 )
229 )
230 if newid is None:
230 if newid is None:
231 ui.status(_(b"nothing to uncommit\n"))
231 ui.status(_(b"nothing to uncommit\n"))
232 return 1
232 return 1
233
233
234 mapping = {}
234 mapping = {}
235 if newid != old.p1().node():
235 if newid != old.p1().node():
236 # Move local changes on filtered changeset
236 # Move local changes on filtered changeset
237 mapping[old.node()] = (newid,)
237 mapping[old.node()] = (newid,)
238 else:
238 else:
239 # Fully removed the old commit
239 # Fully removed the old commit
240 mapping[old.node()] = ()
240 mapping[old.node()] = ()
241
241
242 with repo.dirstate.parentchange():
242 with repo.dirstate.parentchange():
243 scmutil.movedirstate(repo, repo[newid], match)
243 scmutil.movedirstate(repo, repo[newid], match)
244
244
245 scmutil.cleanupnodes(repo, mapping, b'uncommit', fixphase=True)
245 scmutil.cleanupnodes(repo, mapping, b'uncommit', fixphase=True)
246
246
247
247
248 def predecessormarkers(ctx):
248 def predecessormarkers(ctx):
249 """yields the obsolete markers marking the given changeset as a successor"""
249 """yields the obsolete markers marking the given changeset as a successor"""
250 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
250 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
251 yield obsutil.marker(ctx.repo(), data)
251 yield obsutil.marker(ctx.repo(), data)
252
252
253
253
254 @command(
254 @command(
255 b'unamend',
255 b'unamend',
256 [],
256 [],
257 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
257 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
258 helpbasic=True,
258 helpbasic=True,
259 )
259 )
260 def unamend(ui, repo, **opts):
260 def unamend(ui, repo, **opts):
261 """undo the most recent amend operation on a current changeset
261 """undo the most recent amend operation on a current changeset
262
262
263 This command will roll back to the previous version of a changeset,
263 This command will roll back to the previous version of a changeset,
264 leaving working directory in state in which it was before running
264 leaving working directory in state in which it was before running
265 `hg amend` (e.g. files modified as part of an amend will be
265 `hg amend` (e.g. files modified as part of an amend will be
266 marked as modified `hg status`)
266 marked as modified `hg status`)
267 """
267 """
268
268
269 unfi = repo.unfiltered()
269 unfi = repo.unfiltered()
270 with repo.wlock(), repo.lock(), repo.transaction(b'unamend'):
270 with repo.wlock(), repo.lock(), repo.transaction(b'unamend'):
271
271
272 # identify the commit from which to unamend
272 # identify the commit from which to unamend
273 curctx = repo[b'.']
273 curctx = repo[b'.']
274
274
275 rewriteutil.precheck(repo, [curctx.rev()], b'unamend')
275 rewriteutil.precheck(repo, [curctx.rev()], b'unamend')
276 if len(curctx.parents()) > 1:
276 if len(curctx.parents()) > 1:
277 raise error.InputError(_(b"cannot unamend merge changeset"))
277 raise error.InputError(_(b"cannot unamend merge changeset"))
278
278
279 expected_keys = (b'amend_source', b'unamend_source')
280 if not any(key in curctx.extra() for key in expected_keys):
281 raise error.InputError(
282 _(
283 b"working copy parent was not created by 'hg amend' or "
284 b"'hg unamend'"
285 )
286 )
287
279 # identify the commit to which to unamend
288 # identify the commit to which to unamend
280 markers = list(predecessormarkers(curctx))
289 markers = list(predecessormarkers(curctx))
281 if len(markers) != 1:
290 if len(markers) != 1:
282 e = _(b"changeset must have one predecessor, found %i predecessors")
291 e = _(b"changeset must have one predecessor, found %i predecessors")
283 raise error.InputError(e % len(markers))
292 raise error.InputError(e % len(markers))
284
293
285 prednode = markers[0].prednode()
294 prednode = markers[0].prednode()
286 predctx = unfi[prednode]
295 predctx = unfi[prednode]
287
296
288 # add an extra so that we get a new hash
297 # add an extra so that we get a new hash
289 # note: allowing unamend to undo an unamend is an intentional feature
298 # note: allowing unamend to undo an unamend is an intentional feature
290 extras = predctx.extra()
299 extras = predctx.extra()
291 extras[b'unamend_source'] = curctx.hex()
300 extras[b'unamend_source'] = curctx.hex()
292
301
293 def filectxfn(repo, ctx_, path):
302 def filectxfn(repo, ctx_, path):
294 try:
303 try:
295 return predctx.filectx(path)
304 return predctx.filectx(path)
296 except KeyError:
305 except KeyError:
297 return None
306 return None
298
307
299 # Make a new commit same as predctx
308 # Make a new commit same as predctx
300 newctx = context.memctx(
309 newctx = context.memctx(
301 repo,
310 repo,
302 parents=(predctx.p1(), predctx.p2()),
311 parents=(predctx.p1(), predctx.p2()),
303 text=predctx.description(),
312 text=predctx.description(),
304 files=predctx.files(),
313 files=predctx.files(),
305 filectxfn=filectxfn,
314 filectxfn=filectxfn,
306 user=predctx.user(),
315 user=predctx.user(),
307 date=predctx.date(),
316 date=predctx.date(),
308 extra=extras,
317 extra=extras,
309 )
318 )
310 newprednode = repo.commitctx(newctx)
319 newprednode = repo.commitctx(newctx)
311 newpredctx = repo[newprednode]
320 newpredctx = repo[newprednode]
312 dirstate = repo.dirstate
321 dirstate = repo.dirstate
313
322
314 with dirstate.parentchange():
323 with dirstate.parentchange():
315 scmutil.movedirstate(repo, newpredctx)
324 scmutil.movedirstate(repo, newpredctx)
316
325
317 mapping = {curctx.node(): (newprednode,)}
326 mapping = {curctx.node(): (newprednode,)}
318 scmutil.cleanupnodes(repo, mapping, b'unamend', fixphase=True)
327 scmutil.cleanupnodes(repo, mapping, b'unamend', fixphase=True)
@@ -1,447 +1,462 b''
1 Test for command `hg unamend` which lives in uncommit extension
1 Test for command `hg unamend` which lives in uncommit extension
2 ===============================================================
2 ===============================================================
3
3
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [alias]
5 > [alias]
6 > glog = log -G -T '{rev}:{node|short} {desc}'
6 > glog = log -G -T '{rev}:{node|short} {desc}'
7 > [experimental]
7 > [experimental]
8 > evolution = createmarkers, allowunstable
8 > evolution = createmarkers, allowunstable
9 > evolution.allowdivergence = true
9 > evolution.allowdivergence = true
10 > [extensions]
10 > [extensions]
11 > rebase =
11 > rebase =
12 > amend =
12 > amend =
13 > uncommit =
13 > uncommit =
14 > EOF
14 > EOF
15
15
16 Repo Setup
16 Repo Setup
17
17
18 $ hg init repo
18 $ hg init repo
19 $ cd repo
19 $ cd repo
20 $ for ch in a b c d e f g h; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
20 $ for ch in a b c d e f g h; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
21
21
22 $ hg glog
22 $ hg glog
23 @ 7:ec2426147f0e Added h
23 @ 7:ec2426147f0e Added h
24 |
24 |
25 o 6:87d6d6676308 Added g
25 o 6:87d6d6676308 Added g
26 |
26 |
27 o 5:825660c69f0c Added f
27 o 5:825660c69f0c Added f
28 |
28 |
29 o 4:aa98ab95a928 Added e
29 o 4:aa98ab95a928 Added e
30 |
30 |
31 o 3:62615734edd5 Added d
31 o 3:62615734edd5 Added d
32 |
32 |
33 o 2:28ad74487de9 Added c
33 o 2:28ad74487de9 Added c
34 |
34 |
35 o 1:29becc82797a Added b
35 o 1:29becc82797a Added b
36 |
36 |
37 o 0:18d04c59bb5d Added a
37 o 0:18d04c59bb5d Added a
38
38
39 Trying to unamend when there was no amend done
39 Trying to unamend when there was no amend done
40
40
41 $ hg unamend
41 $ hg unamend
42 abort: working copy parent was not created by 'hg amend' or 'hg unamend'
43 [10]
44 $ echo "bar" >> h
45
46 Trying to unamend when the obsmarker is missing
47
48 $ hg amend
49 $ hg debugobsolete --delete 0
50 deleted 1 obsolescence markers
51 $ hg unamend
42 abort: changeset must have one predecessor, found 0 predecessors
52 abort: changeset must have one predecessor, found 0 predecessors
43 [10]
53 [10]
54 $ hg strip tip --config extensions.strip=
55 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
56 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/c9fa1a715c1b-06e5c233-backup.hg
57 $ hg up tip
58 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44
59
45 Unamend on clean wdir and tip
60 Unamend on clean wdir and tip
46
61
47 $ echo "bar" >> h
62 $ echo "bar" >> h
48 $ hg amend
63 $ hg amend
49
64
50 $ hg exp
65 $ hg exp
51 # HG changeset patch
66 # HG changeset patch
52 # User test
67 # User test
53 # Date 0 0
68 # Date 0 0
54 # Thu Jan 01 00:00:00 1970 +0000
69 # Thu Jan 01 00:00:00 1970 +0000
55 # Node ID c9fa1a715c1b7661c0fafb362a9f30bd75878d7d
70 # Node ID c9fa1a715c1b7661c0fafb362a9f30bd75878d7d
56 # Parent 87d6d66763085b629e6d7ed56778c79827273022
71 # Parent 87d6d66763085b629e6d7ed56778c79827273022
57 Added h
72 Added h
58
73
59 diff -r 87d6d6676308 -r c9fa1a715c1b h
74 diff -r 87d6d6676308 -r c9fa1a715c1b h
60 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
75 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61 +++ b/h Thu Jan 01 00:00:00 1970 +0000
76 +++ b/h Thu Jan 01 00:00:00 1970 +0000
62 @@ -0,0 +1,2 @@
77 @@ -0,0 +1,2 @@
63 +foo
78 +foo
64 +bar
79 +bar
65
80
66 $ hg glog --hidden
81 $ hg glog --hidden
67 @ 8:c9fa1a715c1b Added h
82 @ 8:c9fa1a715c1b Added h
68 |
83 |
69 | x 7:ec2426147f0e Added h
84 | x 7:ec2426147f0e Added h
70 |/
85 |/
71 o 6:87d6d6676308 Added g
86 o 6:87d6d6676308 Added g
72 |
87 |
73 o 5:825660c69f0c Added f
88 o 5:825660c69f0c Added f
74 |
89 |
75 o 4:aa98ab95a928 Added e
90 o 4:aa98ab95a928 Added e
76 |
91 |
77 o 3:62615734edd5 Added d
92 o 3:62615734edd5 Added d
78 |
93 |
79 o 2:28ad74487de9 Added c
94 o 2:28ad74487de9 Added c
80 |
95 |
81 o 1:29becc82797a Added b
96 o 1:29becc82797a Added b
82 |
97 |
83 o 0:18d04c59bb5d Added a
98 o 0:18d04c59bb5d Added a
84
99
85 $ hg unamend
100 $ hg unamend
86 $ hg glog --hidden
101 $ hg glog --hidden
87 @ 9:46d02d47eec6 Added h
102 @ 9:46d02d47eec6 Added h
88 |
103 |
89 | x 8:c9fa1a715c1b Added h
104 | x 8:c9fa1a715c1b Added h
90 |/
105 |/
91 | x 7:ec2426147f0e Added h
106 | x 7:ec2426147f0e Added h
92 |/
107 |/
93 o 6:87d6d6676308 Added g
108 o 6:87d6d6676308 Added g
94 |
109 |
95 o 5:825660c69f0c Added f
110 o 5:825660c69f0c Added f
96 |
111 |
97 o 4:aa98ab95a928 Added e
112 o 4:aa98ab95a928 Added e
98 |
113 |
99 o 3:62615734edd5 Added d
114 o 3:62615734edd5 Added d
100 |
115 |
101 o 2:28ad74487de9 Added c
116 o 2:28ad74487de9 Added c
102 |
117 |
103 o 1:29becc82797a Added b
118 o 1:29becc82797a Added b
104 |
119 |
105 o 0:18d04c59bb5d Added a
120 o 0:18d04c59bb5d Added a
106
121
107 $ hg diff
122 $ hg diff
108 diff -r 46d02d47eec6 h
123 diff -r 46d02d47eec6 h
109 --- a/h Thu Jan 01 00:00:00 1970 +0000
124 --- a/h Thu Jan 01 00:00:00 1970 +0000
110 +++ b/h Thu Jan 01 00:00:00 1970 +0000
125 +++ b/h Thu Jan 01 00:00:00 1970 +0000
111 @@ -1,1 +1,2 @@
126 @@ -1,1 +1,2 @@
112 foo
127 foo
113 +bar
128 +bar
114
129
115 $ hg exp
130 $ hg exp
116 # HG changeset patch
131 # HG changeset patch
117 # User test
132 # User test
118 # Date 0 0
133 # Date 0 0
119 # Thu Jan 01 00:00:00 1970 +0000
134 # Thu Jan 01 00:00:00 1970 +0000
120 # Node ID 46d02d47eec6ca096b8dcab3f8f5579c40c3dd9a
135 # Node ID 46d02d47eec6ca096b8dcab3f8f5579c40c3dd9a
121 # Parent 87d6d66763085b629e6d7ed56778c79827273022
136 # Parent 87d6d66763085b629e6d7ed56778c79827273022
122 Added h
137 Added h
123
138
124 diff -r 87d6d6676308 -r 46d02d47eec6 h
139 diff -r 87d6d6676308 -r 46d02d47eec6 h
125 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
140 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126 +++ b/h Thu Jan 01 00:00:00 1970 +0000
141 +++ b/h Thu Jan 01 00:00:00 1970 +0000
127 @@ -0,0 +1,1 @@
142 @@ -0,0 +1,1 @@
128 +foo
143 +foo
129
144
130 $ hg status
145 $ hg status
131 M h
146 M h
132
147
133 $ hg log -r . -T '{extras % "{extra}\n"}' --config alias.log=log
148 $ hg log -r . -T '{extras % "{extra}\n"}' --config alias.log=log
134 branch=default
149 branch=default
135 unamend_source=c9fa1a715c1b7661c0fafb362a9f30bd75878d7d
150 unamend_source=c9fa1a715c1b7661c0fafb362a9f30bd75878d7d
136
151
137 Using unamend to undo an unamed (intentional)
152 Using unamend to undo an unamed (intentional)
138
153
139 $ hg unamend
154 $ hg unamend
140 $ hg exp
155 $ hg exp
141 # HG changeset patch
156 # HG changeset patch
142 # User test
157 # User test
143 # Date 0 0
158 # Date 0 0
144 # Thu Jan 01 00:00:00 1970 +0000
159 # Thu Jan 01 00:00:00 1970 +0000
145 # Node ID 850ddfc1bc662997ec6094ada958f01f0cc8070a
160 # Node ID 850ddfc1bc662997ec6094ada958f01f0cc8070a
146 # Parent 87d6d66763085b629e6d7ed56778c79827273022
161 # Parent 87d6d66763085b629e6d7ed56778c79827273022
147 Added h
162 Added h
148
163
149 diff -r 87d6d6676308 -r 850ddfc1bc66 h
164 diff -r 87d6d6676308 -r 850ddfc1bc66 h
150 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
165 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
151 +++ b/h Thu Jan 01 00:00:00 1970 +0000
166 +++ b/h Thu Jan 01 00:00:00 1970 +0000
152 @@ -0,0 +1,2 @@
167 @@ -0,0 +1,2 @@
153 +foo
168 +foo
154 +bar
169 +bar
155 $ hg diff
170 $ hg diff
156
171
157 Unamend on a dirty working directory
172 Unamend on a dirty working directory
158
173
159 $ echo "bar" >> a
174 $ echo "bar" >> a
160 $ hg amend
175 $ hg amend
161 $ echo "foobar" >> a
176 $ echo "foobar" >> a
162 $ echo "bar" >> b
177 $ echo "bar" >> b
163 $ hg status
178 $ hg status
164 M a
179 M a
165 M b
180 M b
166
181
167 $ hg unamend
182 $ hg unamend
168
183
169 $ hg status
184 $ hg status
170 M a
185 M a
171 M b
186 M b
172
187
173 $ hg diff
188 $ hg diff
174 diff -r ec338db45d51 a
189 diff -r ec338db45d51 a
175 --- a/a Thu Jan 01 00:00:00 1970 +0000
190 --- a/a Thu Jan 01 00:00:00 1970 +0000
176 +++ b/a Thu Jan 01 00:00:00 1970 +0000
191 +++ b/a Thu Jan 01 00:00:00 1970 +0000
177 @@ -1,1 +1,3 @@
192 @@ -1,1 +1,3 @@
178 foo
193 foo
179 +bar
194 +bar
180 +foobar
195 +foobar
181 diff -r ec338db45d51 b
196 diff -r ec338db45d51 b
182 --- a/b Thu Jan 01 00:00:00 1970 +0000
197 --- a/b Thu Jan 01 00:00:00 1970 +0000
183 +++ b/b Thu Jan 01 00:00:00 1970 +0000
198 +++ b/b Thu Jan 01 00:00:00 1970 +0000
184 @@ -1,1 +1,2 @@
199 @@ -1,1 +1,2 @@
185 foo
200 foo
186 +bar
201 +bar
187
202
188 Unamending an added file
203 Unamending an added file
189
204
190 $ hg ci -m "Added things to a and b"
205 $ hg ci -m "Added things to a and b"
191 $ echo foo > bar
206 $ echo foo > bar
192 $ hg add bar
207 $ hg add bar
193 $ hg amend
208 $ hg amend
194
209
195 $ hg unamend
210 $ hg unamend
196 $ hg status
211 $ hg status
197 A bar
212 A bar
198
213
199 $ hg revert --all
214 $ hg revert --all
200 forgetting bar
215 forgetting bar
201
216
202 Unamending a removed file
217 Unamending a removed file
203
218
204 $ hg remove a
219 $ hg remove a
205 $ hg amend
220 $ hg amend
206
221
207 $ hg unamend
222 $ hg unamend
208 $ hg status
223 $ hg status
209 R a
224 R a
210 ? bar
225 ? bar
211
226
212 $ hg revert --all
227 $ hg revert --all
213 undeleting a
228 undeleting a
214
229
215 Unamending an added file with dirty wdir status
230 Unamending an added file with dirty wdir status
216
231
217 $ hg add bar
232 $ hg add bar
218 $ hg amend
233 $ hg amend
219 $ echo bar >> bar
234 $ echo bar >> bar
220 $ hg status
235 $ hg status
221 M bar
236 M bar
222
237
223 $ hg unamend
238 $ hg unamend
224 $ hg status
239 $ hg status
225 A bar
240 A bar
226 $ hg diff
241 $ hg diff
227 diff -r 7f79409af972 bar
242 diff -r 7f79409af972 bar
228 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
243 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
229 +++ b/bar Thu Jan 01 00:00:00 1970 +0000
244 +++ b/bar Thu Jan 01 00:00:00 1970 +0000
230 @@ -0,0 +1,2 @@
245 @@ -0,0 +1,2 @@
231 +foo
246 +foo
232 +bar
247 +bar
233
248
234 $ hg revert --all
249 $ hg revert --all
235 forgetting bar
250 forgetting bar
236 $ rm bar
251 $ rm bar
237
252
238 Unamending in middle of a stack
253 Unamending in middle of a stack
239
254
240 $ hg glog
255 $ hg glog
241 @ 19:7f79409af972 Added things to a and b
256 @ 19:7f79409af972 Added things to a and b
242 |
257 |
243 o 12:ec338db45d51 Added h
258 o 12:ec338db45d51 Added h
244 |
259 |
245 o 6:87d6d6676308 Added g
260 o 6:87d6d6676308 Added g
246 |
261 |
247 o 5:825660c69f0c Added f
262 o 5:825660c69f0c Added f
248 |
263 |
249 o 4:aa98ab95a928 Added e
264 o 4:aa98ab95a928 Added e
250 |
265 |
251 o 3:62615734edd5 Added d
266 o 3:62615734edd5 Added d
252 |
267 |
253 o 2:28ad74487de9 Added c
268 o 2:28ad74487de9 Added c
254 |
269 |
255 o 1:29becc82797a Added b
270 o 1:29becc82797a Added b
256 |
271 |
257 o 0:18d04c59bb5d Added a
272 o 0:18d04c59bb5d Added a
258
273
259 $ hg up 5
274 $ hg up 5
260 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
275 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
261 $ echo bar >> f
276 $ echo bar >> f
262 $ hg amend
277 $ hg amend
263 3 new orphan changesets
278 3 new orphan changesets
264 $ hg rebase -s 6 -d . -q
279 $ hg rebase -s 6 -d . -q
265
280
266 $ hg glog
281 $ hg glog
267 o 23:03ddd6fc5af1 Added things to a and b
282 o 23:03ddd6fc5af1 Added things to a and b
268 |
283 |
269 o 22:3e7b64ee157b Added h
284 o 22:3e7b64ee157b Added h
270 |
285 |
271 o 21:49635b68477e Added g
286 o 21:49635b68477e Added g
272 |
287 |
273 @ 20:93f0e8ffab32 Added f
288 @ 20:93f0e8ffab32 Added f
274 |
289 |
275 o 4:aa98ab95a928 Added e
290 o 4:aa98ab95a928 Added e
276 |
291 |
277 o 3:62615734edd5 Added d
292 o 3:62615734edd5 Added d
278 |
293 |
279 o 2:28ad74487de9 Added c
294 o 2:28ad74487de9 Added c
280 |
295 |
281 o 1:29becc82797a Added b
296 o 1:29becc82797a Added b
282 |
297 |
283 o 0:18d04c59bb5d Added a
298 o 0:18d04c59bb5d Added a
284
299
285
300
286 $ hg --config experimental.evolution=createmarkers unamend
301 $ hg --config experimental.evolution=createmarkers unamend
287 abort: cannot unamend changeset, as that will orphan 3 descendants
302 abort: cannot unamend changeset, as that will orphan 3 descendants
288 (see 'hg help evolution.instability')
303 (see 'hg help evolution.instability')
289 [10]
304 [10]
290
305
291 $ hg unamend
306 $ hg unamend
292 3 new orphan changesets
307 3 new orphan changesets
293
308
294 Trying to unamend a public changeset
309 Trying to unamend a public changeset
295
310
296 $ hg up -C 23
311 $ hg up -C 23
297 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 $ hg phase -r . -p
313 $ hg phase -r . -p
299 1 new phase-divergent changesets
314 1 new phase-divergent changesets
300 $ hg unamend
315 $ hg unamend
301 abort: cannot unamend public changesets: 03ddd6fc5af1
316 abort: cannot unamend public changesets: 03ddd6fc5af1
302 (see 'hg help phases' for details)
317 (see 'hg help phases' for details)
303 [10]
318 [10]
304
319
305 Testing whether unamend retains copies or not
320 Testing whether unamend retains copies or not
306
321
307 $ hg status
322 $ hg status
308
323
309 $ hg mv a foo
324 $ hg mv a foo
310
325
311 $ hg ci -m "Moved a to foo"
326 $ hg ci -m "Moved a to foo"
312 $ hg exp --git
327 $ hg exp --git
313 # HG changeset patch
328 # HG changeset patch
314 # User test
329 # User test
315 # Date 0 0
330 # Date 0 0
316 # Thu Jan 01 00:00:00 1970 +0000
331 # Thu Jan 01 00:00:00 1970 +0000
317 # Node ID cfef290346fbee5126313d7e1aab51d877679b09
332 # Node ID cfef290346fbee5126313d7e1aab51d877679b09
318 # Parent 03ddd6fc5af19e028c44a2fd6d790dd22712f231
333 # Parent 03ddd6fc5af19e028c44a2fd6d790dd22712f231
319 Moved a to foo
334 Moved a to foo
320
335
321 diff --git a/a b/foo
336 diff --git a/a b/foo
322 rename from a
337 rename from a
323 rename to foo
338 rename to foo
324
339
325 $ hg mv b foobar
340 $ hg mv b foobar
326 $ hg diff --git
341 $ hg diff --git
327 diff --git a/b b/foobar
342 diff --git a/b b/foobar
328 rename from b
343 rename from b
329 rename to foobar
344 rename to foobar
330 $ hg amend
345 $ hg amend
331
346
332 $ hg exp --git
347 $ hg exp --git
333 # HG changeset patch
348 # HG changeset patch
334 # User test
349 # User test
335 # Date 0 0
350 # Date 0 0
336 # Thu Jan 01 00:00:00 1970 +0000
351 # Thu Jan 01 00:00:00 1970 +0000
337 # Node ID eca050985275bb271ce3092b54e56ea5c85d29a3
352 # Node ID eca050985275bb271ce3092b54e56ea5c85d29a3
338 # Parent 03ddd6fc5af19e028c44a2fd6d790dd22712f231
353 # Parent 03ddd6fc5af19e028c44a2fd6d790dd22712f231
339 Moved a to foo
354 Moved a to foo
340
355
341 diff --git a/a b/foo
356 diff --git a/a b/foo
342 rename from a
357 rename from a
343 rename to foo
358 rename to foo
344 diff --git a/b b/foobar
359 diff --git a/b b/foobar
345 rename from b
360 rename from b
346 rename to foobar
361 rename to foobar
347
362
348 $ hg mv c wat
363 $ hg mv c wat
349 $ hg unamend
364 $ hg unamend
350
365
351 $ hg verify -v
366 $ hg verify -v
352 repository uses revlog format 1
367 repository uses revlog format 1
353 checking changesets
368 checking changesets
354 checking manifests
369 checking manifests
355 crosschecking files in changesets and manifests
370 crosschecking files in changesets and manifests
356 checking files
371 checking files
357 checked 28 changesets with 16 changes to 11 files
372 checked 28 changesets with 16 changes to 11 files
358
373
359 Retained copies in new prdecessor commit
374 Retained copies in new prdecessor commit
360
375
361 $ hg exp --git
376 $ hg exp --git
362 # HG changeset patch
377 # HG changeset patch
363 # User test
378 # User test
364 # Date 0 0
379 # Date 0 0
365 # Thu Jan 01 00:00:00 1970 +0000
380 # Thu Jan 01 00:00:00 1970 +0000
366 # Node ID 552e3af4f01f620f88ca27be1f898316235b736a
381 # Node ID 552e3af4f01f620f88ca27be1f898316235b736a
367 # Parent 03ddd6fc5af19e028c44a2fd6d790dd22712f231
382 # Parent 03ddd6fc5af19e028c44a2fd6d790dd22712f231
368 Moved a to foo
383 Moved a to foo
369
384
370 diff --git a/a b/foo
385 diff --git a/a b/foo
371 rename from a
386 rename from a
372 rename to foo
387 rename to foo
373
388
374 Retained copies in working directoy
389 Retained copies in working directoy
375
390
376 $ hg diff --git
391 $ hg diff --git
377 diff --git a/b b/foobar
392 diff --git a/b b/foobar
378 rename from b
393 rename from b
379 rename to foobar
394 rename to foobar
380 diff --git a/c b/wat
395 diff --git a/c b/wat
381 rename from c
396 rename from c
382 rename to wat
397 rename to wat
383 $ hg revert -qa
398 $ hg revert -qa
384 $ rm foobar wat
399 $ rm foobar wat
385
400
386 Rename a->b, then amend b->c. After unamend, should look like b->c.
401 Rename a->b, then amend b->c. After unamend, should look like b->c.
387
402
388 $ hg co -q 0
403 $ hg co -q 0
389 $ hg mv a b
404 $ hg mv a b
390 $ hg ci -qm 'move to a b'
405 $ hg ci -qm 'move to a b'
391 $ hg mv b c
406 $ hg mv b c
392 $ hg amend
407 $ hg amend
393 $ hg unamend
408 $ hg unamend
394 $ hg st --copies --change .
409 $ hg st --copies --change .
395 A b
410 A b
396 a
411 a
397 R a
412 R a
398 $ hg st --copies
413 $ hg st --copies
399 A c
414 A c
400 b
415 b
401 R b
416 R b
402 $ hg revert -qa
417 $ hg revert -qa
403 $ rm c
418 $ rm c
404
419
405 Rename a->b, then amend b->c, and working copy change c->d. After unamend, should look like b->d
420 Rename a->b, then amend b->c, and working copy change c->d. After unamend, should look like b->d
406
421
407 $ hg co -q 0
422 $ hg co -q 0
408 $ hg mv a b
423 $ hg mv a b
409 $ hg ci -qm 'move to a b'
424 $ hg ci -qm 'move to a b'
410 warning: commit already existed in the repository!
425 warning: commit already existed in the repository!
411 $ hg mv b c
426 $ hg mv b c
412 $ hg amend
427 $ hg amend
413 warning: commit already existed in the repository!
428 warning: commit already existed in the repository!
414 $ hg mv c d
429 $ hg mv c d
415 $ hg unamend
430 $ hg unamend
416 $ hg st --copies --change .
431 $ hg st --copies --change .
417 A b
432 A b
418 a
433 a
419 R a
434 R a
420 $ hg st --copies
435 $ hg st --copies
421 A d
436 A d
422 b
437 b
423 R b
438 R b
424
439
425 Try to unamend a merge
440 Try to unamend a merge
426
441
427 $ cd ..
442 $ cd ..
428 $ hg init merge
443 $ hg init merge
429 $ cd merge
444 $ cd merge
430 $ echo initial > initial
445 $ echo initial > initial
431 $ hg ci -Aqm initial
446 $ hg ci -Aqm initial
432 $ echo left > left
447 $ echo left > left
433 $ hg ci -Aqm left
448 $ hg ci -Aqm left
434 $ hg co -q 0
449 $ hg co -q 0
435 $ echo right > right
450 $ echo right > right
436 $ hg ci -Aqm right
451 $ hg ci -Aqm right
437 $ hg merge -q 1
452 $ hg merge -q 1
438 $ hg ci -m merge
453 $ hg ci -m merge
439 $ echo accidental > initial
454 $ echo accidental > initial
440 $ hg st --rev 1 --rev .
455 $ hg st --rev 1 --rev .
441 A right
456 A right
442 $ hg st --rev 2 --rev .
457 $ hg st --rev 2 --rev .
443 A left
458 A left
444 $ hg amend
459 $ hg amend
445 $ hg unamend
460 $ hg unamend
446 abort: cannot unamend merge changeset
461 abort: cannot unamend merge changeset
447 [10]
462 [10]
General Comments 0
You need to be logged in to leave comments. Login now