##// END OF EJS Templates
uncommit: document when the commit will be pruned...
Martin von Zweigbergk -
r36991:d63c5c65 default
parent child Browse files
Show More
@@ -1,257 +1,260 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,
28 copies,
29 error,
29 error,
30 node,
30 node,
31 obsutil,
31 obsutil,
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('experimental', 'uncommitondirtywdir',
44 configitem('experimental', 'uncommitondirtywdir',
45 default=False,
45 default=False,
46 )
46 )
47
47
48 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
48 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
49 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
49 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
50 # be specifying the version(s) of Mercurial they are tested with, or
50 # be specifying the version(s) of Mercurial they are tested with, or
51 # leave the attribute unspecified.
51 # leave the attribute unspecified.
52 testedwith = 'ships-with-hg-core'
52 testedwith = 'ships-with-hg-core'
53
53
54 def _commitfiltered(repo, ctx, match, allowempty):
54 def _commitfiltered(repo, ctx, match, allowempty):
55 """Recommit ctx with changed files not in match. Return the new
55 """Recommit ctx with changed files not in match. Return the new
56 node identifier, or None if nothing changed.
56 node identifier, or None if nothing changed.
57 """
57 """
58 base = ctx.p1()
58 base = ctx.p1()
59 # ctx
59 # ctx
60 initialfiles = set(ctx.files())
60 initialfiles = set(ctx.files())
61 exclude = set(f for f in initialfiles if match(f))
61 exclude = set(f for f in initialfiles if match(f))
62
62
63 # No files matched commit, so nothing excluded
63 # No files matched commit, so nothing excluded
64 if not exclude:
64 if not exclude:
65 return None
65 return None
66
66
67 files = (initialfiles - exclude)
67 files = (initialfiles - exclude)
68 # return the p1 so that we don't create an obsmarker later
68 # return the p1 so that we don't create an obsmarker later
69 if not files and not allowempty:
69 if not files and not allowempty:
70 return ctx.parents()[0].node()
70 return ctx.parents()[0].node()
71
71
72 # Filter copies
72 # Filter copies
73 copied = copies.pathcopies(base, ctx)
73 copied = copies.pathcopies(base, ctx)
74 copied = dict((dst, src) for dst, src in copied.iteritems()
74 copied = dict((dst, src) for dst, src in copied.iteritems()
75 if dst in files)
75 if dst in files)
76 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
76 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
77 if path not in contentctx:
77 if path not in contentctx:
78 return None
78 return None
79 fctx = contentctx[path]
79 fctx = contentctx[path]
80 mctx = context.memfilectx(repo, memctx, fctx.path(), fctx.data(),
80 mctx = context.memfilectx(repo, memctx, fctx.path(), fctx.data(),
81 fctx.islink(),
81 fctx.islink(),
82 fctx.isexec(),
82 fctx.isexec(),
83 copied=copied.get(path))
83 copied=copied.get(path))
84 return mctx
84 return mctx
85
85
86 new = context.memctx(repo,
86 new = context.memctx(repo,
87 parents=[base.node(), node.nullid],
87 parents=[base.node(), node.nullid],
88 text=ctx.description(),
88 text=ctx.description(),
89 files=files,
89 files=files,
90 filectxfn=filectxfn,
90 filectxfn=filectxfn,
91 user=ctx.user(),
91 user=ctx.user(),
92 date=ctx.date(),
92 date=ctx.date(),
93 extra=ctx.extra())
93 extra=ctx.extra())
94 # phase handling
94 # phase handling
95 commitphase = ctx.phase()
95 commitphase = ctx.phase()
96 overrides = {('phases', 'new-commit'): commitphase}
96 overrides = {('phases', 'new-commit'): commitphase}
97 with repo.ui.configoverride(overrides, 'uncommit'):
97 with repo.ui.configoverride(overrides, 'uncommit'):
98 newid = repo.commitctx(new)
98 newid = repo.commitctx(new)
99 return newid
99 return newid
100
100
101 def _fixdirstate(repo, oldctx, newctx, status):
101 def _fixdirstate(repo, oldctx, newctx, status):
102 """ fix the dirstate after switching the working directory from oldctx to
102 """ fix the dirstate after switching the working directory from oldctx to
103 newctx which can be result of either unamend or uncommit.
103 newctx which can be result of either unamend or uncommit.
104 """
104 """
105 ds = repo.dirstate
105 ds = repo.dirstate
106 copies = dict(ds.copies())
106 copies = dict(ds.copies())
107 s = status
107 s = status
108 for f in s.modified:
108 for f in s.modified:
109 if ds[f] == 'r':
109 if ds[f] == 'r':
110 # modified + removed -> removed
110 # modified + removed -> removed
111 continue
111 continue
112 ds.normallookup(f)
112 ds.normallookup(f)
113
113
114 for f in s.added:
114 for f in s.added:
115 if ds[f] == 'r':
115 if ds[f] == 'r':
116 # added + removed -> unknown
116 # added + removed -> unknown
117 ds.drop(f)
117 ds.drop(f)
118 elif ds[f] != 'a':
118 elif ds[f] != 'a':
119 ds.add(f)
119 ds.add(f)
120
120
121 for f in s.removed:
121 for f in s.removed:
122 if ds[f] == 'a':
122 if ds[f] == 'a':
123 # removed + added -> normal
123 # removed + added -> normal
124 ds.normallookup(f)
124 ds.normallookup(f)
125 elif ds[f] != 'r':
125 elif ds[f] != 'r':
126 ds.remove(f)
126 ds.remove(f)
127
127
128 # Merge old parent and old working dir copies
128 # Merge old parent and old working dir copies
129 oldcopies = {}
129 oldcopies = {}
130 for f in (s.modified + s.added):
130 for f in (s.modified + s.added):
131 src = oldctx[f].renamed()
131 src = oldctx[f].renamed()
132 if src:
132 if src:
133 oldcopies[f] = src[0]
133 oldcopies[f] = src[0]
134 oldcopies.update(copies)
134 oldcopies.update(copies)
135 copies = dict((dst, oldcopies.get(src, src))
135 copies = dict((dst, oldcopies.get(src, src))
136 for dst, src in oldcopies.iteritems())
136 for dst, src in oldcopies.iteritems())
137 # Adjust the dirstate copies
137 # Adjust the dirstate copies
138 for dst, src in copies.iteritems():
138 for dst, src in copies.iteritems():
139 if (src not in newctx or dst in newctx or ds[dst] != 'a'):
139 if (src not in newctx or dst in newctx or ds[dst] != 'a'):
140 src = None
140 src = None
141 ds.copy(src, dst)
141 ds.copy(src, dst)
142
142
143 @command('uncommit',
143 @command('uncommit',
144 [('', 'keep', False, _('allow an empty commit after uncommiting')),
144 [('', 'keep', False, _('allow an empty commit after uncommiting')),
145 ] + commands.walkopts,
145 ] + commands.walkopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def uncommit(ui, repo, *pats, **opts):
147 def uncommit(ui, repo, *pats, **opts):
148 """uncommit part or all of a local changeset
148 """uncommit part or all of a local changeset
149
149
150 This command undoes the effect of a local commit, returning the affected
150 This command undoes the effect of a local commit, returning the affected
151 files to their uncommitted state. This means that files modified or
151 files to their uncommitted state. This means that files modified or
152 deleted in the changeset will be left unchanged, and so will remain
152 deleted in the changeset will be left unchanged, and so will remain
153 modified in the working directory.
153 modified in the working directory.
154
155 If no files are specified, the commit will be pruned, unless --keep is
156 given.
154 """
157 """
155 opts = pycompat.byteskwargs(opts)
158 opts = pycompat.byteskwargs(opts)
156
159
157 with repo.wlock(), repo.lock():
160 with repo.wlock(), repo.lock():
158
161
159 if not pats and not repo.ui.configbool('experimental',
162 if not pats and not repo.ui.configbool('experimental',
160 'uncommitondirtywdir'):
163 'uncommitondirtywdir'):
161 cmdutil.bailifchanged(repo)
164 cmdutil.bailifchanged(repo)
162 old = repo['.']
165 old = repo['.']
163 rewriteutil.precheck(repo, [old.rev()], 'uncommit')
166 rewriteutil.precheck(repo, [old.rev()], 'uncommit')
164 if len(old.parents()) > 1:
167 if len(old.parents()) > 1:
165 raise error.Abort(_("cannot uncommit merge changeset"))
168 raise error.Abort(_("cannot uncommit merge changeset"))
166
169
167 with repo.transaction('uncommit'):
170 with repo.transaction('uncommit'):
168 match = scmutil.match(old, pats, opts)
171 match = scmutil.match(old, pats, opts)
169 allowempty = opts.get('keep') or pats
172 allowempty = opts.get('keep') or pats
170 newid = _commitfiltered(repo, old, match, allowempty)
173 newid = _commitfiltered(repo, old, match, allowempty)
171 if newid is None:
174 if newid is None:
172 ui.status(_("nothing to uncommit\n"))
175 ui.status(_("nothing to uncommit\n"))
173 return 1
176 return 1
174
177
175 mapping = {}
178 mapping = {}
176 if newid != old.p1().node():
179 if newid != old.p1().node():
177 # Move local changes on filtered changeset
180 # Move local changes on filtered changeset
178 mapping[old.node()] = (newid,)
181 mapping[old.node()] = (newid,)
179 else:
182 else:
180 # Fully removed the old commit
183 # Fully removed the old commit
181 mapping[old.node()] = ()
184 mapping[old.node()] = ()
182
185
183 scmutil.cleanupnodes(repo, mapping, 'uncommit')
186 scmutil.cleanupnodes(repo, mapping, 'uncommit')
184
187
185 with repo.dirstate.parentchange():
188 with repo.dirstate.parentchange():
186 repo.dirstate.setparents(newid, node.nullid)
189 repo.dirstate.setparents(newid, node.nullid)
187 s = repo.status(old.p1(), old, match=match)
190 s = repo.status(old.p1(), old, match=match)
188 _fixdirstate(repo, old, repo[newid], s)
191 _fixdirstate(repo, old, repo[newid], s)
189
192
190 def predecessormarkers(ctx):
193 def predecessormarkers(ctx):
191 """yields the obsolete markers marking the given changeset as a successor"""
194 """yields the obsolete markers marking the given changeset as a successor"""
192 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
195 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
193 yield obsutil.marker(ctx.repo(), data)
196 yield obsutil.marker(ctx.repo(), data)
194
197
195 @command('^unamend', [])
198 @command('^unamend', [])
196 def unamend(ui, repo, **opts):
199 def unamend(ui, repo, **opts):
197 """undo the most recent amend operation on a current changeset
200 """undo the most recent amend operation on a current changeset
198
201
199 This command will roll back to the previous version of a changeset,
202 This command will roll back to the previous version of a changeset,
200 leaving working directory in state in which it was before running
203 leaving working directory in state in which it was before running
201 `hg amend` (e.g. files modified as part of an amend will be
204 `hg amend` (e.g. files modified as part of an amend will be
202 marked as modified `hg status`)
205 marked as modified `hg status`)
203 """
206 """
204
207
205 unfi = repo.unfiltered()
208 unfi = repo.unfiltered()
206 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
209 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
207
210
208 # identify the commit from which to unamend
211 # identify the commit from which to unamend
209 curctx = repo['.']
212 curctx = repo['.']
210
213
211 rewriteutil.precheck(repo, [curctx.rev()], 'unamend')
214 rewriteutil.precheck(repo, [curctx.rev()], 'unamend')
212
215
213 # identify the commit to which to unamend
216 # identify the commit to which to unamend
214 markers = list(predecessormarkers(curctx))
217 markers = list(predecessormarkers(curctx))
215 if len(markers) != 1:
218 if len(markers) != 1:
216 e = _("changeset must have one predecessor, found %i predecessors")
219 e = _("changeset must have one predecessor, found %i predecessors")
217 raise error.Abort(e % len(markers))
220 raise error.Abort(e % len(markers))
218
221
219 prednode = markers[0].prednode()
222 prednode = markers[0].prednode()
220 predctx = unfi[prednode]
223 predctx = unfi[prednode]
221
224
222 # add an extra so that we get a new hash
225 # add an extra so that we get a new hash
223 # note: allowing unamend to undo an unamend is an intentional feature
226 # note: allowing unamend to undo an unamend is an intentional feature
224 extras = predctx.extra()
227 extras = predctx.extra()
225 extras['unamend_source'] = curctx.hex()
228 extras['unamend_source'] = curctx.hex()
226
229
227 def filectxfn(repo, ctx_, path):
230 def filectxfn(repo, ctx_, path):
228 try:
231 try:
229 return predctx.filectx(path)
232 return predctx.filectx(path)
230 except KeyError:
233 except KeyError:
231 return None
234 return None
232
235
233 # Make a new commit same as predctx
236 # Make a new commit same as predctx
234 newctx = context.memctx(repo,
237 newctx = context.memctx(repo,
235 parents=(predctx.p1(), predctx.p2()),
238 parents=(predctx.p1(), predctx.p2()),
236 text=predctx.description(),
239 text=predctx.description(),
237 files=predctx.files(),
240 files=predctx.files(),
238 filectxfn=filectxfn,
241 filectxfn=filectxfn,
239 user=predctx.user(),
242 user=predctx.user(),
240 date=predctx.date(),
243 date=predctx.date(),
241 extra=extras)
244 extra=extras)
242 # phase handling
245 # phase handling
243 commitphase = curctx.phase()
246 commitphase = curctx.phase()
244 overrides = {('phases', 'new-commit'): commitphase}
247 overrides = {('phases', 'new-commit'): commitphase}
245 with repo.ui.configoverride(overrides, 'uncommit'):
248 with repo.ui.configoverride(overrides, 'uncommit'):
246 newprednode = repo.commitctx(newctx)
249 newprednode = repo.commitctx(newctx)
247
250
248 newpredctx = repo[newprednode]
251 newpredctx = repo[newprednode]
249 dirstate = repo.dirstate
252 dirstate = repo.dirstate
250
253
251 with dirstate.parentchange():
254 with dirstate.parentchange():
252 dirstate.setparents(newprednode, node.nullid)
255 dirstate.setparents(newprednode, node.nullid)
253 s = repo.status(predctx, curctx)
256 s = repo.status(predctx, curctx)
254 _fixdirstate(repo, curctx, newpredctx, s)
257 _fixdirstate(repo, curctx, newpredctx, s)
255
258
256 mapping = {curctx.node(): (newprednode,)}
259 mapping = {curctx.node(): (newprednode,)}
257 scmutil.cleanupnodes(repo, mapping, 'unamend')
260 scmutil.cleanupnodes(repo, mapping, 'unamend')
@@ -1,390 +1,393 b''
1 Test uncommit - set up the config
1 Test uncommit - set up the config
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [experimental]
4 > [experimental]
5 > evolution.createmarkers=True
5 > evolution.createmarkers=True
6 > evolution.allowunstable=True
6 > evolution.allowunstable=True
7 > [extensions]
7 > [extensions]
8 > uncommit =
8 > uncommit =
9 > drawdag=$TESTDIR/drawdag.py
9 > drawdag=$TESTDIR/drawdag.py
10 > EOF
10 > EOF
11
11
12 Build up a repo
12 Build up a repo
13
13
14 $ hg init repo
14 $ hg init repo
15 $ cd repo
15 $ cd repo
16 $ hg bookmark foo
16 $ hg bookmark foo
17
17
18 Help for uncommit
18 Help for uncommit
19
19
20 $ hg help uncommit
20 $ hg help uncommit
21 hg uncommit [OPTION]... [FILE]...
21 hg uncommit [OPTION]... [FILE]...
22
22
23 uncommit part or all of a local changeset
23 uncommit part or all of a local changeset
24
24
25 This command undoes the effect of a local commit, returning the affected
25 This command undoes the effect of a local commit, returning the affected
26 files to their uncommitted state. This means that files modified or
26 files to their uncommitted state. This means that files modified or
27 deleted in the changeset will be left unchanged, and so will remain
27 deleted in the changeset will be left unchanged, and so will remain
28 modified in the working directory.
28 modified in the working directory.
29
29
30 If no files are specified, the commit will be pruned, unless --keep is
31 given.
32
30 (use 'hg help -e uncommit' to show help for the uncommit extension)
33 (use 'hg help -e uncommit' to show help for the uncommit extension)
31
34
32 options ([+] can be repeated):
35 options ([+] can be repeated):
33
36
34 --keep allow an empty commit after uncommiting
37 --keep allow an empty commit after uncommiting
35 -I --include PATTERN [+] include names matching the given patterns
38 -I --include PATTERN [+] include names matching the given patterns
36 -X --exclude PATTERN [+] exclude names matching the given patterns
39 -X --exclude PATTERN [+] exclude names matching the given patterns
37
40
38 (some details hidden, use --verbose to show complete help)
41 (some details hidden, use --verbose to show complete help)
39
42
40 Uncommit with no commits should fail
43 Uncommit with no commits should fail
41
44
42 $ hg uncommit
45 $ hg uncommit
43 abort: cannot uncommit null changeset
46 abort: cannot uncommit null changeset
44 (no changeset checked out)
47 (no changeset checked out)
45 [255]
48 [255]
46
49
47 Create some commits
50 Create some commits
48
51
49 $ touch files
52 $ touch files
50 $ hg add files
53 $ hg add files
51 $ for i in a ab abc abcd abcde; do echo $i > files; echo $i > file-$i; hg add file-$i; hg commit -m "added file-$i"; done
54 $ for i in a ab abc abcd abcde; do echo $i > files; echo $i > file-$i; hg add file-$i; hg commit -m "added file-$i"; done
52 $ ls
55 $ ls
53 file-a
56 file-a
54 file-ab
57 file-ab
55 file-abc
58 file-abc
56 file-abcd
59 file-abcd
57 file-abcde
60 file-abcde
58 files
61 files
59
62
60 $ hg log -G -T '{rev}:{node} {desc}' --hidden
63 $ hg log -G -T '{rev}:{node} {desc}' --hidden
61 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
64 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
62 |
65 |
63 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
66 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
64 |
67 |
65 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
68 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
66 |
69 |
67 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
70 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
68 |
71 |
69 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
72 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
70
73
71 Simple uncommit off the top, also moves bookmark
74 Simple uncommit off the top, also moves bookmark
72
75
73 $ hg bookmark
76 $ hg bookmark
74 * foo 4:6c4fd43ed714
77 * foo 4:6c4fd43ed714
75 $ hg uncommit
78 $ hg uncommit
76 $ hg status
79 $ hg status
77 M files
80 M files
78 A file-abcde
81 A file-abcde
79 $ hg bookmark
82 $ hg bookmark
80 * foo 3:6db330d65db4
83 * foo 3:6db330d65db4
81
84
82 $ hg log -G -T '{rev}:{node} {desc}' --hidden
85 $ hg log -G -T '{rev}:{node} {desc}' --hidden
83 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
86 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
84 |
87 |
85 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
88 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
86 |
89 |
87 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
90 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
88 |
91 |
89 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
92 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
90 |
93 |
91 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
94 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
92
95
93
96
94 Recommit
97 Recommit
95
98
96 $ hg commit -m 'new change abcde'
99 $ hg commit -m 'new change abcde'
97 $ hg status
100 $ hg status
98 $ hg heads -T '{rev}:{node} {desc}'
101 $ hg heads -T '{rev}:{node} {desc}'
99 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
102 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
100
103
101 Uncommit of non-existent and unchanged files has no effect
104 Uncommit of non-existent and unchanged files has no effect
102 $ hg uncommit nothinghere
105 $ hg uncommit nothinghere
103 nothing to uncommit
106 nothing to uncommit
104 [1]
107 [1]
105 $ hg status
108 $ hg status
106 $ hg uncommit file-abc
109 $ hg uncommit file-abc
107 nothing to uncommit
110 nothing to uncommit
108 [1]
111 [1]
109 $ hg status
112 $ hg status
110
113
111 Try partial uncommit, also moves bookmark
114 Try partial uncommit, also moves bookmark
112
115
113 $ hg bookmark
116 $ hg bookmark
114 * foo 5:0c07a3ccda77
117 * foo 5:0c07a3ccda77
115 $ hg uncommit files
118 $ hg uncommit files
116 $ hg status
119 $ hg status
117 M files
120 M files
118 $ hg bookmark
121 $ hg bookmark
119 * foo 6:3727deee06f7
122 * foo 6:3727deee06f7
120 $ hg heads -T '{rev}:{node} {desc}'
123 $ hg heads -T '{rev}:{node} {desc}'
121 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
124 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
122 $ hg log -r . -p -T '{rev}:{node} {desc}'
125 $ hg log -r . -p -T '{rev}:{node} {desc}'
123 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
126 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
128 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
126 @@ -0,0 +1,1 @@
129 @@ -0,0 +1,1 @@
127 +abcde
130 +abcde
128
131
129 $ hg log -G -T '{rev}:{node} {desc}' --hidden
132 $ hg log -G -T '{rev}:{node} {desc}' --hidden
130 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
133 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
131 |
134 |
132 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
135 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
133 |/
136 |/
134 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
137 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
135 |/
138 |/
136 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
139 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
137 |
140 |
138 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
141 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
139 |
142 |
140 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
143 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
141 |
144 |
142 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
145 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
143
146
144 $ hg commit -m 'update files for abcde'
147 $ hg commit -m 'update files for abcde'
145
148
146 Uncommit with dirty state
149 Uncommit with dirty state
147
150
148 $ echo "foo" >> files
151 $ echo "foo" >> files
149 $ cat files
152 $ cat files
150 abcde
153 abcde
151 foo
154 foo
152 $ hg status
155 $ hg status
153 M files
156 M files
154 $ hg uncommit
157 $ hg uncommit
155 abort: uncommitted changes
158 abort: uncommitted changes
156 [255]
159 [255]
157 $ hg uncommit files
160 $ hg uncommit files
158 $ cat files
161 $ cat files
159 abcde
162 abcde
160 foo
163 foo
161 $ hg commit --amend -m "files abcde + foo"
164 $ hg commit --amend -m "files abcde + foo"
162
165
163 Testing the 'experimental.uncommitondirtywdir' config
166 Testing the 'experimental.uncommitondirtywdir' config
164
167
165 $ echo "bar" >> files
168 $ echo "bar" >> files
166 $ hg uncommit
169 $ hg uncommit
167 abort: uncommitted changes
170 abort: uncommitted changes
168 [255]
171 [255]
169 $ hg uncommit --config experimental.uncommitondirtywdir=True
172 $ hg uncommit --config experimental.uncommitondirtywdir=True
170 $ hg commit -m "files abcde + foo"
173 $ hg commit -m "files abcde + foo"
171
174
172 Uncommit in the middle of a stack, does not move bookmark
175 Uncommit in the middle of a stack, does not move bookmark
173
176
174 $ hg checkout '.^^^'
177 $ hg checkout '.^^^'
175 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
178 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
176 (leaving bookmark foo)
179 (leaving bookmark foo)
177 $ hg log -r . -p -T '{rev}:{node} {desc}'
180 $ hg log -r . -p -T '{rev}:{node} {desc}'
178 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
181 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
179 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
182 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
180 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
183 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
181 @@ -0,0 +1,1 @@
184 @@ -0,0 +1,1 @@
182 +abc
185 +abc
183 diff -r 69a232e754b0 -r abf2df566fc1 files
186 diff -r 69a232e754b0 -r abf2df566fc1 files
184 --- a/files Thu Jan 01 00:00:00 1970 +0000
187 --- a/files Thu Jan 01 00:00:00 1970 +0000
185 +++ b/files Thu Jan 01 00:00:00 1970 +0000
188 +++ b/files Thu Jan 01 00:00:00 1970 +0000
186 @@ -1,1 +1,1 @@
189 @@ -1,1 +1,1 @@
187 -ab
190 -ab
188 +abc
191 +abc
189
192
190 $ hg bookmark
193 $ hg bookmark
191 foo 10:48e5bd7cd583
194 foo 10:48e5bd7cd583
192 $ hg uncommit
195 $ hg uncommit
193 3 new orphan changesets
196 3 new orphan changesets
194 $ hg status
197 $ hg status
195 M files
198 M files
196 A file-abc
199 A file-abc
197 $ hg heads -T '{rev}:{node} {desc}'
200 $ hg heads -T '{rev}:{node} {desc}'
198 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
201 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
199 $ hg bookmark
202 $ hg bookmark
200 foo 10:48e5bd7cd583
203 foo 10:48e5bd7cd583
201 $ hg commit -m 'new abc'
204 $ hg commit -m 'new abc'
202 created new head
205 created new head
203
206
204 Partial uncommit in the middle, does not move bookmark
207 Partial uncommit in the middle, does not move bookmark
205
208
206 $ hg checkout '.^'
209 $ hg checkout '.^'
207 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
210 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
208 $ hg log -r . -p -T '{rev}:{node} {desc}'
211 $ hg log -r . -p -T '{rev}:{node} {desc}'
209 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
212 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
210 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
213 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
211 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
214 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
212 @@ -0,0 +1,1 @@
215 @@ -0,0 +1,1 @@
213 +ab
216 +ab
214 diff -r 3004d2d9b508 -r 69a232e754b0 files
217 diff -r 3004d2d9b508 -r 69a232e754b0 files
215 --- a/files Thu Jan 01 00:00:00 1970 +0000
218 --- a/files Thu Jan 01 00:00:00 1970 +0000
216 +++ b/files Thu Jan 01 00:00:00 1970 +0000
219 +++ b/files Thu Jan 01 00:00:00 1970 +0000
217 @@ -1,1 +1,1 @@
220 @@ -1,1 +1,1 @@
218 -a
221 -a
219 +ab
222 +ab
220
223
221 $ hg bookmark
224 $ hg bookmark
222 foo 10:48e5bd7cd583
225 foo 10:48e5bd7cd583
223 $ hg uncommit file-ab
226 $ hg uncommit file-ab
224 1 new orphan changesets
227 1 new orphan changesets
225 $ hg status
228 $ hg status
226 A file-ab
229 A file-ab
227
230
228 $ hg heads -T '{rev}:{node} {desc}\n'
231 $ hg heads -T '{rev}:{node} {desc}\n'
229 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
232 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
230 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
233 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
231 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
234 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
232
235
233 $ hg bookmark
236 $ hg bookmark
234 foo 10:48e5bd7cd583
237 foo 10:48e5bd7cd583
235 $ hg commit -m 'update ab'
238 $ hg commit -m 'update ab'
236 $ hg status
239 $ hg status
237 $ hg heads -T '{rev}:{node} {desc}\n'
240 $ hg heads -T '{rev}:{node} {desc}\n'
238 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
241 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
239 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
242 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
240 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
243 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
241
244
242 $ hg log -G -T '{rev}:{node} {desc}' --hidden
245 $ hg log -G -T '{rev}:{node} {desc}' --hidden
243 @ 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
246 @ 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
244 |
247 |
245 o 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
248 o 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
246 |
249 |
247 | * 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
250 | * 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
248 | |
251 | |
249 | | * 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
252 | | * 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
250 | | |
253 | | |
251 | | | x 9:8a6b58c173ca6a2e3745d8bd86698718d664bc6c files abcde + foo
254 | | | x 9:8a6b58c173ca6a2e3745d8bd86698718d664bc6c files abcde + foo
252 | | |/
255 | | |/
253 | | | x 8:39ad452c7f684a55d161c574340c5766c4569278 update files for abcde
256 | | | x 8:39ad452c7f684a55d161c574340c5766c4569278 update files for abcde
254 | | |/
257 | | |/
255 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
258 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
256 | | |/
259 | | |/
257 | | * 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
260 | | * 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
258 | | |
261 | | |
259 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
262 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
260 | | |/
263 | | |/
261 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
264 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
262 | | |/
265 | | |/
263 | | * 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
266 | | * 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
264 | | |
267 | | |
265 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
268 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
266 | |/
269 | |/
267 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
270 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
268 |/
271 |/
269 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
272 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
270
273
271 Uncommit with draft parent
274 Uncommit with draft parent
272
275
273 $ hg uncommit
276 $ hg uncommit
274 $ hg phase -r .
277 $ hg phase -r .
275 12: draft
278 12: draft
276 $ hg commit -m 'update ab again'
279 $ hg commit -m 'update ab again'
277
280
278 Uncommit with public parent
281 Uncommit with public parent
279
282
280 $ hg phase -p "::.^"
283 $ hg phase -p "::.^"
281 $ hg uncommit
284 $ hg uncommit
282 $ hg phase -r .
285 $ hg phase -r .
283 12: public
286 12: public
284
287
285 Partial uncommit with public parent
288 Partial uncommit with public parent
286
289
287 $ echo xyz > xyz
290 $ echo xyz > xyz
288 $ hg add xyz
291 $ hg add xyz
289 $ hg commit -m "update ab and add xyz"
292 $ hg commit -m "update ab and add xyz"
290 $ hg uncommit xyz
293 $ hg uncommit xyz
291 $ hg status
294 $ hg status
292 A xyz
295 A xyz
293 $ hg phase -r .
296 $ hg phase -r .
294 16: draft
297 16: draft
295 $ hg phase -r ".^"
298 $ hg phase -r ".^"
296 12: public
299 12: public
297
300
298 Uncommit leaving an empty changeset
301 Uncommit leaving an empty changeset
299
302
300 $ cd $TESTTMP
303 $ cd $TESTTMP
301 $ hg init repo1
304 $ hg init repo1
302 $ cd repo1
305 $ cd repo1
303 $ hg debugdrawdag <<'EOS'
306 $ hg debugdrawdag <<'EOS'
304 > Q
307 > Q
305 > |
308 > |
306 > P
309 > P
307 > EOS
310 > EOS
308 $ hg up Q -q
311 $ hg up Q -q
309 $ hg uncommit --keep
312 $ hg uncommit --keep
310 $ hg log -G -T '{desc} FILES: {files}'
313 $ hg log -G -T '{desc} FILES: {files}'
311 @ Q FILES:
314 @ Q FILES:
312 |
315 |
313 | x Q FILES: Q
316 | x Q FILES: Q
314 |/
317 |/
315 o P FILES: P
318 o P FILES: P
316
319
317 $ hg status
320 $ hg status
318 A Q
321 A Q
319
322
320 $ cd ..
323 $ cd ..
321 $ rm -rf repo1
324 $ rm -rf repo1
322
325
323 Testing uncommit while merge
326 Testing uncommit while merge
324
327
325 $ hg init repo2
328 $ hg init repo2
326 $ cd repo2
329 $ cd repo2
327
330
328 Create some history
331 Create some history
329
332
330 $ touch a
333 $ touch a
331 $ hg add a
334 $ hg add a
332 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
335 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
333 $ hg checkout 0
336 $ hg checkout 0
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
337 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ touch b
338 $ touch b
336 $ hg add b
339 $ hg add b
337 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
340 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
338 created new head
341 created new head
339 $ hg log -G -T '{rev}:{node} {desc}' --hidden
342 $ hg log -G -T '{rev}:{node} {desc}' --hidden
340 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
343 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
341 |
344 |
342 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
345 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
343 |
346 |
344 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
347 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
345 |
348 |
346 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
349 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
347 | |
350 | |
348 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
351 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
349 |/
352 |/
350 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
353 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
351
354
352
355
353 Add and expect uncommit to fail on both merge working dir and merge changeset
356 Add and expect uncommit to fail on both merge working dir and merge changeset
354
357
355 $ hg merge 2
358 $ hg merge 2
356 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
357 (branch merge, don't forget to commit)
360 (branch merge, don't forget to commit)
358
361
359 $ hg uncommit
362 $ hg uncommit
360 abort: outstanding uncommitted merge
363 abort: outstanding uncommitted merge
361 [255]
364 [255]
362
365
363 $ hg uncommit --config experimental.uncommitondirtywdir=True
366 $ hg uncommit --config experimental.uncommitondirtywdir=True
364 abort: cannot uncommit while merging
367 abort: cannot uncommit while merging
365 [255]
368 [255]
366
369
367 $ hg status
370 $ hg status
368 M a
371 M a
369 $ hg commit -m 'merge a and b'
372 $ hg commit -m 'merge a and b'
370
373
371 $ hg uncommit
374 $ hg uncommit
372 abort: cannot uncommit merge changeset
375 abort: cannot uncommit merge changeset
373 [255]
376 [255]
374
377
375 $ hg status
378 $ hg status
376 $ hg log -G -T '{rev}:{node} {desc}' --hidden
379 $ hg log -G -T '{rev}:{node} {desc}' --hidden
377 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
380 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
378 |\
381 |\
379 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
382 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
380 | |
383 | |
381 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
384 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
382 | |
385 | |
383 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
386 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
384 | |
387 | |
385 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
388 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
386 | |
389 | |
387 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
390 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
388 |/
391 |/
389 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
392 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
390
393
General Comments 0
You need to be logged in to leave comments. Login now