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