##// END OF EJS Templates
uncommit: abort if an explicitly given file cannot be uncommitted (BC)...
Matt Harbison -
r42218:f4147ca6 default
parent child Browse files
Show More
@@ -1,223 +1,250 b''
1 1 # uncommit - undo the actions of a commit
2 2 #
3 3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
4 4 # Logilab SA <contact@logilab.fr>
5 5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
6 6 # Patrick Mezard <patrick@mezard.eu>
7 7 # Copyright 2016 Facebook, Inc.
8 8 #
9 9 # This software may be used and distributed according to the terms of the
10 10 # GNU General Public License version 2 or any later version.
11 11
12 12 """uncommit part or all of a local changeset (EXPERIMENTAL)
13 13
14 14 This command undoes the effect of a local commit, returning the affected
15 15 files to their uncommitted state. This means that files modified, added or
16 16 removed in the changeset will be left unchanged, and so will remain modified,
17 17 added and removed in the working directory.
18 18 """
19 19
20 20 from __future__ import absolute_import
21 21
22 22 from mercurial.i18n import _
23 23
24 24 from mercurial import (
25 25 cmdutil,
26 26 commands,
27 27 context,
28 28 copies as copiesmod,
29 29 error,
30 30 node,
31 31 obsutil,
32 32 pycompat,
33 33 registrar,
34 34 rewriteutil,
35 35 scmutil,
36 util,
36 37 )
37 38
38 39 cmdtable = {}
39 40 command = registrar.command(cmdtable)
40 41
41 42 configtable = {}
42 43 configitem = registrar.configitem(configtable)
43 44
44 45 configitem('experimental', 'uncommitondirtywdir',
45 46 default=False,
46 47 )
47 48 configitem('experimental', 'uncommit.keep',
48 49 default=False,
49 50 )
50 51
51 52 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
52 53 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
53 54 # be specifying the version(s) of Mercurial they are tested with, or
54 55 # leave the attribute unspecified.
55 56 testedwith = 'ships-with-hg-core'
56 57
57 58 def _commitfiltered(repo, ctx, match, keepcommit):
58 59 """Recommit ctx with changed files not in match. Return the new
59 60 node identifier, or None if nothing changed.
60 61 """
61 62 base = ctx.p1()
62 63 # ctx
63 64 initialfiles = set(ctx.files())
64 65 exclude = set(f for f in initialfiles if match(f))
65 66
66 67 # No files matched commit, so nothing excluded
67 68 if not exclude:
68 69 return None
69 70
70 71 # return the p1 so that we don't create an obsmarker later
71 72 if not keepcommit:
72 73 return ctx.p1().node()
73 74
74 75 files = (initialfiles - exclude)
75 76 # Filter copies
76 77 copied = copiesmod.pathcopies(base, ctx)
77 78 copied = dict((dst, src) for dst, src in copied.iteritems()
78 79 if dst in files)
79 80 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
80 81 if path not in contentctx:
81 82 return None
82 83 fctx = contentctx[path]
83 84 mctx = context.memfilectx(repo, memctx, fctx.path(), fctx.data(),
84 85 fctx.islink(),
85 86 fctx.isexec(),
86 87 copysource=copied.get(path))
87 88 return mctx
88 89
89 90 if not files:
90 91 repo.ui.status(_("note: keeping empty commit\n"))
91 92
92 93 new = context.memctx(repo,
93 94 parents=[base.node(), node.nullid],
94 95 text=ctx.description(),
95 96 files=files,
96 97 filectxfn=filectxfn,
97 98 user=ctx.user(),
98 99 date=ctx.date(),
99 100 extra=ctx.extra())
100 101 return repo.commitctx(new)
101 102
102 103 @command('uncommit',
103 104 [('', 'keep', None, _('allow an empty commit after uncommiting')),
104 105 ('', 'allow-dirty-working-copy', False,
105 106 _('allow uncommit with outstanding changes'))
106 107 ] + commands.walkopts,
107 108 _('[OPTION]... [FILE]...'),
108 109 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
109 110 def uncommit(ui, repo, *pats, **opts):
110 111 """uncommit part or all of a local changeset
111 112
112 113 This command undoes the effect of a local commit, returning the affected
113 114 files to their uncommitted state. This means that files modified or
114 115 deleted in the changeset will be left unchanged, and so will remain
115 116 modified in the working directory.
116 117
117 118 If no files are specified, the commit will be pruned, unless --keep is
118 119 given.
119 120 """
120 121 opts = pycompat.byteskwargs(opts)
121 122
122 123 with repo.wlock(), repo.lock():
123 124
124 125 m, a, r, d = repo.status()[:4]
125 126 isdirtypath = any(set(m + a + r + d) & set(pats))
126 127 allowdirtywcopy = (opts['allow_dirty_working_copy'] or
127 128 repo.ui.configbool('experimental', 'uncommitondirtywdir'))
128 129 if not allowdirtywcopy and (not pats or isdirtypath):
129 130 cmdutil.bailifchanged(repo, hint=_('requires '
130 131 '--allow-dirty-working-copy to uncommit'))
131 132 old = repo['.']
132 133 rewriteutil.precheck(repo, [old.rev()], 'uncommit')
133 134 if len(old.parents()) > 1:
134 135 raise error.Abort(_("cannot uncommit merge changeset"))
135 136
137 match = scmutil.match(old, pats, opts)
138
139 # Check all explicitly given files; abort if there's a problem.
140 if match.files():
141 s = old.status(old.p1(), match, listclean=True)
142 eligible = set(s.added) | set(s.modified) | set(s.removed)
143
144 badfiles = set(match.files()) - eligible
145
146 # Naming a parent directory of an eligible file is OK, even
147 # if not everything tracked in that directory can be
148 # uncommitted.
149 if badfiles:
150 badfiles -= set([f for f in util.dirs(eligible)])
151
152 for f in sorted(badfiles):
153 if f in s.clean:
154 hint = _(b"file was not changed in working directory "
155 b"parent")
156 elif repo.wvfs.exists(f):
157 hint = _(b"file was untracked in working directory parent")
158 else:
159 hint = _(b"file does not exist")
160
161 raise error.Abort(_(b'cannot uncommit "%s"')
162 % scmutil.getuipathfn(repo)(f), hint=hint)
163
136 164 with repo.transaction('uncommit'):
137 match = scmutil.match(old, pats, opts)
138 165 keepcommit = pats
139 166 if not keepcommit:
140 167 if opts.get('keep') is not None:
141 168 keepcommit = opts.get('keep')
142 169 else:
143 170 keepcommit = ui.configbool('experimental', 'uncommit.keep')
144 171 newid = _commitfiltered(repo, old, match, keepcommit)
145 172 if newid is None:
146 173 ui.status(_("nothing to uncommit\n"))
147 174 return 1
148 175
149 176 mapping = {}
150 177 if newid != old.p1().node():
151 178 # Move local changes on filtered changeset
152 179 mapping[old.node()] = (newid,)
153 180 else:
154 181 # Fully removed the old commit
155 182 mapping[old.node()] = ()
156 183
157 184 with repo.dirstate.parentchange():
158 185 scmutil.movedirstate(repo, repo[newid], match)
159 186
160 187 scmutil.cleanupnodes(repo, mapping, 'uncommit', fixphase=True)
161 188
162 189 def predecessormarkers(ctx):
163 190 """yields the obsolete markers marking the given changeset as a successor"""
164 191 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
165 192 yield obsutil.marker(ctx.repo(), data)
166 193
167 194 @command('unamend', [], helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
168 195 helpbasic=True)
169 196 def unamend(ui, repo, **opts):
170 197 """undo the most recent amend operation on a current changeset
171 198
172 199 This command will roll back to the previous version of a changeset,
173 200 leaving working directory in state in which it was before running
174 201 `hg amend` (e.g. files modified as part of an amend will be
175 202 marked as modified `hg status`)
176 203 """
177 204
178 205 unfi = repo.unfiltered()
179 206 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
180 207
181 208 # identify the commit from which to unamend
182 209 curctx = repo['.']
183 210
184 211 rewriteutil.precheck(repo, [curctx.rev()], 'unamend')
185 212
186 213 # identify the commit to which to unamend
187 214 markers = list(predecessormarkers(curctx))
188 215 if len(markers) != 1:
189 216 e = _("changeset must have one predecessor, found %i predecessors")
190 217 raise error.Abort(e % len(markers))
191 218
192 219 prednode = markers[0].prednode()
193 220 predctx = unfi[prednode]
194 221
195 222 # add an extra so that we get a new hash
196 223 # note: allowing unamend to undo an unamend is an intentional feature
197 224 extras = predctx.extra()
198 225 extras['unamend_source'] = curctx.hex()
199 226
200 227 def filectxfn(repo, ctx_, path):
201 228 try:
202 229 return predctx.filectx(path)
203 230 except KeyError:
204 231 return None
205 232
206 233 # Make a new commit same as predctx
207 234 newctx = context.memctx(repo,
208 235 parents=(predctx.p1(), predctx.p2()),
209 236 text=predctx.description(),
210 237 files=predctx.files(),
211 238 filectxfn=filectxfn,
212 239 user=predctx.user(),
213 240 date=predctx.date(),
214 241 extra=extras)
215 242 newprednode = repo.commitctx(newctx)
216 243 newpredctx = repo[newprednode]
217 244 dirstate = repo.dirstate
218 245
219 246 with dirstate.parentchange():
220 247 scmutil.movedirstate(repo, newpredctx)
221 248
222 249 mapping = {curctx.node(): (newprednode,)}
223 250 scmutil.cleanupnodes(repo, mapping, 'unamend', fixphase=True)
@@ -1,515 +1,571 b''
1 1 Test uncommit - set up the config
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [experimental]
5 5 > evolution.createmarkers=True
6 6 > evolution.allowunstable=True
7 7 > [extensions]
8 8 > uncommit =
9 9 > drawdag=$TESTDIR/drawdag.py
10 10 > EOF
11 11
12 12 Build up a repo
13 13
14 14 $ hg init repo
15 15 $ cd repo
16 16 $ hg bookmark foo
17 17
18 18 Help for uncommit
19 19
20 20 $ hg help uncommit
21 21 hg uncommit [OPTION]... [FILE]...
22 22
23 23 uncommit part or all of a local changeset
24 24
25 25 This command undoes the effect of a local commit, returning the affected
26 26 files to their uncommitted state. This means that files modified or
27 27 deleted in the changeset will be left unchanged, and so will remain
28 28 modified in the working directory.
29 29
30 30 If no files are specified, the commit will be pruned, unless --keep is
31 31 given.
32 32
33 33 (use 'hg help -e uncommit' to show help for the uncommit extension)
34 34
35 35 options ([+] can be repeated):
36 36
37 37 --keep allow an empty commit after uncommiting
38 38 --allow-dirty-working-copy allow uncommit with outstanding changes
39 39 -I --include PATTERN [+] include names matching the given patterns
40 40 -X --exclude PATTERN [+] exclude names matching the given patterns
41 41
42 42 (some details hidden, use --verbose to show complete help)
43 43
44 44 Uncommit with no commits should fail
45 45
46 46 $ hg uncommit
47 47 abort: cannot uncommit null changeset
48 48 (no changeset checked out)
49 49 [255]
50 50
51 51 Create some commits
52 52
53 53 $ touch files
54 54 $ hg add files
55 55 $ 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
56 56 $ ls
57 57 file-a
58 58 file-ab
59 59 file-abc
60 60 file-abcd
61 61 file-abcde
62 62 files
63 63
64 64 $ hg log -G -T '{rev}:{node} {desc}' --hidden
65 65 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
66 66 |
67 67 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
68 68 |
69 69 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
70 70 |
71 71 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
72 72 |
73 73 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
74 74
75 75 Simple uncommit off the top, also moves bookmark
76 76
77 77 $ hg bookmark
78 78 * foo 4:6c4fd43ed714
79 79 $ hg uncommit
80 80 $ hg status
81 81 M files
82 82 A file-abcde
83 83 $ hg bookmark
84 84 * foo 3:6db330d65db4
85 85
86 86 $ hg log -G -T '{rev}:{node} {desc}' --hidden
87 87 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
88 88 |
89 89 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
90 90 |
91 91 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
92 92 |
93 93 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
94 94 |
95 95 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
96 96
97 97
98 98 Recommit
99 99
100 100 $ hg commit -m 'new change abcde'
101 101 $ hg status
102 102 $ hg heads -T '{rev}:{node} {desc}'
103 103 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
104 104
105 Uncommit of non-existent and unchanged files has no effect
105 Uncommit of non-existent and unchanged files aborts
106 106 $ hg uncommit nothinghere
107 nothing to uncommit
108 [1]
107 abort: cannot uncommit "nothinghere"
108 (file does not exist)
109 [255]
109 110 $ hg status
110 111 $ hg uncommit file-abc
111 nothing to uncommit
112 [1]
112 abort: cannot uncommit "file-abc"
113 (file was not changed in working directory parent)
114 [255]
113 115 $ hg status
114 116
115 117 Try partial uncommit, also moves bookmark
116 118
117 119 $ hg bookmark
118 120 * foo 5:0c07a3ccda77
119 121 $ hg uncommit files
120 122 $ hg status
121 123 M files
122 124 $ hg bookmark
123 125 * foo 6:3727deee06f7
124 126 $ hg heads -T '{rev}:{node} {desc}'
125 127 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
126 128 $ hg log -r . -p -T '{rev}:{node} {desc}'
127 129 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
128 130 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
129 131 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
130 132 @@ -0,0 +1,1 @@
131 133 +abcde
132 134
133 135 $ hg log -G -T '{rev}:{node} {desc}' --hidden
134 136 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
135 137 |
136 138 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
137 139 |/
138 140 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
139 141 |/
140 142 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
141 143 |
142 144 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
143 145 |
144 146 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
145 147 |
146 148 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
147 149
148 150 $ hg commit -m 'update files for abcde'
149 151
150 152 Uncommit with dirty state
151 153
152 154 $ echo "foo" >> files
153 155 $ cat files
154 156 abcde
155 157 foo
156 158 $ hg status
157 159 M files
158 160 $ hg uncommit
159 161 abort: uncommitted changes
160 162 (requires --allow-dirty-working-copy to uncommit)
161 163 [255]
162 164 $ hg uncommit files
163 165 abort: uncommitted changes
164 166 (requires --allow-dirty-working-copy to uncommit)
165 167 [255]
166 168 $ cat files
167 169 abcde
168 170 foo
169 171 $ hg commit --amend -m "files abcde + foo"
170 172
171 173 Testing the 'experimental.uncommitondirtywdir' config
172 174
173 175 $ echo "bar" >> files
174 176 $ hg uncommit
175 177 abort: uncommitted changes
176 178 (requires --allow-dirty-working-copy to uncommit)
177 179 [255]
178 180 $ hg uncommit --config experimental.uncommitondirtywdir=True
179 181 $ hg commit -m "files abcde + foo"
180 182
181 183 Uncommit in the middle of a stack, does not move bookmark
182 184
183 185 $ hg checkout '.^^^'
184 186 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
185 187 (leaving bookmark foo)
186 188 $ hg log -r . -p -T '{rev}:{node} {desc}'
187 189 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
188 190 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
189 191 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
190 192 @@ -0,0 +1,1 @@
191 193 +abc
192 194 diff -r 69a232e754b0 -r abf2df566fc1 files
193 195 --- a/files Thu Jan 01 00:00:00 1970 +0000
194 196 +++ b/files Thu Jan 01 00:00:00 1970 +0000
195 197 @@ -1,1 +1,1 @@
196 198 -ab
197 199 +abc
198 200
199 201 $ hg bookmark
200 202 foo 9:48e5bd7cd583
201 203 $ hg uncommit
202 204 3 new orphan changesets
203 205 $ hg status
204 206 M files
205 207 A file-abc
206 208 $ hg heads -T '{rev}:{node} {desc}'
207 209 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
208 210 $ hg bookmark
209 211 foo 9:48e5bd7cd583
210 212 $ hg commit -m 'new abc'
211 213 created new head
212 214
213 215 Partial uncommit in the middle, does not move bookmark
214 216
215 217 $ hg checkout '.^'
216 218 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
217 219 $ hg log -r . -p -T '{rev}:{node} {desc}'
218 220 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
219 221 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
220 222 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
221 223 @@ -0,0 +1,1 @@
222 224 +ab
223 225 diff -r 3004d2d9b508 -r 69a232e754b0 files
224 226 --- a/files Thu Jan 01 00:00:00 1970 +0000
225 227 +++ b/files Thu Jan 01 00:00:00 1970 +0000
226 228 @@ -1,1 +1,1 @@
227 229 -a
228 230 +ab
229 231
230 232 $ hg bookmark
231 233 foo 9:48e5bd7cd583
232 234 $ hg uncommit file-ab
233 235 1 new orphan changesets
234 236 $ hg status
235 237 A file-ab
236 238
237 239 $ hg heads -T '{rev}:{node} {desc}\n'
238 240 11:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
239 241 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
240 242 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
241 243
242 244 $ hg bookmark
243 245 foo 9:48e5bd7cd583
244 246 $ hg commit -m 'update ab'
245 247 $ hg status
246 248 $ hg heads -T '{rev}:{node} {desc}\n'
247 249 12:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
248 250 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
249 251 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
250 252
251 253 $ hg log -G -T '{rev}:{node} {desc}' --hidden
252 254 @ 12:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
253 255 |
254 256 o 11:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
255 257 |
256 258 | * 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
257 259 | |
258 260 | | * 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
259 261 | | |
260 262 | | | x 8:84beeba0ac30e19521c036e4d2dd3a5fa02586ff files abcde + foo
261 263 | | |/
262 264 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
263 265 | | |/
264 266 | | * 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
265 267 | | |
266 268 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
267 269 | | |/
268 270 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
269 271 | | |/
270 272 | | * 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
271 273 | | |
272 274 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
273 275 | |/
274 276 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
275 277 |/
276 278 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
277 279
278 280 Uncommit with draft parent
279 281
280 282 $ hg uncommit
281 283 $ hg phase -r .
282 284 11: draft
283 285 $ hg commit -m 'update ab again'
284 286
285 287 Phase is preserved
286 288
287 289 $ hg uncommit --keep --config phases.new-commit=secret
288 290 note: keeping empty commit
289 291 $ hg phase -r .
290 292 14: draft
291 293 $ hg commit --amend -m 'update ab again'
292 294
293 295 Uncommit with public parent
294 296
295 297 $ hg phase -p "::.^"
296 298 $ hg uncommit
297 299 $ hg phase -r .
298 300 11: public
299 301
300 302 Partial uncommit with public parent
301 303
302 304 $ echo xyz > xyz
303 305 $ hg add xyz
304 306 $ hg commit -m "update ab and add xyz"
305 307 $ hg uncommit xyz
306 308 $ hg status
307 309 A xyz
308 310 $ hg phase -r .
309 311 17: draft
310 312 $ hg phase -r ".^"
311 313 11: public
312 314
313 315 Uncommit with --keep or experimental.uncommit.keep leaves an empty changeset
314 316
315 317 $ cd $TESTTMP
316 318 $ hg init repo1
317 319 $ cd repo1
318 320 $ hg debugdrawdag <<'EOS'
319 321 > Q
320 322 > |
321 323 > P
322 324 > EOS
323 325 $ hg up Q -q
324 326 $ hg uncommit --keep
325 327 note: keeping empty commit
326 328 $ hg log -G -T '{desc} FILES: {files}'
327 329 @ Q FILES:
328 330 |
329 331 | x Q FILES: Q
330 332 |/
331 333 o P FILES: P
332 334
333 335 $ cat >> .hg/hgrc <<EOF
334 336 > [experimental]
335 337 > uncommit.keep=True
336 338 > EOF
337 339 $ hg ci --amend
338 340 $ hg uncommit
339 341 note: keeping empty commit
340 342 $ hg log -G -T '{desc} FILES: {files}'
341 343 @ Q FILES:
342 344 |
343 345 | x Q FILES: Q
344 346 |/
345 347 o P FILES: P
346 348
347 349 $ hg status
348 350 A Q
349 351 $ hg ci --amend
350 352 $ hg uncommit --no-keep
351 353 $ hg log -G -T '{desc} FILES: {files}'
352 354 x Q FILES: Q
353 355 |
354 356 @ P FILES: P
355 357
356 358 $ hg status
357 359 A Q
358 360 $ cd ..
359 361 $ rm -rf repo1
360 362
361 363 Testing uncommit while merge
362 364
363 365 $ hg init repo2
364 366 $ cd repo2
365 367
366 368 Create some history
367 369
368 370 $ touch a
369 371 $ hg add a
370 372 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
371 373 $ hg checkout 0
372 374 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 375 $ touch b
374 376 $ hg add b
375 377 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
376 378 created new head
377 379 $ hg log -G -T '{rev}:{node} {desc}' --hidden
378 380 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
379 381 |
380 382 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
381 383 |
382 384 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
383 385 |
384 386 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
385 387 | |
386 388 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
387 389 |/
388 390 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
389 391
390 392
391 393 Add and expect uncommit to fail on both merge working dir and merge changeset
392 394
393 395 $ hg merge 2
394 396 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 397 (branch merge, don't forget to commit)
396 398
397 399 $ hg uncommit
398 400 abort: outstanding uncommitted merge
399 401 (requires --allow-dirty-working-copy to uncommit)
400 402 [255]
401 403
402 404 $ hg uncommit --config experimental.uncommitondirtywdir=True
403 405 abort: cannot uncommit while merging
404 406 [255]
405 407
406 408 $ hg status
407 409 M a
408 410 $ hg commit -m 'merge a and b'
409 411
410 412 $ hg uncommit
411 413 abort: cannot uncommit merge changeset
412 414 [255]
413 415
414 416 $ hg status
415 417 $ hg log -G -T '{rev}:{node} {desc}' --hidden
416 418 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
417 419 |\
418 420 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
419 421 | |
420 422 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
421 423 | |
422 424 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
423 425 | |
424 426 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
425 427 | |
426 428 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
427 429 |/
428 430 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
429 431
430 432
431 433 Rename a->b, then remove b in working copy. Result should remove a.
432 434
433 435 $ hg co -q 0
434 436 $ hg mv a b
435 437 $ hg ci -qm 'move a to b'
436 438 $ hg rm b
437 439 $ hg uncommit --config experimental.uncommitondirtywdir=True
438 440 $ hg st --copies
439 441 R a
440 442 $ hg revert a
441 443
442 444 Rename a->b, then rename b->c in working copy. Result should rename a->c.
443 445
444 446 $ hg co -q 0
445 447 $ hg mv a b
446 448 $ hg ci -qm 'move a to b'
447 449 $ hg mv b c
448 450 $ hg uncommit --config experimental.uncommitondirtywdir=True
449 451 $ hg st --copies
450 452 A c
451 453 a
452 454 R a
453 455 $ hg revert a
454 456 $ hg forget c
455 457 $ rm c
456 458
457 459 Copy a->b1 and a->b2, then rename b1->c in working copy. Result should copy a->b2 and a->c.
458 460
459 461 $ hg co -q 0
460 462 $ hg cp a b1
461 463 $ hg cp a b2
462 464 $ hg ci -qm 'move a to b1 and b2'
463 465 $ hg mv b1 c
464 466 $ hg uncommit --config experimental.uncommitondirtywdir=True
465 467 $ hg st --copies
466 468 A b2
467 469 a
468 470 A c
469 471 a
470 472 $ cd ..
471 473
472 474 --allow-dirty-working-copy should also work on a dirty PATH
473 475
474 476 $ hg init issue5977
475 477 $ cd issue5977
476 478 $ echo 'super critical info!' > a
477 479 $ hg ci -Am 'add a'
478 480 adding a
479 481 $ echo 'foo' > b
480 482 $ hg add b
481 483 $ hg status
482 484 A b
483 485 $ hg unc a
484 486 note: keeping empty commit
485 487 $ cat a
486 488 super critical info!
487 489 $ hg log
488 490 changeset: 1:656ba143d384
489 491 tag: tip
490 492 parent: -1:000000000000
491 493 user: test
492 494 date: Thu Jan 01 00:00:00 1970 +0000
493 495 summary: add a
494 496
495 497 $ hg ci -Am 'add b'
496 498 $ echo 'foo bar' > b
497 499 $ hg unc b
498 500 abort: uncommitted changes
499 501 (requires --allow-dirty-working-copy to uncommit)
500 502 [255]
501 503 $ hg unc --allow-dirty-working-copy b
502 504 $ hg log
503 505 changeset: 3:30fa958635b2
504 506 tag: tip
505 507 parent: 1:656ba143d384
506 508 user: test
507 509 date: Thu Jan 01 00:00:00 1970 +0000
508 510 summary: add b
509 511
510 512 changeset: 1:656ba143d384
511 513 parent: -1:000000000000
512 514 user: test
513 515 date: Thu Jan 01 00:00:00 1970 +0000
514 516 summary: add a
515 517
518 Removes can be uncommitted
519
520 $ hg ci -m 'modified b'
521 $ hg rm b
522 $ hg ci -m 'remove b'
523 $ hg uncommit b
524 note: keeping empty commit
525 $ hg status
526 R b
527
528 Uncommitting a directory won't run afoul of the checks that an explicit file
529 can be uncommitted.
530
531 $ mkdir dir
532 $ echo 1 > dir/file.txt
533 $ hg ci -Aqm 'add file in directory'
534 $ hg uncommit dir
535 $ hg status
536 A dir/file.txt
537
538 `uncommit <dir>` and `cd <dir> && uncommit .` behave the same...
539
540 $ hg rollback -q --config ui.rollback=True
541 $ echo 2 > dir/file2.txt
542 $ hg ci -Aqm 'add file2 in directory'
543 $ hg uncommit dir
544 note: keeping empty commit
545 $ hg status
546 A dir/file2.txt
547
548 $ hg rollback -q --config ui.rollback=True
549 $ cd dir
550 $ hg uncommit .
551 note: keeping empty commit
552 $ hg status
553 A dir/file2.txt
554 $ cd ..
555
556 ... and errors out the same way when nothing can be uncommitted
557
558 $ hg rollback -q --config ui.rollback=True
559 $ mkdir emptydir
560 $ hg uncommit emptydir
561 abort: cannot uncommit "emptydir"
562 (file was untracked in working directory parent)
563 [255]
564
565 $ cd emptydir
566 $ hg uncommit .
567 abort: cannot uncommit "emptydir"
568 (file was untracked in working directory parent)
569 [255]
570 $ hg status
571 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now