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