##// END OF EJS Templates
graphlog: use '%' for other context in merge conflict...
Martin von Zweigbergk -
r45204:14d0e895 default
parent child Browse files
Show More
@@ -1,107 +1,109 b''
1 # -*- coding: UTF-8 -*-
1 # -*- coding: UTF-8 -*-
2 # beautifygraph.py - improve graph output by using Unicode characters
2 # beautifygraph.py - improve graph output by using Unicode characters
3 #
3 #
4 # Copyright 2018 John Stiles <johnstiles@gmail.com>
4 # Copyright 2018 John Stiles <johnstiles@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''beautify log -G output by using Unicode characters (EXPERIMENTAL)
9 '''beautify log -G output by using Unicode characters (EXPERIMENTAL)
10
10
11 A terminal with UTF-8 support and monospace narrow text are required.
11 A terminal with UTF-8 support and monospace narrow text are required.
12 '''
12 '''
13
13
14 from __future__ import absolute_import
14 from __future__ import absolute_import
15
15
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial import (
17 from mercurial import (
18 encoding,
18 encoding,
19 extensions,
19 extensions,
20 graphmod,
20 graphmod,
21 pycompat,
21 pycompat,
22 templatekw,
22 templatekw,
23 )
23 )
24
24
25 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
25 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
26 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
26 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
27 # be specifying the version(s) of Mercurial they are tested with, or
27 # be specifying the version(s) of Mercurial they are tested with, or
28 # leave the attribute unspecified.
28 # leave the attribute unspecified.
29 testedwith = b'ships-with-hg-core'
29 testedwith = b'ships-with-hg-core'
30
30
31
31
32 def prettyedge(before, edge, after):
32 def prettyedge(before, edge, after):
33 if edge == b'~':
33 if edge == b'~':
34 return b'\xE2\x95\xA7' # U+2567 ╧
34 return b'\xE2\x95\xA7' # U+2567 ╧
35 if edge == b'/':
35 if edge == b'/':
36 return b'\xE2\x95\xB1' # U+2571 β•±
36 return b'\xE2\x95\xB1' # U+2571 β•±
37 if edge == b'-':
37 if edge == b'-':
38 return b'\xE2\x94\x80' # U+2500 ─
38 return b'\xE2\x94\x80' # U+2500 ─
39 if edge == b'|':
39 if edge == b'|':
40 return b'\xE2\x94\x82' # U+2502 β”‚
40 return b'\xE2\x94\x82' # U+2502 β”‚
41 if edge == b':':
41 if edge == b':':
42 return b'\xE2\x94\x86' # U+2506 ┆
42 return b'\xE2\x94\x86' # U+2506 ┆
43 if edge == b'\\':
43 if edge == b'\\':
44 return b'\xE2\x95\xB2' # U+2572 β•²
44 return b'\xE2\x95\xB2' # U+2572 β•²
45 if edge == b'+':
45 if edge == b'+':
46 if before == b' ' and not after == b' ':
46 if before == b' ' and not after == b' ':
47 return b'\xE2\x94\x9C' # U+251C β”œ
47 return b'\xE2\x94\x9C' # U+251C β”œ
48 if after == b' ' and not before == b' ':
48 if after == b' ' and not before == b' ':
49 return b'\xE2\x94\xA4' # U+2524 ─
49 return b'\xE2\x94\xA4' # U+2524 ─
50 return b'\xE2\x94\xBC' # U+253C β”Ό
50 return b'\xE2\x94\xBC' # U+253C β”Ό
51 return edge
51 return edge
52
52
53
53
54 def convertedges(line):
54 def convertedges(line):
55 line = b' %s ' % line
55 line = b' %s ' % line
56 pretty = []
56 pretty = []
57 for idx in pycompat.xrange(len(line) - 2):
57 for idx in pycompat.xrange(len(line) - 2):
58 pretty.append(
58 pretty.append(
59 prettyedge(
59 prettyedge(
60 line[idx : idx + 1],
60 line[idx : idx + 1],
61 line[idx + 1 : idx + 2],
61 line[idx + 1 : idx + 2],
62 line[idx + 2 : idx + 3],
62 line[idx + 2 : idx + 3],
63 )
63 )
64 )
64 )
65 return b''.join(pretty)
65 return b''.join(pretty)
66
66
67
67
68 def getprettygraphnode(orig, *args, **kwargs):
68 def getprettygraphnode(orig, *args, **kwargs):
69 node = orig(*args, **kwargs)
69 node = orig(*args, **kwargs)
70 if node == b'o':
70 if node == b'o':
71 return b'\xE2\x97\x8B' # U+25CB β—‹
71 return b'\xE2\x97\x8B' # U+25CB β—‹
72 if node == b'@':
72 if node == b'@':
73 return b'\xE2\x97\x8D' # U+25CD ◍
73 return b'\xE2\x97\x8D' # U+25CD ◍
74 if node == b'%':
75 return b'\xE2\x97\x8D' # U+25CE β—Ž
74 if node == b'*':
76 if node == b'*':
75 return b'\xE2\x88\x97' # U+2217 βˆ—
77 return b'\xE2\x88\x97' # U+2217 βˆ—
76 if node == b'x':
78 if node == b'x':
77 return b'\xE2\x97\x8C' # U+25CC β—Œ
79 return b'\xE2\x97\x8C' # U+25CC β—Œ
78 if node == b'_':
80 if node == b'_':
79 return b'\xE2\x95\xA4' # U+2564 β•€
81 return b'\xE2\x95\xA4' # U+2564 β•€
80 return node
82 return node
81
83
82
84
83 def outputprettygraph(orig, ui, graph, *args, **kwargs):
85 def outputprettygraph(orig, ui, graph, *args, **kwargs):
84 (edges, text) = zip(*graph)
86 (edges, text) = zip(*graph)
85 graph = zip([convertedges(e) for e in edges], text)
87 graph = zip([convertedges(e) for e in edges], text)
86 return orig(ui, graph, *args, **kwargs)
88 return orig(ui, graph, *args, **kwargs)
87
89
88
90
89 def extsetup(ui):
91 def extsetup(ui):
90 if ui.plain(b'graph'):
92 if ui.plain(b'graph'):
91 return
93 return
92
94
93 if encoding.encoding != b'UTF-8':
95 if encoding.encoding != b'UTF-8':
94 ui.warn(_(b'beautifygraph: unsupported encoding, UTF-8 required\n'))
96 ui.warn(_(b'beautifygraph: unsupported encoding, UTF-8 required\n'))
95 return
97 return
96
98
97 if 'A' in encoding._wide:
99 if 'A' in encoding._wide:
98 ui.warn(
100 ui.warn(
99 _(
101 _(
100 b'beautifygraph: unsupported terminal settings, '
102 b'beautifygraph: unsupported terminal settings, '
101 b'monospace narrow text required\n'
103 b'monospace narrow text required\n'
102 )
104 )
103 )
105 )
104 return
106 return
105
107
106 extensions.wrapfunction(graphmod, b'outputgraph', outputprettygraph)
108 extensions.wrapfunction(graphmod, b'outputgraph', outputprettygraph)
107 extensions.wrapfunction(templatekw, b'getgraphnode', getprettygraphnode)
109 extensions.wrapfunction(templatekw, b'getgraphnode', getprettygraphnode)
@@ -1,940 +1,940 b''
1 # hgweb/webutil.py - utility library for the web interface.
1 # hgweb/webutil.py - utility library for the web interface.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import copy
11 import copy
12 import difflib
12 import difflib
13 import os
13 import os
14 import re
14 import re
15
15
16 from ..i18n import _
16 from ..i18n import _
17 from ..node import hex, nullid, short
17 from ..node import hex, nullid, short
18 from ..pycompat import setattr
18 from ..pycompat import setattr
19
19
20 from .common import (
20 from .common import (
21 ErrorResponse,
21 ErrorResponse,
22 HTTP_BAD_REQUEST,
22 HTTP_BAD_REQUEST,
23 HTTP_NOT_FOUND,
23 HTTP_NOT_FOUND,
24 paritygen,
24 paritygen,
25 )
25 )
26
26
27 from .. import (
27 from .. import (
28 context,
28 context,
29 diffutil,
29 diffutil,
30 error,
30 error,
31 match,
31 match,
32 mdiff,
32 mdiff,
33 obsutil,
33 obsutil,
34 patch,
34 patch,
35 pathutil,
35 pathutil,
36 pycompat,
36 pycompat,
37 scmutil,
37 scmutil,
38 templatefilters,
38 templatefilters,
39 templatekw,
39 templatekw,
40 templateutil,
40 templateutil,
41 ui as uimod,
41 ui as uimod,
42 util,
42 util,
43 )
43 )
44
44
45 from ..utils import stringutil
45 from ..utils import stringutil
46
46
47 archivespecs = util.sortdict(
47 archivespecs = util.sortdict(
48 (
48 (
49 (b'zip', (b'application/zip', b'zip', b'.zip', None)),
49 (b'zip', (b'application/zip', b'zip', b'.zip', None)),
50 (b'gz', (b'application/x-gzip', b'tgz', b'.tar.gz', None)),
50 (b'gz', (b'application/x-gzip', b'tgz', b'.tar.gz', None)),
51 (b'bz2', (b'application/x-bzip2', b'tbz2', b'.tar.bz2', None)),
51 (b'bz2', (b'application/x-bzip2', b'tbz2', b'.tar.bz2', None)),
52 )
52 )
53 )
53 )
54
54
55
55
56 def archivelist(ui, nodeid, url=None):
56 def archivelist(ui, nodeid, url=None):
57 allowed = ui.configlist(b'web', b'allow-archive', untrusted=True)
57 allowed = ui.configlist(b'web', b'allow-archive', untrusted=True)
58 archives = []
58 archives = []
59
59
60 for typ, spec in pycompat.iteritems(archivespecs):
60 for typ, spec in pycompat.iteritems(archivespecs):
61 if typ in allowed or ui.configbool(
61 if typ in allowed or ui.configbool(
62 b'web', b'allow' + typ, untrusted=True
62 b'web', b'allow' + typ, untrusted=True
63 ):
63 ):
64 archives.append(
64 archives.append(
65 {
65 {
66 b'type': typ,
66 b'type': typ,
67 b'extension': spec[2],
67 b'extension': spec[2],
68 b'node': nodeid,
68 b'node': nodeid,
69 b'url': url,
69 b'url': url,
70 }
70 }
71 )
71 )
72
72
73 return templateutil.mappinglist(archives)
73 return templateutil.mappinglist(archives)
74
74
75
75
76 def up(p):
76 def up(p):
77 if p[0:1] != b"/":
77 if p[0:1] != b"/":
78 p = b"/" + p
78 p = b"/" + p
79 if p[-1:] == b"/":
79 if p[-1:] == b"/":
80 p = p[:-1]
80 p = p[:-1]
81 up = os.path.dirname(p)
81 up = os.path.dirname(p)
82 if up == b"/":
82 if up == b"/":
83 return b"/"
83 return b"/"
84 return up + b"/"
84 return up + b"/"
85
85
86
86
87 def _navseq(step, firststep=None):
87 def _navseq(step, firststep=None):
88 if firststep:
88 if firststep:
89 yield firststep
89 yield firststep
90 if firststep >= 20 and firststep <= 40:
90 if firststep >= 20 and firststep <= 40:
91 firststep = 50
91 firststep = 50
92 yield firststep
92 yield firststep
93 assert step > 0
93 assert step > 0
94 assert firststep > 0
94 assert firststep > 0
95 while step <= firststep:
95 while step <= firststep:
96 step *= 10
96 step *= 10
97 while True:
97 while True:
98 yield 1 * step
98 yield 1 * step
99 yield 3 * step
99 yield 3 * step
100 step *= 10
100 step *= 10
101
101
102
102
103 class revnav(object):
103 class revnav(object):
104 def __init__(self, repo):
104 def __init__(self, repo):
105 """Navigation generation object
105 """Navigation generation object
106
106
107 :repo: repo object we generate nav for
107 :repo: repo object we generate nav for
108 """
108 """
109 # used for hex generation
109 # used for hex generation
110 self._revlog = repo.changelog
110 self._revlog = repo.changelog
111
111
112 def __nonzero__(self):
112 def __nonzero__(self):
113 """return True if any revision to navigate over"""
113 """return True if any revision to navigate over"""
114 return self._first() is not None
114 return self._first() is not None
115
115
116 __bool__ = __nonzero__
116 __bool__ = __nonzero__
117
117
118 def _first(self):
118 def _first(self):
119 """return the minimum non-filtered changeset or None"""
119 """return the minimum non-filtered changeset or None"""
120 try:
120 try:
121 return next(iter(self._revlog))
121 return next(iter(self._revlog))
122 except StopIteration:
122 except StopIteration:
123 return None
123 return None
124
124
125 def hex(self, rev):
125 def hex(self, rev):
126 return hex(self._revlog.node(rev))
126 return hex(self._revlog.node(rev))
127
127
128 def gen(self, pos, pagelen, limit):
128 def gen(self, pos, pagelen, limit):
129 """computes label and revision id for navigation link
129 """computes label and revision id for navigation link
130
130
131 :pos: is the revision relative to which we generate navigation.
131 :pos: is the revision relative to which we generate navigation.
132 :pagelen: the size of each navigation page
132 :pagelen: the size of each navigation page
133 :limit: how far shall we link
133 :limit: how far shall we link
134
134
135 The return is:
135 The return is:
136 - a single element mappinglist
136 - a single element mappinglist
137 - containing a dictionary with a `before` and `after` key
137 - containing a dictionary with a `before` and `after` key
138 - values are dictionaries with `label` and `node` keys
138 - values are dictionaries with `label` and `node` keys
139 """
139 """
140 if not self:
140 if not self:
141 # empty repo
141 # empty repo
142 return templateutil.mappinglist(
142 return templateutil.mappinglist(
143 [
143 [
144 {
144 {
145 b'before': templateutil.mappinglist([]),
145 b'before': templateutil.mappinglist([]),
146 b'after': templateutil.mappinglist([]),
146 b'after': templateutil.mappinglist([]),
147 },
147 },
148 ]
148 ]
149 )
149 )
150
150
151 targets = []
151 targets = []
152 for f in _navseq(1, pagelen):
152 for f in _navseq(1, pagelen):
153 if f > limit:
153 if f > limit:
154 break
154 break
155 targets.append(pos + f)
155 targets.append(pos + f)
156 targets.append(pos - f)
156 targets.append(pos - f)
157 targets.sort()
157 targets.sort()
158
158
159 first = self._first()
159 first = self._first()
160 navbefore = [{b'label': b'(%i)' % first, b'node': self.hex(first)}]
160 navbefore = [{b'label': b'(%i)' % first, b'node': self.hex(first)}]
161 navafter = []
161 navafter = []
162 for rev in targets:
162 for rev in targets:
163 if rev not in self._revlog:
163 if rev not in self._revlog:
164 continue
164 continue
165 if pos < rev < limit:
165 if pos < rev < limit:
166 navafter.append(
166 navafter.append(
167 {b'label': b'+%d' % abs(rev - pos), b'node': self.hex(rev)}
167 {b'label': b'+%d' % abs(rev - pos), b'node': self.hex(rev)}
168 )
168 )
169 if 0 < rev < pos:
169 if 0 < rev < pos:
170 navbefore.append(
170 navbefore.append(
171 {b'label': b'-%d' % abs(rev - pos), b'node': self.hex(rev)}
171 {b'label': b'-%d' % abs(rev - pos), b'node': self.hex(rev)}
172 )
172 )
173
173
174 navafter.append({b'label': b'tip', b'node': b'tip'})
174 navafter.append({b'label': b'tip', b'node': b'tip'})
175
175
176 # TODO: maybe this can be a scalar object supporting tomap()
176 # TODO: maybe this can be a scalar object supporting tomap()
177 return templateutil.mappinglist(
177 return templateutil.mappinglist(
178 [
178 [
179 {
179 {
180 b'before': templateutil.mappinglist(navbefore),
180 b'before': templateutil.mappinglist(navbefore),
181 b'after': templateutil.mappinglist(navafter),
181 b'after': templateutil.mappinglist(navafter),
182 },
182 },
183 ]
183 ]
184 )
184 )
185
185
186
186
187 class filerevnav(revnav):
187 class filerevnav(revnav):
188 def __init__(self, repo, path):
188 def __init__(self, repo, path):
189 """Navigation generation object
189 """Navigation generation object
190
190
191 :repo: repo object we generate nav for
191 :repo: repo object we generate nav for
192 :path: path of the file we generate nav for
192 :path: path of the file we generate nav for
193 """
193 """
194 # used for iteration
194 # used for iteration
195 self._changelog = repo.unfiltered().changelog
195 self._changelog = repo.unfiltered().changelog
196 # used for hex generation
196 # used for hex generation
197 self._revlog = repo.file(path)
197 self._revlog = repo.file(path)
198
198
199 def hex(self, rev):
199 def hex(self, rev):
200 return hex(self._changelog.node(self._revlog.linkrev(rev)))
200 return hex(self._changelog.node(self._revlog.linkrev(rev)))
201
201
202
202
203 # TODO: maybe this can be a wrapper class for changectx/filectx list, which
203 # TODO: maybe this can be a wrapper class for changectx/filectx list, which
204 # yields {'ctx': ctx}
204 # yields {'ctx': ctx}
205 def _ctxsgen(context, ctxs):
205 def _ctxsgen(context, ctxs):
206 for s in ctxs:
206 for s in ctxs:
207 d = {
207 d = {
208 b'node': s.hex(),
208 b'node': s.hex(),
209 b'rev': s.rev(),
209 b'rev': s.rev(),
210 b'user': s.user(),
210 b'user': s.user(),
211 b'date': s.date(),
211 b'date': s.date(),
212 b'description': s.description(),
212 b'description': s.description(),
213 b'branch': s.branch(),
213 b'branch': s.branch(),
214 }
214 }
215 if util.safehasattr(s, b'path'):
215 if util.safehasattr(s, b'path'):
216 d[b'file'] = s.path()
216 d[b'file'] = s.path()
217 yield d
217 yield d
218
218
219
219
220 def _siblings(siblings=None, hiderev=None):
220 def _siblings(siblings=None, hiderev=None):
221 if siblings is None:
221 if siblings is None:
222 siblings = []
222 siblings = []
223 siblings = [s for s in siblings if s.node() != nullid]
223 siblings = [s for s in siblings if s.node() != nullid]
224 if len(siblings) == 1 and siblings[0].rev() == hiderev:
224 if len(siblings) == 1 and siblings[0].rev() == hiderev:
225 siblings = []
225 siblings = []
226 return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
226 return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
227
227
228
228
229 def difffeatureopts(req, ui, section):
229 def difffeatureopts(req, ui, section):
230 diffopts = diffutil.difffeatureopts(
230 diffopts = diffutil.difffeatureopts(
231 ui, untrusted=True, section=section, whitespace=True
231 ui, untrusted=True, section=section, whitespace=True
232 )
232 )
233
233
234 for k in (
234 for k in (
235 b'ignorews',
235 b'ignorews',
236 b'ignorewsamount',
236 b'ignorewsamount',
237 b'ignorewseol',
237 b'ignorewseol',
238 b'ignoreblanklines',
238 b'ignoreblanklines',
239 ):
239 ):
240 v = req.qsparams.get(k)
240 v = req.qsparams.get(k)
241 if v is not None:
241 if v is not None:
242 v = stringutil.parsebool(v)
242 v = stringutil.parsebool(v)
243 setattr(diffopts, k, v if v is not None else True)
243 setattr(diffopts, k, v if v is not None else True)
244
244
245 return diffopts
245 return diffopts
246
246
247
247
248 def annotate(req, fctx, ui):
248 def annotate(req, fctx, ui):
249 diffopts = difffeatureopts(req, ui, b'annotate')
249 diffopts = difffeatureopts(req, ui, b'annotate')
250 return fctx.annotate(follow=True, diffopts=diffopts)
250 return fctx.annotate(follow=True, diffopts=diffopts)
251
251
252
252
253 def parents(ctx, hide=None):
253 def parents(ctx, hide=None):
254 if isinstance(ctx, context.basefilectx):
254 if isinstance(ctx, context.basefilectx):
255 introrev = ctx.introrev()
255 introrev = ctx.introrev()
256 if ctx.changectx().rev() != introrev:
256 if ctx.changectx().rev() != introrev:
257 return _siblings([ctx.repo()[introrev]], hide)
257 return _siblings([ctx.repo()[introrev]], hide)
258 return _siblings(ctx.parents(), hide)
258 return _siblings(ctx.parents(), hide)
259
259
260
260
261 def children(ctx, hide=None):
261 def children(ctx, hide=None):
262 return _siblings(ctx.children(), hide)
262 return _siblings(ctx.children(), hide)
263
263
264
264
265 def renamelink(fctx):
265 def renamelink(fctx):
266 r = fctx.renamed()
266 r = fctx.renamed()
267 if r:
267 if r:
268 return templateutil.mappinglist([{b'file': r[0], b'node': hex(r[1])}])
268 return templateutil.mappinglist([{b'file': r[0], b'node': hex(r[1])}])
269 return templateutil.mappinglist([])
269 return templateutil.mappinglist([])
270
270
271
271
272 def nodetagsdict(repo, node):
272 def nodetagsdict(repo, node):
273 return templateutil.hybridlist(repo.nodetags(node), name=b'name')
273 return templateutil.hybridlist(repo.nodetags(node), name=b'name')
274
274
275
275
276 def nodebookmarksdict(repo, node):
276 def nodebookmarksdict(repo, node):
277 return templateutil.hybridlist(repo.nodebookmarks(node), name=b'name')
277 return templateutil.hybridlist(repo.nodebookmarks(node), name=b'name')
278
278
279
279
280 def nodebranchdict(repo, ctx):
280 def nodebranchdict(repo, ctx):
281 branches = []
281 branches = []
282 branch = ctx.branch()
282 branch = ctx.branch()
283 # If this is an empty repo, ctx.node() == nullid,
283 # If this is an empty repo, ctx.node() == nullid,
284 # ctx.branch() == 'default'.
284 # ctx.branch() == 'default'.
285 try:
285 try:
286 branchnode = repo.branchtip(branch)
286 branchnode = repo.branchtip(branch)
287 except error.RepoLookupError:
287 except error.RepoLookupError:
288 branchnode = None
288 branchnode = None
289 if branchnode == ctx.node():
289 if branchnode == ctx.node():
290 branches.append(branch)
290 branches.append(branch)
291 return templateutil.hybridlist(branches, name=b'name')
291 return templateutil.hybridlist(branches, name=b'name')
292
292
293
293
294 def nodeinbranch(repo, ctx):
294 def nodeinbranch(repo, ctx):
295 branches = []
295 branches = []
296 branch = ctx.branch()
296 branch = ctx.branch()
297 try:
297 try:
298 branchnode = repo.branchtip(branch)
298 branchnode = repo.branchtip(branch)
299 except error.RepoLookupError:
299 except error.RepoLookupError:
300 branchnode = None
300 branchnode = None
301 if branch != b'default' and branchnode != ctx.node():
301 if branch != b'default' and branchnode != ctx.node():
302 branches.append(branch)
302 branches.append(branch)
303 return templateutil.hybridlist(branches, name=b'name')
303 return templateutil.hybridlist(branches, name=b'name')
304
304
305
305
306 def nodebranchnodefault(ctx):
306 def nodebranchnodefault(ctx):
307 branches = []
307 branches = []
308 branch = ctx.branch()
308 branch = ctx.branch()
309 if branch != b'default':
309 if branch != b'default':
310 branches.append(branch)
310 branches.append(branch)
311 return templateutil.hybridlist(branches, name=b'name')
311 return templateutil.hybridlist(branches, name=b'name')
312
312
313
313
314 def _nodenamesgen(context, f, node, name):
314 def _nodenamesgen(context, f, node, name):
315 for t in f(node):
315 for t in f(node):
316 yield {name: t}
316 yield {name: t}
317
317
318
318
319 def showtag(repo, t1, node=nullid):
319 def showtag(repo, t1, node=nullid):
320 args = (repo.nodetags, node, b'tag')
320 args = (repo.nodetags, node, b'tag')
321 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
321 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
322
322
323
323
324 def showbookmark(repo, t1, node=nullid):
324 def showbookmark(repo, t1, node=nullid):
325 args = (repo.nodebookmarks, node, b'bookmark')
325 args = (repo.nodebookmarks, node, b'bookmark')
326 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
326 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
327
327
328
328
329 def branchentries(repo, stripecount, limit=0):
329 def branchentries(repo, stripecount, limit=0):
330 tips = []
330 tips = []
331 heads = repo.heads()
331 heads = repo.heads()
332 parity = paritygen(stripecount)
332 parity = paritygen(stripecount)
333 sortkey = lambda item: (not item[1], item[0].rev())
333 sortkey = lambda item: (not item[1], item[0].rev())
334
334
335 def entries(context):
335 def entries(context):
336 count = 0
336 count = 0
337 if not tips:
337 if not tips:
338 for tag, hs, tip, closed in repo.branchmap().iterbranches():
338 for tag, hs, tip, closed in repo.branchmap().iterbranches():
339 tips.append((repo[tip], closed))
339 tips.append((repo[tip], closed))
340 for ctx, closed in sorted(tips, key=sortkey, reverse=True):
340 for ctx, closed in sorted(tips, key=sortkey, reverse=True):
341 if limit > 0 and count >= limit:
341 if limit > 0 and count >= limit:
342 return
342 return
343 count += 1
343 count += 1
344 if closed:
344 if closed:
345 status = b'closed'
345 status = b'closed'
346 elif ctx.node() not in heads:
346 elif ctx.node() not in heads:
347 status = b'inactive'
347 status = b'inactive'
348 else:
348 else:
349 status = b'open'
349 status = b'open'
350 yield {
350 yield {
351 b'parity': next(parity),
351 b'parity': next(parity),
352 b'branch': ctx.branch(),
352 b'branch': ctx.branch(),
353 b'status': status,
353 b'status': status,
354 b'node': ctx.hex(),
354 b'node': ctx.hex(),
355 b'date': ctx.date(),
355 b'date': ctx.date(),
356 }
356 }
357
357
358 return templateutil.mappinggenerator(entries)
358 return templateutil.mappinggenerator(entries)
359
359
360
360
361 def cleanpath(repo, path):
361 def cleanpath(repo, path):
362 path = path.lstrip(b'/')
362 path = path.lstrip(b'/')
363 auditor = pathutil.pathauditor(repo.root, realfs=False)
363 auditor = pathutil.pathauditor(repo.root, realfs=False)
364 return pathutil.canonpath(repo.root, b'', path, auditor=auditor)
364 return pathutil.canonpath(repo.root, b'', path, auditor=auditor)
365
365
366
366
367 def changectx(repo, req):
367 def changectx(repo, req):
368 changeid = b"tip"
368 changeid = b"tip"
369 if b'node' in req.qsparams:
369 if b'node' in req.qsparams:
370 changeid = req.qsparams[b'node']
370 changeid = req.qsparams[b'node']
371 ipos = changeid.find(b':')
371 ipos = changeid.find(b':')
372 if ipos != -1:
372 if ipos != -1:
373 changeid = changeid[(ipos + 1) :]
373 changeid = changeid[(ipos + 1) :]
374
374
375 return scmutil.revsymbol(repo, changeid)
375 return scmutil.revsymbol(repo, changeid)
376
376
377
377
378 def basechangectx(repo, req):
378 def basechangectx(repo, req):
379 if b'node' in req.qsparams:
379 if b'node' in req.qsparams:
380 changeid = req.qsparams[b'node']
380 changeid = req.qsparams[b'node']
381 ipos = changeid.find(b':')
381 ipos = changeid.find(b':')
382 if ipos != -1:
382 if ipos != -1:
383 changeid = changeid[:ipos]
383 changeid = changeid[:ipos]
384 return scmutil.revsymbol(repo, changeid)
384 return scmutil.revsymbol(repo, changeid)
385
385
386 return None
386 return None
387
387
388
388
389 def filectx(repo, req):
389 def filectx(repo, req):
390 if b'file' not in req.qsparams:
390 if b'file' not in req.qsparams:
391 raise ErrorResponse(HTTP_NOT_FOUND, b'file not given')
391 raise ErrorResponse(HTTP_NOT_FOUND, b'file not given')
392 path = cleanpath(repo, req.qsparams[b'file'])
392 path = cleanpath(repo, req.qsparams[b'file'])
393 if b'node' in req.qsparams:
393 if b'node' in req.qsparams:
394 changeid = req.qsparams[b'node']
394 changeid = req.qsparams[b'node']
395 elif b'filenode' in req.qsparams:
395 elif b'filenode' in req.qsparams:
396 changeid = req.qsparams[b'filenode']
396 changeid = req.qsparams[b'filenode']
397 else:
397 else:
398 raise ErrorResponse(HTTP_NOT_FOUND, b'node or filenode not given')
398 raise ErrorResponse(HTTP_NOT_FOUND, b'node or filenode not given')
399 try:
399 try:
400 fctx = scmutil.revsymbol(repo, changeid)[path]
400 fctx = scmutil.revsymbol(repo, changeid)[path]
401 except error.RepoError:
401 except error.RepoError:
402 fctx = repo.filectx(path, fileid=changeid)
402 fctx = repo.filectx(path, fileid=changeid)
403
403
404 return fctx
404 return fctx
405
405
406
406
407 def linerange(req):
407 def linerange(req):
408 linerange = req.qsparams.getall(b'linerange')
408 linerange = req.qsparams.getall(b'linerange')
409 if not linerange:
409 if not linerange:
410 return None
410 return None
411 if len(linerange) > 1:
411 if len(linerange) > 1:
412 raise ErrorResponse(HTTP_BAD_REQUEST, b'redundant linerange parameter')
412 raise ErrorResponse(HTTP_BAD_REQUEST, b'redundant linerange parameter')
413 try:
413 try:
414 fromline, toline = map(int, linerange[0].split(b':', 1))
414 fromline, toline = map(int, linerange[0].split(b':', 1))
415 except ValueError:
415 except ValueError:
416 raise ErrorResponse(HTTP_BAD_REQUEST, b'invalid linerange parameter')
416 raise ErrorResponse(HTTP_BAD_REQUEST, b'invalid linerange parameter')
417 try:
417 try:
418 return util.processlinerange(fromline, toline)
418 return util.processlinerange(fromline, toline)
419 except error.ParseError as exc:
419 except error.ParseError as exc:
420 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc))
420 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc))
421
421
422
422
423 def formatlinerange(fromline, toline):
423 def formatlinerange(fromline, toline):
424 return b'%d:%d' % (fromline + 1, toline)
424 return b'%d:%d' % (fromline + 1, toline)
425
425
426
426
427 def _succsandmarkersgen(context, mapping):
427 def _succsandmarkersgen(context, mapping):
428 repo = context.resource(mapping, b'repo')
428 repo = context.resource(mapping, b'repo')
429 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
429 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
430 for item in itemmappings.tovalue(context, mapping):
430 for item in itemmappings.tovalue(context, mapping):
431 item[b'successors'] = _siblings(
431 item[b'successors'] = _siblings(
432 repo[successor] for successor in item[b'successors']
432 repo[successor] for successor in item[b'successors']
433 )
433 )
434 yield item
434 yield item
435
435
436
436
437 def succsandmarkers(context, mapping):
437 def succsandmarkers(context, mapping):
438 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
438 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
439
439
440
440
441 # teach templater succsandmarkers is switched to (context, mapping) API
441 # teach templater succsandmarkers is switched to (context, mapping) API
442 succsandmarkers._requires = {b'repo', b'ctx'}
442 succsandmarkers._requires = {b'repo', b'ctx'}
443
443
444
444
445 def _whyunstablegen(context, mapping):
445 def _whyunstablegen(context, mapping):
446 repo = context.resource(mapping, b'repo')
446 repo = context.resource(mapping, b'repo')
447 ctx = context.resource(mapping, b'ctx')
447 ctx = context.resource(mapping, b'ctx')
448
448
449 entries = obsutil.whyunstable(repo, ctx)
449 entries = obsutil.whyunstable(repo, ctx)
450 for entry in entries:
450 for entry in entries:
451 if entry.get(b'divergentnodes'):
451 if entry.get(b'divergentnodes'):
452 entry[b'divergentnodes'] = _siblings(entry[b'divergentnodes'])
452 entry[b'divergentnodes'] = _siblings(entry[b'divergentnodes'])
453 yield entry
453 yield entry
454
454
455
455
456 def whyunstable(context, mapping):
456 def whyunstable(context, mapping):
457 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
457 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
458
458
459
459
460 whyunstable._requires = {b'repo', b'ctx'}
460 whyunstable._requires = {b'repo', b'ctx'}
461
461
462
462
463 def commonentry(repo, ctx):
463 def commonentry(repo, ctx):
464 node = scmutil.binnode(ctx)
464 node = scmutil.binnode(ctx)
465 return {
465 return {
466 # TODO: perhaps ctx.changectx() should be assigned if ctx is a
466 # TODO: perhaps ctx.changectx() should be assigned if ctx is a
467 # filectx, but I'm not pretty sure if that would always work because
467 # filectx, but I'm not pretty sure if that would always work because
468 # fctx.parents() != fctx.changectx.parents() for example.
468 # fctx.parents() != fctx.changectx.parents() for example.
469 b'ctx': ctx,
469 b'ctx': ctx,
470 b'rev': ctx.rev(),
470 b'rev': ctx.rev(),
471 b'node': hex(node),
471 b'node': hex(node),
472 b'author': ctx.user(),
472 b'author': ctx.user(),
473 b'desc': ctx.description(),
473 b'desc': ctx.description(),
474 b'date': ctx.date(),
474 b'date': ctx.date(),
475 b'extra': ctx.extra(),
475 b'extra': ctx.extra(),
476 b'phase': ctx.phasestr(),
476 b'phase': ctx.phasestr(),
477 b'obsolete': ctx.obsolete(),
477 b'obsolete': ctx.obsolete(),
478 b'succsandmarkers': succsandmarkers,
478 b'succsandmarkers': succsandmarkers,
479 b'instabilities': templateutil.hybridlist(
479 b'instabilities': templateutil.hybridlist(
480 ctx.instabilities(), name=b'instability'
480 ctx.instabilities(), name=b'instability'
481 ),
481 ),
482 b'whyunstable': whyunstable,
482 b'whyunstable': whyunstable,
483 b'branch': nodebranchnodefault(ctx),
483 b'branch': nodebranchnodefault(ctx),
484 b'inbranch': nodeinbranch(repo, ctx),
484 b'inbranch': nodeinbranch(repo, ctx),
485 b'branches': nodebranchdict(repo, ctx),
485 b'branches': nodebranchdict(repo, ctx),
486 b'tags': nodetagsdict(repo, node),
486 b'tags': nodetagsdict(repo, node),
487 b'bookmarks': nodebookmarksdict(repo, node),
487 b'bookmarks': nodebookmarksdict(repo, node),
488 b'parent': lambda context, mapping: parents(ctx),
488 b'parent': lambda context, mapping: parents(ctx),
489 b'child': lambda context, mapping: children(ctx),
489 b'child': lambda context, mapping: children(ctx),
490 }
490 }
491
491
492
492
493 def changelistentry(web, ctx):
493 def changelistentry(web, ctx):
494 '''Obtain a dictionary to be used for entries in a changelist.
494 '''Obtain a dictionary to be used for entries in a changelist.
495
495
496 This function is called when producing items for the "entries" list passed
496 This function is called when producing items for the "entries" list passed
497 to the "shortlog" and "changelog" templates.
497 to the "shortlog" and "changelog" templates.
498 '''
498 '''
499 repo = web.repo
499 repo = web.repo
500 rev = ctx.rev()
500 rev = ctx.rev()
501 n = scmutil.binnode(ctx)
501 n = scmutil.binnode(ctx)
502 showtags = showtag(repo, b'changelogtag', n)
502 showtags = showtag(repo, b'changelogtag', n)
503 files = listfilediffs(ctx.files(), n, web.maxfiles)
503 files = listfilediffs(ctx.files(), n, web.maxfiles)
504
504
505 entry = commonentry(repo, ctx)
505 entry = commonentry(repo, ctx)
506 entry.update(
506 entry.update(
507 {
507 {
508 b'allparents': lambda context, mapping: parents(ctx),
508 b'allparents': lambda context, mapping: parents(ctx),
509 b'parent': lambda context, mapping: parents(ctx, rev - 1),
509 b'parent': lambda context, mapping: parents(ctx, rev - 1),
510 b'child': lambda context, mapping: children(ctx, rev + 1),
510 b'child': lambda context, mapping: children(ctx, rev + 1),
511 b'changelogtag': showtags,
511 b'changelogtag': showtags,
512 b'files': files,
512 b'files': files,
513 }
513 }
514 )
514 )
515 return entry
515 return entry
516
516
517
517
518 def changelistentries(web, revs, maxcount, parityfn):
518 def changelistentries(web, revs, maxcount, parityfn):
519 """Emit up to N records for an iterable of revisions."""
519 """Emit up to N records for an iterable of revisions."""
520 repo = web.repo
520 repo = web.repo
521
521
522 count = 0
522 count = 0
523 for rev in revs:
523 for rev in revs:
524 if count >= maxcount:
524 if count >= maxcount:
525 break
525 break
526
526
527 count += 1
527 count += 1
528
528
529 entry = changelistentry(web, repo[rev])
529 entry = changelistentry(web, repo[rev])
530 entry[b'parity'] = next(parityfn)
530 entry[b'parity'] = next(parityfn)
531
531
532 yield entry
532 yield entry
533
533
534
534
535 def symrevorshortnode(req, ctx):
535 def symrevorshortnode(req, ctx):
536 if b'node' in req.qsparams:
536 if b'node' in req.qsparams:
537 return templatefilters.revescape(req.qsparams[b'node'])
537 return templatefilters.revescape(req.qsparams[b'node'])
538 else:
538 else:
539 return short(scmutil.binnode(ctx))
539 return short(scmutil.binnode(ctx))
540
540
541
541
542 def _listfilesgen(context, ctx, stripecount):
542 def _listfilesgen(context, ctx, stripecount):
543 parity = paritygen(stripecount)
543 parity = paritygen(stripecount)
544 filesadded = ctx.filesadded()
544 filesadded = ctx.filesadded()
545 for blockno, f in enumerate(ctx.files()):
545 for blockno, f in enumerate(ctx.files()):
546 if f not in ctx:
546 if f not in ctx:
547 status = b'removed'
547 status = b'removed'
548 elif f in filesadded:
548 elif f in filesadded:
549 status = b'added'
549 status = b'added'
550 else:
550 else:
551 status = b'modified'
551 status = b'modified'
552 template = b'filenolink' if status == b'removed' else b'filenodelink'
552 template = b'filenolink' if status == b'removed' else b'filenodelink'
553 yield context.process(
553 yield context.process(
554 template,
554 template,
555 {
555 {
556 b'node': ctx.hex(),
556 b'node': ctx.hex(),
557 b'file': f,
557 b'file': f,
558 b'blockno': blockno + 1,
558 b'blockno': blockno + 1,
559 b'parity': next(parity),
559 b'parity': next(parity),
560 b'status': status,
560 b'status': status,
561 },
561 },
562 )
562 )
563
563
564
564
565 def changesetentry(web, ctx):
565 def changesetentry(web, ctx):
566 '''Obtain a dictionary to be used to render the "changeset" template.'''
566 '''Obtain a dictionary to be used to render the "changeset" template.'''
567
567
568 showtags = showtag(web.repo, b'changesettag', scmutil.binnode(ctx))
568 showtags = showtag(web.repo, b'changesettag', scmutil.binnode(ctx))
569 showbookmarks = showbookmark(
569 showbookmarks = showbookmark(
570 web.repo, b'changesetbookmark', scmutil.binnode(ctx)
570 web.repo, b'changesetbookmark', scmutil.binnode(ctx)
571 )
571 )
572 showbranch = nodebranchnodefault(ctx)
572 showbranch = nodebranchnodefault(ctx)
573
573
574 basectx = basechangectx(web.repo, web.req)
574 basectx = basechangectx(web.repo, web.req)
575 if basectx is None:
575 if basectx is None:
576 basectx = ctx.p1()
576 basectx = ctx.p1()
577
577
578 style = web.config(b'web', b'style')
578 style = web.config(b'web', b'style')
579 if b'style' in web.req.qsparams:
579 if b'style' in web.req.qsparams:
580 style = web.req.qsparams[b'style']
580 style = web.req.qsparams[b'style']
581
581
582 diff = diffs(web, ctx, basectx, None, style)
582 diff = diffs(web, ctx, basectx, None, style)
583
583
584 parity = paritygen(web.stripecount)
584 parity = paritygen(web.stripecount)
585 diffstatsgen = diffstatgen(web.repo.ui, ctx, basectx)
585 diffstatsgen = diffstatgen(web.repo.ui, ctx, basectx)
586 diffstats = diffstat(ctx, diffstatsgen, parity)
586 diffstats = diffstat(ctx, diffstatsgen, parity)
587
587
588 return dict(
588 return dict(
589 diff=diff,
589 diff=diff,
590 symrev=symrevorshortnode(web.req, ctx),
590 symrev=symrevorshortnode(web.req, ctx),
591 basenode=basectx.hex(),
591 basenode=basectx.hex(),
592 changesettag=showtags,
592 changesettag=showtags,
593 changesetbookmark=showbookmarks,
593 changesetbookmark=showbookmarks,
594 changesetbranch=showbranch,
594 changesetbranch=showbranch,
595 files=templateutil.mappedgenerator(
595 files=templateutil.mappedgenerator(
596 _listfilesgen, args=(ctx, web.stripecount)
596 _listfilesgen, args=(ctx, web.stripecount)
597 ),
597 ),
598 diffsummary=lambda context, mapping: diffsummary(diffstatsgen),
598 diffsummary=lambda context, mapping: diffsummary(diffstatsgen),
599 diffstat=diffstats,
599 diffstat=diffstats,
600 archives=web.archivelist(ctx.hex()),
600 archives=web.archivelist(ctx.hex()),
601 **pycompat.strkwargs(commonentry(web.repo, ctx))
601 **pycompat.strkwargs(commonentry(web.repo, ctx))
602 )
602 )
603
603
604
604
605 def _listfilediffsgen(context, files, node, max):
605 def _listfilediffsgen(context, files, node, max):
606 for f in files[:max]:
606 for f in files[:max]:
607 yield context.process(b'filedifflink', {b'node': hex(node), b'file': f})
607 yield context.process(b'filedifflink', {b'node': hex(node), b'file': f})
608 if len(files) > max:
608 if len(files) > max:
609 yield context.process(b'fileellipses', {})
609 yield context.process(b'fileellipses', {})
610
610
611
611
612 def listfilediffs(files, node, max):
612 def listfilediffs(files, node, max):
613 return templateutil.mappedgenerator(
613 return templateutil.mappedgenerator(
614 _listfilediffsgen, args=(files, node, max)
614 _listfilediffsgen, args=(files, node, max)
615 )
615 )
616
616
617
617
618 def _prettyprintdifflines(context, lines, blockno, lineidprefix):
618 def _prettyprintdifflines(context, lines, blockno, lineidprefix):
619 for lineno, l in enumerate(lines, 1):
619 for lineno, l in enumerate(lines, 1):
620 difflineno = b"%d.%d" % (blockno, lineno)
620 difflineno = b"%d.%d" % (blockno, lineno)
621 if l.startswith(b'+'):
621 if l.startswith(b'+'):
622 ltype = b"difflineplus"
622 ltype = b"difflineplus"
623 elif l.startswith(b'-'):
623 elif l.startswith(b'-'):
624 ltype = b"difflineminus"
624 ltype = b"difflineminus"
625 elif l.startswith(b'@'):
625 elif l.startswith(b'@'):
626 ltype = b"difflineat"
626 ltype = b"difflineat"
627 else:
627 else:
628 ltype = b"diffline"
628 ltype = b"diffline"
629 yield context.process(
629 yield context.process(
630 ltype,
630 ltype,
631 {
631 {
632 b'line': l,
632 b'line': l,
633 b'lineno': lineno,
633 b'lineno': lineno,
634 b'lineid': lineidprefix + b"l%s" % difflineno,
634 b'lineid': lineidprefix + b"l%s" % difflineno,
635 b'linenumber': b"% 8s" % difflineno,
635 b'linenumber': b"% 8s" % difflineno,
636 },
636 },
637 )
637 )
638
638
639
639
640 def _diffsgen(
640 def _diffsgen(
641 context,
641 context,
642 repo,
642 repo,
643 ctx,
643 ctx,
644 basectx,
644 basectx,
645 files,
645 files,
646 style,
646 style,
647 stripecount,
647 stripecount,
648 linerange,
648 linerange,
649 lineidprefix,
649 lineidprefix,
650 ):
650 ):
651 if files:
651 if files:
652 m = match.exact(files)
652 m = match.exact(files)
653 else:
653 else:
654 m = match.always()
654 m = match.always()
655
655
656 diffopts = patch.diffopts(repo.ui, untrusted=True)
656 diffopts = patch.diffopts(repo.ui, untrusted=True)
657 parity = paritygen(stripecount)
657 parity = paritygen(stripecount)
658
658
659 diffhunks = patch.diffhunks(repo, basectx, ctx, m, opts=diffopts)
659 diffhunks = patch.diffhunks(repo, basectx, ctx, m, opts=diffopts)
660 for blockno, (fctx1, fctx2, header, hunks) in enumerate(diffhunks, 1):
660 for blockno, (fctx1, fctx2, header, hunks) in enumerate(diffhunks, 1):
661 if style != b'raw':
661 if style != b'raw':
662 header = header[1:]
662 header = header[1:]
663 lines = [h + b'\n' for h in header]
663 lines = [h + b'\n' for h in header]
664 for hunkrange, hunklines in hunks:
664 for hunkrange, hunklines in hunks:
665 if linerange is not None and hunkrange is not None:
665 if linerange is not None and hunkrange is not None:
666 s1, l1, s2, l2 = hunkrange
666 s1, l1, s2, l2 = hunkrange
667 if not mdiff.hunkinrange((s2, l2), linerange):
667 if not mdiff.hunkinrange((s2, l2), linerange):
668 continue
668 continue
669 lines.extend(hunklines)
669 lines.extend(hunklines)
670 if lines:
670 if lines:
671 l = templateutil.mappedgenerator(
671 l = templateutil.mappedgenerator(
672 _prettyprintdifflines, args=(lines, blockno, lineidprefix)
672 _prettyprintdifflines, args=(lines, blockno, lineidprefix)
673 )
673 )
674 yield {
674 yield {
675 b'parity': next(parity),
675 b'parity': next(parity),
676 b'blockno': blockno,
676 b'blockno': blockno,
677 b'lines': l,
677 b'lines': l,
678 }
678 }
679
679
680
680
681 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=b''):
681 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=b''):
682 args = (
682 args = (
683 web.repo,
683 web.repo,
684 ctx,
684 ctx,
685 basectx,
685 basectx,
686 files,
686 files,
687 style,
687 style,
688 web.stripecount,
688 web.stripecount,
689 linerange,
689 linerange,
690 lineidprefix,
690 lineidprefix,
691 )
691 )
692 return templateutil.mappinggenerator(
692 return templateutil.mappinggenerator(
693 _diffsgen, args=args, name=b'diffblock'
693 _diffsgen, args=args, name=b'diffblock'
694 )
694 )
695
695
696
696
697 def _compline(type, leftlineno, leftline, rightlineno, rightline):
697 def _compline(type, leftlineno, leftline, rightlineno, rightline):
698 lineid = leftlineno and (b"l%d" % leftlineno) or b''
698 lineid = leftlineno and (b"l%d" % leftlineno) or b''
699 lineid += rightlineno and (b"r%d" % rightlineno) or b''
699 lineid += rightlineno and (b"r%d" % rightlineno) or b''
700 llno = b'%d' % leftlineno if leftlineno else b''
700 llno = b'%d' % leftlineno if leftlineno else b''
701 rlno = b'%d' % rightlineno if rightlineno else b''
701 rlno = b'%d' % rightlineno if rightlineno else b''
702 return {
702 return {
703 b'type': type,
703 b'type': type,
704 b'lineid': lineid,
704 b'lineid': lineid,
705 b'leftlineno': leftlineno,
705 b'leftlineno': leftlineno,
706 b'leftlinenumber': b"% 6s" % llno,
706 b'leftlinenumber': b"% 6s" % llno,
707 b'leftline': leftline or b'',
707 b'leftline': leftline or b'',
708 b'rightlineno': rightlineno,
708 b'rightlineno': rightlineno,
709 b'rightlinenumber': b"% 6s" % rlno,
709 b'rightlinenumber': b"% 6s" % rlno,
710 b'rightline': rightline or b'',
710 b'rightline': rightline or b'',
711 }
711 }
712
712
713
713
714 def _getcompblockgen(context, leftlines, rightlines, opcodes):
714 def _getcompblockgen(context, leftlines, rightlines, opcodes):
715 for type, llo, lhi, rlo, rhi in opcodes:
715 for type, llo, lhi, rlo, rhi in opcodes:
716 type = pycompat.sysbytes(type)
716 type = pycompat.sysbytes(type)
717 len1 = lhi - llo
717 len1 = lhi - llo
718 len2 = rhi - rlo
718 len2 = rhi - rlo
719 count = min(len1, len2)
719 count = min(len1, len2)
720 for i in pycompat.xrange(count):
720 for i in pycompat.xrange(count):
721 yield _compline(
721 yield _compline(
722 type=type,
722 type=type,
723 leftlineno=llo + i + 1,
723 leftlineno=llo + i + 1,
724 leftline=leftlines[llo + i],
724 leftline=leftlines[llo + i],
725 rightlineno=rlo + i + 1,
725 rightlineno=rlo + i + 1,
726 rightline=rightlines[rlo + i],
726 rightline=rightlines[rlo + i],
727 )
727 )
728 if len1 > len2:
728 if len1 > len2:
729 for i in pycompat.xrange(llo + count, lhi):
729 for i in pycompat.xrange(llo + count, lhi):
730 yield _compline(
730 yield _compline(
731 type=type,
731 type=type,
732 leftlineno=i + 1,
732 leftlineno=i + 1,
733 leftline=leftlines[i],
733 leftline=leftlines[i],
734 rightlineno=None,
734 rightlineno=None,
735 rightline=None,
735 rightline=None,
736 )
736 )
737 elif len2 > len1:
737 elif len2 > len1:
738 for i in pycompat.xrange(rlo + count, rhi):
738 for i in pycompat.xrange(rlo + count, rhi):
739 yield _compline(
739 yield _compline(
740 type=type,
740 type=type,
741 leftlineno=None,
741 leftlineno=None,
742 leftline=None,
742 leftline=None,
743 rightlineno=i + 1,
743 rightlineno=i + 1,
744 rightline=rightlines[i],
744 rightline=rightlines[i],
745 )
745 )
746
746
747
747
748 def _getcompblock(leftlines, rightlines, opcodes):
748 def _getcompblock(leftlines, rightlines, opcodes):
749 args = (leftlines, rightlines, opcodes)
749 args = (leftlines, rightlines, opcodes)
750 return templateutil.mappinggenerator(
750 return templateutil.mappinggenerator(
751 _getcompblockgen, args=args, name=b'comparisonline'
751 _getcompblockgen, args=args, name=b'comparisonline'
752 )
752 )
753
753
754
754
755 def _comparegen(context, contextnum, leftlines, rightlines):
755 def _comparegen(context, contextnum, leftlines, rightlines):
756 '''Generator function that provides side-by-side comparison data.'''
756 '''Generator function that provides side-by-side comparison data.'''
757 s = difflib.SequenceMatcher(None, leftlines, rightlines)
757 s = difflib.SequenceMatcher(None, leftlines, rightlines)
758 if contextnum < 0:
758 if contextnum < 0:
759 l = _getcompblock(leftlines, rightlines, s.get_opcodes())
759 l = _getcompblock(leftlines, rightlines, s.get_opcodes())
760 yield {b'lines': l}
760 yield {b'lines': l}
761 else:
761 else:
762 for oc in s.get_grouped_opcodes(n=contextnum):
762 for oc in s.get_grouped_opcodes(n=contextnum):
763 l = _getcompblock(leftlines, rightlines, oc)
763 l = _getcompblock(leftlines, rightlines, oc)
764 yield {b'lines': l}
764 yield {b'lines': l}
765
765
766
766
767 def compare(contextnum, leftlines, rightlines):
767 def compare(contextnum, leftlines, rightlines):
768 args = (contextnum, leftlines, rightlines)
768 args = (contextnum, leftlines, rightlines)
769 return templateutil.mappinggenerator(
769 return templateutil.mappinggenerator(
770 _comparegen, args=args, name=b'comparisonblock'
770 _comparegen, args=args, name=b'comparisonblock'
771 )
771 )
772
772
773
773
774 def diffstatgen(ui, ctx, basectx):
774 def diffstatgen(ui, ctx, basectx):
775 '''Generator function that provides the diffstat data.'''
775 '''Generator function that provides the diffstat data.'''
776
776
777 diffopts = patch.diffopts(ui, {b'noprefix': False})
777 diffopts = patch.diffopts(ui, {b'noprefix': False})
778 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx, opts=diffopts)))
778 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx, opts=diffopts)))
779 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
779 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
780 while True:
780 while True:
781 yield stats, maxname, maxtotal, addtotal, removetotal, binary
781 yield stats, maxname, maxtotal, addtotal, removetotal, binary
782
782
783
783
784 def diffsummary(statgen):
784 def diffsummary(statgen):
785 '''Return a short summary of the diff.'''
785 '''Return a short summary of the diff.'''
786
786
787 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
787 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
788 return _(b' %d files changed, %d insertions(+), %d deletions(-)\n') % (
788 return _(b' %d files changed, %d insertions(+), %d deletions(-)\n') % (
789 len(stats),
789 len(stats),
790 addtotal,
790 addtotal,
791 removetotal,
791 removetotal,
792 )
792 )
793
793
794
794
795 def _diffstattmplgen(context, ctx, statgen, parity):
795 def _diffstattmplgen(context, ctx, statgen, parity):
796 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
796 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
797 files = ctx.files()
797 files = ctx.files()
798
798
799 def pct(i):
799 def pct(i):
800 if maxtotal == 0:
800 if maxtotal == 0:
801 return 0
801 return 0
802 return (float(i) / maxtotal) * 100
802 return (float(i) / maxtotal) * 100
803
803
804 fileno = 0
804 fileno = 0
805 for filename, adds, removes, isbinary in stats:
805 for filename, adds, removes, isbinary in stats:
806 template = b'diffstatlink' if filename in files else b'diffstatnolink'
806 template = b'diffstatlink' if filename in files else b'diffstatnolink'
807 total = adds + removes
807 total = adds + removes
808 fileno += 1
808 fileno += 1
809 yield context.process(
809 yield context.process(
810 template,
810 template,
811 {
811 {
812 b'node': ctx.hex(),
812 b'node': ctx.hex(),
813 b'file': filename,
813 b'file': filename,
814 b'fileno': fileno,
814 b'fileno': fileno,
815 b'total': total,
815 b'total': total,
816 b'addpct': pct(adds),
816 b'addpct': pct(adds),
817 b'removepct': pct(removes),
817 b'removepct': pct(removes),
818 b'parity': next(parity),
818 b'parity': next(parity),
819 },
819 },
820 )
820 )
821
821
822
822
823 def diffstat(ctx, statgen, parity):
823 def diffstat(ctx, statgen, parity):
824 '''Return a diffstat template for each file in the diff.'''
824 '''Return a diffstat template for each file in the diff.'''
825 args = (ctx, statgen, parity)
825 args = (ctx, statgen, parity)
826 return templateutil.mappedgenerator(_diffstattmplgen, args=args)
826 return templateutil.mappedgenerator(_diffstattmplgen, args=args)
827
827
828
828
829 class sessionvars(templateutil.wrapped):
829 class sessionvars(templateutil.wrapped):
830 def __init__(self, vars, start=b'?'):
830 def __init__(self, vars, start=b'?'):
831 self._start = start
831 self._start = start
832 self._vars = vars
832 self._vars = vars
833
833
834 def __getitem__(self, key):
834 def __getitem__(self, key):
835 return self._vars[key]
835 return self._vars[key]
836
836
837 def __setitem__(self, key, value):
837 def __setitem__(self, key, value):
838 self._vars[key] = value
838 self._vars[key] = value
839
839
840 def __copy__(self):
840 def __copy__(self):
841 return sessionvars(copy.copy(self._vars), self._start)
841 return sessionvars(copy.copy(self._vars), self._start)
842
842
843 def contains(self, context, mapping, item):
843 def contains(self, context, mapping, item):
844 item = templateutil.unwrapvalue(context, mapping, item)
844 item = templateutil.unwrapvalue(context, mapping, item)
845 return item in self._vars
845 return item in self._vars
846
846
847 def getmember(self, context, mapping, key):
847 def getmember(self, context, mapping, key):
848 key = templateutil.unwrapvalue(context, mapping, key)
848 key = templateutil.unwrapvalue(context, mapping, key)
849 return self._vars.get(key)
849 return self._vars.get(key)
850
850
851 def getmin(self, context, mapping):
851 def getmin(self, context, mapping):
852 raise error.ParseError(_(b'not comparable'))
852 raise error.ParseError(_(b'not comparable'))
853
853
854 def getmax(self, context, mapping):
854 def getmax(self, context, mapping):
855 raise error.ParseError(_(b'not comparable'))
855 raise error.ParseError(_(b'not comparable'))
856
856
857 def filter(self, context, mapping, select):
857 def filter(self, context, mapping, select):
858 # implement if necessary
858 # implement if necessary
859 raise error.ParseError(_(b'not filterable'))
859 raise error.ParseError(_(b'not filterable'))
860
860
861 def itermaps(self, context):
861 def itermaps(self, context):
862 separator = self._start
862 separator = self._start
863 for key, value in sorted(pycompat.iteritems(self._vars)):
863 for key, value in sorted(pycompat.iteritems(self._vars)):
864 yield {
864 yield {
865 b'name': key,
865 b'name': key,
866 b'value': pycompat.bytestr(value),
866 b'value': pycompat.bytestr(value),
867 b'separator': separator,
867 b'separator': separator,
868 }
868 }
869 separator = b'&'
869 separator = b'&'
870
870
871 def join(self, context, mapping, sep):
871 def join(self, context, mapping, sep):
872 # could be '{separator}{name}={value|urlescape}'
872 # could be '{separator}{name}={value|urlescape}'
873 raise error.ParseError(_(b'not displayable without template'))
873 raise error.ParseError(_(b'not displayable without template'))
874
874
875 def show(self, context, mapping):
875 def show(self, context, mapping):
876 return self.join(context, mapping, b'')
876 return self.join(context, mapping, b'')
877
877
878 def tobool(self, context, mapping):
878 def tobool(self, context, mapping):
879 return bool(self._vars)
879 return bool(self._vars)
880
880
881 def tovalue(self, context, mapping):
881 def tovalue(self, context, mapping):
882 return self._vars
882 return self._vars
883
883
884
884
885 class wsgiui(uimod.ui):
885 class wsgiui(uimod.ui):
886 # default termwidth breaks under mod_wsgi
886 # default termwidth breaks under mod_wsgi
887 def termwidth(self):
887 def termwidth(self):
888 return 80
888 return 80
889
889
890
890
891 def getwebsubs(repo):
891 def getwebsubs(repo):
892 websubtable = []
892 websubtable = []
893 websubdefs = repo.ui.configitems(b'websub')
893 websubdefs = repo.ui.configitems(b'websub')
894 # we must maintain interhg backwards compatibility
894 # we must maintain interhg backwards compatibility
895 websubdefs += repo.ui.configitems(b'interhg')
895 websubdefs += repo.ui.configitems(b'interhg')
896 for key, pattern in websubdefs:
896 for key, pattern in websubdefs:
897 # grab the delimiter from the character after the "s"
897 # grab the delimiter from the character after the "s"
898 unesc = pattern[1:2]
898 unesc = pattern[1:2]
899 delim = stringutil.reescape(unesc)
899 delim = stringutil.reescape(unesc)
900
900
901 # identify portions of the pattern, taking care to avoid escaped
901 # identify portions of the pattern, taking care to avoid escaped
902 # delimiters. the replace format and flags are optional, but
902 # delimiters. the replace format and flags are optional, but
903 # delimiters are required.
903 # delimiters are required.
904 match = re.match(
904 match = re.match(
905 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
905 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
906 % (delim, delim, delim),
906 % (delim, delim, delim),
907 pattern,
907 pattern,
908 )
908 )
909 if not match:
909 if not match:
910 repo.ui.warn(
910 repo.ui.warn(
911 _(b"websub: invalid pattern for %s: %s\n") % (key, pattern)
911 _(b"websub: invalid pattern for %s: %s\n") % (key, pattern)
912 )
912 )
913 continue
913 continue
914
914
915 # we need to unescape the delimiter for regexp and format
915 # we need to unescape the delimiter for regexp and format
916 delim_re = re.compile(br'(?<!\\)\\%s' % delim)
916 delim_re = re.compile(br'(?<!\\)\\%s' % delim)
917 regexp = delim_re.sub(unesc, match.group(1))
917 regexp = delim_re.sub(unesc, match.group(1))
918 format = delim_re.sub(unesc, match.group(2))
918 format = delim_re.sub(unesc, match.group(2))
919
919
920 # the pattern allows for 6 regexp flags, so set them if necessary
920 # the pattern allows for 6 regexp flags, so set them if necessary
921 flagin = match.group(3)
921 flagin = match.group(3)
922 flags = 0
922 flags = 0
923 if flagin:
923 if flagin:
924 for flag in pycompat.sysstr(flagin.upper()):
924 for flag in pycompat.sysstr(flagin.upper()):
925 flags |= re.__dict__[flag]
925 flags |= re.__dict__[flag]
926
926
927 try:
927 try:
928 regexp = re.compile(regexp, flags)
928 regexp = re.compile(regexp, flags)
929 websubtable.append((regexp, format))
929 websubtable.append((regexp, format))
930 except re.error:
930 except re.error:
931 repo.ui.warn(
931 repo.ui.warn(
932 _(b"websub: invalid regexp for %s: %s\n") % (key, regexp)
932 _(b"websub: invalid regexp for %s: %s\n") % (key, regexp)
933 )
933 )
934 return websubtable
934 return websubtable
935
935
936
936
937 def getgraphnode(repo, ctx):
937 def getgraphnode(repo, ctx):
938 return templatekw.getgraphnodecurrent(
938 return templatekw.getgraphnodecurrent(
939 repo, ctx
939 repo, ctx, {}
940 ) + templatekw.getgraphnodesymbol(ctx)
940 ) + templatekw.getgraphnodesymbol(ctx)
@@ -1,1088 +1,1089 b''
1 # logcmdutil.py - utility for log-like commands
1 # logcmdutil.py - utility for log-like commands
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import itertools
10 import itertools
11 import os
11 import os
12 import posixpath
12 import posixpath
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 nullid,
16 nullid,
17 wdirid,
17 wdirid,
18 wdirrev,
18 wdirrev,
19 )
19 )
20
20
21 from . import (
21 from . import (
22 dagop,
22 dagop,
23 error,
23 error,
24 formatter,
24 formatter,
25 graphmod,
25 graphmod,
26 match as matchmod,
26 match as matchmod,
27 mdiff,
27 mdiff,
28 patch,
28 patch,
29 pathutil,
29 pathutil,
30 pycompat,
30 pycompat,
31 revset,
31 revset,
32 revsetlang,
32 revsetlang,
33 scmutil,
33 scmutil,
34 smartset,
34 smartset,
35 templatekw,
35 templatekw,
36 templater,
36 templater,
37 util,
37 util,
38 )
38 )
39 from .utils import (
39 from .utils import (
40 dateutil,
40 dateutil,
41 stringutil,
41 stringutil,
42 )
42 )
43
43
44
44
45 if pycompat.TYPE_CHECKING:
45 if pycompat.TYPE_CHECKING:
46 from typing import (
46 from typing import (
47 Any,
47 Any,
48 Optional,
48 Optional,
49 Tuple,
49 Tuple,
50 )
50 )
51
51
52 for t in (Any, Optional, Tuple):
52 for t in (Any, Optional, Tuple):
53 assert t
53 assert t
54
54
55
55
56 def getlimit(opts):
56 def getlimit(opts):
57 """get the log limit according to option -l/--limit"""
57 """get the log limit according to option -l/--limit"""
58 limit = opts.get(b'limit')
58 limit = opts.get(b'limit')
59 if limit:
59 if limit:
60 try:
60 try:
61 limit = int(limit)
61 limit = int(limit)
62 except ValueError:
62 except ValueError:
63 raise error.Abort(_(b'limit must be a positive integer'))
63 raise error.Abort(_(b'limit must be a positive integer'))
64 if limit <= 0:
64 if limit <= 0:
65 raise error.Abort(_(b'limit must be positive'))
65 raise error.Abort(_(b'limit must be positive'))
66 else:
66 else:
67 limit = None
67 limit = None
68 return limit
68 return limit
69
69
70
70
71 def diffordiffstat(
71 def diffordiffstat(
72 ui,
72 ui,
73 repo,
73 repo,
74 diffopts,
74 diffopts,
75 node1,
75 node1,
76 node2,
76 node2,
77 match,
77 match,
78 changes=None,
78 changes=None,
79 stat=False,
79 stat=False,
80 fp=None,
80 fp=None,
81 graphwidth=0,
81 graphwidth=0,
82 prefix=b'',
82 prefix=b'',
83 root=b'',
83 root=b'',
84 listsubrepos=False,
84 listsubrepos=False,
85 hunksfilterfn=None,
85 hunksfilterfn=None,
86 ):
86 ):
87 '''show diff or diffstat.'''
87 '''show diff or diffstat.'''
88 ctx1 = repo[node1]
88 ctx1 = repo[node1]
89 ctx2 = repo[node2]
89 ctx2 = repo[node2]
90 if root:
90 if root:
91 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
91 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
92 else:
92 else:
93 relroot = b''
93 relroot = b''
94 copysourcematch = None
94 copysourcematch = None
95
95
96 def compose(f, g):
96 def compose(f, g):
97 return lambda x: f(g(x))
97 return lambda x: f(g(x))
98
98
99 def pathfn(f):
99 def pathfn(f):
100 return posixpath.join(prefix, f)
100 return posixpath.join(prefix, f)
101
101
102 if relroot != b'':
102 if relroot != b'':
103 # XXX relative roots currently don't work if the root is within a
103 # XXX relative roots currently don't work if the root is within a
104 # subrepo
104 # subrepo
105 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
105 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
106 uirelroot = uipathfn(pathfn(relroot))
106 uirelroot = uipathfn(pathfn(relroot))
107 relroot += b'/'
107 relroot += b'/'
108 for matchroot in match.files():
108 for matchroot in match.files():
109 if not matchroot.startswith(relroot):
109 if not matchroot.startswith(relroot):
110 ui.warn(
110 ui.warn(
111 _(b'warning: %s not inside relative root %s\n')
111 _(b'warning: %s not inside relative root %s\n')
112 % (uipathfn(pathfn(matchroot)), uirelroot)
112 % (uipathfn(pathfn(matchroot)), uirelroot)
113 )
113 )
114
114
115 relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path')
115 relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path')
116 match = matchmod.intersectmatchers(match, relrootmatch)
116 match = matchmod.intersectmatchers(match, relrootmatch)
117 copysourcematch = relrootmatch
117 copysourcematch = relrootmatch
118
118
119 checkroot = repo.ui.configbool(
119 checkroot = repo.ui.configbool(
120 b'devel', b'all-warnings'
120 b'devel', b'all-warnings'
121 ) or repo.ui.configbool(b'devel', b'check-relroot')
121 ) or repo.ui.configbool(b'devel', b'check-relroot')
122
122
123 def relrootpathfn(f):
123 def relrootpathfn(f):
124 if checkroot and not f.startswith(relroot):
124 if checkroot and not f.startswith(relroot):
125 raise AssertionError(
125 raise AssertionError(
126 b"file %s doesn't start with relroot %s" % (f, relroot)
126 b"file %s doesn't start with relroot %s" % (f, relroot)
127 )
127 )
128 return f[len(relroot) :]
128 return f[len(relroot) :]
129
129
130 pathfn = compose(relrootpathfn, pathfn)
130 pathfn = compose(relrootpathfn, pathfn)
131
131
132 if stat:
132 if stat:
133 diffopts = diffopts.copy(context=0, noprefix=False)
133 diffopts = diffopts.copy(context=0, noprefix=False)
134 width = 80
134 width = 80
135 if not ui.plain():
135 if not ui.plain():
136 width = ui.termwidth() - graphwidth
136 width = ui.termwidth() - graphwidth
137 # If an explicit --root was given, don't respect ui.relative-paths
137 # If an explicit --root was given, don't respect ui.relative-paths
138 if not relroot:
138 if not relroot:
139 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
139 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
140
140
141 chunks = ctx2.diff(
141 chunks = ctx2.diff(
142 ctx1,
142 ctx1,
143 match,
143 match,
144 changes,
144 changes,
145 opts=diffopts,
145 opts=diffopts,
146 pathfn=pathfn,
146 pathfn=pathfn,
147 copysourcematch=copysourcematch,
147 copysourcematch=copysourcematch,
148 hunksfilterfn=hunksfilterfn,
148 hunksfilterfn=hunksfilterfn,
149 )
149 )
150
150
151 if fp is not None or ui.canwritewithoutlabels():
151 if fp is not None or ui.canwritewithoutlabels():
152 out = fp or ui
152 out = fp or ui
153 if stat:
153 if stat:
154 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
154 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
155 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
155 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
156 out.write(chunk)
156 out.write(chunk)
157 else:
157 else:
158 if stat:
158 if stat:
159 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
159 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
160 else:
160 else:
161 chunks = patch.difflabel(
161 chunks = patch.difflabel(
162 lambda chunks, **kwargs: chunks, chunks, opts=diffopts
162 lambda chunks, **kwargs: chunks, chunks, opts=diffopts
163 )
163 )
164 if ui.canbatchlabeledwrites():
164 if ui.canbatchlabeledwrites():
165
165
166 def gen():
166 def gen():
167 for chunk, label in chunks:
167 for chunk, label in chunks:
168 yield ui.label(chunk, label=label)
168 yield ui.label(chunk, label=label)
169
169
170 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
170 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
171 ui.write(chunk)
171 ui.write(chunk)
172 else:
172 else:
173 for chunk, label in chunks:
173 for chunk, label in chunks:
174 ui.write(chunk, label=label)
174 ui.write(chunk, label=label)
175
175
176 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
176 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
177 tempnode2 = node2
177 tempnode2 = node2
178 try:
178 try:
179 if node2 is not None:
179 if node2 is not None:
180 tempnode2 = ctx2.substate[subpath][1]
180 tempnode2 = ctx2.substate[subpath][1]
181 except KeyError:
181 except KeyError:
182 # A subrepo that existed in node1 was deleted between node1 and
182 # A subrepo that existed in node1 was deleted between node1 and
183 # node2 (inclusive). Thus, ctx2's substate won't contain that
183 # node2 (inclusive). Thus, ctx2's substate won't contain that
184 # subpath. The best we can do is to ignore it.
184 # subpath. The best we can do is to ignore it.
185 tempnode2 = None
185 tempnode2 = None
186 submatch = matchmod.subdirmatcher(subpath, match)
186 submatch = matchmod.subdirmatcher(subpath, match)
187 subprefix = repo.wvfs.reljoin(prefix, subpath)
187 subprefix = repo.wvfs.reljoin(prefix, subpath)
188 if listsubrepos or match.exact(subpath) or any(submatch.files()):
188 if listsubrepos or match.exact(subpath) or any(submatch.files()):
189 sub.diff(
189 sub.diff(
190 ui,
190 ui,
191 diffopts,
191 diffopts,
192 tempnode2,
192 tempnode2,
193 submatch,
193 submatch,
194 changes=changes,
194 changes=changes,
195 stat=stat,
195 stat=stat,
196 fp=fp,
196 fp=fp,
197 prefix=subprefix,
197 prefix=subprefix,
198 )
198 )
199
199
200
200
201 class changesetdiffer(object):
201 class changesetdiffer(object):
202 """Generate diff of changeset with pre-configured filtering functions"""
202 """Generate diff of changeset with pre-configured filtering functions"""
203
203
204 def _makefilematcher(self, ctx):
204 def _makefilematcher(self, ctx):
205 return scmutil.matchall(ctx.repo())
205 return scmutil.matchall(ctx.repo())
206
206
207 def _makehunksfilter(self, ctx):
207 def _makehunksfilter(self, ctx):
208 return None
208 return None
209
209
210 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
210 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
211 repo = ctx.repo()
211 repo = ctx.repo()
212 node = ctx.node()
212 node = ctx.node()
213 prev = ctx.p1().node()
213 prev = ctx.p1().node()
214 diffordiffstat(
214 diffordiffstat(
215 ui,
215 ui,
216 repo,
216 repo,
217 diffopts,
217 diffopts,
218 prev,
218 prev,
219 node,
219 node,
220 match=self._makefilematcher(ctx),
220 match=self._makefilematcher(ctx),
221 stat=stat,
221 stat=stat,
222 graphwidth=graphwidth,
222 graphwidth=graphwidth,
223 hunksfilterfn=self._makehunksfilter(ctx),
223 hunksfilterfn=self._makehunksfilter(ctx),
224 )
224 )
225
225
226
226
227 def changesetlabels(ctx):
227 def changesetlabels(ctx):
228 labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()]
228 labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()]
229 if ctx.obsolete():
229 if ctx.obsolete():
230 labels.append(b'changeset.obsolete')
230 labels.append(b'changeset.obsolete')
231 if ctx.isunstable():
231 if ctx.isunstable():
232 labels.append(b'changeset.unstable')
232 labels.append(b'changeset.unstable')
233 for instability in ctx.instabilities():
233 for instability in ctx.instabilities():
234 labels.append(b'instability.%s' % instability)
234 labels.append(b'instability.%s' % instability)
235 return b' '.join(labels)
235 return b' '.join(labels)
236
236
237
237
238 class changesetprinter(object):
238 class changesetprinter(object):
239 '''show changeset information when templating not requested.'''
239 '''show changeset information when templating not requested.'''
240
240
241 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
241 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
242 self.ui = ui
242 self.ui = ui
243 self.repo = repo
243 self.repo = repo
244 self.buffered = buffered
244 self.buffered = buffered
245 self._differ = differ or changesetdiffer()
245 self._differ = differ or changesetdiffer()
246 self._diffopts = patch.diffallopts(ui, diffopts)
246 self._diffopts = patch.diffallopts(ui, diffopts)
247 self._includestat = diffopts and diffopts.get(b'stat')
247 self._includestat = diffopts and diffopts.get(b'stat')
248 self._includediff = diffopts and diffopts.get(b'patch')
248 self._includediff = diffopts and diffopts.get(b'patch')
249 self.header = {}
249 self.header = {}
250 self.hunk = {}
250 self.hunk = {}
251 self.lastheader = None
251 self.lastheader = None
252 self.footer = None
252 self.footer = None
253 self._columns = templatekw.getlogcolumns()
253 self._columns = templatekw.getlogcolumns()
254
254
255 def flush(self, ctx):
255 def flush(self, ctx):
256 rev = ctx.rev()
256 rev = ctx.rev()
257 if rev in self.header:
257 if rev in self.header:
258 h = self.header[rev]
258 h = self.header[rev]
259 if h != self.lastheader:
259 if h != self.lastheader:
260 self.lastheader = h
260 self.lastheader = h
261 self.ui.write(h)
261 self.ui.write(h)
262 del self.header[rev]
262 del self.header[rev]
263 if rev in self.hunk:
263 if rev in self.hunk:
264 self.ui.write(self.hunk[rev])
264 self.ui.write(self.hunk[rev])
265 del self.hunk[rev]
265 del self.hunk[rev]
266
266
267 def close(self):
267 def close(self):
268 if self.footer:
268 if self.footer:
269 self.ui.write(self.footer)
269 self.ui.write(self.footer)
270
270
271 def show(self, ctx, copies=None, **props):
271 def show(self, ctx, copies=None, **props):
272 props = pycompat.byteskwargs(props)
272 props = pycompat.byteskwargs(props)
273 if self.buffered:
273 if self.buffered:
274 self.ui.pushbuffer(labeled=True)
274 self.ui.pushbuffer(labeled=True)
275 self._show(ctx, copies, props)
275 self._show(ctx, copies, props)
276 self.hunk[ctx.rev()] = self.ui.popbuffer()
276 self.hunk[ctx.rev()] = self.ui.popbuffer()
277 else:
277 else:
278 self._show(ctx, copies, props)
278 self._show(ctx, copies, props)
279
279
280 def _show(self, ctx, copies, props):
280 def _show(self, ctx, copies, props):
281 '''show a single changeset or file revision'''
281 '''show a single changeset or file revision'''
282 changenode = ctx.node()
282 changenode = ctx.node()
283 graphwidth = props.get(b'graphwidth', 0)
283 graphwidth = props.get(b'graphwidth', 0)
284
284
285 if self.ui.quiet:
285 if self.ui.quiet:
286 self.ui.write(
286 self.ui.write(
287 b"%s\n" % scmutil.formatchangeid(ctx), label=b'log.node'
287 b"%s\n" % scmutil.formatchangeid(ctx), label=b'log.node'
288 )
288 )
289 return
289 return
290
290
291 columns = self._columns
291 columns = self._columns
292 self.ui.write(
292 self.ui.write(
293 columns[b'changeset'] % scmutil.formatchangeid(ctx),
293 columns[b'changeset'] % scmutil.formatchangeid(ctx),
294 label=changesetlabels(ctx),
294 label=changesetlabels(ctx),
295 )
295 )
296
296
297 # branches are shown first before any other names due to backwards
297 # branches are shown first before any other names due to backwards
298 # compatibility
298 # compatibility
299 branch = ctx.branch()
299 branch = ctx.branch()
300 # don't show the default branch name
300 # don't show the default branch name
301 if branch != b'default':
301 if branch != b'default':
302 self.ui.write(columns[b'branch'] % branch, label=b'log.branch')
302 self.ui.write(columns[b'branch'] % branch, label=b'log.branch')
303
303
304 for nsname, ns in pycompat.iteritems(self.repo.names):
304 for nsname, ns in pycompat.iteritems(self.repo.names):
305 # branches has special logic already handled above, so here we just
305 # branches has special logic already handled above, so here we just
306 # skip it
306 # skip it
307 if nsname == b'branches':
307 if nsname == b'branches':
308 continue
308 continue
309 # we will use the templatename as the color name since those two
309 # we will use the templatename as the color name since those two
310 # should be the same
310 # should be the same
311 for name in ns.names(self.repo, changenode):
311 for name in ns.names(self.repo, changenode):
312 self.ui.write(ns.logfmt % name, label=b'log.%s' % ns.colorname)
312 self.ui.write(ns.logfmt % name, label=b'log.%s' % ns.colorname)
313 if self.ui.debugflag:
313 if self.ui.debugflag:
314 self.ui.write(
314 self.ui.write(
315 columns[b'phase'] % ctx.phasestr(), label=b'log.phase'
315 columns[b'phase'] % ctx.phasestr(), label=b'log.phase'
316 )
316 )
317 for pctx in scmutil.meaningfulparents(self.repo, ctx):
317 for pctx in scmutil.meaningfulparents(self.repo, ctx):
318 label = b'log.parent changeset.%s' % pctx.phasestr()
318 label = b'log.parent changeset.%s' % pctx.phasestr()
319 self.ui.write(
319 self.ui.write(
320 columns[b'parent'] % scmutil.formatchangeid(pctx), label=label
320 columns[b'parent'] % scmutil.formatchangeid(pctx), label=label
321 )
321 )
322
322
323 if self.ui.debugflag:
323 if self.ui.debugflag:
324 mnode = ctx.manifestnode()
324 mnode = ctx.manifestnode()
325 if mnode is None:
325 if mnode is None:
326 mnode = wdirid
326 mnode = wdirid
327 mrev = wdirrev
327 mrev = wdirrev
328 else:
328 else:
329 mrev = self.repo.manifestlog.rev(mnode)
329 mrev = self.repo.manifestlog.rev(mnode)
330 self.ui.write(
330 self.ui.write(
331 columns[b'manifest']
331 columns[b'manifest']
332 % scmutil.formatrevnode(self.ui, mrev, mnode),
332 % scmutil.formatrevnode(self.ui, mrev, mnode),
333 label=b'ui.debug log.manifest',
333 label=b'ui.debug log.manifest',
334 )
334 )
335 self.ui.write(columns[b'user'] % ctx.user(), label=b'log.user')
335 self.ui.write(columns[b'user'] % ctx.user(), label=b'log.user')
336 self.ui.write(
336 self.ui.write(
337 columns[b'date'] % dateutil.datestr(ctx.date()), label=b'log.date'
337 columns[b'date'] % dateutil.datestr(ctx.date()), label=b'log.date'
338 )
338 )
339
339
340 if ctx.isunstable():
340 if ctx.isunstable():
341 instabilities = ctx.instabilities()
341 instabilities = ctx.instabilities()
342 self.ui.write(
342 self.ui.write(
343 columns[b'instability'] % b', '.join(instabilities),
343 columns[b'instability'] % b', '.join(instabilities),
344 label=b'log.instability',
344 label=b'log.instability',
345 )
345 )
346
346
347 elif ctx.obsolete():
347 elif ctx.obsolete():
348 self._showobsfate(ctx)
348 self._showobsfate(ctx)
349
349
350 self._exthook(ctx)
350 self._exthook(ctx)
351
351
352 if self.ui.debugflag:
352 if self.ui.debugflag:
353 files = ctx.p1().status(ctx)
353 files = ctx.p1().status(ctx)
354 for key, value in zip(
354 for key, value in zip(
355 [b'files', b'files+', b'files-'],
355 [b'files', b'files+', b'files-'],
356 [files.modified, files.added, files.removed],
356 [files.modified, files.added, files.removed],
357 ):
357 ):
358 if value:
358 if value:
359 self.ui.write(
359 self.ui.write(
360 columns[key] % b" ".join(value),
360 columns[key] % b" ".join(value),
361 label=b'ui.debug log.files',
361 label=b'ui.debug log.files',
362 )
362 )
363 elif ctx.files() and self.ui.verbose:
363 elif ctx.files() and self.ui.verbose:
364 self.ui.write(
364 self.ui.write(
365 columns[b'files'] % b" ".join(ctx.files()),
365 columns[b'files'] % b" ".join(ctx.files()),
366 label=b'ui.note log.files',
366 label=b'ui.note log.files',
367 )
367 )
368 if copies and self.ui.verbose:
368 if copies and self.ui.verbose:
369 copies = [b'%s (%s)' % c for c in copies]
369 copies = [b'%s (%s)' % c for c in copies]
370 self.ui.write(
370 self.ui.write(
371 columns[b'copies'] % b' '.join(copies),
371 columns[b'copies'] % b' '.join(copies),
372 label=b'ui.note log.copies',
372 label=b'ui.note log.copies',
373 )
373 )
374
374
375 extra = ctx.extra()
375 extra = ctx.extra()
376 if extra and self.ui.debugflag:
376 if extra and self.ui.debugflag:
377 for key, value in sorted(extra.items()):
377 for key, value in sorted(extra.items()):
378 self.ui.write(
378 self.ui.write(
379 columns[b'extra'] % (key, stringutil.escapestr(value)),
379 columns[b'extra'] % (key, stringutil.escapestr(value)),
380 label=b'ui.debug log.extra',
380 label=b'ui.debug log.extra',
381 )
381 )
382
382
383 description = ctx.description().strip()
383 description = ctx.description().strip()
384 if description:
384 if description:
385 if self.ui.verbose:
385 if self.ui.verbose:
386 self.ui.write(
386 self.ui.write(
387 _(b"description:\n"), label=b'ui.note log.description'
387 _(b"description:\n"), label=b'ui.note log.description'
388 )
388 )
389 self.ui.write(description, label=b'ui.note log.description')
389 self.ui.write(description, label=b'ui.note log.description')
390 self.ui.write(b"\n\n")
390 self.ui.write(b"\n\n")
391 else:
391 else:
392 self.ui.write(
392 self.ui.write(
393 columns[b'summary'] % description.splitlines()[0],
393 columns[b'summary'] % description.splitlines()[0],
394 label=b'log.summary',
394 label=b'log.summary',
395 )
395 )
396 self.ui.write(b"\n")
396 self.ui.write(b"\n")
397
397
398 self._showpatch(ctx, graphwidth)
398 self._showpatch(ctx, graphwidth)
399
399
400 def _showobsfate(self, ctx):
400 def _showobsfate(self, ctx):
401 # TODO: do not depend on templater
401 # TODO: do not depend on templater
402 tres = formatter.templateresources(self.repo.ui, self.repo)
402 tres = formatter.templateresources(self.repo.ui, self.repo)
403 t = formatter.maketemplater(
403 t = formatter.maketemplater(
404 self.repo.ui,
404 self.repo.ui,
405 b'{join(obsfate, "\n")}',
405 b'{join(obsfate, "\n")}',
406 defaults=templatekw.keywords,
406 defaults=templatekw.keywords,
407 resources=tres,
407 resources=tres,
408 )
408 )
409 obsfate = t.renderdefault({b'ctx': ctx}).splitlines()
409 obsfate = t.renderdefault({b'ctx': ctx}).splitlines()
410
410
411 if obsfate:
411 if obsfate:
412 for obsfateline in obsfate:
412 for obsfateline in obsfate:
413 self.ui.write(
413 self.ui.write(
414 self._columns[b'obsolete'] % obsfateline,
414 self._columns[b'obsolete'] % obsfateline,
415 label=b'log.obsfate',
415 label=b'log.obsfate',
416 )
416 )
417
417
418 def _exthook(self, ctx):
418 def _exthook(self, ctx):
419 '''empty method used by extension as a hook point
419 '''empty method used by extension as a hook point
420 '''
420 '''
421
421
422 def _showpatch(self, ctx, graphwidth=0):
422 def _showpatch(self, ctx, graphwidth=0):
423 if self._includestat:
423 if self._includestat:
424 self._differ.showdiff(
424 self._differ.showdiff(
425 self.ui, ctx, self._diffopts, graphwidth, stat=True
425 self.ui, ctx, self._diffopts, graphwidth, stat=True
426 )
426 )
427 if self._includestat and self._includediff:
427 if self._includestat and self._includediff:
428 self.ui.write(b"\n")
428 self.ui.write(b"\n")
429 if self._includediff:
429 if self._includediff:
430 self._differ.showdiff(
430 self._differ.showdiff(
431 self.ui, ctx, self._diffopts, graphwidth, stat=False
431 self.ui, ctx, self._diffopts, graphwidth, stat=False
432 )
432 )
433 if self._includestat or self._includediff:
433 if self._includestat or self._includediff:
434 self.ui.write(b"\n")
434 self.ui.write(b"\n")
435
435
436
436
437 class changesetformatter(changesetprinter):
437 class changesetformatter(changesetprinter):
438 """Format changeset information by generic formatter"""
438 """Format changeset information by generic formatter"""
439
439
440 def __init__(
440 def __init__(
441 self, ui, repo, fm, differ=None, diffopts=None, buffered=False
441 self, ui, repo, fm, differ=None, diffopts=None, buffered=False
442 ):
442 ):
443 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
443 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
444 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
444 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
445 self._fm = fm
445 self._fm = fm
446
446
447 def close(self):
447 def close(self):
448 self._fm.end()
448 self._fm.end()
449
449
450 def _show(self, ctx, copies, props):
450 def _show(self, ctx, copies, props):
451 '''show a single changeset or file revision'''
451 '''show a single changeset or file revision'''
452 fm = self._fm
452 fm = self._fm
453 fm.startitem()
453 fm.startitem()
454 fm.context(ctx=ctx)
454 fm.context(ctx=ctx)
455 fm.data(rev=scmutil.intrev(ctx), node=fm.hexfunc(scmutil.binnode(ctx)))
455 fm.data(rev=scmutil.intrev(ctx), node=fm.hexfunc(scmutil.binnode(ctx)))
456
456
457 datahint = fm.datahint()
457 datahint = fm.datahint()
458 if self.ui.quiet and not datahint:
458 if self.ui.quiet and not datahint:
459 return
459 return
460
460
461 fm.data(
461 fm.data(
462 branch=ctx.branch(),
462 branch=ctx.branch(),
463 phase=ctx.phasestr(),
463 phase=ctx.phasestr(),
464 user=ctx.user(),
464 user=ctx.user(),
465 date=fm.formatdate(ctx.date()),
465 date=fm.formatdate(ctx.date()),
466 desc=ctx.description(),
466 desc=ctx.description(),
467 bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'),
467 bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'),
468 tags=fm.formatlist(ctx.tags(), name=b'tag'),
468 tags=fm.formatlist(ctx.tags(), name=b'tag'),
469 parents=fm.formatlist(
469 parents=fm.formatlist(
470 [fm.hexfunc(c.node()) for c in ctx.parents()], name=b'node'
470 [fm.hexfunc(c.node()) for c in ctx.parents()], name=b'node'
471 ),
471 ),
472 )
472 )
473
473
474 if self.ui.debugflag or b'manifest' in datahint:
474 if self.ui.debugflag or b'manifest' in datahint:
475 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid))
475 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid))
476 if self.ui.debugflag or b'extra' in datahint:
476 if self.ui.debugflag or b'extra' in datahint:
477 fm.data(extra=fm.formatdict(ctx.extra()))
477 fm.data(extra=fm.formatdict(ctx.extra()))
478
478
479 if (
479 if (
480 self.ui.debugflag
480 self.ui.debugflag
481 or b'modified' in datahint
481 or b'modified' in datahint
482 or b'added' in datahint
482 or b'added' in datahint
483 or b'removed' in datahint
483 or b'removed' in datahint
484 ):
484 ):
485 files = ctx.p1().status(ctx)
485 files = ctx.p1().status(ctx)
486 fm.data(
486 fm.data(
487 modified=fm.formatlist(files.modified, name=b'file'),
487 modified=fm.formatlist(files.modified, name=b'file'),
488 added=fm.formatlist(files.added, name=b'file'),
488 added=fm.formatlist(files.added, name=b'file'),
489 removed=fm.formatlist(files.removed, name=b'file'),
489 removed=fm.formatlist(files.removed, name=b'file'),
490 )
490 )
491
491
492 verbose = not self.ui.debugflag and self.ui.verbose
492 verbose = not self.ui.debugflag and self.ui.verbose
493 if verbose or b'files' in datahint:
493 if verbose or b'files' in datahint:
494 fm.data(files=fm.formatlist(ctx.files(), name=b'file'))
494 fm.data(files=fm.formatlist(ctx.files(), name=b'file'))
495 if verbose and copies or b'copies' in datahint:
495 if verbose and copies or b'copies' in datahint:
496 fm.data(
496 fm.data(
497 copies=fm.formatdict(copies or {}, key=b'name', value=b'source')
497 copies=fm.formatdict(copies or {}, key=b'name', value=b'source')
498 )
498 )
499
499
500 if self._includestat or b'diffstat' in datahint:
500 if self._includestat or b'diffstat' in datahint:
501 self.ui.pushbuffer()
501 self.ui.pushbuffer()
502 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
502 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
503 fm.data(diffstat=self.ui.popbuffer())
503 fm.data(diffstat=self.ui.popbuffer())
504 if self._includediff or b'diff' in datahint:
504 if self._includediff or b'diff' in datahint:
505 self.ui.pushbuffer()
505 self.ui.pushbuffer()
506 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
506 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
507 fm.data(diff=self.ui.popbuffer())
507 fm.data(diff=self.ui.popbuffer())
508
508
509
509
510 class changesettemplater(changesetprinter):
510 class changesettemplater(changesetprinter):
511 '''format changeset information.
511 '''format changeset information.
512
512
513 Note: there are a variety of convenience functions to build a
513 Note: there are a variety of convenience functions to build a
514 changesettemplater for common cases. See functions such as:
514 changesettemplater for common cases. See functions such as:
515 maketemplater, changesetdisplayer, buildcommittemplate, or other
515 maketemplater, changesetdisplayer, buildcommittemplate, or other
516 functions that use changesest_templater.
516 functions that use changesest_templater.
517 '''
517 '''
518
518
519 # Arguments before "buffered" used to be positional. Consider not
519 # Arguments before "buffered" used to be positional. Consider not
520 # adding/removing arguments before "buffered" to not break callers.
520 # adding/removing arguments before "buffered" to not break callers.
521 def __init__(
521 def __init__(
522 self, ui, repo, tmplspec, differ=None, diffopts=None, buffered=False
522 self, ui, repo, tmplspec, differ=None, diffopts=None, buffered=False
523 ):
523 ):
524 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
524 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
525 # tres is shared with _graphnodeformatter()
525 # tres is shared with _graphnodeformatter()
526 self._tresources = tres = formatter.templateresources(ui, repo)
526 self._tresources = tres = formatter.templateresources(ui, repo)
527 self.t = formatter.loadtemplater(
527 self.t = formatter.loadtemplater(
528 ui,
528 ui,
529 tmplspec,
529 tmplspec,
530 defaults=templatekw.keywords,
530 defaults=templatekw.keywords,
531 resources=tres,
531 resources=tres,
532 cache=templatekw.defaulttempl,
532 cache=templatekw.defaulttempl,
533 )
533 )
534 self._counter = itertools.count()
534 self._counter = itertools.count()
535
535
536 self._tref = tmplspec.ref
536 self._tref = tmplspec.ref
537 self._parts = {
537 self._parts = {
538 b'header': b'',
538 b'header': b'',
539 b'footer': b'',
539 b'footer': b'',
540 tmplspec.ref: tmplspec.ref,
540 tmplspec.ref: tmplspec.ref,
541 b'docheader': b'',
541 b'docheader': b'',
542 b'docfooter': b'',
542 b'docfooter': b'',
543 b'separator': b'',
543 b'separator': b'',
544 }
544 }
545 if tmplspec.mapfile:
545 if tmplspec.mapfile:
546 # find correct templates for current mode, for backward
546 # find correct templates for current mode, for backward
547 # compatibility with 'log -v/-q/--debug' using a mapfile
547 # compatibility with 'log -v/-q/--debug' using a mapfile
548 tmplmodes = [
548 tmplmodes = [
549 (True, b''),
549 (True, b''),
550 (self.ui.verbose, b'_verbose'),
550 (self.ui.verbose, b'_verbose'),
551 (self.ui.quiet, b'_quiet'),
551 (self.ui.quiet, b'_quiet'),
552 (self.ui.debugflag, b'_debug'),
552 (self.ui.debugflag, b'_debug'),
553 ]
553 ]
554 for mode, postfix in tmplmodes:
554 for mode, postfix in tmplmodes:
555 for t in self._parts:
555 for t in self._parts:
556 cur = t + postfix
556 cur = t + postfix
557 if mode and cur in self.t:
557 if mode and cur in self.t:
558 self._parts[t] = cur
558 self._parts[t] = cur
559 else:
559 else:
560 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
560 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
561 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
561 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
562 self._parts.update(m)
562 self._parts.update(m)
563
563
564 if self._parts[b'docheader']:
564 if self._parts[b'docheader']:
565 self.ui.write(self.t.render(self._parts[b'docheader'], {}))
565 self.ui.write(self.t.render(self._parts[b'docheader'], {}))
566
566
567 def close(self):
567 def close(self):
568 if self._parts[b'docfooter']:
568 if self._parts[b'docfooter']:
569 if not self.footer:
569 if not self.footer:
570 self.footer = b""
570 self.footer = b""
571 self.footer += self.t.render(self._parts[b'docfooter'], {})
571 self.footer += self.t.render(self._parts[b'docfooter'], {})
572 return super(changesettemplater, self).close()
572 return super(changesettemplater, self).close()
573
573
574 def _show(self, ctx, copies, props):
574 def _show(self, ctx, copies, props):
575 '''show a single changeset or file revision'''
575 '''show a single changeset or file revision'''
576 props = props.copy()
576 props = props.copy()
577 props[b'ctx'] = ctx
577 props[b'ctx'] = ctx
578 props[b'index'] = index = next(self._counter)
578 props[b'index'] = index = next(self._counter)
579 props[b'revcache'] = {b'copies': copies}
579 props[b'revcache'] = {b'copies': copies}
580 graphwidth = props.get(b'graphwidth', 0)
580 graphwidth = props.get(b'graphwidth', 0)
581
581
582 # write separator, which wouldn't work well with the header part below
582 # write separator, which wouldn't work well with the header part below
583 # since there's inherently a conflict between header (across items) and
583 # since there's inherently a conflict between header (across items) and
584 # separator (per item)
584 # separator (per item)
585 if self._parts[b'separator'] and index > 0:
585 if self._parts[b'separator'] and index > 0:
586 self.ui.write(self.t.render(self._parts[b'separator'], {}))
586 self.ui.write(self.t.render(self._parts[b'separator'], {}))
587
587
588 # write header
588 # write header
589 if self._parts[b'header']:
589 if self._parts[b'header']:
590 h = self.t.render(self._parts[b'header'], props)
590 h = self.t.render(self._parts[b'header'], props)
591 if self.buffered:
591 if self.buffered:
592 self.header[ctx.rev()] = h
592 self.header[ctx.rev()] = h
593 else:
593 else:
594 if self.lastheader != h:
594 if self.lastheader != h:
595 self.lastheader = h
595 self.lastheader = h
596 self.ui.write(h)
596 self.ui.write(h)
597
597
598 # write changeset metadata, then patch if requested
598 # write changeset metadata, then patch if requested
599 key = self._parts[self._tref]
599 key = self._parts[self._tref]
600 self.ui.write(self.t.render(key, props))
600 self.ui.write(self.t.render(key, props))
601 self._exthook(ctx)
601 self._exthook(ctx)
602 self._showpatch(ctx, graphwidth)
602 self._showpatch(ctx, graphwidth)
603
603
604 if self._parts[b'footer']:
604 if self._parts[b'footer']:
605 if not self.footer:
605 if not self.footer:
606 self.footer = self.t.render(self._parts[b'footer'], props)
606 self.footer = self.t.render(self._parts[b'footer'], props)
607
607
608
608
609 def templatespec(tmpl, mapfile):
609 def templatespec(tmpl, mapfile):
610 if pycompat.ispy3:
610 if pycompat.ispy3:
611 assert not isinstance(tmpl, str), b'tmpl must not be a str'
611 assert not isinstance(tmpl, str), b'tmpl must not be a str'
612 if mapfile:
612 if mapfile:
613 return formatter.templatespec(b'changeset', tmpl, mapfile)
613 return formatter.templatespec(b'changeset', tmpl, mapfile)
614 else:
614 else:
615 return formatter.templatespec(b'', tmpl, None)
615 return formatter.templatespec(b'', tmpl, None)
616
616
617
617
618 def _lookuptemplate(ui, tmpl, style):
618 def _lookuptemplate(ui, tmpl, style):
619 """Find the template matching the given template spec or style
619 """Find the template matching the given template spec or style
620
620
621 See formatter.lookuptemplate() for details.
621 See formatter.lookuptemplate() for details.
622 """
622 """
623
623
624 # ui settings
624 # ui settings
625 if not tmpl and not style: # template are stronger than style
625 if not tmpl and not style: # template are stronger than style
626 tmpl = ui.config(b'ui', b'logtemplate')
626 tmpl = ui.config(b'ui', b'logtemplate')
627 if tmpl:
627 if tmpl:
628 return templatespec(templater.unquotestring(tmpl), None)
628 return templatespec(templater.unquotestring(tmpl), None)
629 else:
629 else:
630 style = util.expandpath(ui.config(b'ui', b'style'))
630 style = util.expandpath(ui.config(b'ui', b'style'))
631
631
632 if not tmpl and style:
632 if not tmpl and style:
633 mapfile = style
633 mapfile = style
634 if not os.path.split(mapfile)[0]:
634 if not os.path.split(mapfile)[0]:
635 mapname = templater.templatepath(
635 mapname = templater.templatepath(
636 b'map-cmdline.' + mapfile
636 b'map-cmdline.' + mapfile
637 ) or templater.templatepath(mapfile)
637 ) or templater.templatepath(mapfile)
638 if mapname:
638 if mapname:
639 mapfile = mapname
639 mapfile = mapname
640 return templatespec(None, mapfile)
640 return templatespec(None, mapfile)
641
641
642 return formatter.lookuptemplate(ui, b'changeset', tmpl)
642 return formatter.lookuptemplate(ui, b'changeset', tmpl)
643
643
644
644
645 def maketemplater(ui, repo, tmpl, buffered=False):
645 def maketemplater(ui, repo, tmpl, buffered=False):
646 """Create a changesettemplater from a literal template 'tmpl'
646 """Create a changesettemplater from a literal template 'tmpl'
647 byte-string."""
647 byte-string."""
648 spec = templatespec(tmpl, None)
648 spec = templatespec(tmpl, None)
649 return changesettemplater(ui, repo, spec, buffered=buffered)
649 return changesettemplater(ui, repo, spec, buffered=buffered)
650
650
651
651
652 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
652 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
653 """show one changeset using template or regular display.
653 """show one changeset using template or regular display.
654
654
655 Display format will be the first non-empty hit of:
655 Display format will be the first non-empty hit of:
656 1. option 'template'
656 1. option 'template'
657 2. option 'style'
657 2. option 'style'
658 3. [ui] setting 'logtemplate'
658 3. [ui] setting 'logtemplate'
659 4. [ui] setting 'style'
659 4. [ui] setting 'style'
660 If all of these values are either the unset or the empty string,
660 If all of these values are either the unset or the empty string,
661 regular display via changesetprinter() is done.
661 regular display via changesetprinter() is done.
662 """
662 """
663 postargs = (differ, opts, buffered)
663 postargs = (differ, opts, buffered)
664 spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
664 spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
665
665
666 # machine-readable formats have slightly different keyword set than
666 # machine-readable formats have slightly different keyword set than
667 # plain templates, which are handled by changesetformatter.
667 # plain templates, which are handled by changesetformatter.
668 # note that {b'pickle', b'debug'} can also be added to the list if needed.
668 # note that {b'pickle', b'debug'} can also be added to the list if needed.
669 if spec.ref in {b'cbor', b'json'}:
669 if spec.ref in {b'cbor', b'json'}:
670 fm = ui.formatter(b'log', opts)
670 fm = ui.formatter(b'log', opts)
671 return changesetformatter(ui, repo, fm, *postargs)
671 return changesetformatter(ui, repo, fm, *postargs)
672
672
673 if not spec.ref and not spec.tmpl and not spec.mapfile:
673 if not spec.ref and not spec.tmpl and not spec.mapfile:
674 return changesetprinter(ui, repo, *postargs)
674 return changesetprinter(ui, repo, *postargs)
675
675
676 return changesettemplater(ui, repo, spec, *postargs)
676 return changesettemplater(ui, repo, spec, *postargs)
677
677
678
678
679 def _makematcher(repo, revs, pats, opts):
679 def _makematcher(repo, revs, pats, opts):
680 """Build matcher and expanded patterns from log options
680 """Build matcher and expanded patterns from log options
681
681
682 If --follow, revs are the revisions to follow from.
682 If --follow, revs are the revisions to follow from.
683
683
684 Returns (match, pats, slowpath) where
684 Returns (match, pats, slowpath) where
685 - match: a matcher built from the given pats and -I/-X opts
685 - match: a matcher built from the given pats and -I/-X opts
686 - pats: patterns used (globs are expanded on Windows)
686 - pats: patterns used (globs are expanded on Windows)
687 - slowpath: True if patterns aren't as simple as scanning filelogs
687 - slowpath: True if patterns aren't as simple as scanning filelogs
688 """
688 """
689 # pats/include/exclude are passed to match.match() directly in
689 # pats/include/exclude are passed to match.match() directly in
690 # _matchfiles() revset but walkchangerevs() builds its matcher with
690 # _matchfiles() revset but walkchangerevs() builds its matcher with
691 # scmutil.match(). The difference is input pats are globbed on
691 # scmutil.match(). The difference is input pats are globbed on
692 # platforms without shell expansion (windows).
692 # platforms without shell expansion (windows).
693 wctx = repo[None]
693 wctx = repo[None]
694 match, pats = scmutil.matchandpats(wctx, pats, opts)
694 match, pats = scmutil.matchandpats(wctx, pats, opts)
695 slowpath = match.anypats() or (not match.always() and opts.get(b'removed'))
695 slowpath = match.anypats() or (not match.always() and opts.get(b'removed'))
696 if not slowpath:
696 if not slowpath:
697 follow = opts.get(b'follow') or opts.get(b'follow_first')
697 follow = opts.get(b'follow') or opts.get(b'follow_first')
698 startctxs = []
698 startctxs = []
699 if follow and opts.get(b'rev'):
699 if follow and opts.get(b'rev'):
700 startctxs = [repo[r] for r in revs]
700 startctxs = [repo[r] for r in revs]
701 for f in match.files():
701 for f in match.files():
702 if follow and startctxs:
702 if follow and startctxs:
703 # No idea if the path was a directory at that revision, so
703 # No idea if the path was a directory at that revision, so
704 # take the slow path.
704 # take the slow path.
705 if any(f not in c for c in startctxs):
705 if any(f not in c for c in startctxs):
706 slowpath = True
706 slowpath = True
707 continue
707 continue
708 elif follow and f not in wctx:
708 elif follow and f not in wctx:
709 # If the file exists, it may be a directory, so let it
709 # If the file exists, it may be a directory, so let it
710 # take the slow path.
710 # take the slow path.
711 if os.path.exists(repo.wjoin(f)):
711 if os.path.exists(repo.wjoin(f)):
712 slowpath = True
712 slowpath = True
713 continue
713 continue
714 else:
714 else:
715 raise error.Abort(
715 raise error.Abort(
716 _(
716 _(
717 b'cannot follow file not in parent '
717 b'cannot follow file not in parent '
718 b'revision: "%s"'
718 b'revision: "%s"'
719 )
719 )
720 % f
720 % f
721 )
721 )
722 filelog = repo.file(f)
722 filelog = repo.file(f)
723 if not filelog:
723 if not filelog:
724 # A zero count may be a directory or deleted file, so
724 # A zero count may be a directory or deleted file, so
725 # try to find matching entries on the slow path.
725 # try to find matching entries on the slow path.
726 if follow:
726 if follow:
727 raise error.Abort(
727 raise error.Abort(
728 _(b'cannot follow nonexistent file: "%s"') % f
728 _(b'cannot follow nonexistent file: "%s"') % f
729 )
729 )
730 slowpath = True
730 slowpath = True
731
731
732 # We decided to fall back to the slowpath because at least one
732 # We decided to fall back to the slowpath because at least one
733 # of the paths was not a file. Check to see if at least one of them
733 # of the paths was not a file. Check to see if at least one of them
734 # existed in history - in that case, we'll continue down the
734 # existed in history - in that case, we'll continue down the
735 # slowpath; otherwise, we can turn off the slowpath
735 # slowpath; otherwise, we can turn off the slowpath
736 if slowpath:
736 if slowpath:
737 for path in match.files():
737 for path in match.files():
738 if path == b'.' or path in repo.store:
738 if path == b'.' or path in repo.store:
739 break
739 break
740 else:
740 else:
741 slowpath = False
741 slowpath = False
742
742
743 return match, pats, slowpath
743 return match, pats, slowpath
744
744
745
745
746 def _fileancestors(repo, revs, match, followfirst):
746 def _fileancestors(repo, revs, match, followfirst):
747 fctxs = []
747 fctxs = []
748 for r in revs:
748 for r in revs:
749 ctx = repo[r]
749 ctx = repo[r]
750 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
750 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
751
751
752 # When displaying a revision with --patch --follow FILE, we have
752 # When displaying a revision with --patch --follow FILE, we have
753 # to know which file of the revision must be diffed. With
753 # to know which file of the revision must be diffed. With
754 # --follow, we want the names of the ancestors of FILE in the
754 # --follow, we want the names of the ancestors of FILE in the
755 # revision, stored in "fcache". "fcache" is populated as a side effect
755 # revision, stored in "fcache". "fcache" is populated as a side effect
756 # of the graph traversal.
756 # of the graph traversal.
757 fcache = {}
757 fcache = {}
758
758
759 def filematcher(ctx):
759 def filematcher(ctx):
760 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
760 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
761
761
762 def revgen():
762 def revgen():
763 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
763 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
764 fcache[rev] = [c.path() for c in cs]
764 fcache[rev] = [c.path() for c in cs]
765 yield rev
765 yield rev
766
766
767 return smartset.generatorset(revgen(), iterasc=False), filematcher
767 return smartset.generatorset(revgen(), iterasc=False), filematcher
768
768
769
769
770 def _makenofollowfilematcher(repo, pats, opts):
770 def _makenofollowfilematcher(repo, pats, opts):
771 '''hook for extensions to override the filematcher for non-follow cases'''
771 '''hook for extensions to override the filematcher for non-follow cases'''
772 return None
772 return None
773
773
774
774
775 _opt2logrevset = {
775 _opt2logrevset = {
776 b'no_merges': (b'not merge()', None),
776 b'no_merges': (b'not merge()', None),
777 b'only_merges': (b'merge()', None),
777 b'only_merges': (b'merge()', None),
778 b'_matchfiles': (None, b'_matchfiles(%ps)'),
778 b'_matchfiles': (None, b'_matchfiles(%ps)'),
779 b'date': (b'date(%s)', None),
779 b'date': (b'date(%s)', None),
780 b'branch': (b'branch(%s)', b'%lr'),
780 b'branch': (b'branch(%s)', b'%lr'),
781 b'_patslog': (b'filelog(%s)', b'%lr'),
781 b'_patslog': (b'filelog(%s)', b'%lr'),
782 b'keyword': (b'keyword(%s)', b'%lr'),
782 b'keyword': (b'keyword(%s)', b'%lr'),
783 b'prune': (b'ancestors(%s)', b'not %lr'),
783 b'prune': (b'ancestors(%s)', b'not %lr'),
784 b'user': (b'user(%s)', b'%lr'),
784 b'user': (b'user(%s)', b'%lr'),
785 }
785 }
786
786
787
787
788 def _makerevset(repo, match, pats, slowpath, opts):
788 def _makerevset(repo, match, pats, slowpath, opts):
789 """Return a revset string built from log options and file patterns"""
789 """Return a revset string built from log options and file patterns"""
790 opts = dict(opts)
790 opts = dict(opts)
791 # follow or not follow?
791 # follow or not follow?
792 follow = opts.get(b'follow') or opts.get(b'follow_first')
792 follow = opts.get(b'follow') or opts.get(b'follow_first')
793
793
794 # branch and only_branch are really aliases and must be handled at
794 # branch and only_branch are really aliases and must be handled at
795 # the same time
795 # the same time
796 opts[b'branch'] = opts.get(b'branch', []) + opts.get(b'only_branch', [])
796 opts[b'branch'] = opts.get(b'branch', []) + opts.get(b'only_branch', [])
797 opts[b'branch'] = [repo.lookupbranch(b) for b in opts[b'branch']]
797 opts[b'branch'] = [repo.lookupbranch(b) for b in opts[b'branch']]
798
798
799 if slowpath:
799 if slowpath:
800 # See walkchangerevs() slow path.
800 # See walkchangerevs() slow path.
801 #
801 #
802 # pats/include/exclude cannot be represented as separate
802 # pats/include/exclude cannot be represented as separate
803 # revset expressions as their filtering logic applies at file
803 # revset expressions as their filtering logic applies at file
804 # level. For instance "-I a -X b" matches a revision touching
804 # level. For instance "-I a -X b" matches a revision touching
805 # "a" and "b" while "file(a) and not file(b)" does
805 # "a" and "b" while "file(a) and not file(b)" does
806 # not. Besides, filesets are evaluated against the working
806 # not. Besides, filesets are evaluated against the working
807 # directory.
807 # directory.
808 matchargs = [b'r:', b'd:relpath']
808 matchargs = [b'r:', b'd:relpath']
809 for p in pats:
809 for p in pats:
810 matchargs.append(b'p:' + p)
810 matchargs.append(b'p:' + p)
811 for p in opts.get(b'include', []):
811 for p in opts.get(b'include', []):
812 matchargs.append(b'i:' + p)
812 matchargs.append(b'i:' + p)
813 for p in opts.get(b'exclude', []):
813 for p in opts.get(b'exclude', []):
814 matchargs.append(b'x:' + p)
814 matchargs.append(b'x:' + p)
815 opts[b'_matchfiles'] = matchargs
815 opts[b'_matchfiles'] = matchargs
816 elif not follow:
816 elif not follow:
817 opts[b'_patslog'] = list(pats)
817 opts[b'_patslog'] = list(pats)
818
818
819 expr = []
819 expr = []
820 for op, val in sorted(pycompat.iteritems(opts)):
820 for op, val in sorted(pycompat.iteritems(opts)):
821 if not val:
821 if not val:
822 continue
822 continue
823 if op not in _opt2logrevset:
823 if op not in _opt2logrevset:
824 continue
824 continue
825 revop, listop = _opt2logrevset[op]
825 revop, listop = _opt2logrevset[op]
826 if revop and b'%' not in revop:
826 if revop and b'%' not in revop:
827 expr.append(revop)
827 expr.append(revop)
828 elif not listop:
828 elif not listop:
829 expr.append(revsetlang.formatspec(revop, val))
829 expr.append(revsetlang.formatspec(revop, val))
830 else:
830 else:
831 if revop:
831 if revop:
832 val = [revsetlang.formatspec(revop, v) for v in val]
832 val = [revsetlang.formatspec(revop, v) for v in val]
833 expr.append(revsetlang.formatspec(listop, val))
833 expr.append(revsetlang.formatspec(listop, val))
834
834
835 if expr:
835 if expr:
836 expr = b'(' + b' and '.join(expr) + b')'
836 expr = b'(' + b' and '.join(expr) + b')'
837 else:
837 else:
838 expr = None
838 expr = None
839 return expr
839 return expr
840
840
841
841
842 def _initialrevs(repo, opts):
842 def _initialrevs(repo, opts):
843 """Return the initial set of revisions to be filtered or followed"""
843 """Return the initial set of revisions to be filtered or followed"""
844 follow = opts.get(b'follow') or opts.get(b'follow_first')
844 follow = opts.get(b'follow') or opts.get(b'follow_first')
845 if opts.get(b'rev'):
845 if opts.get(b'rev'):
846 revs = scmutil.revrange(repo, opts[b'rev'])
846 revs = scmutil.revrange(repo, opts[b'rev'])
847 elif follow and repo.dirstate.p1() == nullid:
847 elif follow and repo.dirstate.p1() == nullid:
848 revs = smartset.baseset()
848 revs = smartset.baseset()
849 elif follow:
849 elif follow:
850 revs = repo.revs(b'.')
850 revs = repo.revs(b'.')
851 else:
851 else:
852 revs = smartset.spanset(repo)
852 revs = smartset.spanset(repo)
853 revs.reverse()
853 revs.reverse()
854 return revs
854 return revs
855
855
856
856
857 def getrevs(repo, pats, opts):
857 def getrevs(repo, pats, opts):
858 # type: (Any, Any, Any) -> Tuple[smartset.abstractsmartset, Optional[changesetdiffer]]
858 # type: (Any, Any, Any) -> Tuple[smartset.abstractsmartset, Optional[changesetdiffer]]
859 """Return (revs, differ) where revs is a smartset
859 """Return (revs, differ) where revs is a smartset
860
860
861 differ is a changesetdiffer with pre-configured file matcher.
861 differ is a changesetdiffer with pre-configured file matcher.
862 """
862 """
863 follow = opts.get(b'follow') or opts.get(b'follow_first')
863 follow = opts.get(b'follow') or opts.get(b'follow_first')
864 followfirst = opts.get(b'follow_first')
864 followfirst = opts.get(b'follow_first')
865 limit = getlimit(opts)
865 limit = getlimit(opts)
866 revs = _initialrevs(repo, opts)
866 revs = _initialrevs(repo, opts)
867 if not revs:
867 if not revs:
868 return smartset.baseset(), None
868 return smartset.baseset(), None
869 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
869 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
870 filematcher = None
870 filematcher = None
871 if follow:
871 if follow:
872 if slowpath or match.always():
872 if slowpath or match.always():
873 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
873 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
874 else:
874 else:
875 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
875 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
876 revs.reverse()
876 revs.reverse()
877 if filematcher is None:
877 if filematcher is None:
878 filematcher = _makenofollowfilematcher(repo, pats, opts)
878 filematcher = _makenofollowfilematcher(repo, pats, opts)
879 if filematcher is None:
879 if filematcher is None:
880
880
881 def filematcher(ctx):
881 def filematcher(ctx):
882 return match
882 return match
883
883
884 expr = _makerevset(repo, match, pats, slowpath, opts)
884 expr = _makerevset(repo, match, pats, slowpath, opts)
885 if opts.get(b'graph'):
885 if opts.get(b'graph'):
886 # User-specified revs might be unsorted, but don't sort before
886 # User-specified revs might be unsorted, but don't sort before
887 # _makerevset because it might depend on the order of revs
887 # _makerevset because it might depend on the order of revs
888 if repo.ui.configbool(b'experimental', b'log.topo'):
888 if repo.ui.configbool(b'experimental', b'log.topo'):
889 if not revs.istopo():
889 if not revs.istopo():
890 revs = dagop.toposort(revs, repo.changelog.parentrevs)
890 revs = dagop.toposort(revs, repo.changelog.parentrevs)
891 # TODO: try to iterate the set lazily
891 # TODO: try to iterate the set lazily
892 revs = revset.baseset(list(revs), istopo=True)
892 revs = revset.baseset(list(revs), istopo=True)
893 elif not (revs.isdescending() or revs.istopo()):
893 elif not (revs.isdescending() or revs.istopo()):
894 revs.sort(reverse=True)
894 revs.sort(reverse=True)
895 if expr:
895 if expr:
896 matcher = revset.match(None, expr)
896 matcher = revset.match(None, expr)
897 revs = matcher(repo, revs)
897 revs = matcher(repo, revs)
898 if limit is not None:
898 if limit is not None:
899 revs = revs.slice(0, limit)
899 revs = revs.slice(0, limit)
900
900
901 differ = changesetdiffer()
901 differ = changesetdiffer()
902 differ._makefilematcher = filematcher
902 differ._makefilematcher = filematcher
903 return revs, differ
903 return revs, differ
904
904
905
905
906 def _parselinerangeopt(repo, opts):
906 def _parselinerangeopt(repo, opts):
907 """Parse --line-range log option and return a list of tuples (filename,
907 """Parse --line-range log option and return a list of tuples (filename,
908 (fromline, toline)).
908 (fromline, toline)).
909 """
909 """
910 linerangebyfname = []
910 linerangebyfname = []
911 for pat in opts.get(b'line_range', []):
911 for pat in opts.get(b'line_range', []):
912 try:
912 try:
913 pat, linerange = pat.rsplit(b',', 1)
913 pat, linerange = pat.rsplit(b',', 1)
914 except ValueError:
914 except ValueError:
915 raise error.Abort(_(b'malformatted line-range pattern %s') % pat)
915 raise error.Abort(_(b'malformatted line-range pattern %s') % pat)
916 try:
916 try:
917 fromline, toline = map(int, linerange.split(b':'))
917 fromline, toline = map(int, linerange.split(b':'))
918 except ValueError:
918 except ValueError:
919 raise error.Abort(_(b"invalid line range for %s") % pat)
919 raise error.Abort(_(b"invalid line range for %s") % pat)
920 msg = _(b"line range pattern '%s' must match exactly one file") % pat
920 msg = _(b"line range pattern '%s' must match exactly one file") % pat
921 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
921 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
922 linerangebyfname.append(
922 linerangebyfname.append(
923 (fname, util.processlinerange(fromline, toline))
923 (fname, util.processlinerange(fromline, toline))
924 )
924 )
925 return linerangebyfname
925 return linerangebyfname
926
926
927
927
928 def getlinerangerevs(repo, userrevs, opts):
928 def getlinerangerevs(repo, userrevs, opts):
929 """Return (revs, differ).
929 """Return (revs, differ).
930
930
931 "revs" are revisions obtained by processing "line-range" log options and
931 "revs" are revisions obtained by processing "line-range" log options and
932 walking block ancestors of each specified file/line-range.
932 walking block ancestors of each specified file/line-range.
933
933
934 "differ" is a changesetdiffer with pre-configured file matcher and hunks
934 "differ" is a changesetdiffer with pre-configured file matcher and hunks
935 filter.
935 filter.
936 """
936 """
937 wctx = repo[None]
937 wctx = repo[None]
938
938
939 # Two-levels map of "rev -> file ctx -> [line range]".
939 # Two-levels map of "rev -> file ctx -> [line range]".
940 linerangesbyrev = {}
940 linerangesbyrev = {}
941 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
941 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
942 if fname not in wctx:
942 if fname not in wctx:
943 raise error.Abort(
943 raise error.Abort(
944 _(b'cannot follow file not in parent revision: "%s"') % fname
944 _(b'cannot follow file not in parent revision: "%s"') % fname
945 )
945 )
946 fctx = wctx.filectx(fname)
946 fctx = wctx.filectx(fname)
947 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
947 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
948 rev = fctx.introrev()
948 rev = fctx.introrev()
949 if rev is None:
949 if rev is None:
950 rev = wdirrev
950 rev = wdirrev
951 if rev not in userrevs:
951 if rev not in userrevs:
952 continue
952 continue
953 linerangesbyrev.setdefault(rev, {}).setdefault(
953 linerangesbyrev.setdefault(rev, {}).setdefault(
954 fctx.path(), []
954 fctx.path(), []
955 ).append(linerange)
955 ).append(linerange)
956
956
957 def nofilterhunksfn(fctx, hunks):
957 def nofilterhunksfn(fctx, hunks):
958 return hunks
958 return hunks
959
959
960 def hunksfilter(ctx):
960 def hunksfilter(ctx):
961 fctxlineranges = linerangesbyrev.get(scmutil.intrev(ctx))
961 fctxlineranges = linerangesbyrev.get(scmutil.intrev(ctx))
962 if fctxlineranges is None:
962 if fctxlineranges is None:
963 return nofilterhunksfn
963 return nofilterhunksfn
964
964
965 def filterfn(fctx, hunks):
965 def filterfn(fctx, hunks):
966 lineranges = fctxlineranges.get(fctx.path())
966 lineranges = fctxlineranges.get(fctx.path())
967 if lineranges is not None:
967 if lineranges is not None:
968 for hr, lines in hunks:
968 for hr, lines in hunks:
969 if hr is None: # binary
969 if hr is None: # binary
970 yield hr, lines
970 yield hr, lines
971 continue
971 continue
972 if any(mdiff.hunkinrange(hr[2:], lr) for lr in lineranges):
972 if any(mdiff.hunkinrange(hr[2:], lr) for lr in lineranges):
973 yield hr, lines
973 yield hr, lines
974 else:
974 else:
975 for hunk in hunks:
975 for hunk in hunks:
976 yield hunk
976 yield hunk
977
977
978 return filterfn
978 return filterfn
979
979
980 def filematcher(ctx):
980 def filematcher(ctx):
981 files = list(linerangesbyrev.get(scmutil.intrev(ctx), []))
981 files = list(linerangesbyrev.get(scmutil.intrev(ctx), []))
982 return scmutil.matchfiles(repo, files)
982 return scmutil.matchfiles(repo, files)
983
983
984 revs = sorted(linerangesbyrev, reverse=True)
984 revs = sorted(linerangesbyrev, reverse=True)
985
985
986 differ = changesetdiffer()
986 differ = changesetdiffer()
987 differ._makefilematcher = filematcher
987 differ._makefilematcher = filematcher
988 differ._makehunksfilter = hunksfilter
988 differ._makehunksfilter = hunksfilter
989 return smartset.baseset(revs), differ
989 return smartset.baseset(revs), differ
990
990
991
991
992 def _graphnodeformatter(ui, displayer):
992 def _graphnodeformatter(ui, displayer):
993 spec = ui.config(b'ui', b'graphnodetemplate')
993 spec = ui.config(b'ui', b'graphnodetemplate')
994 if not spec:
994 if not spec:
995 return templatekw.getgraphnode # fast path for "{graphnode}"
995 return templatekw.getgraphnode # fast path for "{graphnode}"
996
996
997 spec = templater.unquotestring(spec)
997 spec = templater.unquotestring(spec)
998 if isinstance(displayer, changesettemplater):
998 if isinstance(displayer, changesettemplater):
999 # reuse cache of slow templates
999 # reuse cache of slow templates
1000 tres = displayer._tresources
1000 tres = displayer._tresources
1001 else:
1001 else:
1002 tres = formatter.templateresources(ui)
1002 tres = formatter.templateresources(ui)
1003 templ = formatter.maketemplater(
1003 templ = formatter.maketemplater(
1004 ui, spec, defaults=templatekw.keywords, resources=tres
1004 ui, spec, defaults=templatekw.keywords, resources=tres
1005 )
1005 )
1006
1006
1007 def formatnode(repo, ctx):
1007 def formatnode(repo, ctx, cache):
1008 props = {b'ctx': ctx, b'repo': repo}
1008 props = {b'ctx': ctx, b'repo': repo}
1009 return templ.renderdefault(props)
1009 return templ.renderdefault(props)
1010
1010
1011 return formatnode
1011 return formatnode
1012
1012
1013
1013
1014 def displaygraph(ui, repo, dag, displayer, edgefn, getcopies=None, props=None):
1014 def displaygraph(ui, repo, dag, displayer, edgefn, getcopies=None, props=None):
1015 props = props or {}
1015 props = props or {}
1016 formatnode = _graphnodeformatter(ui, displayer)
1016 formatnode = _graphnodeformatter(ui, displayer)
1017 state = graphmod.asciistate()
1017 state = graphmod.asciistate()
1018 styles = state.styles
1018 styles = state.styles
1019
1019
1020 # only set graph styling if HGPLAIN is not set.
1020 # only set graph styling if HGPLAIN is not set.
1021 if ui.plain(b'graph'):
1021 if ui.plain(b'graph'):
1022 # set all edge styles to |, the default pre-3.8 behaviour
1022 # set all edge styles to |, the default pre-3.8 behaviour
1023 styles.update(dict.fromkeys(styles, b'|'))
1023 styles.update(dict.fromkeys(styles, b'|'))
1024 else:
1024 else:
1025 edgetypes = {
1025 edgetypes = {
1026 b'parent': graphmod.PARENT,
1026 b'parent': graphmod.PARENT,
1027 b'grandparent': graphmod.GRANDPARENT,
1027 b'grandparent': graphmod.GRANDPARENT,
1028 b'missing': graphmod.MISSINGPARENT,
1028 b'missing': graphmod.MISSINGPARENT,
1029 }
1029 }
1030 for name, key in edgetypes.items():
1030 for name, key in edgetypes.items():
1031 # experimental config: experimental.graphstyle.*
1031 # experimental config: experimental.graphstyle.*
1032 styles[key] = ui.config(
1032 styles[key] = ui.config(
1033 b'experimental', b'graphstyle.%s' % name, styles[key]
1033 b'experimental', b'graphstyle.%s' % name, styles[key]
1034 )
1034 )
1035 if not styles[key]:
1035 if not styles[key]:
1036 styles[key] = None
1036 styles[key] = None
1037
1037
1038 # experimental config: experimental.graphshorten
1038 # experimental config: experimental.graphshorten
1039 state.graphshorten = ui.configbool(b'experimental', b'graphshorten')
1039 state.graphshorten = ui.configbool(b'experimental', b'graphshorten')
1040
1040
1041 formatnode_cache = {}
1041 for rev, type, ctx, parents in dag:
1042 for rev, type, ctx, parents in dag:
1042 char = formatnode(repo, ctx)
1043 char = formatnode(repo, ctx, formatnode_cache)
1043 copies = getcopies(ctx) if getcopies else None
1044 copies = getcopies(ctx) if getcopies else None
1044 edges = edgefn(type, char, state, rev, parents)
1045 edges = edgefn(type, char, state, rev, parents)
1045 firstedge = next(edges)
1046 firstedge = next(edges)
1046 width = firstedge[2]
1047 width = firstedge[2]
1047 displayer.show(
1048 displayer.show(
1048 ctx, copies=copies, graphwidth=width, **pycompat.strkwargs(props)
1049 ctx, copies=copies, graphwidth=width, **pycompat.strkwargs(props)
1049 )
1050 )
1050 lines = displayer.hunk.pop(rev).split(b'\n')
1051 lines = displayer.hunk.pop(rev).split(b'\n')
1051 if not lines[-1]:
1052 if not lines[-1]:
1052 del lines[-1]
1053 del lines[-1]
1053 displayer.flush(ctx)
1054 displayer.flush(ctx)
1054 for type, char, width, coldata in itertools.chain([firstedge], edges):
1055 for type, char, width, coldata in itertools.chain([firstedge], edges):
1055 graphmod.ascii(ui, state, type, char, lines, coldata)
1056 graphmod.ascii(ui, state, type, char, lines, coldata)
1056 lines = []
1057 lines = []
1057 displayer.close()
1058 displayer.close()
1058
1059
1059
1060
1060 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
1061 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
1061 revdag = graphmod.dagwalker(repo, revs)
1062 revdag = graphmod.dagwalker(repo, revs)
1062 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
1063 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
1063
1064
1064
1065
1065 def displayrevs(ui, repo, revs, displayer, getcopies):
1066 def displayrevs(ui, repo, revs, displayer, getcopies):
1066 for rev in revs:
1067 for rev in revs:
1067 ctx = repo[rev]
1068 ctx = repo[rev]
1068 copies = getcopies(ctx) if getcopies else None
1069 copies = getcopies(ctx) if getcopies else None
1069 displayer.show(ctx, copies=copies)
1070 displayer.show(ctx, copies=copies)
1070 displayer.flush(ctx)
1071 displayer.flush(ctx)
1071 displayer.close()
1072 displayer.close()
1072
1073
1073
1074
1074 def checkunsupportedgraphflags(pats, opts):
1075 def checkunsupportedgraphflags(pats, opts):
1075 for op in [b"newest_first"]:
1076 for op in [b"newest_first"]:
1076 if op in opts and opts[op]:
1077 if op in opts and opts[op]:
1077 raise error.Abort(
1078 raise error.Abort(
1078 _(b"-G/--graph option is incompatible with --%s")
1079 _(b"-G/--graph option is incompatible with --%s")
1079 % op.replace(b"_", b"-")
1080 % op.replace(b"_", b"-")
1080 )
1081 )
1081
1082
1082
1083
1083 def graphrevs(repo, nodes, opts):
1084 def graphrevs(repo, nodes, opts):
1084 limit = getlimit(opts)
1085 limit = getlimit(opts)
1085 nodes.reverse()
1086 nodes.reverse()
1086 if limit is not None:
1087 if limit is not None:
1087 nodes = nodes[:limit]
1088 nodes = nodes[:limit]
1088 return graphmod.nodes(repo, nodes)
1089 return graphmod.nodes(repo, nodes)
@@ -1,992 +1,1004 b''
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from .node import (
11 from .node import (
12 hex,
12 hex,
13 nullid,
13 nullid,
14 wdirid,
14 wdirid,
15 wdirrev,
15 wdirrev,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 diffutil,
19 diffutil,
20 encoding,
20 encoding,
21 error,
21 error,
22 hbisect,
22 hbisect,
23 i18n,
23 i18n,
24 obsutil,
24 obsutil,
25 patch,
25 patch,
26 pycompat,
26 pycompat,
27 registrar,
27 registrar,
28 scmutil,
28 scmutil,
29 templateutil,
29 templateutil,
30 util,
30 util,
31 )
31 )
32 from .utils import stringutil
32 from .utils import stringutil
33
33
34 _hybrid = templateutil.hybrid
34 _hybrid = templateutil.hybrid
35 hybriddict = templateutil.hybriddict
35 hybriddict = templateutil.hybriddict
36 hybridlist = templateutil.hybridlist
36 hybridlist = templateutil.hybridlist
37 compatdict = templateutil.compatdict
37 compatdict = templateutil.compatdict
38 compatlist = templateutil.compatlist
38 compatlist = templateutil.compatlist
39 _showcompatlist = templateutil._showcompatlist
39 _showcompatlist = templateutil._showcompatlist
40
40
41
41
42 def getlatesttags(context, mapping, pattern=None):
42 def getlatesttags(context, mapping, pattern=None):
43 '''return date, distance and name for the latest tag of rev'''
43 '''return date, distance and name for the latest tag of rev'''
44 repo = context.resource(mapping, b'repo')
44 repo = context.resource(mapping, b'repo')
45 ctx = context.resource(mapping, b'ctx')
45 ctx = context.resource(mapping, b'ctx')
46 cache = context.resource(mapping, b'cache')
46 cache = context.resource(mapping, b'cache')
47
47
48 cachename = b'latesttags'
48 cachename = b'latesttags'
49 if pattern is not None:
49 if pattern is not None:
50 cachename += b'-' + pattern
50 cachename += b'-' + pattern
51 match = stringutil.stringmatcher(pattern)[2]
51 match = stringutil.stringmatcher(pattern)[2]
52 else:
52 else:
53 match = util.always
53 match = util.always
54
54
55 if cachename not in cache:
55 if cachename not in cache:
56 # Cache mapping from rev to a tuple with tag date, tag
56 # Cache mapping from rev to a tuple with tag date, tag
57 # distance and tag name
57 # distance and tag name
58 cache[cachename] = {-1: (0, 0, [b'null'])}
58 cache[cachename] = {-1: (0, 0, [b'null'])}
59 latesttags = cache[cachename]
59 latesttags = cache[cachename]
60
60
61 rev = ctx.rev()
61 rev = ctx.rev()
62 todo = [rev]
62 todo = [rev]
63 while todo:
63 while todo:
64 rev = todo.pop()
64 rev = todo.pop()
65 if rev in latesttags:
65 if rev in latesttags:
66 continue
66 continue
67 ctx = repo[rev]
67 ctx = repo[rev]
68 tags = [
68 tags = [
69 t
69 t
70 for t in ctx.tags()
70 for t in ctx.tags()
71 if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t))
71 if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t))
72 ]
72 ]
73 if tags:
73 if tags:
74 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
74 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
75 continue
75 continue
76 try:
76 try:
77 ptags = [latesttags[p.rev()] for p in ctx.parents()]
77 ptags = [latesttags[p.rev()] for p in ctx.parents()]
78 if len(ptags) > 1:
78 if len(ptags) > 1:
79 if ptags[0][2] == ptags[1][2]:
79 if ptags[0][2] == ptags[1][2]:
80 # The tuples are laid out so the right one can be found by
80 # The tuples are laid out so the right one can be found by
81 # comparison in this case.
81 # comparison in this case.
82 pdate, pdist, ptag = max(ptags)
82 pdate, pdist, ptag = max(ptags)
83 else:
83 else:
84
84
85 def key(x):
85 def key(x):
86 tag = x[2][0]
86 tag = x[2][0]
87 if ctx.rev() is None:
87 if ctx.rev() is None:
88 # only() doesn't support wdir
88 # only() doesn't support wdir
89 prevs = [c.rev() for c in ctx.parents()]
89 prevs = [c.rev() for c in ctx.parents()]
90 changes = repo.revs(b'only(%ld, %s)', prevs, tag)
90 changes = repo.revs(b'only(%ld, %s)', prevs, tag)
91 changessincetag = len(changes) + 1
91 changessincetag = len(changes) + 1
92 else:
92 else:
93 changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag)
93 changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag)
94 changessincetag = len(changes)
94 changessincetag = len(changes)
95 # Smallest number of changes since tag wins. Date is
95 # Smallest number of changes since tag wins. Date is
96 # used as tiebreaker.
96 # used as tiebreaker.
97 return [-changessincetag, x[0]]
97 return [-changessincetag, x[0]]
98
98
99 pdate, pdist, ptag = max(ptags, key=key)
99 pdate, pdist, ptag = max(ptags, key=key)
100 else:
100 else:
101 pdate, pdist, ptag = ptags[0]
101 pdate, pdist, ptag = ptags[0]
102 except KeyError:
102 except KeyError:
103 # Cache miss - recurse
103 # Cache miss - recurse
104 todo.append(rev)
104 todo.append(rev)
105 todo.extend(p.rev() for p in ctx.parents())
105 todo.extend(p.rev() for p in ctx.parents())
106 continue
106 continue
107 latesttags[rev] = pdate, pdist + 1, ptag
107 latesttags[rev] = pdate, pdist + 1, ptag
108 return latesttags[rev]
108 return latesttags[rev]
109
109
110
110
111 def getlogcolumns():
111 def getlogcolumns():
112 """Return a dict of log column labels"""
112 """Return a dict of log column labels"""
113 _ = pycompat.identity # temporarily disable gettext
113 _ = pycompat.identity # temporarily disable gettext
114 # i18n: column positioning for "hg log"
114 # i18n: column positioning for "hg log"
115 columns = _(
115 columns = _(
116 b'bookmark: %s\n'
116 b'bookmark: %s\n'
117 b'branch: %s\n'
117 b'branch: %s\n'
118 b'changeset: %s\n'
118 b'changeset: %s\n'
119 b'copies: %s\n'
119 b'copies: %s\n'
120 b'date: %s\n'
120 b'date: %s\n'
121 b'extra: %s=%s\n'
121 b'extra: %s=%s\n'
122 b'files+: %s\n'
122 b'files+: %s\n'
123 b'files-: %s\n'
123 b'files-: %s\n'
124 b'files: %s\n'
124 b'files: %s\n'
125 b'instability: %s\n'
125 b'instability: %s\n'
126 b'manifest: %s\n'
126 b'manifest: %s\n'
127 b'obsolete: %s\n'
127 b'obsolete: %s\n'
128 b'parent: %s\n'
128 b'parent: %s\n'
129 b'phase: %s\n'
129 b'phase: %s\n'
130 b'summary: %s\n'
130 b'summary: %s\n'
131 b'tag: %s\n'
131 b'tag: %s\n'
132 b'user: %s\n'
132 b'user: %s\n'
133 )
133 )
134 return dict(
134 return dict(
135 zip(
135 zip(
136 [s.split(b':', 1)[0] for s in columns.splitlines()],
136 [s.split(b':', 1)[0] for s in columns.splitlines()],
137 i18n._(columns).splitlines(True),
137 i18n._(columns).splitlines(True),
138 )
138 )
139 )
139 )
140
140
141
141
142 # basic internal templates
142 # basic internal templates
143 _changeidtmpl = b'{rev}:{node|formatnode}'
143 _changeidtmpl = b'{rev}:{node|formatnode}'
144
144
145 # default templates internally used for rendering of lists
145 # default templates internally used for rendering of lists
146 defaulttempl = {
146 defaulttempl = {
147 b'parent': _changeidtmpl + b' ',
147 b'parent': _changeidtmpl + b' ',
148 b'manifest': _changeidtmpl,
148 b'manifest': _changeidtmpl,
149 b'file_copy': b'{name} ({source})',
149 b'file_copy': b'{name} ({source})',
150 b'envvar': b'{key}={value}',
150 b'envvar': b'{key}={value}',
151 b'extra': b'{key}={value|stringescape}',
151 b'extra': b'{key}={value|stringescape}',
152 }
152 }
153 # filecopy is preserved for compatibility reasons
153 # filecopy is preserved for compatibility reasons
154 defaulttempl[b'filecopy'] = defaulttempl[b'file_copy']
154 defaulttempl[b'filecopy'] = defaulttempl[b'file_copy']
155
155
156 # keywords are callables (see registrar.templatekeyword for details)
156 # keywords are callables (see registrar.templatekeyword for details)
157 keywords = {}
157 keywords = {}
158 templatekeyword = registrar.templatekeyword(keywords)
158 templatekeyword = registrar.templatekeyword(keywords)
159
159
160
160
161 @templatekeyword(b'author', requires={b'ctx'})
161 @templatekeyword(b'author', requires={b'ctx'})
162 def showauthor(context, mapping):
162 def showauthor(context, mapping):
163 """Alias for ``{user}``"""
163 """Alias for ``{user}``"""
164 return showuser(context, mapping)
164 return showuser(context, mapping)
165
165
166
166
167 @templatekeyword(b'bisect', requires={b'repo', b'ctx'})
167 @templatekeyword(b'bisect', requires={b'repo', b'ctx'})
168 def showbisect(context, mapping):
168 def showbisect(context, mapping):
169 """String. The changeset bisection status."""
169 """String. The changeset bisection status."""
170 repo = context.resource(mapping, b'repo')
170 repo = context.resource(mapping, b'repo')
171 ctx = context.resource(mapping, b'ctx')
171 ctx = context.resource(mapping, b'ctx')
172 return hbisect.label(repo, ctx.node())
172 return hbisect.label(repo, ctx.node())
173
173
174
174
175 @templatekeyword(b'branch', requires={b'ctx'})
175 @templatekeyword(b'branch', requires={b'ctx'})
176 def showbranch(context, mapping):
176 def showbranch(context, mapping):
177 """String. The name of the branch on which the changeset was
177 """String. The name of the branch on which the changeset was
178 committed.
178 committed.
179 """
179 """
180 ctx = context.resource(mapping, b'ctx')
180 ctx = context.resource(mapping, b'ctx')
181 return ctx.branch()
181 return ctx.branch()
182
182
183
183
184 @templatekeyword(b'branches', requires={b'ctx'})
184 @templatekeyword(b'branches', requires={b'ctx'})
185 def showbranches(context, mapping):
185 def showbranches(context, mapping):
186 """List of strings. The name of the branch on which the
186 """List of strings. The name of the branch on which the
187 changeset was committed. Will be empty if the branch name was
187 changeset was committed. Will be empty if the branch name was
188 default. (DEPRECATED)
188 default. (DEPRECATED)
189 """
189 """
190 ctx = context.resource(mapping, b'ctx')
190 ctx = context.resource(mapping, b'ctx')
191 branch = ctx.branch()
191 branch = ctx.branch()
192 if branch != b'default':
192 if branch != b'default':
193 return compatlist(
193 return compatlist(
194 context, mapping, b'branch', [branch], plural=b'branches'
194 context, mapping, b'branch', [branch], plural=b'branches'
195 )
195 )
196 return compatlist(context, mapping, b'branch', [], plural=b'branches')
196 return compatlist(context, mapping, b'branch', [], plural=b'branches')
197
197
198
198
199 @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'})
199 @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'})
200 def showbookmarks(context, mapping):
200 def showbookmarks(context, mapping):
201 """List of strings. Any bookmarks associated with the
201 """List of strings. Any bookmarks associated with the
202 changeset. Also sets 'active', the name of the active bookmark.
202 changeset. Also sets 'active', the name of the active bookmark.
203 """
203 """
204 repo = context.resource(mapping, b'repo')
204 repo = context.resource(mapping, b'repo')
205 ctx = context.resource(mapping, b'ctx')
205 ctx = context.resource(mapping, b'ctx')
206 bookmarks = ctx.bookmarks()
206 bookmarks = ctx.bookmarks()
207 active = repo._activebookmark
207 active = repo._activebookmark
208 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active}
208 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active}
209 f = _showcompatlist(context, mapping, b'bookmark', bookmarks)
209 f = _showcompatlist(context, mapping, b'bookmark', bookmarks)
210 return _hybrid(f, bookmarks, makemap, pycompat.identity)
210 return _hybrid(f, bookmarks, makemap, pycompat.identity)
211
211
212
212
213 @templatekeyword(b'children', requires={b'ctx'})
213 @templatekeyword(b'children', requires={b'ctx'})
214 def showchildren(context, mapping):
214 def showchildren(context, mapping):
215 """List of strings. The children of the changeset."""
215 """List of strings. The children of the changeset."""
216 ctx = context.resource(mapping, b'ctx')
216 ctx = context.resource(mapping, b'ctx')
217 childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
217 childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
218 return compatlist(
218 return compatlist(
219 context, mapping, b'children', childrevs, element=b'child'
219 context, mapping, b'children', childrevs, element=b'child'
220 )
220 )
221
221
222
222
223 # Deprecated, but kept alive for help generation a purpose.
223 # Deprecated, but kept alive for help generation a purpose.
224 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'})
224 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'})
225 def showcurrentbookmark(context, mapping):
225 def showcurrentbookmark(context, mapping):
226 """String. The active bookmark, if it is associated with the changeset.
226 """String. The active bookmark, if it is associated with the changeset.
227 (DEPRECATED)"""
227 (DEPRECATED)"""
228 return showactivebookmark(context, mapping)
228 return showactivebookmark(context, mapping)
229
229
230
230
231 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'})
231 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'})
232 def showactivebookmark(context, mapping):
232 def showactivebookmark(context, mapping):
233 """String. The active bookmark, if it is associated with the changeset."""
233 """String. The active bookmark, if it is associated with the changeset."""
234 repo = context.resource(mapping, b'repo')
234 repo = context.resource(mapping, b'repo')
235 ctx = context.resource(mapping, b'ctx')
235 ctx = context.resource(mapping, b'ctx')
236 active = repo._activebookmark
236 active = repo._activebookmark
237 if active and active in ctx.bookmarks():
237 if active and active in ctx.bookmarks():
238 return active
238 return active
239 return b''
239 return b''
240
240
241
241
242 @templatekeyword(b'date', requires={b'ctx'})
242 @templatekeyword(b'date', requires={b'ctx'})
243 def showdate(context, mapping):
243 def showdate(context, mapping):
244 """Date information. The date when the changeset was committed."""
244 """Date information. The date when the changeset was committed."""
245 ctx = context.resource(mapping, b'ctx')
245 ctx = context.resource(mapping, b'ctx')
246 # the default string format is '<float(unixtime)><tzoffset>' because
246 # the default string format is '<float(unixtime)><tzoffset>' because
247 # python-hglib splits date at decimal separator.
247 # python-hglib splits date at decimal separator.
248 return templateutil.date(ctx.date(), showfmt=b'%d.0%d')
248 return templateutil.date(ctx.date(), showfmt=b'%d.0%d')
249
249
250
250
251 @templatekeyword(b'desc', requires={b'ctx'})
251 @templatekeyword(b'desc', requires={b'ctx'})
252 def showdescription(context, mapping):
252 def showdescription(context, mapping):
253 """String. The text of the changeset description."""
253 """String. The text of the changeset description."""
254 ctx = context.resource(mapping, b'ctx')
254 ctx = context.resource(mapping, b'ctx')
255 s = ctx.description()
255 s = ctx.description()
256 if isinstance(s, encoding.localstr):
256 if isinstance(s, encoding.localstr):
257 # try hard to preserve utf-8 bytes
257 # try hard to preserve utf-8 bytes
258 return encoding.tolocal(encoding.fromlocal(s).strip())
258 return encoding.tolocal(encoding.fromlocal(s).strip())
259 elif isinstance(s, encoding.safelocalstr):
259 elif isinstance(s, encoding.safelocalstr):
260 return encoding.safelocalstr(s.strip())
260 return encoding.safelocalstr(s.strip())
261 else:
261 else:
262 return s.strip()
262 return s.strip()
263
263
264
264
265 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'})
265 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'})
266 def showdiffstat(context, mapping):
266 def showdiffstat(context, mapping):
267 """String. Statistics of changes with the following format:
267 """String. Statistics of changes with the following format:
268 "modified files: +added/-removed lines"
268 "modified files: +added/-removed lines"
269 """
269 """
270 ui = context.resource(mapping, b'ui')
270 ui = context.resource(mapping, b'ui')
271 ctx = context.resource(mapping, b'ctx')
271 ctx = context.resource(mapping, b'ctx')
272 diffopts = diffutil.diffallopts(ui, {b'noprefix': False})
272 diffopts = diffutil.diffallopts(ui, {b'noprefix': False})
273 diff = ctx.diff(opts=diffopts)
273 diff = ctx.diff(opts=diffopts)
274 stats = patch.diffstatdata(util.iterlines(diff))
274 stats = patch.diffstatdata(util.iterlines(diff))
275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
276 return b'%d: +%d/-%d' % (len(stats), adds, removes)
276 return b'%d: +%d/-%d' % (len(stats), adds, removes)
277
277
278
278
279 @templatekeyword(b'envvars', requires={b'ui'})
279 @templatekeyword(b'envvars', requires={b'ui'})
280 def showenvvars(context, mapping):
280 def showenvvars(context, mapping):
281 """A dictionary of environment variables. (EXPERIMENTAL)"""
281 """A dictionary of environment variables. (EXPERIMENTAL)"""
282 ui = context.resource(mapping, b'ui')
282 ui = context.resource(mapping, b'ui')
283 env = ui.exportableenviron()
283 env = ui.exportableenviron()
284 env = util.sortdict((k, env[k]) for k in sorted(env))
284 env = util.sortdict((k, env[k]) for k in sorted(env))
285 return compatdict(context, mapping, b'envvar', env, plural=b'envvars')
285 return compatdict(context, mapping, b'envvar', env, plural=b'envvars')
286
286
287
287
288 @templatekeyword(b'extras', requires={b'ctx'})
288 @templatekeyword(b'extras', requires={b'ctx'})
289 def showextras(context, mapping):
289 def showextras(context, mapping):
290 """List of dicts with key, value entries of the 'extras'
290 """List of dicts with key, value entries of the 'extras'
291 field of this changeset."""
291 field of this changeset."""
292 ctx = context.resource(mapping, b'ctx')
292 ctx = context.resource(mapping, b'ctx')
293 extras = ctx.extra()
293 extras = ctx.extra()
294 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
294 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
295 makemap = lambda k: {b'key': k, b'value': extras[k]}
295 makemap = lambda k: {b'key': k, b'value': extras[k]}
296 c = [makemap(k) for k in extras]
296 c = [makemap(k) for k in extras]
297 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras')
297 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras')
298 return _hybrid(
298 return _hybrid(
299 f,
299 f,
300 extras,
300 extras,
301 makemap,
301 makemap,
302 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])),
302 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])),
303 )
303 )
304
304
305
305
306 def _getfilestatus(context, mapping, listall=False):
306 def _getfilestatus(context, mapping, listall=False):
307 ctx = context.resource(mapping, b'ctx')
307 ctx = context.resource(mapping, b'ctx')
308 revcache = context.resource(mapping, b'revcache')
308 revcache = context.resource(mapping, b'revcache')
309 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall:
309 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall:
310 stat = ctx.p1().status(
310 stat = ctx.p1().status(
311 ctx, listignored=listall, listclean=listall, listunknown=listall
311 ctx, listignored=listall, listclean=listall, listunknown=listall
312 )
312 )
313 revcache[b'filestatus'] = stat
313 revcache[b'filestatus'] = stat
314 revcache[b'filestatusall'] = listall
314 revcache[b'filestatusall'] = listall
315 return revcache[b'filestatus']
315 return revcache[b'filestatus']
316
316
317
317
318 def _getfilestatusmap(context, mapping, listall=False):
318 def _getfilestatusmap(context, mapping, listall=False):
319 revcache = context.resource(mapping, b'revcache')
319 revcache = context.resource(mapping, b'revcache')
320 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall:
320 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall:
321 stat = _getfilestatus(context, mapping, listall=listall)
321 stat = _getfilestatus(context, mapping, listall=listall)
322 revcache[b'filestatusmap'] = statmap = {}
322 revcache[b'filestatusmap'] = statmap = {}
323 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat):
323 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat):
324 statmap.update((f, char) for f in files)
324 statmap.update((f, char) for f in files)
325 return revcache[b'filestatusmap'] # {path: statchar}
325 return revcache[b'filestatusmap'] # {path: statchar}
326
326
327
327
328 @templatekeyword(
328 @templatekeyword(
329 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'}
329 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'}
330 )
330 )
331 def showfilecopies(context, mapping):
331 def showfilecopies(context, mapping):
332 """List of strings. Files copied in this changeset with
332 """List of strings. Files copied in this changeset with
333 their sources.
333 their sources.
334 """
334 """
335 repo = context.resource(mapping, b'repo')
335 repo = context.resource(mapping, b'repo')
336 ctx = context.resource(mapping, b'ctx')
336 ctx = context.resource(mapping, b'ctx')
337 cache = context.resource(mapping, b'cache')
337 cache = context.resource(mapping, b'cache')
338 copies = context.resource(mapping, b'revcache').get(b'copies')
338 copies = context.resource(mapping, b'revcache').get(b'copies')
339 if copies is None:
339 if copies is None:
340 if b'getcopies' not in cache:
340 if b'getcopies' not in cache:
341 cache[b'getcopies'] = scmutil.getcopiesfn(repo)
341 cache[b'getcopies'] = scmutil.getcopiesfn(repo)
342 getcopies = cache[b'getcopies']
342 getcopies = cache[b'getcopies']
343 copies = getcopies(ctx)
343 copies = getcopies(ctx)
344 return templateutil.compatfilecopiesdict(
344 return templateutil.compatfilecopiesdict(
345 context, mapping, b'file_copy', copies
345 context, mapping, b'file_copy', copies
346 )
346 )
347
347
348
348
349 # showfilecopiesswitch() displays file copies only if copy records are
349 # showfilecopiesswitch() displays file copies only if copy records are
350 # provided before calling the templater, usually with a --copies
350 # provided before calling the templater, usually with a --copies
351 # command line switch.
351 # command line switch.
352 @templatekeyword(b'file_copies_switch', requires={b'revcache'})
352 @templatekeyword(b'file_copies_switch', requires={b'revcache'})
353 def showfilecopiesswitch(context, mapping):
353 def showfilecopiesswitch(context, mapping):
354 """List of strings. Like "file_copies" but displayed
354 """List of strings. Like "file_copies" but displayed
355 only if the --copied switch is set.
355 only if the --copied switch is set.
356 """
356 """
357 copies = context.resource(mapping, b'revcache').get(b'copies') or []
357 copies = context.resource(mapping, b'revcache').get(b'copies') or []
358 return templateutil.compatfilecopiesdict(
358 return templateutil.compatfilecopiesdict(
359 context, mapping, b'file_copy', copies
359 context, mapping, b'file_copy', copies
360 )
360 )
361
361
362
362
363 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'})
363 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'})
364 def showfileadds(context, mapping):
364 def showfileadds(context, mapping):
365 """List of strings. Files added by this changeset."""
365 """List of strings. Files added by this changeset."""
366 ctx = context.resource(mapping, b'ctx')
366 ctx = context.resource(mapping, b'ctx')
367 return templateutil.compatfileslist(
367 return templateutil.compatfileslist(
368 context, mapping, b'file_add', ctx.filesadded()
368 context, mapping, b'file_add', ctx.filesadded()
369 )
369 )
370
370
371
371
372 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'})
372 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'})
373 def showfiledels(context, mapping):
373 def showfiledels(context, mapping):
374 """List of strings. Files removed by this changeset."""
374 """List of strings. Files removed by this changeset."""
375 ctx = context.resource(mapping, b'ctx')
375 ctx = context.resource(mapping, b'ctx')
376 return templateutil.compatfileslist(
376 return templateutil.compatfileslist(
377 context, mapping, b'file_del', ctx.filesremoved()
377 context, mapping, b'file_del', ctx.filesremoved()
378 )
378 )
379
379
380
380
381 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'})
381 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'})
382 def showfilemods(context, mapping):
382 def showfilemods(context, mapping):
383 """List of strings. Files modified by this changeset."""
383 """List of strings. Files modified by this changeset."""
384 ctx = context.resource(mapping, b'ctx')
384 ctx = context.resource(mapping, b'ctx')
385 return templateutil.compatfileslist(
385 return templateutil.compatfileslist(
386 context, mapping, b'file_mod', ctx.filesmodified()
386 context, mapping, b'file_mod', ctx.filesmodified()
387 )
387 )
388
388
389
389
390 @templatekeyword(b'files', requires={b'ctx'})
390 @templatekeyword(b'files', requires={b'ctx'})
391 def showfiles(context, mapping):
391 def showfiles(context, mapping):
392 """List of strings. All files modified, added, or removed by this
392 """List of strings. All files modified, added, or removed by this
393 changeset.
393 changeset.
394 """
394 """
395 ctx = context.resource(mapping, b'ctx')
395 ctx = context.resource(mapping, b'ctx')
396 return templateutil.compatfileslist(context, mapping, b'file', ctx.files())
396 return templateutil.compatfileslist(context, mapping, b'file', ctx.files())
397
397
398
398
399 @templatekeyword(b'graphnode', requires={b'repo', b'ctx'})
399 @templatekeyword(b'graphnode', requires={b'repo', b'ctx', b'cache'})
400 def showgraphnode(context, mapping):
400 def showgraphnode(context, mapping):
401 """String. The character representing the changeset node in an ASCII
401 """String. The character representing the changeset node in an ASCII
402 revision graph."""
402 revision graph."""
403 repo = context.resource(mapping, b'repo')
403 repo = context.resource(mapping, b'repo')
404 ctx = context.resource(mapping, b'ctx')
404 ctx = context.resource(mapping, b'ctx')
405 return getgraphnode(repo, ctx)
405 cache = context.resource(mapping, b'cache')
406 return getgraphnode(repo, ctx, cache)
406
407
407
408
408 def getgraphnode(repo, ctx):
409 def getgraphnode(repo, ctx, cache):
409 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx)
410 return getgraphnodecurrent(repo, ctx, cache) or getgraphnodesymbol(ctx)
410
411
411
412
412 def getgraphnodecurrent(repo, ctx):
413 def getgraphnodecurrent(repo, ctx, cache):
413 wpnodes = repo.dirstate.parents()
414 wpnodes = repo.dirstate.parents()
414 if wpnodes[1] == nullid:
415 if wpnodes[1] == nullid:
415 wpnodes = wpnodes[:1]
416 wpnodes = wpnodes[:1]
416 if ctx.node() in wpnodes:
417 if ctx.node() in wpnodes:
417 return b'@'
418 return b'@'
418 else:
419 else:
420 merge_nodes = cache.get(b'merge_nodes', ())
421 if not merge_nodes:
422 from . import merge
423
424 mergestate = merge.mergestate.read(repo)
425 if mergestate.active():
426 merge_nodes = (mergestate.local, mergestate.other)
427 cache[b'merge_nodes'] = merge_nodes
428
429 if ctx.node() in merge_nodes:
430 return b'%'
419 return b''
431 return b''
420
432
421
433
422 def getgraphnodesymbol(ctx):
434 def getgraphnodesymbol(ctx):
423 if ctx.obsolete():
435 if ctx.obsolete():
424 return b'x'
436 return b'x'
425 elif ctx.isunstable():
437 elif ctx.isunstable():
426 return b'*'
438 return b'*'
427 elif ctx.closesbranch():
439 elif ctx.closesbranch():
428 return b'_'
440 return b'_'
429 else:
441 else:
430 return b'o'
442 return b'o'
431
443
432
444
433 @templatekeyword(b'graphwidth', requires=())
445 @templatekeyword(b'graphwidth', requires=())
434 def showgraphwidth(context, mapping):
446 def showgraphwidth(context, mapping):
435 """Integer. The width of the graph drawn by 'log --graph' or zero."""
447 """Integer. The width of the graph drawn by 'log --graph' or zero."""
436 # just hosts documentation; should be overridden by template mapping
448 # just hosts documentation; should be overridden by template mapping
437 return 0
449 return 0
438
450
439
451
440 @templatekeyword(b'index', requires=())
452 @templatekeyword(b'index', requires=())
441 def showindex(context, mapping):
453 def showindex(context, mapping):
442 """Integer. The current iteration of the loop. (0 indexed)"""
454 """Integer. The current iteration of the loop. (0 indexed)"""
443 # just hosts documentation; should be overridden by template mapping
455 # just hosts documentation; should be overridden by template mapping
444 raise error.Abort(_(b"can't use index in this context"))
456 raise error.Abort(_(b"can't use index in this context"))
445
457
446
458
447 @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'})
459 @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'})
448 def showlatesttag(context, mapping):
460 def showlatesttag(context, mapping):
449 """List of strings. The global tags on the most recent globally
461 """List of strings. The global tags on the most recent globally
450 tagged ancestor of this changeset. If no such tags exist, the list
462 tagged ancestor of this changeset. If no such tags exist, the list
451 consists of the single string "null".
463 consists of the single string "null".
452 """
464 """
453 return showlatesttags(context, mapping, None)
465 return showlatesttags(context, mapping, None)
454
466
455
467
456 def showlatesttags(context, mapping, pattern):
468 def showlatesttags(context, mapping, pattern):
457 """helper method for the latesttag keyword and function"""
469 """helper method for the latesttag keyword and function"""
458 latesttags = getlatesttags(context, mapping, pattern)
470 latesttags = getlatesttags(context, mapping, pattern)
459
471
460 # latesttag[0] is an implementation detail for sorting csets on different
472 # latesttag[0] is an implementation detail for sorting csets on different
461 # branches in a stable manner- it is the date the tagged cset was created,
473 # branches in a stable manner- it is the date the tagged cset was created,
462 # not the date the tag was created. Therefore it isn't made visible here.
474 # not the date the tag was created. Therefore it isn't made visible here.
463 makemap = lambda v: {
475 makemap = lambda v: {
464 b'changes': _showchangessincetag,
476 b'changes': _showchangessincetag,
465 b'distance': latesttags[1],
477 b'distance': latesttags[1],
466 b'latesttag': v, # BC with {latesttag % '{latesttag}'}
478 b'latesttag': v, # BC with {latesttag % '{latesttag}'}
467 b'tag': v,
479 b'tag': v,
468 }
480 }
469
481
470 tags = latesttags[2]
482 tags = latesttags[2]
471 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':')
483 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':')
472 return _hybrid(f, tags, makemap, pycompat.identity)
484 return _hybrid(f, tags, makemap, pycompat.identity)
473
485
474
486
475 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'})
487 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'})
476 def showlatesttagdistance(context, mapping):
488 def showlatesttagdistance(context, mapping):
477 """Integer. Longest path to the latest tag."""
489 """Integer. Longest path to the latest tag."""
478 return getlatesttags(context, mapping)[1]
490 return getlatesttags(context, mapping)[1]
479
491
480
492
481 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'})
493 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'})
482 def showchangessincelatesttag(context, mapping):
494 def showchangessincelatesttag(context, mapping):
483 """Integer. All ancestors not in the latest tag."""
495 """Integer. All ancestors not in the latest tag."""
484 tag = getlatesttags(context, mapping)[2][0]
496 tag = getlatesttags(context, mapping)[2][0]
485 mapping = context.overlaymap(mapping, {b'tag': tag})
497 mapping = context.overlaymap(mapping, {b'tag': tag})
486 return _showchangessincetag(context, mapping)
498 return _showchangessincetag(context, mapping)
487
499
488
500
489 def _showchangessincetag(context, mapping):
501 def _showchangessincetag(context, mapping):
490 repo = context.resource(mapping, b'repo')
502 repo = context.resource(mapping, b'repo')
491 ctx = context.resource(mapping, b'ctx')
503 ctx = context.resource(mapping, b'ctx')
492 offset = 0
504 offset = 0
493 revs = [ctx.rev()]
505 revs = [ctx.rev()]
494 tag = context.symbol(mapping, b'tag')
506 tag = context.symbol(mapping, b'tag')
495
507
496 # The only() revset doesn't currently support wdir()
508 # The only() revset doesn't currently support wdir()
497 if ctx.rev() is None:
509 if ctx.rev() is None:
498 offset = 1
510 offset = 1
499 revs = [p.rev() for p in ctx.parents()]
511 revs = [p.rev() for p in ctx.parents()]
500
512
501 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset
513 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset
502
514
503
515
504 # teach templater latesttags.changes is switched to (context, mapping) API
516 # teach templater latesttags.changes is switched to (context, mapping) API
505 _showchangessincetag._requires = {b'repo', b'ctx'}
517 _showchangessincetag._requires = {b'repo', b'ctx'}
506
518
507
519
508 @templatekeyword(b'manifest', requires={b'repo', b'ctx'})
520 @templatekeyword(b'manifest', requires={b'repo', b'ctx'})
509 def showmanifest(context, mapping):
521 def showmanifest(context, mapping):
510 repo = context.resource(mapping, b'repo')
522 repo = context.resource(mapping, b'repo')
511 ctx = context.resource(mapping, b'ctx')
523 ctx = context.resource(mapping, b'ctx')
512 mnode = ctx.manifestnode()
524 mnode = ctx.manifestnode()
513 if mnode is None:
525 if mnode is None:
514 mnode = wdirid
526 mnode = wdirid
515 mrev = wdirrev
527 mrev = wdirrev
516 else:
528 else:
517 mrev = repo.manifestlog.rev(mnode)
529 mrev = repo.manifestlog.rev(mnode)
518 mhex = hex(mnode)
530 mhex = hex(mnode)
519 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex})
531 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex})
520 f = context.process(b'manifest', mapping)
532 f = context.process(b'manifest', mapping)
521 return templateutil.hybriditem(
533 return templateutil.hybriditem(
522 f, None, f, lambda x: {b'rev': mrev, b'node': mhex}
534 f, None, f, lambda x: {b'rev': mrev, b'node': mhex}
523 )
535 )
524
536
525
537
526 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'})
538 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'})
527 def showobsfate(context, mapping):
539 def showobsfate(context, mapping):
528 # this function returns a list containing pre-formatted obsfate strings.
540 # this function returns a list containing pre-formatted obsfate strings.
529 #
541 #
530 # This function will be replaced by templates fragments when we will have
542 # This function will be replaced by templates fragments when we will have
531 # the verbosity templatekw available.
543 # the verbosity templatekw available.
532 succsandmarkers = showsuccsandmarkers(context, mapping)
544 succsandmarkers = showsuccsandmarkers(context, mapping)
533
545
534 ui = context.resource(mapping, b'ui')
546 ui = context.resource(mapping, b'ui')
535 repo = context.resource(mapping, b'repo')
547 repo = context.resource(mapping, b'repo')
536 values = []
548 values = []
537
549
538 for x in succsandmarkers.tovalue(context, mapping):
550 for x in succsandmarkers.tovalue(context, mapping):
539 v = obsutil.obsfateprinter(
551 v = obsutil.obsfateprinter(
540 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid
552 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid
541 )
553 )
542 values.append(v)
554 values.append(v)
543
555
544 return compatlist(context, mapping, b"fate", values)
556 return compatlist(context, mapping, b"fate", values)
545
557
546
558
547 def shownames(context, mapping, namespace):
559 def shownames(context, mapping, namespace):
548 """helper method to generate a template keyword for a namespace"""
560 """helper method to generate a template keyword for a namespace"""
549 repo = context.resource(mapping, b'repo')
561 repo = context.resource(mapping, b'repo')
550 ctx = context.resource(mapping, b'ctx')
562 ctx = context.resource(mapping, b'ctx')
551 ns = repo.names[namespace]
563 ns = repo.names[namespace]
552 names = ns.names(repo, ctx.node())
564 names = ns.names(repo, ctx.node())
553 return compatlist(
565 return compatlist(
554 context, mapping, ns.templatename, names, plural=namespace
566 context, mapping, ns.templatename, names, plural=namespace
555 )
567 )
556
568
557
569
558 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'})
570 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'})
559 def shownamespaces(context, mapping):
571 def shownamespaces(context, mapping):
560 """Dict of lists. Names attached to this changeset per
572 """Dict of lists. Names attached to this changeset per
561 namespace."""
573 namespace."""
562 repo = context.resource(mapping, b'repo')
574 repo = context.resource(mapping, b'repo')
563 ctx = context.resource(mapping, b'ctx')
575 ctx = context.resource(mapping, b'ctx')
564
576
565 namespaces = util.sortdict()
577 namespaces = util.sortdict()
566
578
567 def makensmapfn(ns):
579 def makensmapfn(ns):
568 # 'name' for iterating over namespaces, templatename for local reference
580 # 'name' for iterating over namespaces, templatename for local reference
569 return lambda v: {b'name': v, ns.templatename: v}
581 return lambda v: {b'name': v, ns.templatename: v}
570
582
571 for k, ns in pycompat.iteritems(repo.names):
583 for k, ns in pycompat.iteritems(repo.names):
572 names = ns.names(repo, ctx.node())
584 names = ns.names(repo, ctx.node())
573 f = _showcompatlist(context, mapping, b'name', names)
585 f = _showcompatlist(context, mapping, b'name', names)
574 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
586 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
575
587
576 f = _showcompatlist(context, mapping, b'namespace', list(namespaces))
588 f = _showcompatlist(context, mapping, b'namespace', list(namespaces))
577
589
578 def makemap(ns):
590 def makemap(ns):
579 return {
591 return {
580 b'namespace': ns,
592 b'namespace': ns,
581 b'names': namespaces[ns],
593 b'names': namespaces[ns],
582 b'builtin': repo.names[ns].builtin,
594 b'builtin': repo.names[ns].builtin,
583 b'colorname': repo.names[ns].colorname,
595 b'colorname': repo.names[ns].colorname,
584 }
596 }
585
597
586 return _hybrid(f, namespaces, makemap, pycompat.identity)
598 return _hybrid(f, namespaces, makemap, pycompat.identity)
587
599
588
600
589 @templatekeyword(b'negrev', requires={b'repo', b'ctx'})
601 @templatekeyword(b'negrev', requires={b'repo', b'ctx'})
590 def shownegrev(context, mapping):
602 def shownegrev(context, mapping):
591 """Integer. The repository-local changeset negative revision number,
603 """Integer. The repository-local changeset negative revision number,
592 which counts in the opposite direction."""
604 which counts in the opposite direction."""
593 ctx = context.resource(mapping, b'ctx')
605 ctx = context.resource(mapping, b'ctx')
594 rev = ctx.rev()
606 rev = ctx.rev()
595 if rev is None or rev < 0: # wdir() or nullrev?
607 if rev is None or rev < 0: # wdir() or nullrev?
596 return None
608 return None
597 repo = context.resource(mapping, b'repo')
609 repo = context.resource(mapping, b'repo')
598 return rev - len(repo)
610 return rev - len(repo)
599
611
600
612
601 @templatekeyword(b'node', requires={b'ctx'})
613 @templatekeyword(b'node', requires={b'ctx'})
602 def shownode(context, mapping):
614 def shownode(context, mapping):
603 """String. The changeset identification hash, as a 40 hexadecimal
615 """String. The changeset identification hash, as a 40 hexadecimal
604 digit string.
616 digit string.
605 """
617 """
606 ctx = context.resource(mapping, b'ctx')
618 ctx = context.resource(mapping, b'ctx')
607 return ctx.hex()
619 return ctx.hex()
608
620
609
621
610 @templatekeyword(b'obsolete', requires={b'ctx'})
622 @templatekeyword(b'obsolete', requires={b'ctx'})
611 def showobsolete(context, mapping):
623 def showobsolete(context, mapping):
612 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
624 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
613 ctx = context.resource(mapping, b'ctx')
625 ctx = context.resource(mapping, b'ctx')
614 if ctx.obsolete():
626 if ctx.obsolete():
615 return b'obsolete'
627 return b'obsolete'
616 return b''
628 return b''
617
629
618
630
619 @templatekeyword(b'path', requires={b'fctx'})
631 @templatekeyword(b'path', requires={b'fctx'})
620 def showpath(context, mapping):
632 def showpath(context, mapping):
621 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
633 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
622 fctx = context.resource(mapping, b'fctx')
634 fctx = context.resource(mapping, b'fctx')
623 return fctx.path()
635 return fctx.path()
624
636
625
637
626 @templatekeyword(b'peerurls', requires={b'repo'})
638 @templatekeyword(b'peerurls', requires={b'repo'})
627 def showpeerurls(context, mapping):
639 def showpeerurls(context, mapping):
628 """A dictionary of repository locations defined in the [paths] section
640 """A dictionary of repository locations defined in the [paths] section
629 of your configuration file."""
641 of your configuration file."""
630 repo = context.resource(mapping, b'repo')
642 repo = context.resource(mapping, b'repo')
631 # see commands.paths() for naming of dictionary keys
643 # see commands.paths() for naming of dictionary keys
632 paths = repo.ui.paths
644 paths = repo.ui.paths
633 urls = util.sortdict(
645 urls = util.sortdict(
634 (k, p.rawloc) for k, p in sorted(pycompat.iteritems(paths))
646 (k, p.rawloc) for k, p in sorted(pycompat.iteritems(paths))
635 )
647 )
636
648
637 def makemap(k):
649 def makemap(k):
638 p = paths[k]
650 p = paths[k]
639 d = {b'name': k, b'url': p.rawloc}
651 d = {b'name': k, b'url': p.rawloc}
640 d.update((o, v) for o, v in sorted(pycompat.iteritems(p.suboptions)))
652 d.update((o, v) for o, v in sorted(pycompat.iteritems(p.suboptions)))
641 return d
653 return d
642
654
643 return _hybrid(None, urls, makemap, lambda k: b'%s=%s' % (k, urls[k]))
655 return _hybrid(None, urls, makemap, lambda k: b'%s=%s' % (k, urls[k]))
644
656
645
657
646 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'})
658 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'})
647 def showpredecessors(context, mapping):
659 def showpredecessors(context, mapping):
648 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)"""
660 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)"""
649 repo = context.resource(mapping, b'repo')
661 repo = context.resource(mapping, b'repo')
650 ctx = context.resource(mapping, b'ctx')
662 ctx = context.resource(mapping, b'ctx')
651 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
663 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
652 predecessors = pycompat.maplist(hex, predecessors)
664 predecessors = pycompat.maplist(hex, predecessors)
653
665
654 return _hybrid(
666 return _hybrid(
655 None,
667 None,
656 predecessors,
668 predecessors,
657 lambda x: {b'ctx': repo[x]},
669 lambda x: {b'ctx': repo[x]},
658 lambda x: scmutil.formatchangeid(repo[x]),
670 lambda x: scmutil.formatchangeid(repo[x]),
659 )
671 )
660
672
661
673
662 @templatekeyword(b'reporoot', requires={b'repo'})
674 @templatekeyword(b'reporoot', requires={b'repo'})
663 def showreporoot(context, mapping):
675 def showreporoot(context, mapping):
664 """String. The root directory of the current repository."""
676 """String. The root directory of the current repository."""
665 repo = context.resource(mapping, b'repo')
677 repo = context.resource(mapping, b'repo')
666 return repo.root
678 return repo.root
667
679
668
680
669 @templatekeyword(b'size', requires={b'fctx'})
681 @templatekeyword(b'size', requires={b'fctx'})
670 def showsize(context, mapping):
682 def showsize(context, mapping):
671 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
683 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
672 fctx = context.resource(mapping, b'fctx')
684 fctx = context.resource(mapping, b'fctx')
673 return fctx.size()
685 return fctx.size()
674
686
675
687
676 # requires 'fctx' to denote {status} depends on (ctx, path) pair
688 # requires 'fctx' to denote {status} depends on (ctx, path) pair
677 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'})
689 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'})
678 def showstatus(context, mapping):
690 def showstatus(context, mapping):
679 """String. Status code of the current file. (EXPERIMENTAL)"""
691 """String. Status code of the current file. (EXPERIMENTAL)"""
680 path = templateutil.runsymbol(context, mapping, b'path')
692 path = templateutil.runsymbol(context, mapping, b'path')
681 path = templateutil.stringify(context, mapping, path)
693 path = templateutil.stringify(context, mapping, path)
682 if not path:
694 if not path:
683 return
695 return
684 statmap = _getfilestatusmap(context, mapping)
696 statmap = _getfilestatusmap(context, mapping)
685 if path not in statmap:
697 if path not in statmap:
686 statmap = _getfilestatusmap(context, mapping, listall=True)
698 statmap = _getfilestatusmap(context, mapping, listall=True)
687 return statmap.get(path)
699 return statmap.get(path)
688
700
689
701
690 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'})
702 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'})
691 def showsuccessorssets(context, mapping):
703 def showsuccessorssets(context, mapping):
692 """Returns a string of sets of successors for a changectx. Format used
704 """Returns a string of sets of successors for a changectx. Format used
693 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2
705 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2
694 while also diverged into ctx3. (EXPERIMENTAL)"""
706 while also diverged into ctx3. (EXPERIMENTAL)"""
695 repo = context.resource(mapping, b'repo')
707 repo = context.resource(mapping, b'repo')
696 ctx = context.resource(mapping, b'ctx')
708 ctx = context.resource(mapping, b'ctx')
697 if not ctx.obsolete():
709 if not ctx.obsolete():
698 return b''
710 return b''
699
711
700 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
712 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
701 ssets = [[hex(n) for n in ss] for ss in ssets]
713 ssets = [[hex(n) for n in ss] for ss in ssets]
702
714
703 data = []
715 data = []
704 for ss in ssets:
716 for ss in ssets:
705 h = _hybrid(
717 h = _hybrid(
706 None,
718 None,
707 ss,
719 ss,
708 lambda x: {b'ctx': repo[x]},
720 lambda x: {b'ctx': repo[x]},
709 lambda x: scmutil.formatchangeid(repo[x]),
721 lambda x: scmutil.formatchangeid(repo[x]),
710 )
722 )
711 data.append(h)
723 data.append(h)
712
724
713 # Format the successorssets
725 # Format the successorssets
714 def render(d):
726 def render(d):
715 return templateutil.stringify(context, mapping, d)
727 return templateutil.stringify(context, mapping, d)
716
728
717 def gen(data):
729 def gen(data):
718 yield b"; ".join(render(d) for d in data)
730 yield b"; ".join(render(d) for d in data)
719
731
720 return _hybrid(
732 return _hybrid(
721 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity
733 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity
722 )
734 )
723
735
724
736
725 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'})
737 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'})
726 def showsuccsandmarkers(context, mapping):
738 def showsuccsandmarkers(context, mapping):
727 """Returns a list of dict for each final successor of ctx. The dict
739 """Returns a list of dict for each final successor of ctx. The dict
728 contains successors node id in "successors" keys and the list of
740 contains successors node id in "successors" keys and the list of
729 obs-markers from ctx to the set of successors in "markers".
741 obs-markers from ctx to the set of successors in "markers".
730 (EXPERIMENTAL)
742 (EXPERIMENTAL)
731 """
743 """
732 repo = context.resource(mapping, b'repo')
744 repo = context.resource(mapping, b'repo')
733 ctx = context.resource(mapping, b'ctx')
745 ctx = context.resource(mapping, b'ctx')
734
746
735 values = obsutil.successorsandmarkers(repo, ctx)
747 values = obsutil.successorsandmarkers(repo, ctx)
736
748
737 if values is None:
749 if values is None:
738 values = []
750 values = []
739
751
740 # Format successors and markers to avoid exposing binary to templates
752 # Format successors and markers to avoid exposing binary to templates
741 data = []
753 data = []
742 for i in values:
754 for i in values:
743 # Format successors
755 # Format successors
744 successors = i[b'successors']
756 successors = i[b'successors']
745
757
746 successors = [hex(n) for n in successors]
758 successors = [hex(n) for n in successors]
747 successors = _hybrid(
759 successors = _hybrid(
748 None,
760 None,
749 successors,
761 successors,
750 lambda x: {b'ctx': repo[x]},
762 lambda x: {b'ctx': repo[x]},
751 lambda x: scmutil.formatchangeid(repo[x]),
763 lambda x: scmutil.formatchangeid(repo[x]),
752 )
764 )
753
765
754 # Format markers
766 # Format markers
755 finalmarkers = []
767 finalmarkers = []
756 for m in i[b'markers']:
768 for m in i[b'markers']:
757 hexprec = hex(m[0])
769 hexprec = hex(m[0])
758 hexsucs = tuple(hex(n) for n in m[1])
770 hexsucs = tuple(hex(n) for n in m[1])
759 hexparents = None
771 hexparents = None
760 if m[5] is not None:
772 if m[5] is not None:
761 hexparents = tuple(hex(n) for n in m[5])
773 hexparents = tuple(hex(n) for n in m[5])
762 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
774 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
763 finalmarkers.append(newmarker)
775 finalmarkers.append(newmarker)
764
776
765 data.append({b'successors': successors, b'markers': finalmarkers})
777 data.append({b'successors': successors, b'markers': finalmarkers})
766
778
767 return templateutil.mappinglist(data)
779 return templateutil.mappinglist(data)
768
780
769
781
770 @templatekeyword(b'p1', requires={b'ctx'})
782 @templatekeyword(b'p1', requires={b'ctx'})
771 def showp1(context, mapping):
783 def showp1(context, mapping):
772 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
784 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
773 number, and ``{p1.node}`` for the identification hash."""
785 number, and ``{p1.node}`` for the identification hash."""
774 ctx = context.resource(mapping, b'ctx')
786 ctx = context.resource(mapping, b'ctx')
775 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl)
787 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl)
776
788
777
789
778 @templatekeyword(b'p2', requires={b'ctx'})
790 @templatekeyword(b'p2', requires={b'ctx'})
779 def showp2(context, mapping):
791 def showp2(context, mapping):
780 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
792 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
781 number, and ``{p2.node}`` for the identification hash."""
793 number, and ``{p2.node}`` for the identification hash."""
782 ctx = context.resource(mapping, b'ctx')
794 ctx = context.resource(mapping, b'ctx')
783 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl)
795 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl)
784
796
785
797
786 @templatekeyword(b'p1rev', requires={b'ctx'})
798 @templatekeyword(b'p1rev', requires={b'ctx'})
787 def showp1rev(context, mapping):
799 def showp1rev(context, mapping):
788 """Integer. The repository-local revision number of the changeset's
800 """Integer. The repository-local revision number of the changeset's
789 first parent, or -1 if the changeset has no parents. (DEPRECATED)"""
801 first parent, or -1 if the changeset has no parents. (DEPRECATED)"""
790 ctx = context.resource(mapping, b'ctx')
802 ctx = context.resource(mapping, b'ctx')
791 return ctx.p1().rev()
803 return ctx.p1().rev()
792
804
793
805
794 @templatekeyword(b'p2rev', requires={b'ctx'})
806 @templatekeyword(b'p2rev', requires={b'ctx'})
795 def showp2rev(context, mapping):
807 def showp2rev(context, mapping):
796 """Integer. The repository-local revision number of the changeset's
808 """Integer. The repository-local revision number of the changeset's
797 second parent, or -1 if the changeset has no second parent. (DEPRECATED)"""
809 second parent, or -1 if the changeset has no second parent. (DEPRECATED)"""
798 ctx = context.resource(mapping, b'ctx')
810 ctx = context.resource(mapping, b'ctx')
799 return ctx.p2().rev()
811 return ctx.p2().rev()
800
812
801
813
802 @templatekeyword(b'p1node', requires={b'ctx'})
814 @templatekeyword(b'p1node', requires={b'ctx'})
803 def showp1node(context, mapping):
815 def showp1node(context, mapping):
804 """String. The identification hash of the changeset's first parent,
816 """String. The identification hash of the changeset's first parent,
805 as a 40 digit hexadecimal string. If the changeset has no parents, all
817 as a 40 digit hexadecimal string. If the changeset has no parents, all
806 digits are 0. (DEPRECATED)"""
818 digits are 0. (DEPRECATED)"""
807 ctx = context.resource(mapping, b'ctx')
819 ctx = context.resource(mapping, b'ctx')
808 return ctx.p1().hex()
820 return ctx.p1().hex()
809
821
810
822
811 @templatekeyword(b'p2node', requires={b'ctx'})
823 @templatekeyword(b'p2node', requires={b'ctx'})
812 def showp2node(context, mapping):
824 def showp2node(context, mapping):
813 """String. The identification hash of the changeset's second
825 """String. The identification hash of the changeset's second
814 parent, as a 40 digit hexadecimal string. If the changeset has no second
826 parent, as a 40 digit hexadecimal string. If the changeset has no second
815 parent, all digits are 0. (DEPRECATED)"""
827 parent, all digits are 0. (DEPRECATED)"""
816 ctx = context.resource(mapping, b'ctx')
828 ctx = context.resource(mapping, b'ctx')
817 return ctx.p2().hex()
829 return ctx.p2().hex()
818
830
819
831
820 @templatekeyword(b'parents', requires={b'repo', b'ctx'})
832 @templatekeyword(b'parents', requires={b'repo', b'ctx'})
821 def showparents(context, mapping):
833 def showparents(context, mapping):
822 """List of strings. The parents of the changeset in "rev:node"
834 """List of strings. The parents of the changeset in "rev:node"
823 format. If the changeset has only one "natural" parent (the predecessor
835 format. If the changeset has only one "natural" parent (the predecessor
824 revision) nothing is shown."""
836 revision) nothing is shown."""
825 repo = context.resource(mapping, b'repo')
837 repo = context.resource(mapping, b'repo')
826 ctx = context.resource(mapping, b'ctx')
838 ctx = context.resource(mapping, b'ctx')
827 pctxs = scmutil.meaningfulparents(repo, ctx)
839 pctxs = scmutil.meaningfulparents(repo, ctx)
828 prevs = [p.rev() for p in pctxs]
840 prevs = [p.rev() for p in pctxs]
829 parents = [
841 parents = [
830 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())]
842 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())]
831 for p in pctxs
843 for p in pctxs
832 ]
844 ]
833 f = _showcompatlist(context, mapping, b'parent', parents)
845 f = _showcompatlist(context, mapping, b'parent', parents)
834 return _hybrid(
846 return _hybrid(
835 f,
847 f,
836 prevs,
848 prevs,
837 lambda x: {b'ctx': repo[x]},
849 lambda x: {b'ctx': repo[x]},
838 lambda x: scmutil.formatchangeid(repo[x]),
850 lambda x: scmutil.formatchangeid(repo[x]),
839 keytype=int,
851 keytype=int,
840 )
852 )
841
853
842
854
843 @templatekeyword(b'phase', requires={b'ctx'})
855 @templatekeyword(b'phase', requires={b'ctx'})
844 def showphase(context, mapping):
856 def showphase(context, mapping):
845 """String. The changeset phase name."""
857 """String. The changeset phase name."""
846 ctx = context.resource(mapping, b'ctx')
858 ctx = context.resource(mapping, b'ctx')
847 return ctx.phasestr()
859 return ctx.phasestr()
848
860
849
861
850 @templatekeyword(b'phaseidx', requires={b'ctx'})
862 @templatekeyword(b'phaseidx', requires={b'ctx'})
851 def showphaseidx(context, mapping):
863 def showphaseidx(context, mapping):
852 """Integer. The changeset phase index. (ADVANCED)"""
864 """Integer. The changeset phase index. (ADVANCED)"""
853 ctx = context.resource(mapping, b'ctx')
865 ctx = context.resource(mapping, b'ctx')
854 return ctx.phase()
866 return ctx.phase()
855
867
856
868
857 @templatekeyword(b'rev', requires={b'ctx'})
869 @templatekeyword(b'rev', requires={b'ctx'})
858 def showrev(context, mapping):
870 def showrev(context, mapping):
859 """Integer. The repository-local changeset revision number."""
871 """Integer. The repository-local changeset revision number."""
860 ctx = context.resource(mapping, b'ctx')
872 ctx = context.resource(mapping, b'ctx')
861 return scmutil.intrev(ctx)
873 return scmutil.intrev(ctx)
862
874
863
875
864 def showrevslist(context, mapping, name, revs):
876 def showrevslist(context, mapping, name, revs):
865 """helper to generate a list of revisions in which a mapped template will
877 """helper to generate a list of revisions in which a mapped template will
866 be evaluated"""
878 be evaluated"""
867 repo = context.resource(mapping, b'repo')
879 repo = context.resource(mapping, b'repo')
868 # revs may be a smartset; don't compute it until f() has to be evaluated
880 # revs may be a smartset; don't compute it until f() has to be evaluated
869 def f():
881 def f():
870 srevs = [b'%d' % r for r in revs]
882 srevs = [b'%d' % r for r in revs]
871 return _showcompatlist(context, mapping, name, srevs)
883 return _showcompatlist(context, mapping, name, srevs)
872
884
873 return _hybrid(
885 return _hybrid(
874 f,
886 f,
875 revs,
887 revs,
876 lambda x: {name: x, b'ctx': repo[x]},
888 lambda x: {name: x, b'ctx': repo[x]},
877 pycompat.identity,
889 pycompat.identity,
878 keytype=int,
890 keytype=int,
879 )
891 )
880
892
881
893
882 @templatekeyword(b'subrepos', requires={b'ctx'})
894 @templatekeyword(b'subrepos', requires={b'ctx'})
883 def showsubrepos(context, mapping):
895 def showsubrepos(context, mapping):
884 """List of strings. Updated subrepositories in the changeset."""
896 """List of strings. Updated subrepositories in the changeset."""
885 ctx = context.resource(mapping, b'ctx')
897 ctx = context.resource(mapping, b'ctx')
886 substate = ctx.substate
898 substate = ctx.substate
887 if not substate:
899 if not substate:
888 return compatlist(context, mapping, b'subrepo', [])
900 return compatlist(context, mapping, b'subrepo', [])
889 psubstate = ctx.p1().substate or {}
901 psubstate = ctx.p1().substate or {}
890 subrepos = []
902 subrepos = []
891 for sub in substate:
903 for sub in substate:
892 if sub not in psubstate or substate[sub] != psubstate[sub]:
904 if sub not in psubstate or substate[sub] != psubstate[sub]:
893 subrepos.append(sub) # modified or newly added in ctx
905 subrepos.append(sub) # modified or newly added in ctx
894 for sub in psubstate:
906 for sub in psubstate:
895 if sub not in substate:
907 if sub not in substate:
896 subrepos.append(sub) # removed in ctx
908 subrepos.append(sub) # removed in ctx
897 return compatlist(context, mapping, b'subrepo', sorted(subrepos))
909 return compatlist(context, mapping, b'subrepo', sorted(subrepos))
898
910
899
911
900 # don't remove "showtags" definition, even though namespaces will put
912 # don't remove "showtags" definition, even though namespaces will put
901 # a helper function for "tags" keyword into "keywords" map automatically,
913 # a helper function for "tags" keyword into "keywords" map automatically,
902 # because online help text is built without namespaces initialization
914 # because online help text is built without namespaces initialization
903 @templatekeyword(b'tags', requires={b'repo', b'ctx'})
915 @templatekeyword(b'tags', requires={b'repo', b'ctx'})
904 def showtags(context, mapping):
916 def showtags(context, mapping):
905 """List of strings. Any tags associated with the changeset."""
917 """List of strings. Any tags associated with the changeset."""
906 return shownames(context, mapping, b'tags')
918 return shownames(context, mapping, b'tags')
907
919
908
920
909 @templatekeyword(b'termwidth', requires={b'ui'})
921 @templatekeyword(b'termwidth', requires={b'ui'})
910 def showtermwidth(context, mapping):
922 def showtermwidth(context, mapping):
911 """Integer. The width of the current terminal."""
923 """Integer. The width of the current terminal."""
912 ui = context.resource(mapping, b'ui')
924 ui = context.resource(mapping, b'ui')
913 return ui.termwidth()
925 return ui.termwidth()
914
926
915
927
916 @templatekeyword(b'user', requires={b'ctx'})
928 @templatekeyword(b'user', requires={b'ctx'})
917 def showuser(context, mapping):
929 def showuser(context, mapping):
918 """String. The unmodified author of the changeset."""
930 """String. The unmodified author of the changeset."""
919 ctx = context.resource(mapping, b'ctx')
931 ctx = context.resource(mapping, b'ctx')
920 return ctx.user()
932 return ctx.user()
921
933
922
934
923 @templatekeyword(b'instabilities', requires={b'ctx'})
935 @templatekeyword(b'instabilities', requires={b'ctx'})
924 def showinstabilities(context, mapping):
936 def showinstabilities(context, mapping):
925 """List of strings. Evolution instabilities affecting the changeset.
937 """List of strings. Evolution instabilities affecting the changeset.
926 (EXPERIMENTAL)
938 (EXPERIMENTAL)
927 """
939 """
928 ctx = context.resource(mapping, b'ctx')
940 ctx = context.resource(mapping, b'ctx')
929 return compatlist(
941 return compatlist(
930 context,
942 context,
931 mapping,
943 mapping,
932 b'instability',
944 b'instability',
933 ctx.instabilities(),
945 ctx.instabilities(),
934 plural=b'instabilities',
946 plural=b'instabilities',
935 )
947 )
936
948
937
949
938 @templatekeyword(b'verbosity', requires={b'ui'})
950 @templatekeyword(b'verbosity', requires={b'ui'})
939 def showverbosity(context, mapping):
951 def showverbosity(context, mapping):
940 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
952 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
941 or ''."""
953 or ''."""
942 ui = context.resource(mapping, b'ui')
954 ui = context.resource(mapping, b'ui')
943 # see logcmdutil.changesettemplater for priority of these flags
955 # see logcmdutil.changesettemplater for priority of these flags
944 if ui.debugflag:
956 if ui.debugflag:
945 return b'debug'
957 return b'debug'
946 elif ui.quiet:
958 elif ui.quiet:
947 return b'quiet'
959 return b'quiet'
948 elif ui.verbose:
960 elif ui.verbose:
949 return b'verbose'
961 return b'verbose'
950 return b''
962 return b''
951
963
952
964
953 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'})
965 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'})
954 def showwhyunstable(context, mapping):
966 def showwhyunstable(context, mapping):
955 """List of dicts explaining all instabilities of a changeset.
967 """List of dicts explaining all instabilities of a changeset.
956 (EXPERIMENTAL)
968 (EXPERIMENTAL)
957 """
969 """
958 repo = context.resource(mapping, b'repo')
970 repo = context.resource(mapping, b'repo')
959 ctx = context.resource(mapping, b'ctx')
971 ctx = context.resource(mapping, b'ctx')
960
972
961 def formatnode(ctx):
973 def formatnode(ctx):
962 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
974 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
963
975
964 entries = obsutil.whyunstable(repo, ctx)
976 entries = obsutil.whyunstable(repo, ctx)
965
977
966 for entry in entries:
978 for entry in entries:
967 if entry.get(b'divergentnodes'):
979 if entry.get(b'divergentnodes'):
968 dnodes = entry[b'divergentnodes']
980 dnodes = entry[b'divergentnodes']
969 dnhybrid = _hybrid(
981 dnhybrid = _hybrid(
970 None,
982 None,
971 [dnode.hex() for dnode in dnodes],
983 [dnode.hex() for dnode in dnodes],
972 lambda x: {b'ctx': repo[x]},
984 lambda x: {b'ctx': repo[x]},
973 lambda x: formatnode(repo[x]),
985 lambda x: formatnode(repo[x]),
974 )
986 )
975 entry[b'divergentnodes'] = dnhybrid
987 entry[b'divergentnodes'] = dnhybrid
976
988
977 tmpl = (
989 tmpl = (
978 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} '
990 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} '
979 b'{reason} {node|short}'
991 b'{reason} {node|short}'
980 )
992 )
981 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n')
993 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n')
982
994
983
995
984 def loadkeyword(ui, extname, registrarobj):
996 def loadkeyword(ui, extname, registrarobj):
985 """Load template keyword from specified registrarobj
997 """Load template keyword from specified registrarobj
986 """
998 """
987 for name, func in pycompat.iteritems(registrarobj._table):
999 for name, func in pycompat.iteritems(registrarobj._table):
988 keywords[name] = func
1000 keywords[name] = func
989
1001
990
1002
991 # tell hggettext to extract docstrings from these functions:
1003 # tell hggettext to extract docstrings from these functions:
992 i18nfunctions = keywords.values()
1004 i18nfunctions = keywords.values()
@@ -1,29 +1,34 b''
1 == New Features ==
1 == New Features ==
2
2
3 * `hg purge`/`hg clean` can now delete ignored files instead of
3 * `hg purge`/`hg clean` can now delete ignored files instead of
4 untracked files, with the new -i flag.
4 untracked files, with the new -i flag.
5
5
6 * New `conflictlocal()` and `conflictother()` revsets returns the
6 * `hg log` now defaults to using an '%' symbol for commits involved
7 in unresolved merge conflicts. That includes unresolved conflicts
8 caused by e.g. `hg update --merge` and `hg graft`. '@' still takes
9 precedence, so what used to be marked '@' still is.
10
11 * New `conflictlocal()` and `conflictother()` revsets return the
7 commits that are being merged, when there are conflicts. Also works
12 commits that are being merged, when there are conflicts. Also works
8 for conflicts caused by e.g. `hg graft`.
13 for conflicts caused by e.g. `hg graft`.
9
14
10
15
11 == New Experimental Features ==
16 == New Experimental Features ==
12
17
13
18
14 == Bug Fixes ==
19 == Bug Fixes ==
15
20
16
21
17 == Backwards Compatibility Changes ==
22 == Backwards Compatibility Changes ==
18
23
19
24
20 == Internal API Changes ==
25 == Internal API Changes ==
21
26
22 * The deprecated `ui.progress()` has now been deleted. Please use
27 * The deprecated `ui.progress()` has now been deleted. Please use
23 `ui.makeprogress()` instead.
28 `ui.makeprogress()` instead.
24
29
25 * `hg.merge()` has lost its `abort` argument. Please call
30 * `hg.merge()` has lost its `abort` argument. Please call
26 `hg.abortmerge()` directly instead.
31 `hg.abortmerge()` directly instead.
27
32
28 * The `*others` argument of `cmdutil.check_incompatible_arguments()`
33 * The `*others` argument of `cmdutil.check_incompatible_arguments()`
29 changed from being varargs argument to being a single collection.
34 changed from being varargs argument to being a single collection.
@@ -1,807 +1,807 b''
1 $ hg init basic
1 $ hg init basic
2 $ cd basic
2 $ cd basic
3
3
4 should complain
4 should complain
5
5
6 $ hg backout
6 $ hg backout
7 abort: please specify a revision to backout
7 abort: please specify a revision to backout
8 [255]
8 [255]
9 $ hg backout -r 0 0
9 $ hg backout -r 0 0
10 abort: please specify just one revision
10 abort: please specify just one revision
11 [255]
11 [255]
12
12
13 basic operation
13 basic operation
14 (this also tests that editor is invoked if the commit message is not
14 (this also tests that editor is invoked if the commit message is not
15 specified explicitly)
15 specified explicitly)
16
16
17 $ echo a > a
17 $ echo a > a
18 $ hg commit -d '0 0' -A -m a
18 $ hg commit -d '0 0' -A -m a
19 adding a
19 adding a
20 $ echo b >> a
20 $ echo b >> a
21 $ hg commit -d '1 0' -m b
21 $ hg commit -d '1 0' -m b
22
22
23 $ hg status --rev tip --rev "tip^1"
23 $ hg status --rev tip --rev "tip^1"
24 M a
24 M a
25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
26 reverting a
26 reverting a
27 Backed out changeset a820f4f40a57
27 Backed out changeset a820f4f40a57
28
28
29
29
30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
31 HG: Leave message empty to abort commit.
31 HG: Leave message empty to abort commit.
32 HG: --
32 HG: --
33 HG: user: test
33 HG: user: test
34 HG: branch 'default'
34 HG: branch 'default'
35 HG: changed a
35 HG: changed a
36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
37 $ cat a
37 $ cat a
38 a
38 a
39 $ hg summary
39 $ hg summary
40 parent: 2:2929462c3dff tip
40 parent: 2:2929462c3dff tip
41 Backed out changeset a820f4f40a57
41 Backed out changeset a820f4f40a57
42 branch: default
42 branch: default
43 commit: (clean)
43 commit: (clean)
44 update: (current)
44 update: (current)
45 phases: 3 draft
45 phases: 3 draft
46
46
47 commit option
47 commit option
48
48
49 $ cd ..
49 $ cd ..
50 $ hg init commit
50 $ hg init commit
51 $ cd commit
51 $ cd commit
52
52
53 $ echo tomatoes > a
53 $ echo tomatoes > a
54 $ hg add a
54 $ hg add a
55 $ hg commit -d '0 0' -m tomatoes
55 $ hg commit -d '0 0' -m tomatoes
56
56
57 $ echo chair > b
57 $ echo chair > b
58 $ hg add b
58 $ hg add b
59 $ hg commit -d '1 0' -m chair
59 $ hg commit -d '1 0' -m chair
60
60
61 $ echo grapes >> a
61 $ echo grapes >> a
62 $ hg commit -d '2 0' -m grapes
62 $ hg commit -d '2 0' -m grapes
63
63
64 $ hg backout -d '4 0' 1 --tool=:fail
64 $ hg backout -d '4 0' 1 --tool=:fail
65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
67 $ hg summary
67 $ hg summary
68 parent: 3:1c2161e97c0a tip
68 parent: 3:1c2161e97c0a tip
69 Backed out changeset 22cb4f70d813
69 Backed out changeset 22cb4f70d813
70 branch: default
70 branch: default
71 commit: (clean)
71 commit: (clean)
72 update: (current)
72 update: (current)
73 phases: 4 draft
73 phases: 4 draft
74
74
75 $ echo ypples > a
75 $ echo ypples > a
76 $ hg commit -d '5 0' -m ypples
76 $ hg commit -d '5 0' -m ypples
77
77
78 $ hg backout -d '6 0' 2 --tool=:fail
78 $ hg backout -d '6 0' 2 --tool=:fail
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 use 'hg resolve' to retry unresolved file merges
80 use 'hg resolve' to retry unresolved file merges
81 [1]
81 [1]
82 $ hg summary
82 $ hg summary
83 parent: 4:ed99997b793d tip
83 parent: 4:ed99997b793d tip
84 ypples
84 ypples
85 branch: default
85 branch: default
86 commit: 1 unresolved (clean)
86 commit: 1 unresolved (clean)
87 update: (current)
87 update: (current)
88 phases: 5 draft
88 phases: 5 draft
89 $ hg log -G
89 $ hg log -G
90 @ changeset: 4:ed99997b793d
90 @ changeset: 4:ed99997b793d
91 | tag: tip
91 | tag: tip
92 | user: test
92 | user: test
93 | date: Thu Jan 01 00:00:05 1970 +0000
93 | date: Thu Jan 01 00:00:05 1970 +0000
94 | summary: ypples
94 | summary: ypples
95 |
95 |
96 o changeset: 3:1c2161e97c0a
96 o changeset: 3:1c2161e97c0a
97 | user: test
97 | user: test
98 | date: Thu Jan 01 00:00:04 1970 +0000
98 | date: Thu Jan 01 00:00:04 1970 +0000
99 | summary: Backed out changeset 22cb4f70d813
99 | summary: Backed out changeset 22cb4f70d813
100 |
100 |
101 o changeset: 2:a8c6e511cfee
101 o changeset: 2:a8c6e511cfee
102 | user: test
102 | user: test
103 | date: Thu Jan 01 00:00:02 1970 +0000
103 | date: Thu Jan 01 00:00:02 1970 +0000
104 | summary: grapes
104 | summary: grapes
105 |
105 |
106 o changeset: 1:22cb4f70d813
106 % changeset: 1:22cb4f70d813
107 | user: test
107 | user: test
108 | date: Thu Jan 01 00:00:01 1970 +0000
108 | date: Thu Jan 01 00:00:01 1970 +0000
109 | summary: chair
109 | summary: chair
110 |
110 |
111 o changeset: 0:a5cb2dde5805
111 o changeset: 0:a5cb2dde5805
112 user: test
112 user: test
113 date: Thu Jan 01 00:00:00 1970 +0000
113 date: Thu Jan 01 00:00:00 1970 +0000
114 summary: tomatoes
114 summary: tomatoes
115
115
116
116
117 file that was removed is recreated
117 file that was removed is recreated
118 (this also tests that editor is not invoked if the commit message is
118 (this also tests that editor is not invoked if the commit message is
119 specified explicitly)
119 specified explicitly)
120
120
121 $ cd ..
121 $ cd ..
122 $ hg init remove
122 $ hg init remove
123 $ cd remove
123 $ cd remove
124
124
125 $ echo content > a
125 $ echo content > a
126 $ hg commit -d '0 0' -A -m a
126 $ hg commit -d '0 0' -A -m a
127 adding a
127 adding a
128
128
129 $ hg rm a
129 $ hg rm a
130 $ hg commit -d '1 0' -m b
130 $ hg commit -d '1 0' -m b
131
131
132 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
132 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
133 adding a
133 adding a
134 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
134 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
135 $ cat a
135 $ cat a
136 content
136 content
137 $ hg summary
137 $ hg summary
138 parent: 2:de31bdc76c0d tip
138 parent: 2:de31bdc76c0d tip
139 Backed out changeset 76862dcce372
139 Backed out changeset 76862dcce372
140 branch: default
140 branch: default
141 commit: (clean)
141 commit: (clean)
142 update: (current)
142 update: (current)
143 phases: 3 draft
143 phases: 3 draft
144
144
145 backout of backout is as if nothing happened
145 backout of backout is as if nothing happened
146
146
147 $ hg backout -d '3 0' --merge tip --tool=true
147 $ hg backout -d '3 0' --merge tip --tool=true
148 removing a
148 removing a
149 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
149 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
150 $ test -f a
150 $ test -f a
151 [1]
151 [1]
152 $ hg summary
152 $ hg summary
153 parent: 3:7f6d0f120113 tip
153 parent: 3:7f6d0f120113 tip
154 Backed out changeset de31bdc76c0d
154 Backed out changeset de31bdc76c0d
155 branch: default
155 branch: default
156 commit: (clean)
156 commit: (clean)
157 update: (current)
157 update: (current)
158 phases: 4 draft
158 phases: 4 draft
159
159
160 Test that 'hg rollback' restores dirstate just before opening
160 Test that 'hg rollback' restores dirstate just before opening
161 transaction: in-memory dirstate changes should be written into
161 transaction: in-memory dirstate changes should be written into
162 '.hg/journal.dirstate' as expected.
162 '.hg/journal.dirstate' as expected.
163
163
164 $ echo 'removed soon' > b
164 $ echo 'removed soon' > b
165 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
165 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
166 adding b
166 adding b
167 $ echo 'newly added' > c
167 $ echo 'newly added' > c
168 $ hg add c
168 $ hg add c
169 $ hg remove b
169 $ hg remove b
170 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
170 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
171 $ touch -t 200001010000 c
171 $ touch -t 200001010000 c
172 $ hg status -A
172 $ hg status -A
173 C c
173 C c
174 $ hg debugstate --no-dates
174 $ hg debugstate --no-dates
175 n 644 12 set c
175 n 644 12 set c
176 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
176 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
177 removing c
177 removing c
178 adding b
178 adding b
179 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
179 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
180 $ hg rollback -q
180 $ hg rollback -q
181 $ hg status -A
181 $ hg status -A
182 A b
182 A b
183 R c
183 R c
184 $ hg debugstate --no-dates
184 $ hg debugstate --no-dates
185 a 0 -1 unset b
185 a 0 -1 unset b
186 r 0 0 set c
186 r 0 0 set c
187
187
188 across branch
188 across branch
189
189
190 $ cd ..
190 $ cd ..
191 $ hg init branch
191 $ hg init branch
192 $ cd branch
192 $ cd branch
193 $ echo a > a
193 $ echo a > a
194 $ hg ci -Am0
194 $ hg ci -Am0
195 adding a
195 adding a
196 $ echo b > b
196 $ echo b > b
197 $ hg ci -Am1
197 $ hg ci -Am1
198 adding b
198 adding b
199 $ hg co -C 0
199 $ hg co -C 0
200 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
200 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
201 $ hg summary
201 $ hg summary
202 parent: 0:f7b1eb17ad24
202 parent: 0:f7b1eb17ad24
203 0
203 0
204 branch: default
204 branch: default
205 commit: (clean)
205 commit: (clean)
206 update: 1 new changesets (update)
206 update: 1 new changesets (update)
207 phases: 2 draft
207 phases: 2 draft
208
208
209 should fail
209 should fail
210
210
211 $ hg backout 1
211 $ hg backout 1
212 abort: cannot backout change that is not an ancestor
212 abort: cannot backout change that is not an ancestor
213 [255]
213 [255]
214 $ echo c > c
214 $ echo c > c
215 $ hg ci -Am2
215 $ hg ci -Am2
216 adding c
216 adding c
217 created new head
217 created new head
218 $ hg summary
218 $ hg summary
219 parent: 2:db815d6d32e6 tip
219 parent: 2:db815d6d32e6 tip
220 2
220 2
221 branch: default
221 branch: default
222 commit: (clean)
222 commit: (clean)
223 update: 1 new changesets, 2 branch heads (merge)
223 update: 1 new changesets, 2 branch heads (merge)
224 phases: 3 draft
224 phases: 3 draft
225
225
226 should fail
226 should fail
227
227
228 $ hg backout 1
228 $ hg backout 1
229 abort: cannot backout change that is not an ancestor
229 abort: cannot backout change that is not an ancestor
230 [255]
230 [255]
231 $ hg summary
231 $ hg summary
232 parent: 2:db815d6d32e6 tip
232 parent: 2:db815d6d32e6 tip
233 2
233 2
234 branch: default
234 branch: default
235 commit: (clean)
235 commit: (clean)
236 update: 1 new changesets, 2 branch heads (merge)
236 update: 1 new changesets, 2 branch heads (merge)
237 phases: 3 draft
237 phases: 3 draft
238
238
239 backout with merge
239 backout with merge
240
240
241 $ cd ..
241 $ cd ..
242 $ hg init merge
242 $ hg init merge
243 $ cd merge
243 $ cd merge
244
244
245 $ echo line 1 > a
245 $ echo line 1 > a
246 $ echo line 2 >> a
246 $ echo line 2 >> a
247 $ hg commit -d '0 0' -A -m a
247 $ hg commit -d '0 0' -A -m a
248 adding a
248 adding a
249 $ hg summary
249 $ hg summary
250 parent: 0:59395513a13a tip
250 parent: 0:59395513a13a tip
251 a
251 a
252 branch: default
252 branch: default
253 commit: (clean)
253 commit: (clean)
254 update: (current)
254 update: (current)
255 phases: 1 draft
255 phases: 1 draft
256
256
257 remove line 1
257 remove line 1
258
258
259 $ echo line 2 > a
259 $ echo line 2 > a
260 $ hg commit -d '1 0' -m b
260 $ hg commit -d '1 0' -m b
261
261
262 $ echo line 3 >> a
262 $ echo line 3 >> a
263 $ hg commit -d '2 0' -m c
263 $ hg commit -d '2 0' -m c
264
264
265 $ hg backout --merge -d '3 0' 1 --tool=true
265 $ hg backout --merge -d '3 0' 1 --tool=true
266 reverting a
266 reverting a
267 created new head
267 created new head
268 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
268 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
269 merging with changeset 3:26b8ccb9ad91
269 merging with changeset 3:26b8ccb9ad91
270 merging a
270 merging a
271 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
271 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
272 (branch merge, don't forget to commit)
272 (branch merge, don't forget to commit)
273 $ hg commit -d '4 0' -m d
273 $ hg commit -d '4 0' -m d
274 $ hg summary
274 $ hg summary
275 parent: 4:c7df5e0b9c09 tip
275 parent: 4:c7df5e0b9c09 tip
276 d
276 d
277 branch: default
277 branch: default
278 commit: (clean)
278 commit: (clean)
279 update: (current)
279 update: (current)
280 phases: 5 draft
280 phases: 5 draft
281
281
282 check line 1 is back
282 check line 1 is back
283
283
284 $ cat a
284 $ cat a
285 line 1
285 line 1
286 line 2
286 line 2
287 line 3
287 line 3
288
288
289 Test visibility of in-memory dirstate changes outside transaction to
289 Test visibility of in-memory dirstate changes outside transaction to
290 external hook process
290 external hook process
291
291
292 $ cat > $TESTTMP/checkvisibility.sh <<EOF
292 $ cat > $TESTTMP/checkvisibility.sh <<EOF
293 > echo "==== \$1:"
293 > echo "==== \$1:"
294 > hg parents --template "{rev}:{node|short}\n"
294 > hg parents --template "{rev}:{node|short}\n"
295 > echo "===="
295 > echo "===="
296 > EOF
296 > EOF
297
297
298 "hg backout --merge REV1" at REV2 below implies steps below:
298 "hg backout --merge REV1" at REV2 below implies steps below:
299
299
300 (1) update to REV1 (REV2 => REV1)
300 (1) update to REV1 (REV2 => REV1)
301 (2) revert by REV1^1
301 (2) revert by REV1^1
302 (3) commit backing out revision (REV3)
302 (3) commit backing out revision (REV3)
303 (4) update to REV2 (REV3 => REV2)
303 (4) update to REV2 (REV3 => REV2)
304 (5) merge with REV3 (REV2 => REV2, REV3)
304 (5) merge with REV3 (REV2 => REV2, REV3)
305
305
306 == test visibility to external preupdate hook
306 == test visibility to external preupdate hook
307
307
308 $ hg update -q -C 2
308 $ hg update -q -C 2
309 $ hg --config extensions.strip= strip 3
309 $ hg --config extensions.strip= strip 3
310 saved backup bundle to * (glob)
310 saved backup bundle to * (glob)
311
311
312 $ cat >> .hg/hgrc <<EOF
312 $ cat >> .hg/hgrc <<EOF
313 > [hooks]
313 > [hooks]
314 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
314 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
315 > EOF
315 > EOF
316
316
317 ("-m" is needed to avoid writing dirstate changes out at other than
317 ("-m" is needed to avoid writing dirstate changes out at other than
318 invocation of the hook to be examined)
318 invocation of the hook to be examined)
319
319
320 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
320 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
321 ==== preupdate:
321 ==== preupdate:
322 2:6ea3f2a197a2
322 2:6ea3f2a197a2
323 ====
323 ====
324 reverting a
324 reverting a
325 created new head
325 created new head
326 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
326 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
327 ==== preupdate:
327 ==== preupdate:
328 3:d92a3f57f067
328 3:d92a3f57f067
329 ====
329 ====
330 merging with changeset 3:d92a3f57f067
330 merging with changeset 3:d92a3f57f067
331 ==== preupdate:
331 ==== preupdate:
332 2:6ea3f2a197a2
332 2:6ea3f2a197a2
333 ====
333 ====
334 merging a
334 merging a
335 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
335 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
336 (branch merge, don't forget to commit)
336 (branch merge, don't forget to commit)
337
337
338 $ cat >> .hg/hgrc <<EOF
338 $ cat >> .hg/hgrc <<EOF
339 > [hooks]
339 > [hooks]
340 > preupdate.visibility =
340 > preupdate.visibility =
341 > EOF
341 > EOF
342
342
343 == test visibility to external update hook
343 == test visibility to external update hook
344
344
345 $ hg update -q -C 2
345 $ hg update -q -C 2
346 $ hg --config extensions.strip= strip 3
346 $ hg --config extensions.strip= strip 3
347 saved backup bundle to * (glob)
347 saved backup bundle to * (glob)
348
348
349 $ cat >> .hg/hgrc <<EOF
349 $ cat >> .hg/hgrc <<EOF
350 > [hooks]
350 > [hooks]
351 > update.visibility = sh $TESTTMP/checkvisibility.sh update
351 > update.visibility = sh $TESTTMP/checkvisibility.sh update
352 > EOF
352 > EOF
353
353
354 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
354 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
355 ==== update:
355 ==== update:
356 1:5a50a024c182
356 1:5a50a024c182
357 ====
357 ====
358 reverting a
358 reverting a
359 created new head
359 created new head
360 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
360 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
361 ==== update:
361 ==== update:
362 2:6ea3f2a197a2
362 2:6ea3f2a197a2
363 ====
363 ====
364 merging with changeset 3:d92a3f57f067
364 merging with changeset 3:d92a3f57f067
365 merging a
365 merging a
366 ==== update:
366 ==== update:
367 2:6ea3f2a197a2
367 2:6ea3f2a197a2
368 3:d92a3f57f067
368 3:d92a3f57f067
369 ====
369 ====
370 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
370 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
371 (branch merge, don't forget to commit)
371 (branch merge, don't forget to commit)
372
372
373 $ cat >> .hg/hgrc <<EOF
373 $ cat >> .hg/hgrc <<EOF
374 > [hooks]
374 > [hooks]
375 > update.visibility =
375 > update.visibility =
376 > EOF
376 > EOF
377
377
378 $ cd ..
378 $ cd ..
379
379
380 backout should not back out subsequent changesets
380 backout should not back out subsequent changesets
381
381
382 $ hg init onecs
382 $ hg init onecs
383 $ cd onecs
383 $ cd onecs
384 $ echo 1 > a
384 $ echo 1 > a
385 $ hg commit -d '0 0' -A -m a
385 $ hg commit -d '0 0' -A -m a
386 adding a
386 adding a
387 $ echo 2 >> a
387 $ echo 2 >> a
388 $ hg commit -d '1 0' -m b
388 $ hg commit -d '1 0' -m b
389 $ echo 1 > b
389 $ echo 1 > b
390 $ hg commit -d '2 0' -A -m c
390 $ hg commit -d '2 0' -A -m c
391 adding b
391 adding b
392 $ hg summary
392 $ hg summary
393 parent: 2:882396649954 tip
393 parent: 2:882396649954 tip
394 c
394 c
395 branch: default
395 branch: default
396 commit: (clean)
396 commit: (clean)
397 update: (current)
397 update: (current)
398 phases: 3 draft
398 phases: 3 draft
399
399
400 without --merge
400 without --merge
401 $ hg backout --no-commit -d '3 0' 1 --tool=true
401 $ hg backout --no-commit -d '3 0' 1 --tool=true
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 changeset 22bca4c721e5 backed out, don't forget to commit.
403 changeset 22bca4c721e5 backed out, don't forget to commit.
404 $ hg locate b
404 $ hg locate b
405 b
405 b
406 $ hg update -C tip
406 $ hg update -C tip
407 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
407 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 $ hg locate b
408 $ hg locate b
409 b
409 b
410 $ hg summary
410 $ hg summary
411 parent: 2:882396649954 tip
411 parent: 2:882396649954 tip
412 c
412 c
413 branch: default
413 branch: default
414 commit: (clean)
414 commit: (clean)
415 update: (current)
415 update: (current)
416 phases: 3 draft
416 phases: 3 draft
417
417
418 with --merge
418 with --merge
419 $ hg backout --merge -d '3 0' 1 --tool=true
419 $ hg backout --merge -d '3 0' 1 --tool=true
420 reverting a
420 reverting a
421 created new head
421 created new head
422 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
422 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
423 merging with changeset 3:3202beb76721
423 merging with changeset 3:3202beb76721
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 (branch merge, don't forget to commit)
425 (branch merge, don't forget to commit)
426 $ hg locate b
426 $ hg locate b
427 b
427 b
428 $ hg update -C tip
428 $ hg update -C tip
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
430 $ hg locate b
430 $ hg locate b
431 [1]
431 [1]
432
432
433 $ cd ..
433 $ cd ..
434 $ hg init m
434 $ hg init m
435 $ cd m
435 $ cd m
436 $ echo a > a
436 $ echo a > a
437 $ hg commit -d '0 0' -A -m a
437 $ hg commit -d '0 0' -A -m a
438 adding a
438 adding a
439 $ echo b > b
439 $ echo b > b
440 $ hg commit -d '1 0' -A -m b
440 $ hg commit -d '1 0' -A -m b
441 adding b
441 adding b
442 $ echo c > c
442 $ echo c > c
443 $ hg commit -d '2 0' -A -m b
443 $ hg commit -d '2 0' -A -m b
444 adding c
444 adding c
445 $ hg update 1
445 $ hg update 1
446 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
446 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
447 $ echo d > d
447 $ echo d > d
448 $ hg commit -d '3 0' -A -m c
448 $ hg commit -d '3 0' -A -m c
449 adding d
449 adding d
450 created new head
450 created new head
451 $ hg merge 2
451 $ hg merge 2
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 (branch merge, don't forget to commit)
453 (branch merge, don't forget to commit)
454 $ hg commit -d '4 0' -A -m d
454 $ hg commit -d '4 0' -A -m d
455 $ hg summary
455 $ hg summary
456 parent: 4:b2f3bb92043e tip
456 parent: 4:b2f3bb92043e tip
457 d
457 d
458 branch: default
458 branch: default
459 commit: (clean)
459 commit: (clean)
460 update: (current)
460 update: (current)
461 phases: 5 draft
461 phases: 5 draft
462
462
463 backout of merge should fail
463 backout of merge should fail
464
464
465 $ hg backout 4
465 $ hg backout 4
466 abort: cannot backout a merge changeset
466 abort: cannot backout a merge changeset
467 [255]
467 [255]
468
468
469 backout of merge with bad parent should fail
469 backout of merge with bad parent should fail
470
470
471 $ hg backout --parent 0 4
471 $ hg backout --parent 0 4
472 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
472 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
473 [255]
473 [255]
474
474
475 backout of non-merge with parent should fail
475 backout of non-merge with parent should fail
476
476
477 $ hg backout --parent 0 3
477 $ hg backout --parent 0 3
478 abort: cannot use --parent on non-merge changeset
478 abort: cannot use --parent on non-merge changeset
479 [255]
479 [255]
480
480
481 backout with valid parent should be ok
481 backout with valid parent should be ok
482
482
483 $ hg backout -d '5 0' --parent 2 4 --tool=true
483 $ hg backout -d '5 0' --parent 2 4 --tool=true
484 removing d
484 removing d
485 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
485 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
486 $ hg summary
486 $ hg summary
487 parent: 5:10e5328c8435 tip
487 parent: 5:10e5328c8435 tip
488 Backed out changeset b2f3bb92043e
488 Backed out changeset b2f3bb92043e
489 branch: default
489 branch: default
490 commit: (clean)
490 commit: (clean)
491 update: (current)
491 update: (current)
492 phases: 6 draft
492 phases: 6 draft
493
493
494 $ hg rollback
494 $ hg rollback
495 repository tip rolled back to revision 4 (undo commit)
495 repository tip rolled back to revision 4 (undo commit)
496 working directory now based on revision 4
496 working directory now based on revision 4
497 $ hg update -C
497 $ hg update -C
498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 $ hg summary
499 $ hg summary
500 parent: 4:b2f3bb92043e tip
500 parent: 4:b2f3bb92043e tip
501 d
501 d
502 branch: default
502 branch: default
503 commit: (clean)
503 commit: (clean)
504 update: (current)
504 update: (current)
505 phases: 5 draft
505 phases: 5 draft
506
506
507 $ hg backout -d '6 0' --parent 3 4 --tool=true
507 $ hg backout -d '6 0' --parent 3 4 --tool=true
508 removing c
508 removing c
509 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
509 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
510 $ hg summary
510 $ hg summary
511 parent: 5:033590168430 tip
511 parent: 5:033590168430 tip
512 Backed out changeset b2f3bb92043e
512 Backed out changeset b2f3bb92043e
513 branch: default
513 branch: default
514 commit: (clean)
514 commit: (clean)
515 update: (current)
515 update: (current)
516 phases: 6 draft
516 phases: 6 draft
517
517
518 $ cd ..
518 $ cd ..
519
519
520 named branches
520 named branches
521
521
522 $ hg init named_branches
522 $ hg init named_branches
523 $ cd named_branches
523 $ cd named_branches
524
524
525 $ echo default > default
525 $ echo default > default
526 $ hg ci -d '0 0' -Am default
526 $ hg ci -d '0 0' -Am default
527 adding default
527 adding default
528 $ hg branch branch1
528 $ hg branch branch1
529 marked working directory as branch branch1
529 marked working directory as branch branch1
530 (branches are permanent and global, did you want a bookmark?)
530 (branches are permanent and global, did you want a bookmark?)
531 $ echo branch1 > file1
531 $ echo branch1 > file1
532 $ hg ci -d '1 0' -Am file1
532 $ hg ci -d '1 0' -Am file1
533 adding file1
533 adding file1
534 $ hg branch branch2
534 $ hg branch branch2
535 marked working directory as branch branch2
535 marked working directory as branch branch2
536 $ echo branch2 > file2
536 $ echo branch2 > file2
537 $ hg ci -d '2 0' -Am file2
537 $ hg ci -d '2 0' -Am file2
538 adding file2
538 adding file2
539
539
540 without --merge
540 without --merge
541 $ hg backout --no-commit -r 1 --tool=true
541 $ hg backout --no-commit -r 1 --tool=true
542 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
542 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
543 changeset bf1602f437f3 backed out, don't forget to commit.
543 changeset bf1602f437f3 backed out, don't forget to commit.
544 $ hg branch
544 $ hg branch
545 branch2
545 branch2
546 $ hg status -A
546 $ hg status -A
547 R file1
547 R file1
548 C default
548 C default
549 C file2
549 C file2
550 $ hg summary
550 $ hg summary
551 parent: 2:45bbcd363bf0 tip
551 parent: 2:45bbcd363bf0 tip
552 file2
552 file2
553 branch: branch2
553 branch: branch2
554 commit: 1 removed
554 commit: 1 removed
555 update: (current)
555 update: (current)
556 phases: 3 draft
556 phases: 3 draft
557
557
558 with --merge
558 with --merge
559 (this also tests that editor is invoked if '--edit' is specified
559 (this also tests that editor is invoked if '--edit' is specified
560 explicitly regardless of '--message')
560 explicitly regardless of '--message')
561
561
562 $ hg update -qC
562 $ hg update -qC
563 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
563 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
564 removing file1
564 removing file1
565 backout on branch1
565 backout on branch1
566
566
567
567
568 HG: Enter commit message. Lines beginning with 'HG:' are removed.
568 HG: Enter commit message. Lines beginning with 'HG:' are removed.
569 HG: Leave message empty to abort commit.
569 HG: Leave message empty to abort commit.
570 HG: --
570 HG: --
571 HG: user: test
571 HG: user: test
572 HG: branch 'branch2'
572 HG: branch 'branch2'
573 HG: removed file1
573 HG: removed file1
574 created new head
574 created new head
575 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
575 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
576 merging with changeset 3:d4e8f6db59fb
576 merging with changeset 3:d4e8f6db59fb
577 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
577 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
578 (branch merge, don't forget to commit)
578 (branch merge, don't forget to commit)
579 $ hg summary
579 $ hg summary
580 parent: 2:45bbcd363bf0
580 parent: 2:45bbcd363bf0
581 file2
581 file2
582 parent: 3:d4e8f6db59fb tip
582 parent: 3:d4e8f6db59fb tip
583 backout on branch1
583 backout on branch1
584 branch: branch2
584 branch: branch2
585 commit: 1 removed (merge)
585 commit: 1 removed (merge)
586 update: (current)
586 update: (current)
587 phases: 4 draft
587 phases: 4 draft
588 $ hg update -q -C 2
588 $ hg update -q -C 2
589
589
590 on branch2 with branch1 not merged, so file1 should still exist:
590 on branch2 with branch1 not merged, so file1 should still exist:
591
591
592 $ hg id
592 $ hg id
593 45bbcd363bf0 (branch2)
593 45bbcd363bf0 (branch2)
594 $ hg st -A
594 $ hg st -A
595 C default
595 C default
596 C file1
596 C file1
597 C file2
597 C file2
598 $ hg summary
598 $ hg summary
599 parent: 2:45bbcd363bf0
599 parent: 2:45bbcd363bf0
600 file2
600 file2
601 branch: branch2
601 branch: branch2
602 commit: (clean)
602 commit: (clean)
603 update: 1 new changesets, 2 branch heads (merge)
603 update: 1 new changesets, 2 branch heads (merge)
604 phases: 4 draft
604 phases: 4 draft
605
605
606 on branch2 with branch1 merged, so file1 should be gone:
606 on branch2 with branch1 merged, so file1 should be gone:
607
607
608 $ hg merge
608 $ hg merge
609 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
609 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
610 (branch merge, don't forget to commit)
610 (branch merge, don't forget to commit)
611 $ hg ci -d '4 0' -m 'merge backout of branch1'
611 $ hg ci -d '4 0' -m 'merge backout of branch1'
612 $ hg id
612 $ hg id
613 d97a8500a969 (branch2) tip
613 d97a8500a969 (branch2) tip
614 $ hg st -A
614 $ hg st -A
615 C default
615 C default
616 C file2
616 C file2
617 $ hg summary
617 $ hg summary
618 parent: 4:d97a8500a969 tip
618 parent: 4:d97a8500a969 tip
619 merge backout of branch1
619 merge backout of branch1
620 branch: branch2
620 branch: branch2
621 commit: (clean)
621 commit: (clean)
622 update: (current)
622 update: (current)
623 phases: 5 draft
623 phases: 5 draft
624
624
625 on branch1, so no file1 and file2:
625 on branch1, so no file1 and file2:
626
626
627 $ hg co -C branch1
627 $ hg co -C branch1
628 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
628 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
629 $ hg id
629 $ hg id
630 bf1602f437f3 (branch1)
630 bf1602f437f3 (branch1)
631 $ hg st -A
631 $ hg st -A
632 C default
632 C default
633 C file1
633 C file1
634 $ hg summary
634 $ hg summary
635 parent: 1:bf1602f437f3
635 parent: 1:bf1602f437f3
636 file1
636 file1
637 branch: branch1
637 branch: branch1
638 commit: (clean)
638 commit: (clean)
639 update: (current)
639 update: (current)
640 phases: 5 draft
640 phases: 5 draft
641
641
642 $ cd ..
642 $ cd ..
643
643
644 backout of empty changeset (issue4190)
644 backout of empty changeset (issue4190)
645
645
646 $ hg init emptycommit
646 $ hg init emptycommit
647 $ cd emptycommit
647 $ cd emptycommit
648
648
649 $ touch file1
649 $ touch file1
650 $ hg ci -Aqm file1
650 $ hg ci -Aqm file1
651 $ hg branch -q branch1
651 $ hg branch -q branch1
652 $ hg ci -qm branch1
652 $ hg ci -qm branch1
653 $ hg backout -v 1
653 $ hg backout -v 1
654 resolving manifests
654 resolving manifests
655 nothing changed
655 nothing changed
656 [1]
656 [1]
657
657
658 $ cd ..
658 $ cd ..
659
659
660
660
661 Test usage of `hg resolve` in case of conflict
661 Test usage of `hg resolve` in case of conflict
662 (issue4163)
662 (issue4163)
663
663
664 $ hg init issue4163
664 $ hg init issue4163
665 $ cd issue4163
665 $ cd issue4163
666 $ touch foo
666 $ touch foo
667 $ hg add foo
667 $ hg add foo
668 $ cat > foo << EOF
668 $ cat > foo << EOF
669 > one
669 > one
670 > two
670 > two
671 > three
671 > three
672 > four
672 > four
673 > five
673 > five
674 > six
674 > six
675 > seven
675 > seven
676 > height
676 > height
677 > nine
677 > nine
678 > ten
678 > ten
679 > EOF
679 > EOF
680 $ hg ci -m 'initial'
680 $ hg ci -m 'initial'
681 $ cat > foo << EOF
681 $ cat > foo << EOF
682 > one
682 > one
683 > two
683 > two
684 > THREE
684 > THREE
685 > four
685 > four
686 > five
686 > five
687 > six
687 > six
688 > seven
688 > seven
689 > height
689 > height
690 > nine
690 > nine
691 > ten
691 > ten
692 > EOF
692 > EOF
693 $ hg ci -m 'capital three'
693 $ hg ci -m 'capital three'
694 $ cat > foo << EOF
694 $ cat > foo << EOF
695 > one
695 > one
696 > two
696 > two
697 > THREE
697 > THREE
698 > four
698 > four
699 > five
699 > five
700 > six
700 > six
701 > seven
701 > seven
702 > height
702 > height
703 > nine
703 > nine
704 > TEN
704 > TEN
705 > EOF
705 > EOF
706 $ hg ci -m 'capital ten'
706 $ hg ci -m 'capital ten'
707 $ hg backout -r 'desc("capital three")' --tool internal:fail
707 $ hg backout -r 'desc("capital three")' --tool internal:fail
708 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
708 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
709 use 'hg resolve' to retry unresolved file merges
709 use 'hg resolve' to retry unresolved file merges
710 [1]
710 [1]
711 $ hg status
711 $ hg status
712 $ hg debugmergestate
712 $ hg debugmergestate
713 * version 2 records
713 * version 2 records
714 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
714 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
715 other: a30dd8addae3ce71b8667868478542bc417439e6
715 other: a30dd8addae3ce71b8667868478542bc417439e6
716 file extras: foo (ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553)
716 file extras: foo (ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553)
717 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
717 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
718 local path: foo (flags "")
718 local path: foo (flags "")
719 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
719 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
720 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
720 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
721 $ mv .hg/merge/state2 .hg/merge/state2-moved
721 $ mv .hg/merge/state2 .hg/merge/state2-moved
722 $ hg debugmergestate
722 $ hg debugmergestate
723 * version 1 records
723 * version 1 records
724 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
724 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
725 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
725 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
726 local path: foo (flags "")
726 local path: foo (flags "")
727 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
727 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
728 other path: foo (node not stored in v1 format)
728 other path: foo (node not stored in v1 format)
729 $ mv .hg/merge/state2-moved .hg/merge/state2
729 $ mv .hg/merge/state2-moved .hg/merge/state2
730 $ hg resolve -l # still unresolved
730 $ hg resolve -l # still unresolved
731 U foo
731 U foo
732 $ hg summary
732 $ hg summary
733 parent: 2:b71750c4b0fd tip
733 parent: 2:b71750c4b0fd tip
734 capital ten
734 capital ten
735 branch: default
735 branch: default
736 commit: 1 unresolved (clean)
736 commit: 1 unresolved (clean)
737 update: (current)
737 update: (current)
738 phases: 3 draft
738 phases: 3 draft
739 $ hg log -G
739 $ hg log -G
740 @ changeset: 2:b71750c4b0fd
740 @ changeset: 2:b71750c4b0fd
741 | tag: tip
741 | tag: tip
742 | user: test
742 | user: test
743 | date: Thu Jan 01 00:00:00 1970 +0000
743 | date: Thu Jan 01 00:00:00 1970 +0000
744 | summary: capital ten
744 | summary: capital ten
745 |
745 |
746 o changeset: 1:913609522437
746 o changeset: 1:913609522437
747 | user: test
747 | user: test
748 | date: Thu Jan 01 00:00:00 1970 +0000
748 | date: Thu Jan 01 00:00:00 1970 +0000
749 | summary: capital three
749 | summary: capital three
750 |
750 |
751 o changeset: 0:a30dd8addae3
751 % changeset: 0:a30dd8addae3
752 user: test
752 user: test
753 date: Thu Jan 01 00:00:00 1970 +0000
753 date: Thu Jan 01 00:00:00 1970 +0000
754 summary: initial
754 summary: initial
755
755
756 $ hg resolve --all --debug
756 $ hg resolve --all --debug
757 picked tool ':merge' for foo (binary False symlink False changedelete False)
757 picked tool ':merge' for foo (binary False symlink False changedelete False)
758 merging foo
758 merging foo
759 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
759 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
760 premerge successful
760 premerge successful
761 (no more unresolved files)
761 (no more unresolved files)
762 continue: hg commit
762 continue: hg commit
763 $ hg status
763 $ hg status
764 M foo
764 M foo
765 ? foo.orig
765 ? foo.orig
766 $ hg resolve -l
766 $ hg resolve -l
767 R foo
767 R foo
768 $ hg summary
768 $ hg summary
769 parent: 2:b71750c4b0fd tip
769 parent: 2:b71750c4b0fd tip
770 capital ten
770 capital ten
771 branch: default
771 branch: default
772 commit: 1 modified, 1 unknown
772 commit: 1 modified, 1 unknown
773 update: (current)
773 update: (current)
774 phases: 3 draft
774 phases: 3 draft
775 $ cat foo
775 $ cat foo
776 one
776 one
777 two
777 two
778 three
778 three
779 four
779 four
780 five
780 five
781 six
781 six
782 seven
782 seven
783 height
783 height
784 nine
784 nine
785 TEN
785 TEN
786
786
787 --no-commit shouldn't commit
787 --no-commit shouldn't commit
788
788
789 $ hg init a
789 $ hg init a
790 $ cd a
790 $ cd a
791 $ for i in 1 2 3; do
791 $ for i in 1 2 3; do
792 > touch $i
792 > touch $i
793 > hg ci -Am $i
793 > hg ci -Am $i
794 > done
794 > done
795 adding 1
795 adding 1
796 adding 2
796 adding 2
797 adding 3
797 adding 3
798 $ hg backout --no-commit .
798 $ hg backout --no-commit .
799 removing 3
799 removing 3
800 changeset cccc23d9d68f backed out, don't forget to commit.
800 changeset cccc23d9d68f backed out, don't forget to commit.
801 $ hg revert -aq
801 $ hg revert -aq
802
802
803 --no-commit can't be used with --merge
803 --no-commit can't be used with --merge
804
804
805 $ hg backout --merge --no-commit 2
805 $ hg backout --merge --no-commit 2
806 abort: cannot use --merge with --no-commit
806 abort: cannot use --merge with --no-commit
807 [255]
807 [255]
@@ -1,771 +1,771 b''
1 #testcases abortcommand abortflag
1 #testcases abortcommand abortflag
2
2
3 #if abortflag
3 #if abortflag
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [alias]
5 > [alias]
6 > abort = graft --abort
6 > abort = graft --abort
7 > EOF
7 > EOF
8 #endif
8 #endif
9
9
10
10
11 Testing the reading of old format graftstate file with newer mercurial
11 Testing the reading of old format graftstate file with newer mercurial
12
12
13 $ hg init oldgraft
13 $ hg init oldgraft
14 $ cd oldgraft
14 $ cd oldgraft
15 $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
15 $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
16 $ hg log -GT "{rev}:{node|short} {desc}\n"
16 $ hg log -GT "{rev}:{node|short} {desc}\n"
17 @ 2:8be98ac1a569 added c
17 @ 2:8be98ac1a569 added c
18 |
18 |
19 o 1:80e6d2c47cfe added b
19 o 1:80e6d2c47cfe added b
20 |
20 |
21 o 0:f7ad41964313 added a
21 o 0:f7ad41964313 added a
22
22
23 $ hg up 0
23 $ hg up 0
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 $ echo bar > b
25 $ echo bar > b
26 $ hg add b
26 $ hg add b
27 $ hg ci -m "bar to b"
27 $ hg ci -m "bar to b"
28 created new head
28 created new head
29 $ hg graft -r 1 -r 2
29 $ hg graft -r 1 -r 2
30 grafting 1:80e6d2c47cfe "added b"
30 grafting 1:80e6d2c47cfe "added b"
31 merging b
31 merging b
32 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
32 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
33 abort: unresolved conflicts, can't continue
33 abort: unresolved conflicts, can't continue
34 (use 'hg resolve' and 'hg graft --continue')
34 (use 'hg resolve' and 'hg graft --continue')
35 [255]
35 [255]
36
36
37 Writing the nodes in old format to graftstate
37 Writing the nodes in old format to graftstate
38
38
39 $ hg log -r 1 -r 2 -T '{node}\n' > .hg/graftstate
39 $ hg log -r 1 -r 2 -T '{node}\n' > .hg/graftstate
40 $ echo foo > b
40 $ echo foo > b
41 $ hg resolve -m
41 $ hg resolve -m
42 (no more unresolved files)
42 (no more unresolved files)
43 continue: hg graft --continue
43 continue: hg graft --continue
44 $ hg graft --continue
44 $ hg graft --continue
45 grafting 1:80e6d2c47cfe "added b"
45 grafting 1:80e6d2c47cfe "added b"
46 grafting 2:8be98ac1a569 "added c"
46 grafting 2:8be98ac1a569 "added c"
47
47
48 Testing that --user is preserved during conflicts and value is reused while
48 Testing that --user is preserved during conflicts and value is reused while
49 running `hg graft --continue`
49 running `hg graft --continue`
50
50
51 $ hg log -G
51 $ hg log -G
52 @ changeset: 5:711e9fa999f1
52 @ changeset: 5:711e9fa999f1
53 | tag: tip
53 | tag: tip
54 | user: test
54 | user: test
55 | date: Thu Jan 01 00:00:00 1970 +0000
55 | date: Thu Jan 01 00:00:00 1970 +0000
56 | summary: added c
56 | summary: added c
57 |
57 |
58 o changeset: 4:e5ad7353b408
58 o changeset: 4:e5ad7353b408
59 | user: test
59 | user: test
60 | date: Thu Jan 01 00:00:00 1970 +0000
60 | date: Thu Jan 01 00:00:00 1970 +0000
61 | summary: added b
61 | summary: added b
62 |
62 |
63 o changeset: 3:9e887f7a939c
63 o changeset: 3:9e887f7a939c
64 | parent: 0:f7ad41964313
64 | parent: 0:f7ad41964313
65 | user: test
65 | user: test
66 | date: Thu Jan 01 00:00:00 1970 +0000
66 | date: Thu Jan 01 00:00:00 1970 +0000
67 | summary: bar to b
67 | summary: bar to b
68 |
68 |
69 | o changeset: 2:8be98ac1a569
69 | o changeset: 2:8be98ac1a569
70 | | user: test
70 | | user: test
71 | | date: Thu Jan 01 00:00:00 1970 +0000
71 | | date: Thu Jan 01 00:00:00 1970 +0000
72 | | summary: added c
72 | | summary: added c
73 | |
73 | |
74 | o changeset: 1:80e6d2c47cfe
74 | o changeset: 1:80e6d2c47cfe
75 |/ user: test
75 |/ user: test
76 | date: Thu Jan 01 00:00:00 1970 +0000
76 | date: Thu Jan 01 00:00:00 1970 +0000
77 | summary: added b
77 | summary: added b
78 |
78 |
79 o changeset: 0:f7ad41964313
79 o changeset: 0:f7ad41964313
80 user: test
80 user: test
81 date: Thu Jan 01 00:00:00 1970 +0000
81 date: Thu Jan 01 00:00:00 1970 +0000
82 summary: added a
82 summary: added a
83
83
84
84
85 $ hg up '.^^'
85 $ hg up '.^^'
86 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
86 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
87
87
88 $ hg graft -r 1 -r 2 --user batman
88 $ hg graft -r 1 -r 2 --user batman
89 grafting 1:80e6d2c47cfe "added b"
89 grafting 1:80e6d2c47cfe "added b"
90 merging b
90 merging b
91 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
91 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
92 abort: unresolved conflicts, can't continue
92 abort: unresolved conflicts, can't continue
93 (use 'hg resolve' and 'hg graft --continue')
93 (use 'hg resolve' and 'hg graft --continue')
94 [255]
94 [255]
95
95
96 $ echo wat > b
96 $ echo wat > b
97 $ hg resolve -m
97 $ hg resolve -m
98 (no more unresolved files)
98 (no more unresolved files)
99 continue: hg graft --continue
99 continue: hg graft --continue
100
100
101 $ hg graft --continue
101 $ hg graft --continue
102 grafting 1:80e6d2c47cfe "added b"
102 grafting 1:80e6d2c47cfe "added b"
103 grafting 2:8be98ac1a569 "added c"
103 grafting 2:8be98ac1a569 "added c"
104
104
105 $ hg log -Gr 3::
105 $ hg log -Gr 3::
106 @ changeset: 7:11a36ffaacf2
106 @ changeset: 7:11a36ffaacf2
107 | tag: tip
107 | tag: tip
108 | user: batman
108 | user: batman
109 | date: Thu Jan 01 00:00:00 1970 +0000
109 | date: Thu Jan 01 00:00:00 1970 +0000
110 | summary: added c
110 | summary: added c
111 |
111 |
112 o changeset: 6:76803afc6511
112 o changeset: 6:76803afc6511
113 | parent: 3:9e887f7a939c
113 | parent: 3:9e887f7a939c
114 | user: batman
114 | user: batman
115 | date: Thu Jan 01 00:00:00 1970 +0000
115 | date: Thu Jan 01 00:00:00 1970 +0000
116 | summary: added b
116 | summary: added b
117 |
117 |
118 | o changeset: 5:711e9fa999f1
118 | o changeset: 5:711e9fa999f1
119 | | user: test
119 | | user: test
120 | | date: Thu Jan 01 00:00:00 1970 +0000
120 | | date: Thu Jan 01 00:00:00 1970 +0000
121 | | summary: added c
121 | | summary: added c
122 | |
122 | |
123 | o changeset: 4:e5ad7353b408
123 | o changeset: 4:e5ad7353b408
124 |/ user: test
124 |/ user: test
125 | date: Thu Jan 01 00:00:00 1970 +0000
125 | date: Thu Jan 01 00:00:00 1970 +0000
126 | summary: added b
126 | summary: added b
127 |
127 |
128 o changeset: 3:9e887f7a939c
128 o changeset: 3:9e887f7a939c
129 | parent: 0:f7ad41964313
129 | parent: 0:f7ad41964313
130 ~ user: test
130 ~ user: test
131 date: Thu Jan 01 00:00:00 1970 +0000
131 date: Thu Jan 01 00:00:00 1970 +0000
132 summary: bar to b
132 summary: bar to b
133
133
134 Test that --date is preserved and reused in `hg graft --continue`
134 Test that --date is preserved and reused in `hg graft --continue`
135
135
136 $ hg up '.^^'
136 $ hg up '.^^'
137 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
137 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
138 $ hg graft -r 1 -r 2 --date '1234560000 120'
138 $ hg graft -r 1 -r 2 --date '1234560000 120'
139 grafting 1:80e6d2c47cfe "added b"
139 grafting 1:80e6d2c47cfe "added b"
140 merging b
140 merging b
141 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
141 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
142 abort: unresolved conflicts, can't continue
142 abort: unresolved conflicts, can't continue
143 (use 'hg resolve' and 'hg graft --continue')
143 (use 'hg resolve' and 'hg graft --continue')
144 [255]
144 [255]
145
145
146 $ echo foobar > b
146 $ echo foobar > b
147 $ hg resolve -m
147 $ hg resolve -m
148 (no more unresolved files)
148 (no more unresolved files)
149 continue: hg graft --continue
149 continue: hg graft --continue
150 $ hg graft --continue
150 $ hg graft --continue
151 grafting 1:80e6d2c47cfe "added b"
151 grafting 1:80e6d2c47cfe "added b"
152 grafting 2:8be98ac1a569 "added c"
152 grafting 2:8be98ac1a569 "added c"
153
153
154 $ hg log -Gr '.^^::.'
154 $ hg log -Gr '.^^::.'
155 @ changeset: 9:1896b76e007a
155 @ changeset: 9:1896b76e007a
156 | tag: tip
156 | tag: tip
157 | user: test
157 | user: test
158 | date: Fri Feb 13 21:18:00 2009 -0002
158 | date: Fri Feb 13 21:18:00 2009 -0002
159 | summary: added c
159 | summary: added c
160 |
160 |
161 o changeset: 8:ce2b4f1632af
161 o changeset: 8:ce2b4f1632af
162 | parent: 3:9e887f7a939c
162 | parent: 3:9e887f7a939c
163 | user: test
163 | user: test
164 | date: Fri Feb 13 21:18:00 2009 -0002
164 | date: Fri Feb 13 21:18:00 2009 -0002
165 | summary: added b
165 | summary: added b
166 |
166 |
167 o changeset: 3:9e887f7a939c
167 o changeset: 3:9e887f7a939c
168 | parent: 0:f7ad41964313
168 | parent: 0:f7ad41964313
169 ~ user: test
169 ~ user: test
170 date: Thu Jan 01 00:00:00 1970 +0000
170 date: Thu Jan 01 00:00:00 1970 +0000
171 summary: bar to b
171 summary: bar to b
172
172
173 Test that --log is preserved and reused in `hg graft --continue`
173 Test that --log is preserved and reused in `hg graft --continue`
174
174
175 $ hg up '.^^'
175 $ hg up '.^^'
176 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
176 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
177 $ hg graft -r 1 -r 2 --log
177 $ hg graft -r 1 -r 2 --log
178 grafting 1:80e6d2c47cfe "added b"
178 grafting 1:80e6d2c47cfe "added b"
179 merging b
179 merging b
180 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
180 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
181 abort: unresolved conflicts, can't continue
181 abort: unresolved conflicts, can't continue
182 (use 'hg resolve' and 'hg graft --continue')
182 (use 'hg resolve' and 'hg graft --continue')
183 [255]
183 [255]
184
184
185 $ echo foobar > b
185 $ echo foobar > b
186 $ hg resolve -m
186 $ hg resolve -m
187 (no more unresolved files)
187 (no more unresolved files)
188 continue: hg graft --continue
188 continue: hg graft --continue
189
189
190 $ hg graft --continue
190 $ hg graft --continue
191 grafting 1:80e6d2c47cfe "added b"
191 grafting 1:80e6d2c47cfe "added b"
192 grafting 2:8be98ac1a569 "added c"
192 grafting 2:8be98ac1a569 "added c"
193
193
194 $ hg log -GT "{rev}:{node|short} {desc}" -r '.^^::.'
194 $ hg log -GT "{rev}:{node|short} {desc}" -r '.^^::.'
195 @ 11:30c1050a58b2 added c
195 @ 11:30c1050a58b2 added c
196 | (grafted from 8be98ac1a56990c2d9ca6861041b8390af7bd6f3)
196 | (grafted from 8be98ac1a56990c2d9ca6861041b8390af7bd6f3)
197 o 10:ec7eda2313e2 added b
197 o 10:ec7eda2313e2 added b
198 | (grafted from 80e6d2c47cfe5b3185519568327a17a061c7efb6)
198 | (grafted from 80e6d2c47cfe5b3185519568327a17a061c7efb6)
199 o 3:9e887f7a939c bar to b
199 o 3:9e887f7a939c bar to b
200 |
200 |
201 ~
201 ~
202
202
203 $ cd ..
203 $ cd ..
204
204
205 Testing the --stop flag of `hg graft` which stops the interrupted graft
205 Testing the --stop flag of `hg graft` which stops the interrupted graft
206
206
207 $ hg init stopgraft
207 $ hg init stopgraft
208 $ cd stopgraft
208 $ cd stopgraft
209 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
209 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
210
210
211 $ hg log -G
211 $ hg log -G
212 @ changeset: 3:9150fe93bec6
212 @ changeset: 3:9150fe93bec6
213 | tag: tip
213 | tag: tip
214 | user: test
214 | user: test
215 | date: Thu Jan 01 00:00:00 1970 +0000
215 | date: Thu Jan 01 00:00:00 1970 +0000
216 | summary: added d
216 | summary: added d
217 |
217 |
218 o changeset: 2:155349b645be
218 o changeset: 2:155349b645be
219 | user: test
219 | user: test
220 | date: Thu Jan 01 00:00:00 1970 +0000
220 | date: Thu Jan 01 00:00:00 1970 +0000
221 | summary: added c
221 | summary: added c
222 |
222 |
223 o changeset: 1:5f6d8a4bf34a
223 o changeset: 1:5f6d8a4bf34a
224 | user: test
224 | user: test
225 | date: Thu Jan 01 00:00:00 1970 +0000
225 | date: Thu Jan 01 00:00:00 1970 +0000
226 | summary: added b
226 | summary: added b
227 |
227 |
228 o changeset: 0:9092f1db7931
228 o changeset: 0:9092f1db7931
229 user: test
229 user: test
230 date: Thu Jan 01 00:00:00 1970 +0000
230 date: Thu Jan 01 00:00:00 1970 +0000
231 summary: added a
231 summary: added a
232
232
233 $ hg up '.^^'
233 $ hg up '.^^'
234 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
234 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
235
235
236 $ echo foo > d
236 $ echo foo > d
237 $ hg ci -Aqm "added foo to d"
237 $ hg ci -Aqm "added foo to d"
238
238
239 $ hg graft --stop
239 $ hg graft --stop
240 abort: no interrupted graft found
240 abort: no interrupted graft found
241 [255]
241 [255]
242
242
243 $ hg graft -r 3
243 $ hg graft -r 3
244 grafting 3:9150fe93bec6 "added d"
244 grafting 3:9150fe93bec6 "added d"
245 merging d
245 merging d
246 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
246 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
247 abort: unresolved conflicts, can't continue
247 abort: unresolved conflicts, can't continue
248 (use 'hg resolve' and 'hg graft --continue')
248 (use 'hg resolve' and 'hg graft --continue')
249 [255]
249 [255]
250
250
251 $ hg graft --stop --continue
251 $ hg graft --stop --continue
252 abort: cannot use '--continue' and '--stop' together
252 abort: cannot use '--continue' and '--stop' together
253 [255]
253 [255]
254
254
255 $ hg graft --stop -U
255 $ hg graft --stop -U
256 abort: cannot specify any other flag with '--stop'
256 abort: cannot specify any other flag with '--stop'
257 [255]
257 [255]
258 $ hg graft --stop --rev 4
258 $ hg graft --stop --rev 4
259 abort: cannot specify any other flag with '--stop'
259 abort: cannot specify any other flag with '--stop'
260 [255]
260 [255]
261 $ hg graft --stop --log
261 $ hg graft --stop --log
262 abort: cannot specify any other flag with '--stop'
262 abort: cannot specify any other flag with '--stop'
263 [255]
263 [255]
264
264
265 $ hg graft --stop
265 $ hg graft --stop
266 stopped the interrupted graft
266 stopped the interrupted graft
267 working directory is now at a0deacecd59d
267 working directory is now at a0deacecd59d
268
268
269 $ hg diff
269 $ hg diff
270
270
271 $ hg log -Gr '.'
271 $ hg log -Gr '.'
272 @ changeset: 4:a0deacecd59d
272 @ changeset: 4:a0deacecd59d
273 | tag: tip
273 | tag: tip
274 ~ parent: 1:5f6d8a4bf34a
274 ~ parent: 1:5f6d8a4bf34a
275 user: test
275 user: test
276 date: Thu Jan 01 00:00:00 1970 +0000
276 date: Thu Jan 01 00:00:00 1970 +0000
277 summary: added foo to d
277 summary: added foo to d
278
278
279 $ hg graft -r 2 -r 3
279 $ hg graft -r 2 -r 3
280 grafting 2:155349b645be "added c"
280 grafting 2:155349b645be "added c"
281 grafting 3:9150fe93bec6 "added d"
281 grafting 3:9150fe93bec6 "added d"
282 merging d
282 merging d
283 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
283 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
284 abort: unresolved conflicts, can't continue
284 abort: unresolved conflicts, can't continue
285 (use 'hg resolve' and 'hg graft --continue')
285 (use 'hg resolve' and 'hg graft --continue')
286 [255]
286 [255]
287
287
288 $ hg graft --stop
288 $ hg graft --stop
289 stopped the interrupted graft
289 stopped the interrupted graft
290 working directory is now at 75b447541a9e
290 working directory is now at 75b447541a9e
291
291
292 $ hg diff
292 $ hg diff
293
293
294 $ hg log -G -T "{rev}:{node|short} {desc}"
294 $ hg log -G -T "{rev}:{node|short} {desc}"
295 @ 5:75b447541a9e added c
295 @ 5:75b447541a9e added c
296 |
296 |
297 o 4:a0deacecd59d added foo to d
297 o 4:a0deacecd59d added foo to d
298 |
298 |
299 | o 3:9150fe93bec6 added d
299 | o 3:9150fe93bec6 added d
300 | |
300 | |
301 | o 2:155349b645be added c
301 | o 2:155349b645be added c
302 |/
302 |/
303 o 1:5f6d8a4bf34a added b
303 o 1:5f6d8a4bf34a added b
304 |
304 |
305 o 0:9092f1db7931 added a
305 o 0:9092f1db7931 added a
306
306
307 $ cd ..
307 $ cd ..
308
308
309 Testing the --abort flag for `hg graft` which aborts and rollback to state
309 Testing the --abort flag for `hg graft` which aborts and rollback to state
310 before the graft
310 before the graft
311
311
312 $ hg init abortgraft
312 $ hg init abortgraft
313 $ cd abortgraft
313 $ cd abortgraft
314 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
314 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
315
315
316 $ hg up '.^^'
316 $ hg up '.^^'
317 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
317 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
318
318
319 $ echo x > x
319 $ echo x > x
320 $ hg ci -Aqm "added x"
320 $ hg ci -Aqm "added x"
321 $ hg up '.^'
321 $ hg up '.^'
322 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
322 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
323 $ echo foo > c
323 $ echo foo > c
324 $ hg ci -Aqm "added foo to c"
324 $ hg ci -Aqm "added foo to c"
325
325
326 $ hg log -GT "{rev}:{node|short} {desc}"
326 $ hg log -GT "{rev}:{node|short} {desc}"
327 @ 5:36b793615f78 added foo to c
327 @ 5:36b793615f78 added foo to c
328 |
328 |
329 | o 4:863a25e1a9ea added x
329 | o 4:863a25e1a9ea added x
330 |/
330 |/
331 | o 3:9150fe93bec6 added d
331 | o 3:9150fe93bec6 added d
332 | |
332 | |
333 | o 2:155349b645be added c
333 | o 2:155349b645be added c
334 |/
334 |/
335 o 1:5f6d8a4bf34a added b
335 o 1:5f6d8a4bf34a added b
336 |
336 |
337 o 0:9092f1db7931 added a
337 o 0:9092f1db7931 added a
338
338
339 $ hg up 9150fe93bec6
339 $ hg up 9150fe93bec6
340 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
341
341
342 $ hg abort
342 $ hg abort
343 abort: no interrupted graft to abort (abortflag !)
343 abort: no interrupted graft to abort (abortflag !)
344 abort: no operation in progress (abortcommand !)
344 abort: no operation in progress (abortcommand !)
345 [255]
345 [255]
346
346
347 when stripping is required
347 when stripping is required
348 $ hg graft -r 4 -r 5
348 $ hg graft -r 4 -r 5
349 grafting 4:863a25e1a9ea "added x"
349 grafting 4:863a25e1a9ea "added x"
350 grafting 5:36b793615f78 "added foo to c" (tip)
350 grafting 5:36b793615f78 "added foo to c" (tip)
351 merging c
351 merging c
352 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
352 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
353 abort: unresolved conflicts, can't continue
353 abort: unresolved conflicts, can't continue
354 (use 'hg resolve' and 'hg graft --continue')
354 (use 'hg resolve' and 'hg graft --continue')
355 [255]
355 [255]
356
356
357 $ hg graft --continue --abort
357 $ hg graft --continue --abort
358 abort: cannot use '--continue' and '--abort' together
358 abort: cannot use '--continue' and '--abort' together
359 [255]
359 [255]
360
360
361 $ hg graft --abort --stop
361 $ hg graft --abort --stop
362 abort: cannot use '--abort' and '--stop' together
362 abort: cannot use '--abort' and '--stop' together
363 [255]
363 [255]
364
364
365 $ hg graft --abort --currentuser
365 $ hg graft --abort --currentuser
366 abort: cannot specify any other flag with '--abort'
366 abort: cannot specify any other flag with '--abort'
367 [255]
367 [255]
368
368
369 $ hg graft --abort --edit
369 $ hg graft --abort --edit
370 abort: cannot specify any other flag with '--abort'
370 abort: cannot specify any other flag with '--abort'
371 [255]
371 [255]
372
372
373 #if abortcommand
373 #if abortcommand
374 when in dry-run mode
374 when in dry-run mode
375 $ hg abort --dry-run
375 $ hg abort --dry-run
376 graft in progress, will be aborted
376 graft in progress, will be aborted
377 #endif
377 #endif
378
378
379 $ hg abort
379 $ hg abort
380 graft aborted
380 graft aborted
381 working directory is now at 9150fe93bec6
381 working directory is now at 9150fe93bec6
382 $ hg log -GT "{rev}:{node|short} {desc}"
382 $ hg log -GT "{rev}:{node|short} {desc}"
383 o 5:36b793615f78 added foo to c
383 o 5:36b793615f78 added foo to c
384 |
384 |
385 | o 4:863a25e1a9ea added x
385 | o 4:863a25e1a9ea added x
386 |/
386 |/
387 | @ 3:9150fe93bec6 added d
387 | @ 3:9150fe93bec6 added d
388 | |
388 | |
389 | o 2:155349b645be added c
389 | o 2:155349b645be added c
390 |/
390 |/
391 o 1:5f6d8a4bf34a added b
391 o 1:5f6d8a4bf34a added b
392 |
392 |
393 o 0:9092f1db7931 added a
393 o 0:9092f1db7931 added a
394
394
395 when stripping is not required
395 when stripping is not required
396 $ hg graft -r 5
396 $ hg graft -r 5
397 grafting 5:36b793615f78 "added foo to c" (tip)
397 grafting 5:36b793615f78 "added foo to c" (tip)
398 merging c
398 merging c
399 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
399 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
400 abort: unresolved conflicts, can't continue
400 abort: unresolved conflicts, can't continue
401 (use 'hg resolve' and 'hg graft --continue')
401 (use 'hg resolve' and 'hg graft --continue')
402 [255]
402 [255]
403
403
404 $ hg abort
404 $ hg abort
405 graft aborted
405 graft aborted
406 working directory is now at 9150fe93bec6
406 working directory is now at 9150fe93bec6
407 $ hg log -GT "{rev}:{node|short} {desc}"
407 $ hg log -GT "{rev}:{node|short} {desc}"
408 o 5:36b793615f78 added foo to c
408 o 5:36b793615f78 added foo to c
409 |
409 |
410 | o 4:863a25e1a9ea added x
410 | o 4:863a25e1a9ea added x
411 |/
411 |/
412 | @ 3:9150fe93bec6 added d
412 | @ 3:9150fe93bec6 added d
413 | |
413 | |
414 | o 2:155349b645be added c
414 | o 2:155349b645be added c
415 |/
415 |/
416 o 1:5f6d8a4bf34a added b
416 o 1:5f6d8a4bf34a added b
417 |
417 |
418 o 0:9092f1db7931 added a
418 o 0:9092f1db7931 added a
419
419
420 when some of the changesets became public
420 when some of the changesets became public
421
421
422 $ hg graft -r 4 -r 5
422 $ hg graft -r 4 -r 5
423 grafting 4:863a25e1a9ea "added x"
423 grafting 4:863a25e1a9ea "added x"
424 grafting 5:36b793615f78 "added foo to c" (tip)
424 grafting 5:36b793615f78 "added foo to c" (tip)
425 merging c
425 merging c
426 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
426 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
427 abort: unresolved conflicts, can't continue
427 abort: unresolved conflicts, can't continue
428 (use 'hg resolve' and 'hg graft --continue')
428 (use 'hg resolve' and 'hg graft --continue')
429 [255]
429 [255]
430
430
431 $ hg log -GT "{rev}:{node|short} {desc}"
431 $ hg log -GT "{rev}:{node|short} {desc}"
432 @ 6:6ec71c037d94 added x
432 @ 6:6ec71c037d94 added x
433 |
433 |
434 | o 5:36b793615f78 added foo to c
434 | % 5:36b793615f78 added foo to c
435 | |
435 | |
436 | | o 4:863a25e1a9ea added x
436 | | o 4:863a25e1a9ea added x
437 | |/
437 | |/
438 o | 3:9150fe93bec6 added d
438 o | 3:9150fe93bec6 added d
439 | |
439 | |
440 o | 2:155349b645be added c
440 o | 2:155349b645be added c
441 |/
441 |/
442 o 1:5f6d8a4bf34a added b
442 o 1:5f6d8a4bf34a added b
443 |
443 |
444 o 0:9092f1db7931 added a
444 o 0:9092f1db7931 added a
445
445
446 $ hg phase -r 6 --public
446 $ hg phase -r 6 --public
447
447
448 $ hg abort
448 $ hg abort
449 cannot clean up public changesets 6ec71c037d94
449 cannot clean up public changesets 6ec71c037d94
450 graft aborted
450 graft aborted
451 working directory is now at 6ec71c037d94
451 working directory is now at 6ec71c037d94
452
452
453 when we created new changesets on top of existing one
453 when we created new changesets on top of existing one
454
454
455 $ hg up '.^^'
455 $ hg up '.^^'
456 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
456 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
457 $ echo y > y
457 $ echo y > y
458 $ hg ci -Aqm "added y"
458 $ hg ci -Aqm "added y"
459 $ echo z > z
459 $ echo z > z
460 $ hg ci -Aqm "added z"
460 $ hg ci -Aqm "added z"
461
461
462 $ hg up 3
462 $ hg up 3
463 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
463 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
464 $ hg log -GT "{rev}:{node|short} {desc}"
464 $ hg log -GT "{rev}:{node|short} {desc}"
465 o 8:637f9e9bbfd4 added z
465 o 8:637f9e9bbfd4 added z
466 |
466 |
467 o 7:123221671fd4 added y
467 o 7:123221671fd4 added y
468 |
468 |
469 | o 6:6ec71c037d94 added x
469 | o 6:6ec71c037d94 added x
470 | |
470 | |
471 | | o 5:36b793615f78 added foo to c
471 | | o 5:36b793615f78 added foo to c
472 | | |
472 | | |
473 | | | o 4:863a25e1a9ea added x
473 | | | o 4:863a25e1a9ea added x
474 | | |/
474 | | |/
475 | @ | 3:9150fe93bec6 added d
475 | @ | 3:9150fe93bec6 added d
476 |/ /
476 |/ /
477 o / 2:155349b645be added c
477 o / 2:155349b645be added c
478 |/
478 |/
479 o 1:5f6d8a4bf34a added b
479 o 1:5f6d8a4bf34a added b
480 |
480 |
481 o 0:9092f1db7931 added a
481 o 0:9092f1db7931 added a
482
482
483 $ hg graft -r 8 -r 7 -r 5
483 $ hg graft -r 8 -r 7 -r 5
484 grafting 8:637f9e9bbfd4 "added z" (tip)
484 grafting 8:637f9e9bbfd4 "added z" (tip)
485 grafting 7:123221671fd4 "added y"
485 grafting 7:123221671fd4 "added y"
486 grafting 5:36b793615f78 "added foo to c"
486 grafting 5:36b793615f78 "added foo to c"
487 merging c
487 merging c
488 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
488 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
489 abort: unresolved conflicts, can't continue
489 abort: unresolved conflicts, can't continue
490 (use 'hg resolve' and 'hg graft --continue')
490 (use 'hg resolve' and 'hg graft --continue')
491 [255]
491 [255]
492
492
493 $ cd ..
493 $ cd ..
494 $ hg init pullrepo
494 $ hg init pullrepo
495 $ cd pullrepo
495 $ cd pullrepo
496 $ cat >> .hg/hgrc <<EOF
496 $ cat >> .hg/hgrc <<EOF
497 > [phases]
497 > [phases]
498 > publish=False
498 > publish=False
499 > EOF
499 > EOF
500 $ hg pull ../abortgraft --config phases.publish=False
500 $ hg pull ../abortgraft --config phases.publish=False
501 pulling from ../abortgraft
501 pulling from ../abortgraft
502 requesting all changes
502 requesting all changes
503 adding changesets
503 adding changesets
504 adding manifests
504 adding manifests
505 adding file changes
505 adding file changes
506 added 11 changesets with 9 changes to 8 files (+4 heads)
506 added 11 changesets with 9 changes to 8 files (+4 heads)
507 new changesets 9092f1db7931:6b98ff0062dd (6 drafts)
507 new changesets 9092f1db7931:6b98ff0062dd (6 drafts)
508 (run 'hg heads' to see heads, 'hg merge' to merge)
508 (run 'hg heads' to see heads, 'hg merge' to merge)
509 $ hg up 9
509 $ hg up 9
510 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
511 $ echo w > w
511 $ echo w > w
512 $ hg ci -Aqm "added w" --config phases.publish=False
512 $ hg ci -Aqm "added w" --config phases.publish=False
513
513
514 $ cd ../abortgraft
514 $ cd ../abortgraft
515 $ hg pull ../pullrepo
515 $ hg pull ../pullrepo
516 pulling from ../pullrepo
516 pulling from ../pullrepo
517 searching for changes
517 searching for changes
518 adding changesets
518 adding changesets
519 adding manifests
519 adding manifests
520 adding file changes
520 adding file changes
521 added 1 changesets with 1 changes to 1 files (+1 heads)
521 added 1 changesets with 1 changes to 1 files (+1 heads)
522 new changesets 311dfc6cf3bf (1 drafts)
522 new changesets 311dfc6cf3bf (1 drafts)
523 (run 'hg heads .' to see heads, 'hg merge' to merge)
523 (run 'hg heads .' to see heads, 'hg merge' to merge)
524
524
525 $ hg abort
525 $ hg abort
526 new changesets detected on destination branch, can't strip
526 new changesets detected on destination branch, can't strip
527 graft aborted
527 graft aborted
528 working directory is now at 6b98ff0062dd
528 working directory is now at 6b98ff0062dd
529
529
530 $ cd ..
530 $ cd ..
531
531
532 ============================
532 ============================
533 Testing --no-commit option:|
533 Testing --no-commit option:|
534 ============================
534 ============================
535
535
536 $ hg init nocommit
536 $ hg init nocommit
537 $ cd nocommit
537 $ cd nocommit
538 $ echo a > a
538 $ echo a > a
539 $ hg ci -qAma
539 $ hg ci -qAma
540 $ echo b > b
540 $ echo b > b
541 $ hg ci -qAmb
541 $ hg ci -qAmb
542 $ hg up -q 0
542 $ hg up -q 0
543 $ echo c > c
543 $ echo c > c
544 $ hg ci -qAmc
544 $ hg ci -qAmc
545 $ hg log -GT "{rev}:{node|short} {desc}\n"
545 $ hg log -GT "{rev}:{node|short} {desc}\n"
546 @ 2:d36c0562f908 c
546 @ 2:d36c0562f908 c
547 |
547 |
548 | o 1:d2ae7f538514 b
548 | o 1:d2ae7f538514 b
549 |/
549 |/
550 o 0:cb9a9f314b8b a
550 o 0:cb9a9f314b8b a
551
551
552
552
553 Check reporting when --no-commit used with non-applicable options:
553 Check reporting when --no-commit used with non-applicable options:
554
554
555 $ hg graft 1 --no-commit -e
555 $ hg graft 1 --no-commit -e
556 abort: cannot specify --no-commit and --edit together
556 abort: cannot specify --no-commit and --edit together
557 [255]
557 [255]
558
558
559 $ hg graft 1 --no-commit --log
559 $ hg graft 1 --no-commit --log
560 abort: cannot specify --no-commit and --log together
560 abort: cannot specify --no-commit and --log together
561 [255]
561 [255]
562
562
563 $ hg graft 1 --no-commit -D
563 $ hg graft 1 --no-commit -D
564 abort: cannot specify --no-commit and --currentdate together
564 abort: cannot specify --no-commit and --currentdate together
565 [255]
565 [255]
566
566
567 Test --no-commit is working:
567 Test --no-commit is working:
568 $ hg graft 1 --no-commit
568 $ hg graft 1 --no-commit
569 grafting 1:d2ae7f538514 "b"
569 grafting 1:d2ae7f538514 "b"
570
570
571 $ hg log -GT "{rev}:{node|short} {desc}\n"
571 $ hg log -GT "{rev}:{node|short} {desc}\n"
572 @ 2:d36c0562f908 c
572 @ 2:d36c0562f908 c
573 |
573 |
574 | o 1:d2ae7f538514 b
574 | o 1:d2ae7f538514 b
575 |/
575 |/
576 o 0:cb9a9f314b8b a
576 o 0:cb9a9f314b8b a
577
577
578
578
579 $ hg diff
579 $ hg diff
580 diff -r d36c0562f908 b
580 diff -r d36c0562f908 b
581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
582 +++ b/b Thu Jan 01 00:00:00 1970 +0000
582 +++ b/b Thu Jan 01 00:00:00 1970 +0000
583 @@ -0,0 +1,1 @@
583 @@ -0,0 +1,1 @@
584 +b
584 +b
585
585
586 Prepare wrdir to check --no-commit is resepected after --continue:
586 Prepare wrdir to check --no-commit is resepected after --continue:
587
587
588 $ hg up -qC
588 $ hg up -qC
589 $ echo A>a
589 $ echo A>a
590 $ hg ci -qm "A in file a"
590 $ hg ci -qm "A in file a"
591 $ hg up -q 1
591 $ hg up -q 1
592 $ echo B>a
592 $ echo B>a
593 $ hg ci -qm "B in file a"
593 $ hg ci -qm "B in file a"
594 $ hg log -GT "{rev}:{node|short} {desc}\n"
594 $ hg log -GT "{rev}:{node|short} {desc}\n"
595 @ 4:2aa9ad1006ff B in file a
595 @ 4:2aa9ad1006ff B in file a
596 |
596 |
597 | o 3:09e253b87e17 A in file a
597 | o 3:09e253b87e17 A in file a
598 | |
598 | |
599 | o 2:d36c0562f908 c
599 | o 2:d36c0562f908 c
600 | |
600 | |
601 o | 1:d2ae7f538514 b
601 o | 1:d2ae7f538514 b
602 |/
602 |/
603 o 0:cb9a9f314b8b a
603 o 0:cb9a9f314b8b a
604
604
605
605
606 $ hg graft 3 --no-commit
606 $ hg graft 3 --no-commit
607 grafting 3:09e253b87e17 "A in file a"
607 grafting 3:09e253b87e17 "A in file a"
608 merging a
608 merging a
609 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
609 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
610 abort: unresolved conflicts, can't continue
610 abort: unresolved conflicts, can't continue
611 (use 'hg resolve' and 'hg graft --continue')
611 (use 'hg resolve' and 'hg graft --continue')
612 [255]
612 [255]
613
613
614 Resolve conflict:
614 Resolve conflict:
615 $ echo A>a
615 $ echo A>a
616 $ hg resolve --mark
616 $ hg resolve --mark
617 (no more unresolved files)
617 (no more unresolved files)
618 continue: hg graft --continue
618 continue: hg graft --continue
619
619
620 $ hg graft --continue
620 $ hg graft --continue
621 grafting 3:09e253b87e17 "A in file a"
621 grafting 3:09e253b87e17 "A in file a"
622 $ hg log -GT "{rev}:{node|short} {desc}\n"
622 $ hg log -GT "{rev}:{node|short} {desc}\n"
623 @ 4:2aa9ad1006ff B in file a
623 @ 4:2aa9ad1006ff B in file a
624 |
624 |
625 | o 3:09e253b87e17 A in file a
625 | % 3:09e253b87e17 A in file a
626 | |
626 | |
627 | o 2:d36c0562f908 c
627 | o 2:d36c0562f908 c
628 | |
628 | |
629 o | 1:d2ae7f538514 b
629 o | 1:d2ae7f538514 b
630 |/
630 |/
631 o 0:cb9a9f314b8b a
631 o 0:cb9a9f314b8b a
632
632
633 $ hg diff
633 $ hg diff
634 diff -r 2aa9ad1006ff a
634 diff -r 2aa9ad1006ff a
635 --- a/a Thu Jan 01 00:00:00 1970 +0000
635 --- a/a Thu Jan 01 00:00:00 1970 +0000
636 +++ b/a Thu Jan 01 00:00:00 1970 +0000
636 +++ b/a Thu Jan 01 00:00:00 1970 +0000
637 @@ -1,1 +1,1 @@
637 @@ -1,1 +1,1 @@
638 -B
638 -B
639 +A
639 +A
640
640
641 $ hg up -qC
641 $ hg up -qC
642
642
643 Check --no-commit is resepected when passed with --continue:
643 Check --no-commit is resepected when passed with --continue:
644
644
645 $ hg graft 3
645 $ hg graft 3
646 grafting 3:09e253b87e17 "A in file a"
646 grafting 3:09e253b87e17 "A in file a"
647 merging a
647 merging a
648 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
648 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
649 abort: unresolved conflicts, can't continue
649 abort: unresolved conflicts, can't continue
650 (use 'hg resolve' and 'hg graft --continue')
650 (use 'hg resolve' and 'hg graft --continue')
651 [255]
651 [255]
652
652
653 Resolve conflict:
653 Resolve conflict:
654 $ echo A>a
654 $ echo A>a
655 $ hg resolve --mark
655 $ hg resolve --mark
656 (no more unresolved files)
656 (no more unresolved files)
657 continue: hg graft --continue
657 continue: hg graft --continue
658
658
659 $ hg graft --continue --no-commit
659 $ hg graft --continue --no-commit
660 grafting 3:09e253b87e17 "A in file a"
660 grafting 3:09e253b87e17 "A in file a"
661 $ hg diff
661 $ hg diff
662 diff -r 2aa9ad1006ff a
662 diff -r 2aa9ad1006ff a
663 --- a/a Thu Jan 01 00:00:00 1970 +0000
663 --- a/a Thu Jan 01 00:00:00 1970 +0000
664 +++ b/a Thu Jan 01 00:00:00 1970 +0000
664 +++ b/a Thu Jan 01 00:00:00 1970 +0000
665 @@ -1,1 +1,1 @@
665 @@ -1,1 +1,1 @@
666 -B
666 -B
667 +A
667 +A
668
668
669 $ hg log -GT "{rev}:{node|short} {desc}\n"
669 $ hg log -GT "{rev}:{node|short} {desc}\n"
670 @ 4:2aa9ad1006ff B in file a
670 @ 4:2aa9ad1006ff B in file a
671 |
671 |
672 | o 3:09e253b87e17 A in file a
672 | % 3:09e253b87e17 A in file a
673 | |
673 | |
674 | o 2:d36c0562f908 c
674 | o 2:d36c0562f908 c
675 | |
675 | |
676 o | 1:d2ae7f538514 b
676 o | 1:d2ae7f538514 b
677 |/
677 |/
678 o 0:cb9a9f314b8b a
678 o 0:cb9a9f314b8b a
679
679
680 $ hg up -qC
680 $ hg up -qC
681
681
682 Test --no-commit when graft multiple revisions:
682 Test --no-commit when graft multiple revisions:
683 When there is conflict:
683 When there is conflict:
684 $ hg graft -r "2::3" --no-commit
684 $ hg graft -r "2::3" --no-commit
685 grafting 2:d36c0562f908 "c"
685 grafting 2:d36c0562f908 "c"
686 grafting 3:09e253b87e17 "A in file a"
686 grafting 3:09e253b87e17 "A in file a"
687 merging a
687 merging a
688 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
688 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
689 abort: unresolved conflicts, can't continue
689 abort: unresolved conflicts, can't continue
690 (use 'hg resolve' and 'hg graft --continue')
690 (use 'hg resolve' and 'hg graft --continue')
691 [255]
691 [255]
692
692
693 $ echo A>a
693 $ echo A>a
694 $ hg resolve --mark
694 $ hg resolve --mark
695 (no more unresolved files)
695 (no more unresolved files)
696 continue: hg graft --continue
696 continue: hg graft --continue
697 $ hg graft --continue
697 $ hg graft --continue
698 grafting 3:09e253b87e17 "A in file a"
698 grafting 3:09e253b87e17 "A in file a"
699 $ hg diff
699 $ hg diff
700 diff -r 2aa9ad1006ff a
700 diff -r 2aa9ad1006ff a
701 --- a/a Thu Jan 01 00:00:00 1970 +0000
701 --- a/a Thu Jan 01 00:00:00 1970 +0000
702 +++ b/a Thu Jan 01 00:00:00 1970 +0000
702 +++ b/a Thu Jan 01 00:00:00 1970 +0000
703 @@ -1,1 +1,1 @@
703 @@ -1,1 +1,1 @@
704 -B
704 -B
705 +A
705 +A
706 diff -r 2aa9ad1006ff c
706 diff -r 2aa9ad1006ff c
707 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
707 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
708 +++ b/c Thu Jan 01 00:00:00 1970 +0000
708 +++ b/c Thu Jan 01 00:00:00 1970 +0000
709 @@ -0,0 +1,1 @@
709 @@ -0,0 +1,1 @@
710 +c
710 +c
711
711
712 $ hg log -GT "{rev}:{node|short} {desc}\n"
712 $ hg log -GT "{rev}:{node|short} {desc}\n"
713 @ 4:2aa9ad1006ff B in file a
713 @ 4:2aa9ad1006ff B in file a
714 |
714 |
715 | o 3:09e253b87e17 A in file a
715 | % 3:09e253b87e17 A in file a
716 | |
716 | |
717 | o 2:d36c0562f908 c
717 | o 2:d36c0562f908 c
718 | |
718 | |
719 o | 1:d2ae7f538514 b
719 o | 1:d2ae7f538514 b
720 |/
720 |/
721 o 0:cb9a9f314b8b a
721 o 0:cb9a9f314b8b a
722
722
723 $ hg up -qC
723 $ hg up -qC
724
724
725 When there is no conflict:
725 When there is no conflict:
726 $ echo d>d
726 $ echo d>d
727 $ hg add d -q
727 $ hg add d -q
728 $ hg ci -qmd
728 $ hg ci -qmd
729 $ hg up 3 -q
729 $ hg up 3 -q
730 $ hg log -GT "{rev}:{node|short} {desc}\n"
730 $ hg log -GT "{rev}:{node|short} {desc}\n"
731 o 5:baefa8927fc0 d
731 o 5:baefa8927fc0 d
732 |
732 |
733 o 4:2aa9ad1006ff B in file a
733 o 4:2aa9ad1006ff B in file a
734 |
734 |
735 | @ 3:09e253b87e17 A in file a
735 | @ 3:09e253b87e17 A in file a
736 | |
736 | |
737 | o 2:d36c0562f908 c
737 | o 2:d36c0562f908 c
738 | |
738 | |
739 o | 1:d2ae7f538514 b
739 o | 1:d2ae7f538514 b
740 |/
740 |/
741 o 0:cb9a9f314b8b a
741 o 0:cb9a9f314b8b a
742
742
743
743
744 $ hg graft -r 1 -r 5 --no-commit
744 $ hg graft -r 1 -r 5 --no-commit
745 grafting 1:d2ae7f538514 "b"
745 grafting 1:d2ae7f538514 "b"
746 grafting 5:baefa8927fc0 "d" (tip)
746 grafting 5:baefa8927fc0 "d" (tip)
747 $ hg diff
747 $ hg diff
748 diff -r 09e253b87e17 b
748 diff -r 09e253b87e17 b
749 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
749 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
750 +++ b/b Thu Jan 01 00:00:00 1970 +0000
750 +++ b/b Thu Jan 01 00:00:00 1970 +0000
751 @@ -0,0 +1,1 @@
751 @@ -0,0 +1,1 @@
752 +b
752 +b
753 diff -r 09e253b87e17 d
753 diff -r 09e253b87e17 d
754 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
754 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
755 +++ b/d Thu Jan 01 00:00:00 1970 +0000
755 +++ b/d Thu Jan 01 00:00:00 1970 +0000
756 @@ -0,0 +1,1 @@
756 @@ -0,0 +1,1 @@
757 +d
757 +d
758 $ hg log -GT "{rev}:{node|short} {desc}\n"
758 $ hg log -GT "{rev}:{node|short} {desc}\n"
759 o 5:baefa8927fc0 d
759 o 5:baefa8927fc0 d
760 |
760 |
761 o 4:2aa9ad1006ff B in file a
761 o 4:2aa9ad1006ff B in file a
762 |
762 |
763 | @ 3:09e253b87e17 A in file a
763 | @ 3:09e253b87e17 A in file a
764 | |
764 | |
765 | o 2:d36c0562f908 c
765 | o 2:d36c0562f908 c
766 | |
766 | |
767 o | 1:d2ae7f538514 b
767 o | 1:d2ae7f538514 b
768 |/
768 |/
769 o 0:cb9a9f314b8b a
769 o 0:cb9a9f314b8b a
770
770
771 $ cd ..
771 $ cd ..
@@ -1,776 +1,776 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 > mq=
4 > mq=
5 > drawdag=$TESTDIR/drawdag.py
5 > drawdag=$TESTDIR/drawdag.py
6 >
6 >
7 > [phases]
7 > [phases]
8 > publish=False
8 > publish=False
9 >
9 >
10 > [alias]
10 > [alias]
11 > tglog = log -G --template "{rev}: {node|short} '{desc}' {branches}\n"
11 > tglog = log -G --template "{rev}: {node|short} '{desc}' {branches}\n"
12 > tglogp = log -G --template "{rev}: {node|short} {phase} '{desc}' {branches}\n"
12 > tglogp = log -G --template "{rev}: {node|short} {phase} '{desc}' {branches}\n"
13 > EOF
13 > EOF
14
14
15 Highest phase of source commits is used:
15 Highest phase of source commits is used:
16
16
17 $ hg init phase
17 $ hg init phase
18 $ cd phase
18 $ cd phase
19 $ hg debugdrawdag << 'EOF'
19 $ hg debugdrawdag << 'EOF'
20 > D
20 > D
21 > |
21 > |
22 > F C
22 > F C
23 > | |
23 > | |
24 > E B
24 > E B
25 > |/
25 > |/
26 > A
26 > A
27 > EOF
27 > EOF
28
28
29 $ hg phase --force --secret D
29 $ hg phase --force --secret D
30
30
31 $ cat > $TESTTMP/editor.sh <<EOF
31 $ cat > $TESTTMP/editor.sh <<EOF
32 > echo "==== before editing"
32 > echo "==== before editing"
33 > cat \$1
33 > cat \$1
34 > echo "===="
34 > echo "===="
35 > echo "edited manually" >> \$1
35 > echo "edited manually" >> \$1
36 > EOF
36 > EOF
37 $ HGEDITOR="sh $TESTTMP/editor.sh" hg rebase --collapse --keepbranches -e --source B --dest F
37 $ HGEDITOR="sh $TESTTMP/editor.sh" hg rebase --collapse --keepbranches -e --source B --dest F
38 rebasing 1:112478962961 "B" (B)
38 rebasing 1:112478962961 "B" (B)
39 rebasing 3:26805aba1e60 "C" (C)
39 rebasing 3:26805aba1e60 "C" (C)
40 rebasing 5:f585351a92f8 "D" (D tip)
40 rebasing 5:f585351a92f8 "D" (D tip)
41 ==== before editing
41 ==== before editing
42 Collapsed revision
42 Collapsed revision
43 * B
43 * B
44 * C
44 * C
45 * D
45 * D
46
46
47
47
48 HG: Enter commit message. Lines beginning with 'HG:' are removed.
48 HG: Enter commit message. Lines beginning with 'HG:' are removed.
49 HG: Leave message empty to abort commit.
49 HG: Leave message empty to abort commit.
50 HG: --
50 HG: --
51 HG: user: test
51 HG: user: test
52 HG: branch 'default'
52 HG: branch 'default'
53 HG: added B
53 HG: added B
54 HG: added C
54 HG: added C
55 HG: added D
55 HG: added D
56 ====
56 ====
57 saved backup bundle to $TESTTMP/phase/.hg/strip-backup/112478962961-cb2a9b47-rebase.hg
57 saved backup bundle to $TESTTMP/phase/.hg/strip-backup/112478962961-cb2a9b47-rebase.hg
58
58
59 $ hg tglogp
59 $ hg tglogp
60 o 3: 92fa5f5fe108 secret 'Collapsed revision
60 o 3: 92fa5f5fe108 secret 'Collapsed revision
61 | * B
61 | * B
62 | * C
62 | * C
63 | * D
63 | * D
64 |
64 |
65 |
65 |
66 | edited manually'
66 | edited manually'
67 o 2: 64a8289d2492 draft 'F'
67 o 2: 64a8289d2492 draft 'F'
68 |
68 |
69 o 1: 7fb047a69f22 draft 'E'
69 o 1: 7fb047a69f22 draft 'E'
70 |
70 |
71 o 0: 426bada5c675 draft 'A'
71 o 0: 426bada5c675 draft 'A'
72
72
73 $ hg manifest --rev tip
73 $ hg manifest --rev tip
74 A
74 A
75 B
75 B
76 C
76 C
77 D
77 D
78 E
78 E
79 F
79 F
80
80
81 $ cd ..
81 $ cd ..
82
82
83
83
84 Merge gets linearized:
84 Merge gets linearized:
85
85
86 $ hg init linearized-merge
86 $ hg init linearized-merge
87 $ cd linearized-merge
87 $ cd linearized-merge
88
88
89 $ hg debugdrawdag << 'EOF'
89 $ hg debugdrawdag << 'EOF'
90 > F D
90 > F D
91 > |/|
91 > |/|
92 > C B
92 > C B
93 > |/
93 > |/
94 > A
94 > A
95 > EOF
95 > EOF
96
96
97 $ hg phase --force --secret D
97 $ hg phase --force --secret D
98 $ hg rebase --source B --collapse --dest F
98 $ hg rebase --source B --collapse --dest F
99 rebasing 1:112478962961 "B" (B)
99 rebasing 1:112478962961 "B" (B)
100 rebasing 3:4e4f9194f9f1 "D" (D)
100 rebasing 3:4e4f9194f9f1 "D" (D)
101 saved backup bundle to $TESTTMP/linearized-merge/.hg/strip-backup/112478962961-e389075b-rebase.hg
101 saved backup bundle to $TESTTMP/linearized-merge/.hg/strip-backup/112478962961-e389075b-rebase.hg
102
102
103 $ hg tglog
103 $ hg tglog
104 o 3: 5bdc08b7da2b 'Collapsed revision
104 o 3: 5bdc08b7da2b 'Collapsed revision
105 | * B
105 | * B
106 | * D'
106 | * D'
107 o 2: afc707c82df0 'F'
107 o 2: afc707c82df0 'F'
108 |
108 |
109 o 1: dc0947a82db8 'C'
109 o 1: dc0947a82db8 'C'
110 |
110 |
111 o 0: 426bada5c675 'A'
111 o 0: 426bada5c675 'A'
112
112
113 $ hg manifest --rev tip
113 $ hg manifest --rev tip
114 A
114 A
115 B
115 B
116 C
116 C
117 F
117 F
118
118
119 $ cd ..
119 $ cd ..
120
120
121 Custom message:
121 Custom message:
122
122
123 $ hg init message
123 $ hg init message
124 $ cd message
124 $ cd message
125
125
126 $ hg debugdrawdag << 'EOF'
126 $ hg debugdrawdag << 'EOF'
127 > C
127 > C
128 > |
128 > |
129 > D B
129 > D B
130 > |/
130 > |/
131 > A
131 > A
132 > EOF
132 > EOF
133
133
134
134
135 $ hg rebase --base B -m 'custom message'
135 $ hg rebase --base B -m 'custom message'
136 abort: message can only be specified with collapse
136 abort: message can only be specified with collapse
137 [255]
137 [255]
138
138
139 $ cat > $TESTTMP/checkeditform.sh <<EOF
139 $ cat > $TESTTMP/checkeditform.sh <<EOF
140 > env | grep HGEDITFORM
140 > env | grep HGEDITFORM
141 > true
141 > true
142 > EOF
142 > EOF
143 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --source B --collapse -m 'custom message' -e --dest D
143 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --source B --collapse -m 'custom message' -e --dest D
144 rebasing 1:112478962961 "B" (B)
144 rebasing 1:112478962961 "B" (B)
145 rebasing 3:26805aba1e60 "C" (C tip)
145 rebasing 3:26805aba1e60 "C" (C tip)
146 HGEDITFORM=rebase.collapse
146 HGEDITFORM=rebase.collapse
147 saved backup bundle to $TESTTMP/message/.hg/strip-backup/112478962961-f4131707-rebase.hg
147 saved backup bundle to $TESTTMP/message/.hg/strip-backup/112478962961-f4131707-rebase.hg
148
148
149 $ hg tglog
149 $ hg tglog
150 o 2: 2f197b9a08f3 'custom message'
150 o 2: 2f197b9a08f3 'custom message'
151 |
151 |
152 o 1: b18e25de2cf5 'D'
152 o 1: b18e25de2cf5 'D'
153 |
153 |
154 o 0: 426bada5c675 'A'
154 o 0: 426bada5c675 'A'
155
155
156 $ hg manifest --rev tip
156 $ hg manifest --rev tip
157 A
157 A
158 B
158 B
159 C
159 C
160 D
160 D
161
161
162 $ cd ..
162 $ cd ..
163
163
164 Rebase and collapse - more than one external (fail):
164 Rebase and collapse - more than one external (fail):
165
165
166 $ hg init multiple-external-parents
166 $ hg init multiple-external-parents
167 $ cd multiple-external-parents
167 $ cd multiple-external-parents
168
168
169 $ hg debugdrawdag << 'EOF'
169 $ hg debugdrawdag << 'EOF'
170 > G
170 > G
171 > |\
171 > |\
172 > | F
172 > | F
173 > | |
173 > | |
174 > D E
174 > D E
175 > |\|
175 > |\|
176 > H C B
176 > H C B
177 > \|/
177 > \|/
178 > A
178 > A
179 > EOF
179 > EOF
180
180
181 $ hg rebase -s C --dest H --collapse
181 $ hg rebase -s C --dest H --collapse
182 abort: unable to collapse on top of 3, there is more than one external parent: 1, 6
182 abort: unable to collapse on top of 3, there is more than one external parent: 1, 6
183 [255]
183 [255]
184
184
185 Rebase and collapse - E onto H:
185 Rebase and collapse - E onto H:
186
186
187 $ hg rebase -s E --dest I --collapse # root (E) is not a merge
187 $ hg rebase -s E --dest I --collapse # root (E) is not a merge
188 abort: unknown revision 'I'!
188 abort: unknown revision 'I'!
189 [255]
189 [255]
190
190
191 $ hg tglog
191 $ hg tglog
192 o 7: 64e264db77f0 'G'
192 o 7: 64e264db77f0 'G'
193 |\
193 |\
194 | o 6: 11abe3fb10b8 'F'
194 | o 6: 11abe3fb10b8 'F'
195 | |
195 | |
196 | o 5: 49cb92066bfd 'E'
196 | o 5: 49cb92066bfd 'E'
197 | |
197 | |
198 o | 4: 4e4f9194f9f1 'D'
198 o | 4: 4e4f9194f9f1 'D'
199 |\|
199 |\|
200 | | o 3: 575c4b5ec114 'H'
200 | | o 3: 575c4b5ec114 'H'
201 | | |
201 | | |
202 o---+ 2: dc0947a82db8 'C'
202 o---+ 2: dc0947a82db8 'C'
203 / /
203 / /
204 o / 1: 112478962961 'B'
204 o / 1: 112478962961 'B'
205 |/
205 |/
206 o 0: 426bada5c675 'A'
206 o 0: 426bada5c675 'A'
207
207
208 $ hg manifest --rev tip
208 $ hg manifest --rev tip
209 A
209 A
210 B
210 B
211 C
211 C
212 E
212 E
213 F
213 F
214
214
215 $ cd ..
215 $ cd ..
216
216
217
217
218
218
219
219
220 Test that branchheads cache is updated correctly when doing a strip in which
220 Test that branchheads cache is updated correctly when doing a strip in which
221 the parent of the ancestor node to be stripped does not become a head and also,
221 the parent of the ancestor node to be stripped does not become a head and also,
222 the parent of a node that is a child of the node stripped becomes a head (node
222 the parent of a node that is a child of the node stripped becomes a head (node
223 3). The code is now much simpler and we could just test a simpler scenario
223 3). The code is now much simpler and we could just test a simpler scenario
224 We keep it the test this way in case new complexity is injected.
224 We keep it the test this way in case new complexity is injected.
225
225
226 Create repo b:
226 Create repo b:
227
227
228 $ hg init branch-heads
228 $ hg init branch-heads
229 $ cd branch-heads
229 $ cd branch-heads
230
230
231 $ hg debugdrawdag << 'EOF'
231 $ hg debugdrawdag << 'EOF'
232 > G
232 > G
233 > |\
233 > |\
234 > | F
234 > | F
235 > | |
235 > | |
236 > D E
236 > D E
237 > |\|
237 > |\|
238 > H C B
238 > H C B
239 > \|/
239 > \|/
240 > A
240 > A
241 > EOF
241 > EOF
242
242
243 $ hg heads --template="{rev}:{node} {branch}\n"
243 $ hg heads --template="{rev}:{node} {branch}\n"
244 7:64e264db77f061f16d9132b70c5a58e2461fb630 default
244 7:64e264db77f061f16d9132b70c5a58e2461fb630 default
245 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default
245 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default
246
246
247 $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served
247 $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served
248 64e264db77f061f16d9132b70c5a58e2461fb630 7
248 64e264db77f061f16d9132b70c5a58e2461fb630 7
249 575c4b5ec114d64b681d33f8792853568bfb2b2c o default
249 575c4b5ec114d64b681d33f8792853568bfb2b2c o default
250 64e264db77f061f16d9132b70c5a58e2461fb630 o default
250 64e264db77f061f16d9132b70c5a58e2461fb630 o default
251
251
252 $ hg strip 4
252 $ hg strip 4
253 saved backup bundle to $TESTTMP/branch-heads/.hg/strip-backup/4e4f9194f9f1-5ec4b5e6-backup.hg
253 saved backup bundle to $TESTTMP/branch-heads/.hg/strip-backup/4e4f9194f9f1-5ec4b5e6-backup.hg
254
254
255 $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served
255 $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served
256 11abe3fb10b8689b560681094b17fe161871d043 5
256 11abe3fb10b8689b560681094b17fe161871d043 5
257 dc0947a82db884575bb76ea10ac97b08536bfa03 o default
257 dc0947a82db884575bb76ea10ac97b08536bfa03 o default
258 575c4b5ec114d64b681d33f8792853568bfb2b2c o default
258 575c4b5ec114d64b681d33f8792853568bfb2b2c o default
259 11abe3fb10b8689b560681094b17fe161871d043 o default
259 11abe3fb10b8689b560681094b17fe161871d043 o default
260
260
261 $ hg heads --template="{rev}:{node} {branch}\n"
261 $ hg heads --template="{rev}:{node} {branch}\n"
262 5:11abe3fb10b8689b560681094b17fe161871d043 default
262 5:11abe3fb10b8689b560681094b17fe161871d043 default
263 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default
263 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default
264 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default
264 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default
265
265
266 $ cd ..
266 $ cd ..
267
267
268
268
269
269
270 Preserves external parent
270 Preserves external parent
271
271
272 $ hg init external-parent
272 $ hg init external-parent
273 $ cd external-parent
273 $ cd external-parent
274
274
275 $ hg debugdrawdag << 'EOF'
275 $ hg debugdrawdag << 'EOF'
276 > H
276 > H
277 > |\
277 > |\
278 > | G
278 > | G
279 > | |
279 > | |
280 > | F # F/E = F\n
280 > | F # F/E = F\n
281 > | |
281 > | |
282 > D E # D/D = D\n
282 > D E # D/D = D\n
283 > |\|
283 > |\|
284 > I C B
284 > I C B
285 > \|/
285 > \|/
286 > A
286 > A
287 > EOF
287 > EOF
288
288
289 $ hg rebase -s F --dest I --collapse # root (F) is not a merge
289 $ hg rebase -s F --dest I --collapse # root (F) is not a merge
290 rebasing 6:c82b08f646f1 "F" (F)
290 rebasing 6:c82b08f646f1 "F" (F)
291 file 'E' was deleted in local [dest] but was modified in other [source].
291 file 'E' was deleted in local [dest] but was modified in other [source].
292 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
292 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
293 What do you want to do? u
293 What do you want to do? u
294 unresolved conflicts (see hg resolve, then hg rebase --continue)
294 unresolved conflicts (see hg resolve, then hg rebase --continue)
295 [1]
295 [1]
296
296
297 $ echo F > E
297 $ echo F > E
298 $ hg resolve -m
298 $ hg resolve -m
299 (no more unresolved files)
299 (no more unresolved files)
300 continue: hg rebase --continue
300 continue: hg rebase --continue
301 $ hg rebase -c
301 $ hg rebase -c
302 rebasing 6:c82b08f646f1 "F" (F)
302 rebasing 6:c82b08f646f1 "F" (F)
303 rebasing 7:a6db7fa104e1 "G" (G)
303 rebasing 7:a6db7fa104e1 "G" (G)
304 rebasing 8:e1d201b72d91 "H" (H tip)
304 rebasing 8:e1d201b72d91 "H" (H tip)
305 saved backup bundle to $TESTTMP/external-parent/.hg/strip-backup/c82b08f646f1-f2721fbf-rebase.hg
305 saved backup bundle to $TESTTMP/external-parent/.hg/strip-backup/c82b08f646f1-f2721fbf-rebase.hg
306
306
307 $ hg tglog
307 $ hg tglog
308 o 6: 681daa3e686d 'Collapsed revision
308 o 6: 681daa3e686d 'Collapsed revision
309 |\ * F
309 |\ * F
310 | | * G
310 | | * G
311 | | * H'
311 | | * H'
312 | | o 5: 49cb92066bfd 'E'
312 | | o 5: 49cb92066bfd 'E'
313 | | |
313 | | |
314 | o | 4: 09143c0bf13e 'D'
314 | o | 4: 09143c0bf13e 'D'
315 | |\|
315 | |\|
316 o | | 3: 08ebfeb61bac 'I'
316 o | | 3: 08ebfeb61bac 'I'
317 | | |
317 | | |
318 | o | 2: dc0947a82db8 'C'
318 | o | 2: dc0947a82db8 'C'
319 |/ /
319 |/ /
320 | o 1: 112478962961 'B'
320 | o 1: 112478962961 'B'
321 |/
321 |/
322 o 0: 426bada5c675 'A'
322 o 0: 426bada5c675 'A'
323
323
324 $ hg manifest --rev tip
324 $ hg manifest --rev tip
325 A
325 A
326 C
326 C
327 D
327 D
328 E
328 E
329 F
329 F
330 G
330 G
331 I
331 I
332
332
333 $ hg up tip -q
333 $ hg up tip -q
334 $ cat E
334 $ cat E
335 F
335 F
336
336
337 $ cd ..
337 $ cd ..
338
338
339 Rebasing from multiple bases:
339 Rebasing from multiple bases:
340
340
341 $ hg init multiple-bases
341 $ hg init multiple-bases
342 $ cd multiple-bases
342 $ cd multiple-bases
343 $ hg debugdrawdag << 'EOF'
343 $ hg debugdrawdag << 'EOF'
344 > C B
344 > C B
345 > D |/
345 > D |/
346 > |/
346 > |/
347 > A
347 > A
348 > EOF
348 > EOF
349 $ hg rebase --collapse -r 'B+C' -d D
349 $ hg rebase --collapse -r 'B+C' -d D
350 rebasing 1:fc2b737bb2e5 "B" (B)
350 rebasing 1:fc2b737bb2e5 "B" (B)
351 rebasing 2:dc0947a82db8 "C" (C)
351 rebasing 2:dc0947a82db8 "C" (C)
352 saved backup bundle to $TESTTMP/multiple-bases/.hg/strip-backup/dc0947a82db8-b0c1a7ea-rebase.hg
352 saved backup bundle to $TESTTMP/multiple-bases/.hg/strip-backup/dc0947a82db8-b0c1a7ea-rebase.hg
353 $ hg tglog
353 $ hg tglog
354 o 2: 2127ae44d291 'Collapsed revision
354 o 2: 2127ae44d291 'Collapsed revision
355 | * B
355 | * B
356 | * C'
356 | * C'
357 o 1: b18e25de2cf5 'D'
357 o 1: b18e25de2cf5 'D'
358 |
358 |
359 o 0: 426bada5c675 'A'
359 o 0: 426bada5c675 'A'
360
360
361 $ cd ..
361 $ cd ..
362
362
363 With non-contiguous commits:
363 With non-contiguous commits:
364
364
365 $ hg init non-contiguous
365 $ hg init non-contiguous
366 $ cd non-contiguous
366 $ cd non-contiguous
367 $ cat >> .hg/hgrc <<EOF
367 $ cat >> .hg/hgrc <<EOF
368 > [experimental]
368 > [experimental]
369 > evolution=all
369 > evolution=all
370 > EOF
370 > EOF
371
371
372 $ hg debugdrawdag << 'EOF'
372 $ hg debugdrawdag << 'EOF'
373 > F
373 > F
374 > |
374 > |
375 > E
375 > E
376 > |
376 > |
377 > D
377 > D
378 > |
378 > |
379 > C
379 > C
380 > |
380 > |
381 > B G
381 > B G
382 > |/
382 > |/
383 > A
383 > A
384 > EOF
384 > EOF
385
385
386 BROKEN: should be allowed
386 BROKEN: should be allowed
387 $ hg rebase --collapse -r 'B+D+F' -d G
387 $ hg rebase --collapse -r 'B+D+F' -d G
388 abort: unable to collapse on top of 2, there is more than one external parent: 3, 5
388 abort: unable to collapse on top of 2, there is more than one external parent: 3, 5
389 [255]
389 [255]
390 $ cd ..
390 $ cd ..
391
391
392
392
393 $ hg init multiple-external-parents-2
393 $ hg init multiple-external-parents-2
394 $ cd multiple-external-parents-2
394 $ cd multiple-external-parents-2
395 $ hg debugdrawdag << 'EOF'
395 $ hg debugdrawdag << 'EOF'
396 > D G
396 > D G
397 > |\ /|
397 > |\ /|
398 > B C E F
398 > B C E F
399 > \| |/
399 > \| |/
400 > \ H /
400 > \ H /
401 > \|/
401 > \|/
402 > A
402 > A
403 > EOF
403 > EOF
404
404
405 $ hg rebase --collapse -d H -s 'B+F'
405 $ hg rebase --collapse -d H -s 'B+F'
406 abort: unable to collapse on top of 5, there is more than one external parent: 1, 3
406 abort: unable to collapse on top of 5, there is more than one external parent: 1, 3
407 [255]
407 [255]
408 $ cd ..
408 $ cd ..
409
409
410 With internal merge:
410 With internal merge:
411
411
412 $ hg init internal-merge
412 $ hg init internal-merge
413 $ cd internal-merge
413 $ cd internal-merge
414
414
415 $ hg debugdrawdag << 'EOF'
415 $ hg debugdrawdag << 'EOF'
416 > E
416 > E
417 > |\
417 > |\
418 > C D
418 > C D
419 > |/
419 > |/
420 > F B
420 > F B
421 > |/
421 > |/
422 > A
422 > A
423 > EOF
423 > EOF
424
424
425
425
426 $ hg rebase -s B --collapse --dest F
426 $ hg rebase -s B --collapse --dest F
427 rebasing 1:112478962961 "B" (B)
427 rebasing 1:112478962961 "B" (B)
428 rebasing 3:26805aba1e60 "C" (C)
428 rebasing 3:26805aba1e60 "C" (C)
429 rebasing 4:be0ef73c17ad "D" (D)
429 rebasing 4:be0ef73c17ad "D" (D)
430 rebasing 5:02c4367d6973 "E" (E tip)
430 rebasing 5:02c4367d6973 "E" (E tip)
431 saved backup bundle to $TESTTMP/internal-merge/.hg/strip-backup/112478962961-1dfb057b-rebase.hg
431 saved backup bundle to $TESTTMP/internal-merge/.hg/strip-backup/112478962961-1dfb057b-rebase.hg
432
432
433 $ hg tglog
433 $ hg tglog
434 o 2: c0512a1797b0 'Collapsed revision
434 o 2: c0512a1797b0 'Collapsed revision
435 | * B
435 | * B
436 | * C
436 | * C
437 | * D
437 | * D
438 | * E'
438 | * E'
439 o 1: 8908a377a434 'F'
439 o 1: 8908a377a434 'F'
440 |
440 |
441 o 0: 426bada5c675 'A'
441 o 0: 426bada5c675 'A'
442
442
443 $ hg manifest --rev tip
443 $ hg manifest --rev tip
444 A
444 A
445 B
445 B
446 C
446 C
447 D
447 D
448 F
448 F
449 $ cd ..
449 $ cd ..
450
450
451 Interactions between collapse and keepbranches
451 Interactions between collapse and keepbranches
452 $ hg init e
452 $ hg init e
453 $ cd e
453 $ cd e
454 $ echo 'a' > a
454 $ echo 'a' > a
455 $ hg ci -Am 'A'
455 $ hg ci -Am 'A'
456 adding a
456 adding a
457
457
458 $ hg branch 'one'
458 $ hg branch 'one'
459 marked working directory as branch one
459 marked working directory as branch one
460 (branches are permanent and global, did you want a bookmark?)
460 (branches are permanent and global, did you want a bookmark?)
461 $ echo 'b' > b
461 $ echo 'b' > b
462 $ hg ci -Am 'B'
462 $ hg ci -Am 'B'
463 adding b
463 adding b
464
464
465 $ hg branch 'two'
465 $ hg branch 'two'
466 marked working directory as branch two
466 marked working directory as branch two
467 $ echo 'c' > c
467 $ echo 'c' > c
468 $ hg ci -Am 'C'
468 $ hg ci -Am 'C'
469 adding c
469 adding c
470
470
471 $ hg up -q 0
471 $ hg up -q 0
472 $ echo 'd' > d
472 $ echo 'd' > d
473 $ hg ci -Am 'D'
473 $ hg ci -Am 'D'
474 adding d
474 adding d
475
475
476 $ hg tglog
476 $ hg tglog
477 @ 3: 41acb9dca9eb 'D'
477 @ 3: 41acb9dca9eb 'D'
478 |
478 |
479 | o 2: 8ac4a08debf1 'C' two
479 | o 2: 8ac4a08debf1 'C' two
480 | |
480 | |
481 | o 1: 1ba175478953 'B' one
481 | o 1: 1ba175478953 'B' one
482 |/
482 |/
483 o 0: 1994f17a630e 'A'
483 o 0: 1994f17a630e 'A'
484
484
485 $ hg rebase --keepbranches --collapse -s 1 -d 3
485 $ hg rebase --keepbranches --collapse -s 1 -d 3
486 abort: cannot collapse multiple named branches
486 abort: cannot collapse multiple named branches
487 [255]
487 [255]
488
488
489 $ cd ..
489 $ cd ..
490
490
491 Rebase, collapse and copies
491 Rebase, collapse and copies
492
492
493 $ hg init copies
493 $ hg init copies
494 $ cd copies
494 $ cd copies
495 $ hg unbundle "$TESTDIR/bundles/renames.hg"
495 $ hg unbundle "$TESTDIR/bundles/renames.hg"
496 adding changesets
496 adding changesets
497 adding manifests
497 adding manifests
498 adding file changes
498 adding file changes
499 added 4 changesets with 11 changes to 7 files (+1 heads)
499 added 4 changesets with 11 changes to 7 files (+1 heads)
500 new changesets f447d5abf5ea:338e84e2e558 (4 drafts)
500 new changesets f447d5abf5ea:338e84e2e558 (4 drafts)
501 (run 'hg heads' to see heads, 'hg merge' to merge)
501 (run 'hg heads' to see heads, 'hg merge' to merge)
502 $ hg up -q tip
502 $ hg up -q tip
503 $ hg tglog
503 $ hg tglog
504 @ 3: 338e84e2e558 'move2'
504 @ 3: 338e84e2e558 'move2'
505 |
505 |
506 o 2: 6e7340ee38c0 'move1'
506 o 2: 6e7340ee38c0 'move1'
507 |
507 |
508 | o 1: 1352765a01d4 'change'
508 | o 1: 1352765a01d4 'change'
509 |/
509 |/
510 o 0: f447d5abf5ea 'add'
510 o 0: f447d5abf5ea 'add'
511
511
512 $ hg rebase --collapse -d 1
512 $ hg rebase --collapse -d 1
513 rebasing 2:6e7340ee38c0 "move1"
513 rebasing 2:6e7340ee38c0 "move1"
514 merging a and d to d
514 merging a and d to d
515 merging b and e to e
515 merging b and e to e
516 merging c and f to f
516 merging c and f to f
517 rebasing 3:338e84e2e558 "move2" (tip)
517 rebasing 3:338e84e2e558 "move2" (tip)
518 merging f and c to c
518 merging f and c to c
519 merging e and g to g
519 merging e and g to g
520 saved backup bundle to $TESTTMP/copies/.hg/strip-backup/6e7340ee38c0-ef8ef003-rebase.hg
520 saved backup bundle to $TESTTMP/copies/.hg/strip-backup/6e7340ee38c0-ef8ef003-rebase.hg
521 $ hg st
521 $ hg st
522 $ hg st --copies --change tip
522 $ hg st --copies --change tip
523 A d
523 A d
524 a
524 a
525 A g
525 A g
526 b
526 b
527 R b
527 R b
528 $ hg up tip -q
528 $ hg up tip -q
529 $ cat c
529 $ cat c
530 c
530 c
531 c
531 c
532 $ cat d
532 $ cat d
533 a
533 a
534 a
534 a
535 $ cat g
535 $ cat g
536 b
536 b
537 b
537 b
538 $ hg log -r . --template "{file_copies}\n"
538 $ hg log -r . --template "{file_copies}\n"
539 d (a)g (b)
539 d (a)g (b)
540
540
541 Test collapsing a middle revision in-place
541 Test collapsing a middle revision in-place
542
542
543 $ hg tglog
543 $ hg tglog
544 @ 2: 64b456429f67 'Collapsed revision
544 @ 2: 64b456429f67 'Collapsed revision
545 | * move1
545 | * move1
546 | * move2'
546 | * move2'
547 o 1: 1352765a01d4 'change'
547 o 1: 1352765a01d4 'change'
548 |
548 |
549 o 0: f447d5abf5ea 'add'
549 o 0: f447d5abf5ea 'add'
550
550
551 $ hg rebase --collapse -r 1 -d 0
551 $ hg rebase --collapse -r 1 -d 0
552 abort: cannot rebase changeset with children
552 abort: cannot rebase changeset with children
553 (use --keep to keep original changesets)
553 (use --keep to keep original changesets)
554 [255]
554 [255]
555
555
556 Test collapsing in place
556 Test collapsing in place
557
557
558 $ hg rebase --collapse -b . -d 0
558 $ hg rebase --collapse -b . -d 0
559 rebasing 1:1352765a01d4 "change"
559 rebasing 1:1352765a01d4 "change"
560 rebasing 2:64b456429f67 "Collapsed revision" (tip)
560 rebasing 2:64b456429f67 "Collapsed revision" (tip)
561 saved backup bundle to $TESTTMP/copies/.hg/strip-backup/1352765a01d4-45a352ea-rebase.hg
561 saved backup bundle to $TESTTMP/copies/.hg/strip-backup/1352765a01d4-45a352ea-rebase.hg
562 $ hg st --change tip --copies
562 $ hg st --change tip --copies
563 M a
563 M a
564 M c
564 M c
565 A d
565 A d
566 a
566 a
567 A g
567 A g
568 b
568 b
569 R b
569 R b
570 $ hg up tip -q
570 $ hg up tip -q
571 $ cat a
571 $ cat a
572 a
572 a
573 a
573 a
574 $ cat c
574 $ cat c
575 c
575 c
576 c
576 c
577 $ cat d
577 $ cat d
578 a
578 a
579 a
579 a
580 $ cat g
580 $ cat g
581 b
581 b
582 b
582 b
583 $ cd ..
583 $ cd ..
584
584
585
585
586 Test stripping a revision with another child
586 Test stripping a revision with another child
587
587
588 $ hg init f
588 $ hg init f
589 $ cd f
589 $ cd f
590
590
591 $ hg debugdrawdag << 'EOF'
591 $ hg debugdrawdag << 'EOF'
592 > C B
592 > C B
593 > |/
593 > |/
594 > A
594 > A
595 > EOF
595 > EOF
596
596
597 $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
597 $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
598 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default: C
598 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default: C
599 1:112478962961147124edd43549aedd1a335e44bf default: B
599 1:112478962961147124edd43549aedd1a335e44bf default: B
600
600
601 $ hg strip C
601 $ hg strip C
602 saved backup bundle to $TESTTMP/f/.hg/strip-backup/dc0947a82db8-d21b92a4-backup.hg
602 saved backup bundle to $TESTTMP/f/.hg/strip-backup/dc0947a82db8-d21b92a4-backup.hg
603
603
604 $ hg tglog
604 $ hg tglog
605 o 1: 112478962961 'B'
605 o 1: 112478962961 'B'
606 |
606 |
607 o 0: 426bada5c675 'A'
607 o 0: 426bada5c675 'A'
608
608
609
609
610
610
611 $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
611 $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
612 1:112478962961147124edd43549aedd1a335e44bf default: B
612 1:112478962961147124edd43549aedd1a335e44bf default: B
613
613
614 $ cd ..
614 $ cd ..
615
615
616 Test collapsing changes that add then remove a file
616 Test collapsing changes that add then remove a file
617
617
618 $ hg init collapseaddremove
618 $ hg init collapseaddremove
619 $ cd collapseaddremove
619 $ cd collapseaddremove
620
620
621 $ touch base
621 $ touch base
622 $ hg commit -Am base
622 $ hg commit -Am base
623 adding base
623 adding base
624 $ touch a
624 $ touch a
625 $ hg commit -Am a
625 $ hg commit -Am a
626 adding a
626 adding a
627 $ hg rm a
627 $ hg rm a
628 $ touch b
628 $ touch b
629 $ hg commit -Am b
629 $ hg commit -Am b
630 adding b
630 adding b
631 $ hg book foo
631 $ hg book foo
632 $ hg rebase -d 0 -r "1::2" --collapse -m collapsed
632 $ hg rebase -d 0 -r "1::2" --collapse -m collapsed
633 rebasing 1:6d8d9f24eec3 "a"
633 rebasing 1:6d8d9f24eec3 "a"
634 rebasing 2:1cc73eca5ecc "b" (foo tip)
634 rebasing 2:1cc73eca5ecc "b" (foo tip)
635 saved backup bundle to $TESTTMP/collapseaddremove/.hg/strip-backup/6d8d9f24eec3-77d3b6e2-rebase.hg
635 saved backup bundle to $TESTTMP/collapseaddremove/.hg/strip-backup/6d8d9f24eec3-77d3b6e2-rebase.hg
636 $ hg log -G --template "{rev}: '{desc}' {bookmarks}"
636 $ hg log -G --template "{rev}: '{desc}' {bookmarks}"
637 @ 1: 'collapsed' foo
637 @ 1: 'collapsed' foo
638 |
638 |
639 o 0: 'base'
639 o 0: 'base'
640
640
641 $ hg manifest --rev tip
641 $ hg manifest --rev tip
642 b
642 b
643 base
643 base
644
644
645 $ cd ..
645 $ cd ..
646
646
647 Test that rebase --collapse will remember message after
647 Test that rebase --collapse will remember message after
648 running into merge conflict and invoking rebase --continue.
648 running into merge conflict and invoking rebase --continue.
649
649
650 $ hg init collapse_remember_message
650 $ hg init collapse_remember_message
651 $ cd collapse_remember_message
651 $ cd collapse_remember_message
652 $ hg debugdrawdag << 'EOF'
652 $ hg debugdrawdag << 'EOF'
653 > C B # B/A = B\n
653 > C B # B/A = B\n
654 > |/ # C/A = C\n
654 > |/ # C/A = C\n
655 > A
655 > A
656 > EOF
656 > EOF
657 $ hg rebase --collapse -m "new message" -b B -d C
657 $ hg rebase --collapse -m "new message" -b B -d C
658 rebasing 1:81e5401e4d37 "B" (B)
658 rebasing 1:81e5401e4d37 "B" (B)
659 merging A
659 merging A
660 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
660 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
661 unresolved conflicts (see hg resolve, then hg rebase --continue)
661 unresolved conflicts (see hg resolve, then hg rebase --continue)
662 [1]
662 [1]
663 $ rm A.orig
663 $ rm A.orig
664 $ hg resolve --mark A
664 $ hg resolve --mark A
665 (no more unresolved files)
665 (no more unresolved files)
666 continue: hg rebase --continue
666 continue: hg rebase --continue
667 $ hg rebase --continue
667 $ hg rebase --continue
668 rebasing 1:81e5401e4d37 "B" (B)
668 rebasing 1:81e5401e4d37 "B" (B)
669 saved backup bundle to $TESTTMP/collapse_remember_message/.hg/strip-backup/81e5401e4d37-96c3dd30-rebase.hg
669 saved backup bundle to $TESTTMP/collapse_remember_message/.hg/strip-backup/81e5401e4d37-96c3dd30-rebase.hg
670 $ hg log
670 $ hg log
671 changeset: 2:17186933e123
671 changeset: 2:17186933e123
672 tag: tip
672 tag: tip
673 user: test
673 user: test
674 date: Thu Jan 01 00:00:00 1970 +0000
674 date: Thu Jan 01 00:00:00 1970 +0000
675 summary: new message
675 summary: new message
676
676
677 changeset: 1:043039e9df84
677 changeset: 1:043039e9df84
678 tag: C
678 tag: C
679 user: test
679 user: test
680 date: Thu Jan 01 00:00:00 1970 +0000
680 date: Thu Jan 01 00:00:00 1970 +0000
681 summary: C
681 summary: C
682
682
683 changeset: 0:426bada5c675
683 changeset: 0:426bada5c675
684 tag: A
684 tag: A
685 user: test
685 user: test
686 date: Thu Jan 01 00:00:00 1970 +0000
686 date: Thu Jan 01 00:00:00 1970 +0000
687 summary: A
687 summary: A
688
688
689 $ cd ..
689 $ cd ..
690
690
691 Test aborted editor on final message
691 Test aborted editor on final message
692
692
693 $ HGMERGE=:merge3
693 $ HGMERGE=:merge3
694 $ export HGMERGE
694 $ export HGMERGE
695 $ hg init aborted-editor
695 $ hg init aborted-editor
696 $ cd aborted-editor
696 $ cd aborted-editor
697 $ hg debugdrawdag << 'EOF'
697 $ hg debugdrawdag << 'EOF'
698 > C # D/A = D\n
698 > C # D/A = D\n
699 > | # C/A = C\n
699 > | # C/A = C\n
700 > B D # B/A = B\n
700 > B D # B/A = B\n
701 > |/ # A/A = A\n
701 > |/ # A/A = A\n
702 > A
702 > A
703 > EOF
703 > EOF
704 $ hg rebase --collapse -t internal:merge3 -s B -d D
704 $ hg rebase --collapse -t internal:merge3 -s B -d D
705 rebasing 1:f899f3910ce7 "B" (B)
705 rebasing 1:f899f3910ce7 "B" (B)
706 merging A
706 merging A
707 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
707 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
708 unresolved conflicts (see hg resolve, then hg rebase --continue)
708 unresolved conflicts (see hg resolve, then hg rebase --continue)
709 [1]
709 [1]
710 $ hg tglog
710 $ hg tglog
711 o 3: 63668d570d21 'C'
711 o 3: 63668d570d21 'C'
712 |
712 |
713 | @ 2: 82b8abf9c185 'D'
713 | @ 2: 82b8abf9c185 'D'
714 | |
714 | |
715 @ | 1: f899f3910ce7 'B'
715 @ | 1: f899f3910ce7 'B'
716 |/
716 |/
717 o 0: 4a2df7238c3b 'A'
717 o 0: 4a2df7238c3b 'A'
718
718
719 $ cat A
719 $ cat A
720 <<<<<<< dest: 82b8abf9c185 D - test: D
720 <<<<<<< dest: 82b8abf9c185 D - test: D
721 D
721 D
722 ||||||| base
722 ||||||| base
723 A
723 A
724 =======
724 =======
725 B
725 B
726 >>>>>>> source: f899f3910ce7 B - test: B
726 >>>>>>> source: f899f3910ce7 B - test: B
727 $ echo BC > A
727 $ echo BC > A
728 $ hg resolve -m
728 $ hg resolve -m
729 (no more unresolved files)
729 (no more unresolved files)
730 continue: hg rebase --continue
730 continue: hg rebase --continue
731 $ hg rebase --continue
731 $ hg rebase --continue
732 rebasing 1:f899f3910ce7 "B" (B)
732 rebasing 1:f899f3910ce7 "B" (B)
733 rebasing 3:63668d570d21 "C" (C tip)
733 rebasing 3:63668d570d21 "C" (C tip)
734 merging A
734 merging A
735 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
735 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
736 unresolved conflicts (see hg resolve, then hg rebase --continue)
736 unresolved conflicts (see hg resolve, then hg rebase --continue)
737 [1]
737 [1]
738 $ hg tglog
738 $ hg tglog
739 @ 3: 63668d570d21 'C'
739 @ 3: 63668d570d21 'C'
740 |
740 |
741 | @ 2: 82b8abf9c185 'D'
741 | @ 2: 82b8abf9c185 'D'
742 | |
742 | |
743 o | 1: f899f3910ce7 'B'
743 o | 1: f899f3910ce7 'B'
744 |/
744 |/
745 o 0: 4a2df7238c3b 'A'
745 o 0: 4a2df7238c3b 'A'
746
746
747 $ cat A
747 $ cat A
748 <<<<<<< dest: 82b8abf9c185 D - test: D
748 <<<<<<< dest: 82b8abf9c185 D - test: D
749 BC
749 BC
750 ||||||| base
750 ||||||| base
751 B
751 B
752 =======
752 =======
753 C
753 C
754 >>>>>>> source: 63668d570d21 C tip - test: C
754 >>>>>>> source: 63668d570d21 C tip - test: C
755 $ echo BD > A
755 $ echo BD > A
756 $ hg resolve -m
756 $ hg resolve -m
757 (no more unresolved files)
757 (no more unresolved files)
758 continue: hg rebase --continue
758 continue: hg rebase --continue
759 $ HGEDITOR=false hg rebase --continue --config ui.interactive=1
759 $ HGEDITOR=false hg rebase --continue --config ui.interactive=1
760 already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185
760 already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185
761 rebasing 3:63668d570d21 "C" (C tip)
761 rebasing 3:63668d570d21 "C" (C tip)
762 abort: edit failed: false exited with status 1
762 abort: edit failed: false exited with status 1
763 [255]
763 [255]
764 $ hg tglog
764 $ hg tglog
765 o 3: 63668d570d21 'C'
765 % 3: 63668d570d21 'C'
766 |
766 |
767 | @ 2: 82b8abf9c185 'D'
767 | @ 2: 82b8abf9c185 'D'
768 | |
768 | |
769 o | 1: f899f3910ce7 'B'
769 o | 1: f899f3910ce7 'B'
770 |/
770 |/
771 o 0: 4a2df7238c3b 'A'
771 o 0: 4a2df7238c3b 'A'
772
772
773 $ hg rebase --continue
773 $ hg rebase --continue
774 already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185
774 already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185
775 already rebased 3:63668d570d21 "C" (C tip) as 82b8abf9c185
775 already rebased 3:63668d570d21 "C" (C tip) as 82b8abf9c185
776 saved backup bundle to $TESTTMP/aborted-editor/.hg/strip-backup/f899f3910ce7-7cab5e15-rebase.hg
776 saved backup bundle to $TESTTMP/aborted-editor/.hg/strip-backup/f899f3910ce7-7cab5e15-rebase.hg
@@ -1,1407 +1,1407 b''
1 $ echo "[extensions]" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "strip=" >> $HGRCPATH
2 $ echo "strip=" >> $HGRCPATH
3 $ echo "drawdag=$TESTDIR/drawdag.py" >> $HGRCPATH
3 $ echo "drawdag=$TESTDIR/drawdag.py" >> $HGRCPATH
4
4
5 $ restore() {
5 $ restore() {
6 > hg unbundle -q .hg/strip-backup/*
6 > hg unbundle -q .hg/strip-backup/*
7 > rm .hg/strip-backup/*
7 > rm .hg/strip-backup/*
8 > }
8 > }
9 $ teststrip() {
9 $ teststrip() {
10 > hg up -C $1
10 > hg up -C $1
11 > echo % before update $1, strip $2
11 > echo % before update $1, strip $2
12 > hg log -G -T '{rev}:{node}'
12 > hg log -G -T '{rev}:{node}'
13 > hg --traceback strip $2
13 > hg --traceback strip $2
14 > echo % after update $1, strip $2
14 > echo % after update $1, strip $2
15 > hg log -G -T '{rev}:{node}'
15 > hg log -G -T '{rev}:{node}'
16 > restore
16 > restore
17 > }
17 > }
18
18
19 $ hg init test
19 $ hg init test
20 $ cd test
20 $ cd test
21
21
22 $ echo foo > bar
22 $ echo foo > bar
23 $ hg ci -Ama
23 $ hg ci -Ama
24 adding bar
24 adding bar
25
25
26 $ echo more >> bar
26 $ echo more >> bar
27 $ hg ci -Amb
27 $ hg ci -Amb
28
28
29 $ echo blah >> bar
29 $ echo blah >> bar
30 $ hg ci -Amc
30 $ hg ci -Amc
31
31
32 $ hg up 1
32 $ hg up 1
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 $ echo blah >> bar
34 $ echo blah >> bar
35 $ hg ci -Amd
35 $ hg ci -Amd
36 created new head
36 created new head
37
37
38 $ echo final >> bar
38 $ echo final >> bar
39 $ hg ci -Ame
39 $ hg ci -Ame
40
40
41 $ hg log
41 $ hg log
42 changeset: 4:443431ffac4f
42 changeset: 4:443431ffac4f
43 tag: tip
43 tag: tip
44 user: test
44 user: test
45 date: Thu Jan 01 00:00:00 1970 +0000
45 date: Thu Jan 01 00:00:00 1970 +0000
46 summary: e
46 summary: e
47
47
48 changeset: 3:65bd5f99a4a3
48 changeset: 3:65bd5f99a4a3
49 parent: 1:ef3a871183d7
49 parent: 1:ef3a871183d7
50 user: test
50 user: test
51 date: Thu Jan 01 00:00:00 1970 +0000
51 date: Thu Jan 01 00:00:00 1970 +0000
52 summary: d
52 summary: d
53
53
54 changeset: 2:264128213d29
54 changeset: 2:264128213d29
55 user: test
55 user: test
56 date: Thu Jan 01 00:00:00 1970 +0000
56 date: Thu Jan 01 00:00:00 1970 +0000
57 summary: c
57 summary: c
58
58
59 changeset: 1:ef3a871183d7
59 changeset: 1:ef3a871183d7
60 user: test
60 user: test
61 date: Thu Jan 01 00:00:00 1970 +0000
61 date: Thu Jan 01 00:00:00 1970 +0000
62 summary: b
62 summary: b
63
63
64 changeset: 0:9ab35a2d17cb
64 changeset: 0:9ab35a2d17cb
65 user: test
65 user: test
66 date: Thu Jan 01 00:00:00 1970 +0000
66 date: Thu Jan 01 00:00:00 1970 +0000
67 summary: a
67 summary: a
68
68
69
69
70 $ teststrip 4 4
70 $ teststrip 4 4
71 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 % before update 4, strip 4
72 % before update 4, strip 4
73 @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
73 @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
74 |
74 |
75 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
75 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
76 |
76 |
77 | o 2:264128213d290d868c54642d13aeaa3675551a78
77 | o 2:264128213d290d868c54642d13aeaa3675551a78
78 |/
78 |/
79 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
79 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
80 |
80 |
81 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
81 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
82
82
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
84 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
85 % after update 4, strip 4
85 % after update 4, strip 4
86 @ 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
86 @ 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
87 |
87 |
88 | o 2:264128213d290d868c54642d13aeaa3675551a78
88 | o 2:264128213d290d868c54642d13aeaa3675551a78
89 |/
89 |/
90 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
90 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
91 |
91 |
92 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
92 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
93
93
94 $ teststrip 4 3
94 $ teststrip 4 3
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 % before update 4, strip 3
96 % before update 4, strip 3
97 @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
97 @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
98 |
98 |
99 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
99 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
100 |
100 |
101 | o 2:264128213d290d868c54642d13aeaa3675551a78
101 | o 2:264128213d290d868c54642d13aeaa3675551a78
102 |/
102 |/
103 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
103 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
104 |
104 |
105 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
105 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
106
106
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
108 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
109 % after update 4, strip 3
109 % after update 4, strip 3
110 o 2:264128213d290d868c54642d13aeaa3675551a78
110 o 2:264128213d290d868c54642d13aeaa3675551a78
111 |
111 |
112 @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a
112 @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a
113 |
113 |
114 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
114 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
115
115
116 $ teststrip 1 4
116 $ teststrip 1 4
117 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 % before update 1, strip 4
118 % before update 1, strip 4
119 o 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
119 o 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
120 |
120 |
121 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
121 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
122 |
122 |
123 | o 2:264128213d290d868c54642d13aeaa3675551a78
123 | o 2:264128213d290d868c54642d13aeaa3675551a78
124 |/
124 |/
125 @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a
125 @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a
126 |
126 |
127 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
127 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
128
128
129 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
129 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
130 % after update 1, strip 4
130 % after update 1, strip 4
131 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
131 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
132 |
132 |
133 | o 2:264128213d290d868c54642d13aeaa3675551a78
133 | o 2:264128213d290d868c54642d13aeaa3675551a78
134 |/
134 |/
135 @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a
135 @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a
136 |
136 |
137 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
137 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
138
138
139 $ teststrip 4 2
139 $ teststrip 4 2
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 % before update 4, strip 2
141 % before update 4, strip 2
142 @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
142 @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
143 |
143 |
144 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
144 o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64
145 |
145 |
146 | o 2:264128213d290d868c54642d13aeaa3675551a78
146 | o 2:264128213d290d868c54642d13aeaa3675551a78
147 |/
147 |/
148 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
148 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
149 |
149 |
150 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
150 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
151
151
152 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
152 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
153 % after update 4, strip 2
153 % after update 4, strip 2
154 @ 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
154 @ 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
155 |
155 |
156 o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
156 o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
157 |
157 |
158 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
158 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
159 |
159 |
160 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
160 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
161
161
162 $ teststrip 4 1
162 $ teststrip 4 1
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 % before update 4, strip 1
164 % before update 4, strip 1
165 @ 4:264128213d290d868c54642d13aeaa3675551a78
165 @ 4:264128213d290d868c54642d13aeaa3675551a78
166 |
166 |
167 | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
167 | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
168 | |
168 | |
169 | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
169 | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
170 |/
170 |/
171 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
171 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
172 |
172 |
173 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
173 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
174
174
175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
176 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
177 % after update 4, strip 1
177 % after update 4, strip 1
178 @ 0:9ab35a2d17cb64271241ea881efcc19dd953215b
178 @ 0:9ab35a2d17cb64271241ea881efcc19dd953215b
179
179
180 $ teststrip null 4
180 $ teststrip null 4
181 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
181 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
182 % before update null, strip 4
182 % before update null, strip 4
183 o 4:264128213d290d868c54642d13aeaa3675551a78
183 o 4:264128213d290d868c54642d13aeaa3675551a78
184 |
184 |
185 | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
185 | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
186 | |
186 | |
187 | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
187 | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
188 |/
188 |/
189 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
189 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
190 |
190 |
191 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
191 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
192
192
193 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
193 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
194 % after update null, strip 4
194 % after update null, strip 4
195 o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
195 o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce
196 |
196 |
197 o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
197 o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64
198 |
198 |
199 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
199 o 1:ef3a871183d7199c541cc140218298bbfcc6c28a
200 |
200 |
201 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
201 o 0:9ab35a2d17cb64271241ea881efcc19dd953215b
202
202
203
203
204 $ hg log
204 $ hg log
205 changeset: 4:264128213d29
205 changeset: 4:264128213d29
206 tag: tip
206 tag: tip
207 parent: 1:ef3a871183d7
207 parent: 1:ef3a871183d7
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:00 1970 +0000
209 date: Thu Jan 01 00:00:00 1970 +0000
210 summary: c
210 summary: c
211
211
212 changeset: 3:443431ffac4f
212 changeset: 3:443431ffac4f
213 user: test
213 user: test
214 date: Thu Jan 01 00:00:00 1970 +0000
214 date: Thu Jan 01 00:00:00 1970 +0000
215 summary: e
215 summary: e
216
216
217 changeset: 2:65bd5f99a4a3
217 changeset: 2:65bd5f99a4a3
218 user: test
218 user: test
219 date: Thu Jan 01 00:00:00 1970 +0000
219 date: Thu Jan 01 00:00:00 1970 +0000
220 summary: d
220 summary: d
221
221
222 changeset: 1:ef3a871183d7
222 changeset: 1:ef3a871183d7
223 user: test
223 user: test
224 date: Thu Jan 01 00:00:00 1970 +0000
224 date: Thu Jan 01 00:00:00 1970 +0000
225 summary: b
225 summary: b
226
226
227 changeset: 0:9ab35a2d17cb
227 changeset: 0:9ab35a2d17cb
228 user: test
228 user: test
229 date: Thu Jan 01 00:00:00 1970 +0000
229 date: Thu Jan 01 00:00:00 1970 +0000
230 summary: a
230 summary: a
231
231
232 $ hg up -C 4
232 $ hg up -C 4
233 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 $ hg parents
234 $ hg parents
235 changeset: 4:264128213d29
235 changeset: 4:264128213d29
236 tag: tip
236 tag: tip
237 parent: 1:ef3a871183d7
237 parent: 1:ef3a871183d7
238 user: test
238 user: test
239 date: Thu Jan 01 00:00:00 1970 +0000
239 date: Thu Jan 01 00:00:00 1970 +0000
240 summary: c
240 summary: c
241
241
242
242
243 $ hg --traceback strip 4
243 $ hg --traceback strip 4
244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg
245 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg
246 $ hg parents
246 $ hg parents
247 changeset: 1:ef3a871183d7
247 changeset: 1:ef3a871183d7
248 user: test
248 user: test
249 date: Thu Jan 01 00:00:00 1970 +0000
249 date: Thu Jan 01 00:00:00 1970 +0000
250 summary: b
250 summary: b
251
251
252 $ hg debugbundle .hg/strip-backup/*
252 $ hg debugbundle .hg/strip-backup/*
253 Stream params: {Compression: BZ}
253 Stream params: {Compression: BZ}
254 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
254 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
255 264128213d290d868c54642d13aeaa3675551a78
255 264128213d290d868c54642d13aeaa3675551a78
256 cache:rev-branch-cache -- {} (mandatory: False)
256 cache:rev-branch-cache -- {} (mandatory: False)
257 phase-heads -- {} (mandatory: True)
257 phase-heads -- {} (mandatory: True)
258 264128213d290d868c54642d13aeaa3675551a78 draft
258 264128213d290d868c54642d13aeaa3675551a78 draft
259 $ hg unbundle .hg/strip-backup/*
259 $ hg unbundle .hg/strip-backup/*
260 adding changesets
260 adding changesets
261 adding manifests
261 adding manifests
262 adding file changes
262 adding file changes
263 added 1 changesets with 0 changes to 1 files (+1 heads)
263 added 1 changesets with 0 changes to 1 files (+1 heads)
264 new changesets 264128213d29 (1 drafts)
264 new changesets 264128213d29 (1 drafts)
265 (run 'hg heads' to see heads, 'hg merge' to merge)
265 (run 'hg heads' to see heads, 'hg merge' to merge)
266 $ rm .hg/strip-backup/*
266 $ rm .hg/strip-backup/*
267 $ hg log --graph
267 $ hg log --graph
268 o changeset: 4:264128213d29
268 o changeset: 4:264128213d29
269 | tag: tip
269 | tag: tip
270 | parent: 1:ef3a871183d7
270 | parent: 1:ef3a871183d7
271 | user: test
271 | user: test
272 | date: Thu Jan 01 00:00:00 1970 +0000
272 | date: Thu Jan 01 00:00:00 1970 +0000
273 | summary: c
273 | summary: c
274 |
274 |
275 | o changeset: 3:443431ffac4f
275 | o changeset: 3:443431ffac4f
276 | | user: test
276 | | user: test
277 | | date: Thu Jan 01 00:00:00 1970 +0000
277 | | date: Thu Jan 01 00:00:00 1970 +0000
278 | | summary: e
278 | | summary: e
279 | |
279 | |
280 | o changeset: 2:65bd5f99a4a3
280 | o changeset: 2:65bd5f99a4a3
281 |/ user: test
281 |/ user: test
282 | date: Thu Jan 01 00:00:00 1970 +0000
282 | date: Thu Jan 01 00:00:00 1970 +0000
283 | summary: d
283 | summary: d
284 |
284 |
285 @ changeset: 1:ef3a871183d7
285 @ changeset: 1:ef3a871183d7
286 | user: test
286 | user: test
287 | date: Thu Jan 01 00:00:00 1970 +0000
287 | date: Thu Jan 01 00:00:00 1970 +0000
288 | summary: b
288 | summary: b
289 |
289 |
290 o changeset: 0:9ab35a2d17cb
290 o changeset: 0:9ab35a2d17cb
291 user: test
291 user: test
292 date: Thu Jan 01 00:00:00 1970 +0000
292 date: Thu Jan 01 00:00:00 1970 +0000
293 summary: a
293 summary: a
294
294
295 $ hg up -C 2
295 $ hg up -C 2
296 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 $ hg merge 4
297 $ hg merge 4
298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 (branch merge, don't forget to commit)
299 (branch merge, don't forget to commit)
300
300
301 before strip of merge parent
301 before strip of merge parent
302
302
303 $ hg parents
303 $ hg parents
304 changeset: 2:65bd5f99a4a3
304 changeset: 2:65bd5f99a4a3
305 user: test
305 user: test
306 date: Thu Jan 01 00:00:00 1970 +0000
306 date: Thu Jan 01 00:00:00 1970 +0000
307 summary: d
307 summary: d
308
308
309 changeset: 4:264128213d29
309 changeset: 4:264128213d29
310 tag: tip
310 tag: tip
311 parent: 1:ef3a871183d7
311 parent: 1:ef3a871183d7
312 user: test
312 user: test
313 date: Thu Jan 01 00:00:00 1970 +0000
313 date: Thu Jan 01 00:00:00 1970 +0000
314 summary: c
314 summary: c
315
315
316 ##strip not allowed with merge in progress
316 ##strip not allowed with merge in progress
317 $ hg strip 4
317 $ hg strip 4
318 abort: outstanding uncommitted merge
318 abort: outstanding uncommitted merge
319 (use 'hg commit' or 'hg merge --abort')
319 (use 'hg commit' or 'hg merge --abort')
320 [255]
320 [255]
321 ##strip allowed --force with merge in progress
321 ##strip allowed --force with merge in progress
322 $ hg strip 4 --force
322 $ hg strip 4 --force
323 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
323 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
324 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
325
325
326 after strip of merge parent
326 after strip of merge parent
327
327
328 $ hg parents
328 $ hg parents
329 changeset: 1:ef3a871183d7
329 changeset: 1:ef3a871183d7
330 user: test
330 user: test
331 date: Thu Jan 01 00:00:00 1970 +0000
331 date: Thu Jan 01 00:00:00 1970 +0000
332 summary: b
332 summary: b
333
333
334 $ restore
334 $ restore
335
335
336 $ hg up
336 $ hg up
337 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
338 updated to "264128213d29: c"
338 updated to "264128213d29: c"
339 1 other heads for branch "default"
339 1 other heads for branch "default"
340 $ hg log -G
340 $ hg log -G
341 @ changeset: 4:264128213d29
341 @ changeset: 4:264128213d29
342 | tag: tip
342 | tag: tip
343 | parent: 1:ef3a871183d7
343 | parent: 1:ef3a871183d7
344 | user: test
344 | user: test
345 | date: Thu Jan 01 00:00:00 1970 +0000
345 | date: Thu Jan 01 00:00:00 1970 +0000
346 | summary: c
346 | summary: c
347 |
347 |
348 | o changeset: 3:443431ffac4f
348 | o changeset: 3:443431ffac4f
349 | | user: test
349 | | user: test
350 | | date: Thu Jan 01 00:00:00 1970 +0000
350 | | date: Thu Jan 01 00:00:00 1970 +0000
351 | | summary: e
351 | | summary: e
352 | |
352 | |
353 | o changeset: 2:65bd5f99a4a3
353 | o changeset: 2:65bd5f99a4a3
354 |/ user: test
354 |/ user: test
355 | date: Thu Jan 01 00:00:00 1970 +0000
355 | date: Thu Jan 01 00:00:00 1970 +0000
356 | summary: d
356 | summary: d
357 |
357 |
358 o changeset: 1:ef3a871183d7
358 o changeset: 1:ef3a871183d7
359 | user: test
359 | user: test
360 | date: Thu Jan 01 00:00:00 1970 +0000
360 | date: Thu Jan 01 00:00:00 1970 +0000
361 | summary: b
361 | summary: b
362 |
362 |
363 o changeset: 0:9ab35a2d17cb
363 o changeset: 0:9ab35a2d17cb
364 user: test
364 user: test
365 date: Thu Jan 01 00:00:00 1970 +0000
365 date: Thu Jan 01 00:00:00 1970 +0000
366 summary: a
366 summary: a
367
367
368
368
369 2 is parent of 3, only one strip should happen
369 2 is parent of 3, only one strip should happen
370
370
371 $ hg strip "roots(2)" 3
371 $ hg strip "roots(2)" 3
372 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
372 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
373 $ hg log -G
373 $ hg log -G
374 @ changeset: 2:264128213d29
374 @ changeset: 2:264128213d29
375 | tag: tip
375 | tag: tip
376 | user: test
376 | user: test
377 | date: Thu Jan 01 00:00:00 1970 +0000
377 | date: Thu Jan 01 00:00:00 1970 +0000
378 | summary: c
378 | summary: c
379 |
379 |
380 o changeset: 1:ef3a871183d7
380 o changeset: 1:ef3a871183d7
381 | user: test
381 | user: test
382 | date: Thu Jan 01 00:00:00 1970 +0000
382 | date: Thu Jan 01 00:00:00 1970 +0000
383 | summary: b
383 | summary: b
384 |
384 |
385 o changeset: 0:9ab35a2d17cb
385 o changeset: 0:9ab35a2d17cb
386 user: test
386 user: test
387 date: Thu Jan 01 00:00:00 1970 +0000
387 date: Thu Jan 01 00:00:00 1970 +0000
388 summary: a
388 summary: a
389
389
390 $ restore
390 $ restore
391 $ hg log -G
391 $ hg log -G
392 o changeset: 4:443431ffac4f
392 o changeset: 4:443431ffac4f
393 | tag: tip
393 | tag: tip
394 | user: test
394 | user: test
395 | date: Thu Jan 01 00:00:00 1970 +0000
395 | date: Thu Jan 01 00:00:00 1970 +0000
396 | summary: e
396 | summary: e
397 |
397 |
398 o changeset: 3:65bd5f99a4a3
398 o changeset: 3:65bd5f99a4a3
399 | parent: 1:ef3a871183d7
399 | parent: 1:ef3a871183d7
400 | user: test
400 | user: test
401 | date: Thu Jan 01 00:00:00 1970 +0000
401 | date: Thu Jan 01 00:00:00 1970 +0000
402 | summary: d
402 | summary: d
403 |
403 |
404 | @ changeset: 2:264128213d29
404 | @ changeset: 2:264128213d29
405 |/ user: test
405 |/ user: test
406 | date: Thu Jan 01 00:00:00 1970 +0000
406 | date: Thu Jan 01 00:00:00 1970 +0000
407 | summary: c
407 | summary: c
408 |
408 |
409 o changeset: 1:ef3a871183d7
409 o changeset: 1:ef3a871183d7
410 | user: test
410 | user: test
411 | date: Thu Jan 01 00:00:00 1970 +0000
411 | date: Thu Jan 01 00:00:00 1970 +0000
412 | summary: b
412 | summary: b
413 |
413 |
414 o changeset: 0:9ab35a2d17cb
414 o changeset: 0:9ab35a2d17cb
415 user: test
415 user: test
416 date: Thu Jan 01 00:00:00 1970 +0000
416 date: Thu Jan 01 00:00:00 1970 +0000
417 summary: a
417 summary: a
418
418
419 Failed hook while applying "saveheads" bundle.
419 Failed hook while applying "saveheads" bundle.
420
420
421 $ hg strip 2 --config hooks.pretxnchangegroup.bad=false
421 $ hg strip 2 --config hooks.pretxnchangegroup.bad=false
422 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
423 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
424 transaction abort!
424 transaction abort!
425 rollback completed
425 rollback completed
426 strip failed, backup bundle stored in '$TESTTMP/test/.hg/strip-backup/*-backup.hg' (glob)
426 strip failed, backup bundle stored in '$TESTTMP/test/.hg/strip-backup/*-backup.hg' (glob)
427 strip failed, unrecovered changes stored in '$TESTTMP/test/.hg/strip-backup/*-temp.hg' (glob)
427 strip failed, unrecovered changes stored in '$TESTTMP/test/.hg/strip-backup/*-temp.hg' (glob)
428 (fix the problem, then recover the changesets with "hg unbundle '$TESTTMP/test/.hg/strip-backup/*-temp.hg'") (glob)
428 (fix the problem, then recover the changesets with "hg unbundle '$TESTTMP/test/.hg/strip-backup/*-temp.hg'") (glob)
429 abort: pretxnchangegroup.bad hook exited with status 1
429 abort: pretxnchangegroup.bad hook exited with status 1
430 [255]
430 [255]
431 $ restore
431 $ restore
432 $ hg log -G
432 $ hg log -G
433 o changeset: 4:443431ffac4f
433 o changeset: 4:443431ffac4f
434 | tag: tip
434 | tag: tip
435 | user: test
435 | user: test
436 | date: Thu Jan 01 00:00:00 1970 +0000
436 | date: Thu Jan 01 00:00:00 1970 +0000
437 | summary: e
437 | summary: e
438 |
438 |
439 o changeset: 3:65bd5f99a4a3
439 o changeset: 3:65bd5f99a4a3
440 | parent: 1:ef3a871183d7
440 | parent: 1:ef3a871183d7
441 | user: test
441 | user: test
442 | date: Thu Jan 01 00:00:00 1970 +0000
442 | date: Thu Jan 01 00:00:00 1970 +0000
443 | summary: d
443 | summary: d
444 |
444 |
445 | o changeset: 2:264128213d29
445 | o changeset: 2:264128213d29
446 |/ user: test
446 |/ user: test
447 | date: Thu Jan 01 00:00:00 1970 +0000
447 | date: Thu Jan 01 00:00:00 1970 +0000
448 | summary: c
448 | summary: c
449 |
449 |
450 @ changeset: 1:ef3a871183d7
450 @ changeset: 1:ef3a871183d7
451 | user: test
451 | user: test
452 | date: Thu Jan 01 00:00:00 1970 +0000
452 | date: Thu Jan 01 00:00:00 1970 +0000
453 | summary: b
453 | summary: b
454 |
454 |
455 o changeset: 0:9ab35a2d17cb
455 o changeset: 0:9ab35a2d17cb
456 user: test
456 user: test
457 date: Thu Jan 01 00:00:00 1970 +0000
457 date: Thu Jan 01 00:00:00 1970 +0000
458 summary: a
458 summary: a
459
459
460
460
461 2 different branches: 2 strips
461 2 different branches: 2 strips
462
462
463 $ hg strip 2 4
463 $ hg strip 2 4
464 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
464 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
465 $ hg log -G
465 $ hg log -G
466 o changeset: 2:65bd5f99a4a3
466 o changeset: 2:65bd5f99a4a3
467 | tag: tip
467 | tag: tip
468 | user: test
468 | user: test
469 | date: Thu Jan 01 00:00:00 1970 +0000
469 | date: Thu Jan 01 00:00:00 1970 +0000
470 | summary: d
470 | summary: d
471 |
471 |
472 @ changeset: 1:ef3a871183d7
472 @ changeset: 1:ef3a871183d7
473 | user: test
473 | user: test
474 | date: Thu Jan 01 00:00:00 1970 +0000
474 | date: Thu Jan 01 00:00:00 1970 +0000
475 | summary: b
475 | summary: b
476 |
476 |
477 o changeset: 0:9ab35a2d17cb
477 o changeset: 0:9ab35a2d17cb
478 user: test
478 user: test
479 date: Thu Jan 01 00:00:00 1970 +0000
479 date: Thu Jan 01 00:00:00 1970 +0000
480 summary: a
480 summary: a
481
481
482 $ restore
482 $ restore
483
483
484 2 different branches and a common ancestor: 1 strip
484 2 different branches and a common ancestor: 1 strip
485
485
486 $ hg strip 1 "2|4"
486 $ hg strip 1 "2|4"
487 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
487 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
488 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
488 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
489 $ restore
489 $ restore
490
490
491 verify fncache is kept up-to-date
491 verify fncache is kept up-to-date
492
492
493 $ touch a
493 $ touch a
494 $ hg ci -qAm a
494 $ hg ci -qAm a
495 #if repofncache
495 #if repofncache
496 $ cat .hg/store/fncache | sort
496 $ cat .hg/store/fncache | sort
497 data/a.i
497 data/a.i
498 data/bar.i
498 data/bar.i
499 #endif
499 #endif
500
500
501 $ hg strip tip
501 $ hg strip tip
502 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
502 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
503 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
503 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
504 #if repofncache
504 #if repofncache
505 $ cat .hg/store/fncache
505 $ cat .hg/store/fncache
506 data/bar.i
506 data/bar.i
507 #endif
507 #endif
508
508
509 stripping an empty revset
509 stripping an empty revset
510
510
511 $ hg strip "1 and not 1"
511 $ hg strip "1 and not 1"
512 abort: empty revision set
512 abort: empty revision set
513 [255]
513 [255]
514
514
515 remove branchy history for qimport tests
515 remove branchy history for qimport tests
516
516
517 $ hg strip 3
517 $ hg strip 3
518 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
518 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
519
519
520
520
521 strip of applied mq should cleanup status file
521 strip of applied mq should cleanup status file
522
522
523 $ echo "mq=" >> $HGRCPATH
523 $ echo "mq=" >> $HGRCPATH
524 $ hg up -C 3
524 $ hg up -C 3
525 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
525 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
526 $ echo fooagain >> bar
526 $ echo fooagain >> bar
527 $ hg ci -mf
527 $ hg ci -mf
528 $ hg qimport -r tip:2
528 $ hg qimport -r tip:2
529
529
530 applied patches before strip
530 applied patches before strip
531
531
532 $ hg qapplied
532 $ hg qapplied
533 d
533 d
534 e
534 e
535 f
535 f
536
536
537 stripping revision in queue
537 stripping revision in queue
538
538
539 $ hg strip 3
539 $ hg strip 3
540 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
541 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
541 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
542
542
543 applied patches after stripping rev in queue
543 applied patches after stripping rev in queue
544
544
545 $ hg qapplied
545 $ hg qapplied
546 d
546 d
547
547
548 stripping ancestor of queue
548 stripping ancestor of queue
549
549
550 $ hg strip 1
550 $ hg strip 1
551 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
551 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
552 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
552 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
553
553
554 applied patches after stripping ancestor of queue
554 applied patches after stripping ancestor of queue
555
555
556 $ hg qapplied
556 $ hg qapplied
557
557
558 Verify strip protects against stripping wc parent when there are uncommitted mods
558 Verify strip protects against stripping wc parent when there are uncommitted mods
559
559
560 $ echo b > b
560 $ echo b > b
561 $ echo bb > bar
561 $ echo bb > bar
562 $ hg add b
562 $ hg add b
563 $ hg ci -m 'b'
563 $ hg ci -m 'b'
564 $ hg log --graph
564 $ hg log --graph
565 @ changeset: 1:76dcf9fab855
565 @ changeset: 1:76dcf9fab855
566 | tag: tip
566 | tag: tip
567 | user: test
567 | user: test
568 | date: Thu Jan 01 00:00:00 1970 +0000
568 | date: Thu Jan 01 00:00:00 1970 +0000
569 | summary: b
569 | summary: b
570 |
570 |
571 o changeset: 0:9ab35a2d17cb
571 o changeset: 0:9ab35a2d17cb
572 user: test
572 user: test
573 date: Thu Jan 01 00:00:00 1970 +0000
573 date: Thu Jan 01 00:00:00 1970 +0000
574 summary: a
574 summary: a
575
575
576 $ hg up 0
576 $ hg up 0
577 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
577 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
578 $ echo c > bar
578 $ echo c > bar
579 $ hg up -t false
579 $ hg up -t false
580 merging bar
580 merging bar
581 merging bar failed!
581 merging bar failed!
582 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
582 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
583 use 'hg resolve' to retry unresolved file merges
583 use 'hg resolve' to retry unresolved file merges
584 [1]
584 [1]
585 $ hg sum
585 $ hg sum
586 parent: 1:76dcf9fab855 tip
586 parent: 1:76dcf9fab855 tip
587 b
587 b
588 branch: default
588 branch: default
589 commit: 1 modified, 1 unknown, 1 unresolved
589 commit: 1 modified, 1 unknown, 1 unresolved
590 update: (current)
590 update: (current)
591 phases: 2 draft
591 phases: 2 draft
592 mq: 3 unapplied
592 mq: 3 unapplied
593
593
594 $ hg log --graph
594 $ hg log --graph
595 @ changeset: 1:76dcf9fab855
595 @ changeset: 1:76dcf9fab855
596 | tag: tip
596 | tag: tip
597 | user: test
597 | user: test
598 | date: Thu Jan 01 00:00:00 1970 +0000
598 | date: Thu Jan 01 00:00:00 1970 +0000
599 | summary: b
599 | summary: b
600 |
600 |
601 o changeset: 0:9ab35a2d17cb
601 % changeset: 0:9ab35a2d17cb
602 user: test
602 user: test
603 date: Thu Jan 01 00:00:00 1970 +0000
603 date: Thu Jan 01 00:00:00 1970 +0000
604 summary: a
604 summary: a
605
605
606 $ echo c > b
606 $ echo c > b
607 $ hg strip tip
607 $ hg strip tip
608 abort: uncommitted changes
608 abort: uncommitted changes
609 [255]
609 [255]
610 $ hg strip tip --keep
610 $ hg strip tip --keep
611 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
611 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
612 $ hg log --graph
612 $ hg log --graph
613 @ changeset: 0:9ab35a2d17cb
613 @ changeset: 0:9ab35a2d17cb
614 tag: tip
614 tag: tip
615 user: test
615 user: test
616 date: Thu Jan 01 00:00:00 1970 +0000
616 date: Thu Jan 01 00:00:00 1970 +0000
617 summary: a
617 summary: a
618
618
619 $ hg status
619 $ hg status
620 M bar
620 M bar
621 ? b
621 ? b
622 ? bar.orig
622 ? bar.orig
623
623
624 $ rm bar.orig
624 $ rm bar.orig
625 $ hg sum
625 $ hg sum
626 parent: 0:9ab35a2d17cb tip
626 parent: 0:9ab35a2d17cb tip
627 a
627 a
628 branch: default
628 branch: default
629 commit: 1 modified, 1 unknown
629 commit: 1 modified, 1 unknown
630 update: (current)
630 update: (current)
631 phases: 1 draft
631 phases: 1 draft
632 mq: 3 unapplied
632 mq: 3 unapplied
633
633
634 Strip adds, removes, modifies with --keep
634 Strip adds, removes, modifies with --keep
635
635
636 $ touch b
636 $ touch b
637 $ hg add b
637 $ hg add b
638 $ hg commit -mb
638 $ hg commit -mb
639 $ touch c
639 $ touch c
640
640
641 ... with a clean working dir
641 ... with a clean working dir
642
642
643 $ hg add c
643 $ hg add c
644 $ hg rm bar
644 $ hg rm bar
645 $ hg commit -mc
645 $ hg commit -mc
646 $ hg status
646 $ hg status
647 $ hg strip --keep tip
647 $ hg strip --keep tip
648 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
648 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
649 $ hg status
649 $ hg status
650 ! bar
650 ! bar
651 ? c
651 ? c
652
652
653 ... with a dirty working dir
653 ... with a dirty working dir
654
654
655 $ hg add c
655 $ hg add c
656 $ hg rm bar
656 $ hg rm bar
657 $ hg commit -mc
657 $ hg commit -mc
658 $ hg status
658 $ hg status
659 $ echo b > b
659 $ echo b > b
660 $ echo d > d
660 $ echo d > d
661 $ hg strip --keep tip
661 $ hg strip --keep tip
662 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
662 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
663 $ hg status
663 $ hg status
664 M b
664 M b
665 ! bar
665 ! bar
666 ? c
666 ? c
667 ? d
667 ? d
668
668
669 ... after updating the dirstate
669 ... after updating the dirstate
670 $ hg add c
670 $ hg add c
671 $ hg commit -mc
671 $ hg commit -mc
672 $ hg rm c
672 $ hg rm c
673 $ hg commit -mc
673 $ hg commit -mc
674 $ hg strip --keep '.^' -q
674 $ hg strip --keep '.^' -q
675 $ cd ..
675 $ cd ..
676
676
677 stripping many nodes on a complex graph (issue3299)
677 stripping many nodes on a complex graph (issue3299)
678
678
679 $ hg init issue3299
679 $ hg init issue3299
680 $ cd issue3299
680 $ cd issue3299
681 $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a'
681 $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a'
682 $ hg strip 'not ancestors(x)'
682 $ hg strip 'not ancestors(x)'
683 saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob)
683 saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob)
684
684
685 test hg strip -B bookmark
685 test hg strip -B bookmark
686
686
687 $ cd ..
687 $ cd ..
688 $ hg init bookmarks
688 $ hg init bookmarks
689 $ cd bookmarks
689 $ cd bookmarks
690 $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b<m+2:d<2.:e<m+1:f'
690 $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b<m+2:d<2.:e<m+1:f'
691 $ hg bookmark -r 'a' 'todelete'
691 $ hg bookmark -r 'a' 'todelete'
692 $ hg bookmark -r 'b' 'B'
692 $ hg bookmark -r 'b' 'B'
693 $ hg bookmark -r 'b' 'nostrip'
693 $ hg bookmark -r 'b' 'nostrip'
694 $ hg bookmark -r 'c' 'delete'
694 $ hg bookmark -r 'c' 'delete'
695 $ hg bookmark -r 'd' 'multipledelete1'
695 $ hg bookmark -r 'd' 'multipledelete1'
696 $ hg bookmark -r 'e' 'multipledelete2'
696 $ hg bookmark -r 'e' 'multipledelete2'
697 $ hg bookmark -r 'f' 'singlenode1'
697 $ hg bookmark -r 'f' 'singlenode1'
698 $ hg bookmark -r 'f' 'singlenode2'
698 $ hg bookmark -r 'f' 'singlenode2'
699 $ hg up -C todelete
699 $ hg up -C todelete
700 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
700 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
701 (activating bookmark todelete)
701 (activating bookmark todelete)
702 $ hg strip -B nostrip
702 $ hg strip -B nostrip
703 bookmark 'nostrip' deleted
703 bookmark 'nostrip' deleted
704 abort: empty revision set
704 abort: empty revision set
705 [255]
705 [255]
706 $ hg strip -B todelete
706 $ hg strip -B todelete
707 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
707 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
708 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
708 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
709 bookmark 'todelete' deleted
709 bookmark 'todelete' deleted
710 $ hg id -ir dcbb326fdec2
710 $ hg id -ir dcbb326fdec2
711 abort: unknown revision 'dcbb326fdec2'!
711 abort: unknown revision 'dcbb326fdec2'!
712 [255]
712 [255]
713 $ hg id -ir d62d843c9a01
713 $ hg id -ir d62d843c9a01
714 d62d843c9a01
714 d62d843c9a01
715 $ hg bookmarks
715 $ hg bookmarks
716 B 9:ff43616e5d0f
716 B 9:ff43616e5d0f
717 delete 6:2702dd0c91e7
717 delete 6:2702dd0c91e7
718 multipledelete1 11:e46a4836065c
718 multipledelete1 11:e46a4836065c
719 multipledelete2 12:b4594d867745
719 multipledelete2 12:b4594d867745
720 singlenode1 13:43227190fef8
720 singlenode1 13:43227190fef8
721 singlenode2 13:43227190fef8
721 singlenode2 13:43227190fef8
722 $ hg strip -B multipledelete1 -B multipledelete2
722 $ hg strip -B multipledelete1 -B multipledelete2
723 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/e46a4836065c-89ec65c2-backup.hg
723 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/e46a4836065c-89ec65c2-backup.hg
724 bookmark 'multipledelete1' deleted
724 bookmark 'multipledelete1' deleted
725 bookmark 'multipledelete2' deleted
725 bookmark 'multipledelete2' deleted
726 $ hg id -ir e46a4836065c
726 $ hg id -ir e46a4836065c
727 abort: unknown revision 'e46a4836065c'!
727 abort: unknown revision 'e46a4836065c'!
728 [255]
728 [255]
729 $ hg id -ir b4594d867745
729 $ hg id -ir b4594d867745
730 abort: unknown revision 'b4594d867745'!
730 abort: unknown revision 'b4594d867745'!
731 [255]
731 [255]
732 $ hg strip -B singlenode1 -B singlenode2
732 $ hg strip -B singlenode1 -B singlenode2
733 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/43227190fef8-8da858f2-backup.hg
733 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/43227190fef8-8da858f2-backup.hg
734 bookmark 'singlenode1' deleted
734 bookmark 'singlenode1' deleted
735 bookmark 'singlenode2' deleted
735 bookmark 'singlenode2' deleted
736 $ hg id -ir 43227190fef8
736 $ hg id -ir 43227190fef8
737 abort: unknown revision '43227190fef8'!
737 abort: unknown revision '43227190fef8'!
738 [255]
738 [255]
739 $ hg strip -B unknownbookmark
739 $ hg strip -B unknownbookmark
740 abort: bookmark 'unknownbookmark' not found
740 abort: bookmark 'unknownbookmark' not found
741 [255]
741 [255]
742 $ hg strip -B unknownbookmark1 -B unknownbookmark2
742 $ hg strip -B unknownbookmark1 -B unknownbookmark2
743 abort: bookmark 'unknownbookmark1,unknownbookmark2' not found
743 abort: bookmark 'unknownbookmark1,unknownbookmark2' not found
744 [255]
744 [255]
745 $ hg strip -B delete -B unknownbookmark
745 $ hg strip -B delete -B unknownbookmark
746 abort: bookmark 'unknownbookmark' not found
746 abort: bookmark 'unknownbookmark' not found
747 [255]
747 [255]
748 $ hg strip -B delete
748 $ hg strip -B delete
749 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
749 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
750 bookmark 'delete' deleted
750 bookmark 'delete' deleted
751 $ hg id -ir 6:2702dd0c91e7
751 $ hg id -ir 6:2702dd0c91e7
752 abort: unknown revision '2702dd0c91e7'!
752 abort: unknown revision '2702dd0c91e7'!
753 [255]
753 [255]
754 $ hg update B
754 $ hg update B
755 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
755 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
756 (activating bookmark B)
756 (activating bookmark B)
757 $ echo a > a
757 $ echo a > a
758 $ hg add a
758 $ hg add a
759 $ hg strip -B B
759 $ hg strip -B B
760 abort: uncommitted changes
760 abort: uncommitted changes
761 [255]
761 [255]
762 $ hg bookmarks
762 $ hg bookmarks
763 * B 6:ff43616e5d0f
763 * B 6:ff43616e5d0f
764
764
765 Make sure no one adds back a -b option:
765 Make sure no one adds back a -b option:
766
766
767 $ hg strip -b tip
767 $ hg strip -b tip
768 hg strip: option -b not recognized
768 hg strip: option -b not recognized
769 hg strip [-k] [-f] [-B bookmark] [-r] REV...
769 hg strip [-k] [-f] [-B bookmark] [-r] REV...
770
770
771 strip changesets and all their descendants from the repository
771 strip changesets and all their descendants from the repository
772
772
773 (use 'hg help -e strip' to show help for the strip extension)
773 (use 'hg help -e strip' to show help for the strip extension)
774
774
775 options ([+] can be repeated):
775 options ([+] can be repeated):
776
776
777 -r --rev REV [+] strip specified revision (optional, can specify
777 -r --rev REV [+] strip specified revision (optional, can specify
778 revisions without this option)
778 revisions without this option)
779 -f --force force removal of changesets, discard uncommitted
779 -f --force force removal of changesets, discard uncommitted
780 changes (no backup)
780 changes (no backup)
781 --no-backup do not save backup bundle
781 --no-backup do not save backup bundle
782 -k --keep do not modify working directory during strip
782 -k --keep do not modify working directory during strip
783 -B --bookmark BOOKMARK [+] remove revs only reachable from given bookmark
783 -B --bookmark BOOKMARK [+] remove revs only reachable from given bookmark
784 --mq operate on patch repository
784 --mq operate on patch repository
785
785
786 (use 'hg strip -h' to show more help)
786 (use 'hg strip -h' to show more help)
787 [255]
787 [255]
788
788
789 $ cd ..
789 $ cd ..
790
790
791 Verify bundles don't get overwritten:
791 Verify bundles don't get overwritten:
792
792
793 $ hg init doublebundle
793 $ hg init doublebundle
794 $ cd doublebundle
794 $ cd doublebundle
795 $ touch a
795 $ touch a
796 $ hg commit -Aqm a
796 $ hg commit -Aqm a
797 $ touch b
797 $ touch b
798 $ hg commit -Aqm b
798 $ hg commit -Aqm b
799 $ hg strip -r 0
799 $ hg strip -r 0
800 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
800 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
801 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-e68910bd-backup.hg
801 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-e68910bd-backup.hg
802 $ ls .hg/strip-backup
802 $ ls .hg/strip-backup
803 3903775176ed-e68910bd-backup.hg
803 3903775176ed-e68910bd-backup.hg
804 #if repobundlerepo
804 #if repobundlerepo
805 $ hg pull -q -r 3903775176ed .hg/strip-backup/3903775176ed-e68910bd-backup.hg
805 $ hg pull -q -r 3903775176ed .hg/strip-backup/3903775176ed-e68910bd-backup.hg
806 $ hg strip -r 0
806 $ hg strip -r 0
807 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-54390173-backup.hg
807 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-54390173-backup.hg
808 $ ls .hg/strip-backup
808 $ ls .hg/strip-backup
809 3903775176ed-54390173-backup.hg
809 3903775176ed-54390173-backup.hg
810 3903775176ed-e68910bd-backup.hg
810 3903775176ed-e68910bd-backup.hg
811 #endif
811 #endif
812 $ cd ..
812 $ cd ..
813
813
814 Test that we only bundle the stripped changesets (issue4736)
814 Test that we only bundle the stripped changesets (issue4736)
815 ------------------------------------------------------------
815 ------------------------------------------------------------
816
816
817 initialization (previous repo is empty anyway)
817 initialization (previous repo is empty anyway)
818
818
819 $ hg init issue4736
819 $ hg init issue4736
820 $ cd issue4736
820 $ cd issue4736
821 $ echo a > a
821 $ echo a > a
822 $ hg add a
822 $ hg add a
823 $ hg commit -m commitA
823 $ hg commit -m commitA
824 $ echo b > b
824 $ echo b > b
825 $ hg add b
825 $ hg add b
826 $ hg commit -m commitB
826 $ hg commit -m commitB
827 $ echo c > c
827 $ echo c > c
828 $ hg add c
828 $ hg add c
829 $ hg commit -m commitC
829 $ hg commit -m commitC
830 $ hg up 'desc(commitB)'
830 $ hg up 'desc(commitB)'
831 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
831 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
832 $ echo d > d
832 $ echo d > d
833 $ hg add d
833 $ hg add d
834 $ hg commit -m commitD
834 $ hg commit -m commitD
835 created new head
835 created new head
836 $ hg up 'desc(commitC)'
836 $ hg up 'desc(commitC)'
837 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
837 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
838 $ hg merge 'desc(commitD)'
838 $ hg merge 'desc(commitD)'
839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
840 (branch merge, don't forget to commit)
840 (branch merge, don't forget to commit)
841 $ hg ci -m 'mergeCD'
841 $ hg ci -m 'mergeCD'
842 $ hg log -G
842 $ hg log -G
843 @ changeset: 4:d8db9d137221
843 @ changeset: 4:d8db9d137221
844 |\ tag: tip
844 |\ tag: tip
845 | | parent: 2:5c51d8d6557d
845 | | parent: 2:5c51d8d6557d
846 | | parent: 3:6625a5168474
846 | | parent: 3:6625a5168474
847 | | user: test
847 | | user: test
848 | | date: Thu Jan 01 00:00:00 1970 +0000
848 | | date: Thu Jan 01 00:00:00 1970 +0000
849 | | summary: mergeCD
849 | | summary: mergeCD
850 | |
850 | |
851 | o changeset: 3:6625a5168474
851 | o changeset: 3:6625a5168474
852 | | parent: 1:eca11cf91c71
852 | | parent: 1:eca11cf91c71
853 | | user: test
853 | | user: test
854 | | date: Thu Jan 01 00:00:00 1970 +0000
854 | | date: Thu Jan 01 00:00:00 1970 +0000
855 | | summary: commitD
855 | | summary: commitD
856 | |
856 | |
857 o | changeset: 2:5c51d8d6557d
857 o | changeset: 2:5c51d8d6557d
858 |/ user: test
858 |/ user: test
859 | date: Thu Jan 01 00:00:00 1970 +0000
859 | date: Thu Jan 01 00:00:00 1970 +0000
860 | summary: commitC
860 | summary: commitC
861 |
861 |
862 o changeset: 1:eca11cf91c71
862 o changeset: 1:eca11cf91c71
863 | user: test
863 | user: test
864 | date: Thu Jan 01 00:00:00 1970 +0000
864 | date: Thu Jan 01 00:00:00 1970 +0000
865 | summary: commitB
865 | summary: commitB
866 |
866 |
867 o changeset: 0:105141ef12d0
867 o changeset: 0:105141ef12d0
868 user: test
868 user: test
869 date: Thu Jan 01 00:00:00 1970 +0000
869 date: Thu Jan 01 00:00:00 1970 +0000
870 summary: commitA
870 summary: commitA
871
871
872
872
873 Check bundle behavior:
873 Check bundle behavior:
874
874
875 $ hg bundle -r 'desc(mergeCD)' --base 'desc(commitC)' ../issue4736.hg
875 $ hg bundle -r 'desc(mergeCD)' --base 'desc(commitC)' ../issue4736.hg
876 2 changesets found
876 2 changesets found
877 #if repobundlerepo
877 #if repobundlerepo
878 $ hg log -r 'bundle()' -R ../issue4736.hg
878 $ hg log -r 'bundle()' -R ../issue4736.hg
879 changeset: 3:6625a5168474
879 changeset: 3:6625a5168474
880 parent: 1:eca11cf91c71
880 parent: 1:eca11cf91c71
881 user: test
881 user: test
882 date: Thu Jan 01 00:00:00 1970 +0000
882 date: Thu Jan 01 00:00:00 1970 +0000
883 summary: commitD
883 summary: commitD
884
884
885 changeset: 4:d8db9d137221
885 changeset: 4:d8db9d137221
886 tag: tip
886 tag: tip
887 parent: 2:5c51d8d6557d
887 parent: 2:5c51d8d6557d
888 parent: 3:6625a5168474
888 parent: 3:6625a5168474
889 user: test
889 user: test
890 date: Thu Jan 01 00:00:00 1970 +0000
890 date: Thu Jan 01 00:00:00 1970 +0000
891 summary: mergeCD
891 summary: mergeCD
892
892
893 #endif
893 #endif
894
894
895 check strip behavior
895 check strip behavior
896
896
897 $ hg --config extensions.strip= strip 'desc(commitD)' --debug
897 $ hg --config extensions.strip= strip 'desc(commitD)' --debug
898 resolving manifests
898 resolving manifests
899 branchmerge: False, force: True, partial: False
899 branchmerge: False, force: True, partial: False
900 ancestor: d8db9d137221+, local: d8db9d137221+, remote: eca11cf91c71
900 ancestor: d8db9d137221+, local: d8db9d137221+, remote: eca11cf91c71
901 c: other deleted -> r
901 c: other deleted -> r
902 removing c
902 removing c
903 d: other deleted -> r
903 d: other deleted -> r
904 removing d
904 removing d
905 starting 4 threads for background file closing (?)
905 starting 4 threads for background file closing (?)
906 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
906 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
907 2 changesets found
907 2 changesets found
908 list of changesets:
908 list of changesets:
909 6625a516847449b6f0fa3737b9ba56e9f0f3032c
909 6625a516847449b6f0fa3737b9ba56e9f0f3032c
910 d8db9d1372214336d2b5570f20ee468d2c72fa8b
910 d8db9d1372214336d2b5570f20ee468d2c72fa8b
911 bundle2-output-bundle: "HG20", (1 params) 3 parts total
911 bundle2-output-bundle: "HG20", (1 params) 3 parts total
912 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
912 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
913 bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload
913 bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload
914 bundle2-output-part: "phase-heads" 24 bytes payload
914 bundle2-output-part: "phase-heads" 24 bytes payload
915 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/6625a5168474-345bb43d-backup.hg
915 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/6625a5168474-345bb43d-backup.hg
916 updating the branch cache
916 updating the branch cache
917 invalid branch cache (served): tip differs
917 invalid branch cache (served): tip differs
918 $ hg log -G
918 $ hg log -G
919 o changeset: 2:5c51d8d6557d
919 o changeset: 2:5c51d8d6557d
920 | tag: tip
920 | tag: tip
921 | user: test
921 | user: test
922 | date: Thu Jan 01 00:00:00 1970 +0000
922 | date: Thu Jan 01 00:00:00 1970 +0000
923 | summary: commitC
923 | summary: commitC
924 |
924 |
925 @ changeset: 1:eca11cf91c71
925 @ changeset: 1:eca11cf91c71
926 | user: test
926 | user: test
927 | date: Thu Jan 01 00:00:00 1970 +0000
927 | date: Thu Jan 01 00:00:00 1970 +0000
928 | summary: commitB
928 | summary: commitB
929 |
929 |
930 o changeset: 0:105141ef12d0
930 o changeset: 0:105141ef12d0
931 user: test
931 user: test
932 date: Thu Jan 01 00:00:00 1970 +0000
932 date: Thu Jan 01 00:00:00 1970 +0000
933 summary: commitA
933 summary: commitA
934
934
935
935
936 strip backup content
936 strip backup content
937
937
938 #if repobundlerepo
938 #if repobundlerepo
939 $ hg log -r 'bundle()' -R .hg/strip-backup/6625a5168474-*-backup.hg
939 $ hg log -r 'bundle()' -R .hg/strip-backup/6625a5168474-*-backup.hg
940 changeset: 3:6625a5168474
940 changeset: 3:6625a5168474
941 parent: 1:eca11cf91c71
941 parent: 1:eca11cf91c71
942 user: test
942 user: test
943 date: Thu Jan 01 00:00:00 1970 +0000
943 date: Thu Jan 01 00:00:00 1970 +0000
944 summary: commitD
944 summary: commitD
945
945
946 changeset: 4:d8db9d137221
946 changeset: 4:d8db9d137221
947 tag: tip
947 tag: tip
948 parent: 2:5c51d8d6557d
948 parent: 2:5c51d8d6557d
949 parent: 3:6625a5168474
949 parent: 3:6625a5168474
950 user: test
950 user: test
951 date: Thu Jan 01 00:00:00 1970 +0000
951 date: Thu Jan 01 00:00:00 1970 +0000
952 summary: mergeCD
952 summary: mergeCD
953
953
954
954
955 #endif
955 #endif
956
956
957 Check that the phase cache is properly invalidated after a strip with bookmark.
957 Check that the phase cache is properly invalidated after a strip with bookmark.
958
958
959 $ cat > ../stripstalephasecache.py << EOF
959 $ cat > ../stripstalephasecache.py << EOF
960 > from mercurial import extensions, localrepo
960 > from mercurial import extensions, localrepo
961 > def transactioncallback(orig, repo, desc, *args, **kwargs):
961 > def transactioncallback(orig, repo, desc, *args, **kwargs):
962 > def test(transaction):
962 > def test(transaction):
963 > # observe cache inconsistency
963 > # observe cache inconsistency
964 > try:
964 > try:
965 > [repo.changelog.node(r) for r in repo.revs(b"not public()")]
965 > [repo.changelog.node(r) for r in repo.revs(b"not public()")]
966 > except IndexError:
966 > except IndexError:
967 > repo.ui.status(b"Index error!\n")
967 > repo.ui.status(b"Index error!\n")
968 > transaction = orig(repo, desc, *args, **kwargs)
968 > transaction = orig(repo, desc, *args, **kwargs)
969 > # warm up the phase cache
969 > # warm up the phase cache
970 > list(repo.revs(b"not public()"))
970 > list(repo.revs(b"not public()"))
971 > if desc != b'strip':
971 > if desc != b'strip':
972 > transaction.addpostclose(b"phase invalidation test", test)
972 > transaction.addpostclose(b"phase invalidation test", test)
973 > return transaction
973 > return transaction
974 > def extsetup(ui):
974 > def extsetup(ui):
975 > extensions.wrapfunction(localrepo.localrepository, b"transaction",
975 > extensions.wrapfunction(localrepo.localrepository, b"transaction",
976 > transactioncallback)
976 > transactioncallback)
977 > EOF
977 > EOF
978 $ hg up -C 2
978 $ hg up -C 2
979 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
979 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
980 $ echo k > k
980 $ echo k > k
981 $ hg add k
981 $ hg add k
982 $ hg commit -m commitK
982 $ hg commit -m commitK
983 $ echo l > l
983 $ echo l > l
984 $ hg add l
984 $ hg add l
985 $ hg commit -m commitL
985 $ hg commit -m commitL
986 $ hg book -r tip blah
986 $ hg book -r tip blah
987 $ hg strip ".^" --config extensions.crash=$TESTTMP/stripstalephasecache.py
987 $ hg strip ".^" --config extensions.crash=$TESTTMP/stripstalephasecache.py
988 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
988 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
989 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/8f0b4384875c-4fa10deb-backup.hg
989 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/8f0b4384875c-4fa10deb-backup.hg
990 $ hg up -C 1
990 $ hg up -C 1
991 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
991 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
992
992
993 Error during post-close callback of the strip transaction
993 Error during post-close callback of the strip transaction
994 (They should be gracefully handled and reported)
994 (They should be gracefully handled and reported)
995
995
996 $ cat > ../crashstrip.py << EOF
996 $ cat > ../crashstrip.py << EOF
997 > from mercurial import error
997 > from mercurial import error
998 > def reposetup(ui, repo):
998 > def reposetup(ui, repo):
999 > class crashstriprepo(repo.__class__):
999 > class crashstriprepo(repo.__class__):
1000 > def transaction(self, desc, *args, **kwargs):
1000 > def transaction(self, desc, *args, **kwargs):
1001 > tr = super(crashstriprepo, self).transaction(desc, *args, **kwargs)
1001 > tr = super(crashstriprepo, self).transaction(desc, *args, **kwargs)
1002 > if desc == b'strip':
1002 > if desc == b'strip':
1003 > def crash(tra): raise error.Abort(b'boom')
1003 > def crash(tra): raise error.Abort(b'boom')
1004 > tr.addpostclose(b'crash', crash)
1004 > tr.addpostclose(b'crash', crash)
1005 > return tr
1005 > return tr
1006 > repo.__class__ = crashstriprepo
1006 > repo.__class__ = crashstriprepo
1007 > EOF
1007 > EOF
1008 $ hg strip tip --config extensions.crash=$TESTTMP/crashstrip.py
1008 $ hg strip tip --config extensions.crash=$TESTTMP/crashstrip.py
1009 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/5c51d8d6557d-70daef06-backup.hg
1009 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/5c51d8d6557d-70daef06-backup.hg
1010 strip failed, backup bundle stored in '$TESTTMP/issue4736/.hg/strip-backup/5c51d8d6557d-70daef06-backup.hg'
1010 strip failed, backup bundle stored in '$TESTTMP/issue4736/.hg/strip-backup/5c51d8d6557d-70daef06-backup.hg'
1011 abort: boom
1011 abort: boom
1012 [255]
1012 [255]
1013
1013
1014 test stripping a working directory parent doesn't switch named branches
1014 test stripping a working directory parent doesn't switch named branches
1015
1015
1016 $ hg log -G
1016 $ hg log -G
1017 @ changeset: 1:eca11cf91c71
1017 @ changeset: 1:eca11cf91c71
1018 | tag: tip
1018 | tag: tip
1019 | user: test
1019 | user: test
1020 | date: Thu Jan 01 00:00:00 1970 +0000
1020 | date: Thu Jan 01 00:00:00 1970 +0000
1021 | summary: commitB
1021 | summary: commitB
1022 |
1022 |
1023 o changeset: 0:105141ef12d0
1023 o changeset: 0:105141ef12d0
1024 user: test
1024 user: test
1025 date: Thu Jan 01 00:00:00 1970 +0000
1025 date: Thu Jan 01 00:00:00 1970 +0000
1026 summary: commitA
1026 summary: commitA
1027
1027
1028
1028
1029 $ hg branch new-branch
1029 $ hg branch new-branch
1030 marked working directory as branch new-branch
1030 marked working directory as branch new-branch
1031 (branches are permanent and global, did you want a bookmark?)
1031 (branches are permanent and global, did you want a bookmark?)
1032 $ hg ci -m "start new branch"
1032 $ hg ci -m "start new branch"
1033 $ echo 'foo' > foo.txt
1033 $ echo 'foo' > foo.txt
1034 $ hg ci -Aqm foo
1034 $ hg ci -Aqm foo
1035 $ hg up default
1035 $ hg up default
1036 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1036 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1037 $ echo 'bar' > bar.txt
1037 $ echo 'bar' > bar.txt
1038 $ hg ci -Aqm bar
1038 $ hg ci -Aqm bar
1039 $ hg up new-branch
1039 $ hg up new-branch
1040 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1040 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1041 $ hg merge default
1041 $ hg merge default
1042 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1042 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1043 (branch merge, don't forget to commit)
1043 (branch merge, don't forget to commit)
1044 $ hg log -G
1044 $ hg log -G
1045 @ changeset: 4:35358f982181
1045 @ changeset: 4:35358f982181
1046 | tag: tip
1046 | tag: tip
1047 | parent: 1:eca11cf91c71
1047 | parent: 1:eca11cf91c71
1048 | user: test
1048 | user: test
1049 | date: Thu Jan 01 00:00:00 1970 +0000
1049 | date: Thu Jan 01 00:00:00 1970 +0000
1050 | summary: bar
1050 | summary: bar
1051 |
1051 |
1052 | @ changeset: 3:f62c6c09b707
1052 | @ changeset: 3:f62c6c09b707
1053 | | branch: new-branch
1053 | | branch: new-branch
1054 | | user: test
1054 | | user: test
1055 | | date: Thu Jan 01 00:00:00 1970 +0000
1055 | | date: Thu Jan 01 00:00:00 1970 +0000
1056 | | summary: foo
1056 | | summary: foo
1057 | |
1057 | |
1058 | o changeset: 2:b1d33a8cadd9
1058 | o changeset: 2:b1d33a8cadd9
1059 |/ branch: new-branch
1059 |/ branch: new-branch
1060 | user: test
1060 | user: test
1061 | date: Thu Jan 01 00:00:00 1970 +0000
1061 | date: Thu Jan 01 00:00:00 1970 +0000
1062 | summary: start new branch
1062 | summary: start new branch
1063 |
1063 |
1064 o changeset: 1:eca11cf91c71
1064 o changeset: 1:eca11cf91c71
1065 | user: test
1065 | user: test
1066 | date: Thu Jan 01 00:00:00 1970 +0000
1066 | date: Thu Jan 01 00:00:00 1970 +0000
1067 | summary: commitB
1067 | summary: commitB
1068 |
1068 |
1069 o changeset: 0:105141ef12d0
1069 o changeset: 0:105141ef12d0
1070 user: test
1070 user: test
1071 date: Thu Jan 01 00:00:00 1970 +0000
1071 date: Thu Jan 01 00:00:00 1970 +0000
1072 summary: commitA
1072 summary: commitA
1073
1073
1074
1074
1075 $ hg strip --force -r 35358f982181
1075 $ hg strip --force -r 35358f982181
1076 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1076 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1077 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-50d992d4-backup.hg
1077 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-50d992d4-backup.hg
1078 $ hg log -G
1078 $ hg log -G
1079 @ changeset: 3:f62c6c09b707
1079 @ changeset: 3:f62c6c09b707
1080 | branch: new-branch
1080 | branch: new-branch
1081 | tag: tip
1081 | tag: tip
1082 | user: test
1082 | user: test
1083 | date: Thu Jan 01 00:00:00 1970 +0000
1083 | date: Thu Jan 01 00:00:00 1970 +0000
1084 | summary: foo
1084 | summary: foo
1085 |
1085 |
1086 o changeset: 2:b1d33a8cadd9
1086 o changeset: 2:b1d33a8cadd9
1087 | branch: new-branch
1087 | branch: new-branch
1088 | user: test
1088 | user: test
1089 | date: Thu Jan 01 00:00:00 1970 +0000
1089 | date: Thu Jan 01 00:00:00 1970 +0000
1090 | summary: start new branch
1090 | summary: start new branch
1091 |
1091 |
1092 o changeset: 1:eca11cf91c71
1092 o changeset: 1:eca11cf91c71
1093 | user: test
1093 | user: test
1094 | date: Thu Jan 01 00:00:00 1970 +0000
1094 | date: Thu Jan 01 00:00:00 1970 +0000
1095 | summary: commitB
1095 | summary: commitB
1096 |
1096 |
1097 o changeset: 0:105141ef12d0
1097 o changeset: 0:105141ef12d0
1098 user: test
1098 user: test
1099 date: Thu Jan 01 00:00:00 1970 +0000
1099 date: Thu Jan 01 00:00:00 1970 +0000
1100 summary: commitA
1100 summary: commitA
1101
1101
1102
1102
1103 $ hg up default
1103 $ hg up default
1104 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1104 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1105 $ echo 'bar' > bar.txt
1105 $ echo 'bar' > bar.txt
1106 $ hg ci -Aqm bar
1106 $ hg ci -Aqm bar
1107 $ hg up new-branch
1107 $ hg up new-branch
1108 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1108 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1109 $ hg merge default
1109 $ hg merge default
1110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1111 (branch merge, don't forget to commit)
1111 (branch merge, don't forget to commit)
1112 $ hg ci -m merge
1112 $ hg ci -m merge
1113 $ hg log -G
1113 $ hg log -G
1114 @ changeset: 5:4cf5e92caec2
1114 @ changeset: 5:4cf5e92caec2
1115 |\ branch: new-branch
1115 |\ branch: new-branch
1116 | | tag: tip
1116 | | tag: tip
1117 | | parent: 3:f62c6c09b707
1117 | | parent: 3:f62c6c09b707
1118 | | parent: 4:35358f982181
1118 | | parent: 4:35358f982181
1119 | | user: test
1119 | | user: test
1120 | | date: Thu Jan 01 00:00:00 1970 +0000
1120 | | date: Thu Jan 01 00:00:00 1970 +0000
1121 | | summary: merge
1121 | | summary: merge
1122 | |
1122 | |
1123 | o changeset: 4:35358f982181
1123 | o changeset: 4:35358f982181
1124 | | parent: 1:eca11cf91c71
1124 | | parent: 1:eca11cf91c71
1125 | | user: test
1125 | | user: test
1126 | | date: Thu Jan 01 00:00:00 1970 +0000
1126 | | date: Thu Jan 01 00:00:00 1970 +0000
1127 | | summary: bar
1127 | | summary: bar
1128 | |
1128 | |
1129 o | changeset: 3:f62c6c09b707
1129 o | changeset: 3:f62c6c09b707
1130 | | branch: new-branch
1130 | | branch: new-branch
1131 | | user: test
1131 | | user: test
1132 | | date: Thu Jan 01 00:00:00 1970 +0000
1132 | | date: Thu Jan 01 00:00:00 1970 +0000
1133 | | summary: foo
1133 | | summary: foo
1134 | |
1134 | |
1135 o | changeset: 2:b1d33a8cadd9
1135 o | changeset: 2:b1d33a8cadd9
1136 |/ branch: new-branch
1136 |/ branch: new-branch
1137 | user: test
1137 | user: test
1138 | date: Thu Jan 01 00:00:00 1970 +0000
1138 | date: Thu Jan 01 00:00:00 1970 +0000
1139 | summary: start new branch
1139 | summary: start new branch
1140 |
1140 |
1141 o changeset: 1:eca11cf91c71
1141 o changeset: 1:eca11cf91c71
1142 | user: test
1142 | user: test
1143 | date: Thu Jan 01 00:00:00 1970 +0000
1143 | date: Thu Jan 01 00:00:00 1970 +0000
1144 | summary: commitB
1144 | summary: commitB
1145 |
1145 |
1146 o changeset: 0:105141ef12d0
1146 o changeset: 0:105141ef12d0
1147 user: test
1147 user: test
1148 date: Thu Jan 01 00:00:00 1970 +0000
1148 date: Thu Jan 01 00:00:00 1970 +0000
1149 summary: commitA
1149 summary: commitA
1150
1150
1151
1151
1152 $ hg strip -r 35358f982181
1152 $ hg strip -r 35358f982181
1153 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1153 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1154 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg
1154 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg
1155 $ hg log -G
1155 $ hg log -G
1156 @ changeset: 3:f62c6c09b707
1156 @ changeset: 3:f62c6c09b707
1157 | branch: new-branch
1157 | branch: new-branch
1158 | tag: tip
1158 | tag: tip
1159 | user: test
1159 | user: test
1160 | date: Thu Jan 01 00:00:00 1970 +0000
1160 | date: Thu Jan 01 00:00:00 1970 +0000
1161 | summary: foo
1161 | summary: foo
1162 |
1162 |
1163 o changeset: 2:b1d33a8cadd9
1163 o changeset: 2:b1d33a8cadd9
1164 | branch: new-branch
1164 | branch: new-branch
1165 | user: test
1165 | user: test
1166 | date: Thu Jan 01 00:00:00 1970 +0000
1166 | date: Thu Jan 01 00:00:00 1970 +0000
1167 | summary: start new branch
1167 | summary: start new branch
1168 |
1168 |
1169 o changeset: 1:eca11cf91c71
1169 o changeset: 1:eca11cf91c71
1170 | user: test
1170 | user: test
1171 | date: Thu Jan 01 00:00:00 1970 +0000
1171 | date: Thu Jan 01 00:00:00 1970 +0000
1172 | summary: commitB
1172 | summary: commitB
1173 |
1173 |
1174 o changeset: 0:105141ef12d0
1174 o changeset: 0:105141ef12d0
1175 user: test
1175 user: test
1176 date: Thu Jan 01 00:00:00 1970 +0000
1176 date: Thu Jan 01 00:00:00 1970 +0000
1177 summary: commitA
1177 summary: commitA
1178
1178
1179
1179
1180 $ hg unbundle -u $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg
1180 $ hg unbundle -u $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg
1181 adding changesets
1181 adding changesets
1182 adding manifests
1182 adding manifests
1183 adding file changes
1183 adding file changes
1184 added 2 changesets with 1 changes to 1 files
1184 added 2 changesets with 1 changes to 1 files
1185 new changesets 35358f982181:4cf5e92caec2 (2 drafts)
1185 new changesets 35358f982181:4cf5e92caec2 (2 drafts)
1186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1187
1187
1188 $ hg strip -k -r 35358f982181
1188 $ hg strip -k -r 35358f982181
1189 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg
1189 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg
1190 $ hg log -G
1190 $ hg log -G
1191 @ changeset: 3:f62c6c09b707
1191 @ changeset: 3:f62c6c09b707
1192 | branch: new-branch
1192 | branch: new-branch
1193 | tag: tip
1193 | tag: tip
1194 | user: test
1194 | user: test
1195 | date: Thu Jan 01 00:00:00 1970 +0000
1195 | date: Thu Jan 01 00:00:00 1970 +0000
1196 | summary: foo
1196 | summary: foo
1197 |
1197 |
1198 o changeset: 2:b1d33a8cadd9
1198 o changeset: 2:b1d33a8cadd9
1199 | branch: new-branch
1199 | branch: new-branch
1200 | user: test
1200 | user: test
1201 | date: Thu Jan 01 00:00:00 1970 +0000
1201 | date: Thu Jan 01 00:00:00 1970 +0000
1202 | summary: start new branch
1202 | summary: start new branch
1203 |
1203 |
1204 o changeset: 1:eca11cf91c71
1204 o changeset: 1:eca11cf91c71
1205 | user: test
1205 | user: test
1206 | date: Thu Jan 01 00:00:00 1970 +0000
1206 | date: Thu Jan 01 00:00:00 1970 +0000
1207 | summary: commitB
1207 | summary: commitB
1208 |
1208 |
1209 o changeset: 0:105141ef12d0
1209 o changeset: 0:105141ef12d0
1210 user: test
1210 user: test
1211 date: Thu Jan 01 00:00:00 1970 +0000
1211 date: Thu Jan 01 00:00:00 1970 +0000
1212 summary: commitA
1212 summary: commitA
1213
1213
1214 $ hg diff
1214 $ hg diff
1215 diff -r f62c6c09b707 bar.txt
1215 diff -r f62c6c09b707 bar.txt
1216 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1216 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1217 +++ b/bar.txt Thu Jan 01 00:00:00 1970 +0000
1217 +++ b/bar.txt Thu Jan 01 00:00:00 1970 +0000
1218 @@ -0,0 +1,1 @@
1218 @@ -0,0 +1,1 @@
1219 +bar
1219 +bar
1220
1220
1221 Use delayedstrip to strip inside a transaction
1221 Use delayedstrip to strip inside a transaction
1222
1222
1223 $ cd $TESTTMP
1223 $ cd $TESTTMP
1224 $ hg init delayedstrip
1224 $ hg init delayedstrip
1225 $ cd delayedstrip
1225 $ cd delayedstrip
1226 $ hg debugdrawdag <<'EOS'
1226 $ hg debugdrawdag <<'EOS'
1227 > D
1227 > D
1228 > |
1228 > |
1229 > C F H # Commit on top of "I",
1229 > C F H # Commit on top of "I",
1230 > | |/| # Strip B+D+I+E+G+H+Z
1230 > | |/| # Strip B+D+I+E+G+H+Z
1231 > I B E G
1231 > I B E G
1232 > \|/
1232 > \|/
1233 > A Z
1233 > A Z
1234 > EOS
1234 > EOS
1235 $ cp -R . ../scmutilcleanup
1235 $ cp -R . ../scmutilcleanup
1236
1236
1237 $ hg up -C I
1237 $ hg up -C I
1238 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1238 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1239 $ echo 3 >> I
1239 $ echo 3 >> I
1240 $ cat > $TESTTMP/delayedstrip.py <<EOF
1240 $ cat > $TESTTMP/delayedstrip.py <<EOF
1241 > from __future__ import absolute_import
1241 > from __future__ import absolute_import
1242 > from mercurial import commands, registrar, repair
1242 > from mercurial import commands, registrar, repair
1243 > cmdtable = {}
1243 > cmdtable = {}
1244 > command = registrar.command(cmdtable)
1244 > command = registrar.command(cmdtable)
1245 > @command(b'testdelayedstrip')
1245 > @command(b'testdelayedstrip')
1246 > def testdelayedstrip(ui, repo):
1246 > def testdelayedstrip(ui, repo):
1247 > def getnodes(expr):
1247 > def getnodes(expr):
1248 > return [repo.changelog.node(r) for r in repo.revs(expr)]
1248 > return [repo.changelog.node(r) for r in repo.revs(expr)]
1249 > with repo.wlock():
1249 > with repo.wlock():
1250 > with repo.lock():
1250 > with repo.lock():
1251 > with repo.transaction(b'delayedstrip'):
1251 > with repo.transaction(b'delayedstrip'):
1252 > repair.delayedstrip(ui, repo, getnodes(b'B+I+Z+D+E'), b'J')
1252 > repair.delayedstrip(ui, repo, getnodes(b'B+I+Z+D+E'), b'J')
1253 > repair.delayedstrip(ui, repo, getnodes(b'G+H+Z'), b'I')
1253 > repair.delayedstrip(ui, repo, getnodes(b'G+H+Z'), b'I')
1254 > commands.commit(ui, repo, message=b'J', date=b'0 0')
1254 > commands.commit(ui, repo, message=b'J', date=b'0 0')
1255 > EOF
1255 > EOF
1256 $ hg testdelayedstrip --config extensions.t=$TESTTMP/delayedstrip.py
1256 $ hg testdelayedstrip --config extensions.t=$TESTTMP/delayedstrip.py
1257 warning: orphaned descendants detected, not stripping 08ebfeb61bac, 112478962961, 7fb047a69f22
1257 warning: orphaned descendants detected, not stripping 08ebfeb61bac, 112478962961, 7fb047a69f22
1258 saved backup bundle to $TESTTMP/delayedstrip/.hg/strip-backup/f585351a92f8-17475721-I.hg
1258 saved backup bundle to $TESTTMP/delayedstrip/.hg/strip-backup/f585351a92f8-17475721-I.hg
1259
1259
1260 $ hg log -G -T '{rev}:{node|short} {desc}' -r 'sort(all(), topo)'
1260 $ hg log -G -T '{rev}:{node|short} {desc}' -r 'sort(all(), topo)'
1261 @ 6:2f2d51af6205 J
1261 @ 6:2f2d51af6205 J
1262 |
1262 |
1263 o 3:08ebfeb61bac I
1263 o 3:08ebfeb61bac I
1264 |
1264 |
1265 | o 5:64a8289d2492 F
1265 | o 5:64a8289d2492 F
1266 | |
1266 | |
1267 | o 2:7fb047a69f22 E
1267 | o 2:7fb047a69f22 E
1268 |/
1268 |/
1269 | o 4:26805aba1e60 C
1269 | o 4:26805aba1e60 C
1270 | |
1270 | |
1271 | o 1:112478962961 B
1271 | o 1:112478962961 B
1272 |/
1272 |/
1273 o 0:426bada5c675 A
1273 o 0:426bada5c675 A
1274
1274
1275 Test high-level scmutil.cleanupnodes API
1275 Test high-level scmutil.cleanupnodes API
1276
1276
1277 $ cd $TESTTMP/scmutilcleanup
1277 $ cd $TESTTMP/scmutilcleanup
1278 $ hg debugdrawdag <<'EOS'
1278 $ hg debugdrawdag <<'EOS'
1279 > D2 F2 G2 # D2, F2, G2 are replacements for D, F, G
1279 > D2 F2 G2 # D2, F2, G2 are replacements for D, F, G
1280 > | | |
1280 > | | |
1281 > C H G
1281 > C H G
1282 > EOS
1282 > EOS
1283 $ for i in B C D F G I Z; do
1283 $ for i in B C D F G I Z; do
1284 > hg bookmark -i -r $i b-$i
1284 > hg bookmark -i -r $i b-$i
1285 > done
1285 > done
1286 $ hg bookmark -i -r E 'b-F@divergent1'
1286 $ hg bookmark -i -r E 'b-F@divergent1'
1287 $ hg bookmark -i -r H 'b-F@divergent2'
1287 $ hg bookmark -i -r H 'b-F@divergent2'
1288 $ hg bookmark -i -r G 'b-F@divergent3'
1288 $ hg bookmark -i -r G 'b-F@divergent3'
1289 $ cp -R . ../scmutilcleanup.obsstore
1289 $ cp -R . ../scmutilcleanup.obsstore
1290
1290
1291 $ cat > $TESTTMP/scmutilcleanup.py <<EOF
1291 $ cat > $TESTTMP/scmutilcleanup.py <<EOF
1292 > from mercurial import registrar, scmutil
1292 > from mercurial import registrar, scmutil
1293 > cmdtable = {}
1293 > cmdtable = {}
1294 > command = registrar.command(cmdtable)
1294 > command = registrar.command(cmdtable)
1295 > @command(b'testnodescleanup')
1295 > @command(b'testnodescleanup')
1296 > def testnodescleanup(ui, repo):
1296 > def testnodescleanup(ui, repo):
1297 > def nodes(expr):
1297 > def nodes(expr):
1298 > return [repo.changelog.node(r) for r in repo.revs(expr)]
1298 > return [repo.changelog.node(r) for r in repo.revs(expr)]
1299 > def node(expr):
1299 > def node(expr):
1300 > return nodes(expr)[0]
1300 > return nodes(expr)[0]
1301 > with repo.wlock():
1301 > with repo.wlock():
1302 > with repo.lock():
1302 > with repo.lock():
1303 > with repo.transaction(b'delayedstrip'):
1303 > with repo.transaction(b'delayedstrip'):
1304 > mapping = {node(b'F'): [node(b'F2')],
1304 > mapping = {node(b'F'): [node(b'F2')],
1305 > node(b'D'): [node(b'D2')],
1305 > node(b'D'): [node(b'D2')],
1306 > node(b'G'): [node(b'G2')]}
1306 > node(b'G'): [node(b'G2')]}
1307 > scmutil.cleanupnodes(repo, mapping, b'replace')
1307 > scmutil.cleanupnodes(repo, mapping, b'replace')
1308 > scmutil.cleanupnodes(repo, nodes(b'((B::)+I+Z)-D2-obsolete()'),
1308 > scmutil.cleanupnodes(repo, nodes(b'((B::)+I+Z)-D2-obsolete()'),
1309 > b'replace')
1309 > b'replace')
1310 > EOF
1310 > EOF
1311 $ hg testnodescleanup --config extensions.t=$TESTTMP/scmutilcleanup.py
1311 $ hg testnodescleanup --config extensions.t=$TESTTMP/scmutilcleanup.py
1312 warning: orphaned descendants detected, not stripping 112478962961, 1fc8102cda62, 26805aba1e60
1312 warning: orphaned descendants detected, not stripping 112478962961, 1fc8102cda62, 26805aba1e60
1313 saved backup bundle to $TESTTMP/scmutilcleanup/.hg/strip-backup/f585351a92f8-73fb7c03-replace.hg
1313 saved backup bundle to $TESTTMP/scmutilcleanup/.hg/strip-backup/f585351a92f8-73fb7c03-replace.hg
1314
1314
1315 $ hg log -G -T '{rev}:{node|short} {desc} {bookmarks}' -r 'sort(all(), topo)'
1315 $ hg log -G -T '{rev}:{node|short} {desc} {bookmarks}' -r 'sort(all(), topo)'
1316 o 8:1473d4b996d1 G2 b-F@divergent3 b-G
1316 o 8:1473d4b996d1 G2 b-F@divergent3 b-G
1317 |
1317 |
1318 | o 7:d11b3456a873 F2 b-F
1318 | o 7:d11b3456a873 F2 b-F
1319 | |
1319 | |
1320 | o 5:5cb05ba470a7 H
1320 | o 5:5cb05ba470a7 H
1321 |/|
1321 |/|
1322 | o 3:7fb047a69f22 E b-F@divergent1
1322 | o 3:7fb047a69f22 E b-F@divergent1
1323 | |
1323 | |
1324 | | o 6:7c78f703e465 D2 b-D
1324 | | o 6:7c78f703e465 D2 b-D
1325 | | |
1325 | | |
1326 | | o 4:26805aba1e60 C
1326 | | o 4:26805aba1e60 C
1327 | | |
1327 | | |
1328 | | o 2:112478962961 B
1328 | | o 2:112478962961 B
1329 | |/
1329 | |/
1330 o | 1:1fc8102cda62 G
1330 o | 1:1fc8102cda62 G
1331 /
1331 /
1332 o 0:426bada5c675 A b-B b-C b-I
1332 o 0:426bada5c675 A b-B b-C b-I
1333
1333
1334 $ hg bookmark
1334 $ hg bookmark
1335 b-B 0:426bada5c675
1335 b-B 0:426bada5c675
1336 b-C 0:426bada5c675
1336 b-C 0:426bada5c675
1337 b-D 6:7c78f703e465
1337 b-D 6:7c78f703e465
1338 b-F 7:d11b3456a873
1338 b-F 7:d11b3456a873
1339 b-F@divergent1 3:7fb047a69f22
1339 b-F@divergent1 3:7fb047a69f22
1340 b-F@divergent3 8:1473d4b996d1
1340 b-F@divergent3 8:1473d4b996d1
1341 b-G 8:1473d4b996d1
1341 b-G 8:1473d4b996d1
1342 b-I 0:426bada5c675
1342 b-I 0:426bada5c675
1343 b-Z -1:000000000000
1343 b-Z -1:000000000000
1344
1344
1345 Test the above using obsstore "by the way". Not directly related to strip, but
1345 Test the above using obsstore "by the way". Not directly related to strip, but
1346 we have reusable code here
1346 we have reusable code here
1347
1347
1348 $ cd $TESTTMP/scmutilcleanup.obsstore
1348 $ cd $TESTTMP/scmutilcleanup.obsstore
1349 $ cat >> .hg/hgrc <<EOF
1349 $ cat >> .hg/hgrc <<EOF
1350 > [experimental]
1350 > [experimental]
1351 > evolution=true
1351 > evolution=true
1352 > evolution.track-operation=1
1352 > evolution.track-operation=1
1353 > EOF
1353 > EOF
1354
1354
1355 $ hg testnodescleanup --config extensions.t=$TESTTMP/scmutilcleanup.py
1355 $ hg testnodescleanup --config extensions.t=$TESTTMP/scmutilcleanup.py
1356 4 new orphan changesets
1356 4 new orphan changesets
1357
1357
1358 $ rm .hg/localtags
1358 $ rm .hg/localtags
1359 $ hg log -G -T '{rev}:{node|short} {desc} {bookmarks}' -r 'sort(all(), topo)'
1359 $ hg log -G -T '{rev}:{node|short} {desc} {bookmarks}' -r 'sort(all(), topo)'
1360 * 12:1473d4b996d1 G2 b-F@divergent3 b-G
1360 * 12:1473d4b996d1 G2 b-F@divergent3 b-G
1361 |
1361 |
1362 | * 11:d11b3456a873 F2 b-F
1362 | * 11:d11b3456a873 F2 b-F
1363 | |
1363 | |
1364 | * 8:5cb05ba470a7 H
1364 | * 8:5cb05ba470a7 H
1365 |/|
1365 |/|
1366 | o 4:7fb047a69f22 E b-F@divergent1
1366 | o 4:7fb047a69f22 E b-F@divergent1
1367 | |
1367 | |
1368 | | * 10:7c78f703e465 D2 b-D
1368 | | * 10:7c78f703e465 D2 b-D
1369 | | |
1369 | | |
1370 | | x 6:26805aba1e60 C
1370 | | x 6:26805aba1e60 C
1371 | | |
1371 | | |
1372 | | x 3:112478962961 B
1372 | | x 3:112478962961 B
1373 | |/
1373 | |/
1374 x | 1:1fc8102cda62 G
1374 x | 1:1fc8102cda62 G
1375 /
1375 /
1376 o 0:426bada5c675 A b-B b-C b-I
1376 o 0:426bada5c675 A b-B b-C b-I
1377
1377
1378 $ hg debugobsolete
1378 $ hg debugobsolete
1379 1fc8102cda6204549f031015641606ccf5513ec3 1473d4b996d1d1b121de6b39fab6a04fbf9d873e 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'replace', 'user': 'test'}
1379 1fc8102cda6204549f031015641606ccf5513ec3 1473d4b996d1d1b121de6b39fab6a04fbf9d873e 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'replace', 'user': 'test'}
1380 64a8289d249234b9886244d379f15e6b650b28e3 d11b3456a873daec7c7bc53e5622e8df6d741bd2 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'replace', 'user': 'test'}
1380 64a8289d249234b9886244d379f15e6b650b28e3 d11b3456a873daec7c7bc53e5622e8df6d741bd2 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'replace', 'user': 'test'}
1381 f585351a92f85104bff7c284233c338b10eb1df7 7c78f703e465d73102cc8780667ce269c5208a40 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '9', 'operation': 'replace', 'user': 'test'}
1381 f585351a92f85104bff7c284233c338b10eb1df7 7c78f703e465d73102cc8780667ce269c5208a40 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '9', 'operation': 'replace', 'user': 'test'}
1382 48b9aae0607f43ff110d84e6883c151942add5ab 0 {0000000000000000000000000000000000000000} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1382 48b9aae0607f43ff110d84e6883c151942add5ab 0 {0000000000000000000000000000000000000000} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1383 112478962961147124edd43549aedd1a335e44bf 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1383 112478962961147124edd43549aedd1a335e44bf 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1384 08ebfeb61bac6e3f12079de774d285a0d6689eba 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1384 08ebfeb61bac6e3f12079de774d285a0d6689eba 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1385 26805aba1e600a82e93661149f2313866a221a7b 0 {112478962961147124edd43549aedd1a335e44bf} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1385 26805aba1e600a82e93661149f2313866a221a7b 0 {112478962961147124edd43549aedd1a335e44bf} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'}
1386 $ cd ..
1386 $ cd ..
1387
1387
1388 Test that obsmarkers are restored even when not using generaldelta
1388 Test that obsmarkers are restored even when not using generaldelta
1389
1389
1390 $ hg --config format.usegeneraldelta=no init issue5678
1390 $ hg --config format.usegeneraldelta=no init issue5678
1391 $ cd issue5678
1391 $ cd issue5678
1392 $ cat >> .hg/hgrc <<EOF
1392 $ cat >> .hg/hgrc <<EOF
1393 > [experimental]
1393 > [experimental]
1394 > evolution=true
1394 > evolution=true
1395 > EOF
1395 > EOF
1396 $ echo a > a
1396 $ echo a > a
1397 $ hg ci -Aqm a
1397 $ hg ci -Aqm a
1398 $ hg ci --amend -m a2
1398 $ hg ci --amend -m a2
1399 $ hg debugobsolete
1399 $ hg debugobsolete
1400 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1400 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1401 $ hg strip .
1401 $ hg strip .
1402 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1402 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1403 saved backup bundle to $TESTTMP/issue5678/.hg/strip-backup/489bac576828-bef27e14-backup.hg
1403 saved backup bundle to $TESTTMP/issue5678/.hg/strip-backup/489bac576828-bef27e14-backup.hg
1404 $ hg unbundle -q .hg/strip-backup/*
1404 $ hg unbundle -q .hg/strip-backup/*
1405 $ hg debugobsolete
1405 $ hg debugobsolete
1406 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1406 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1407 $ cd ..
1407 $ cd ..
@@ -1,691 +1,691 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [commands]
2 > [commands]
3 > status.verbose=1
3 > status.verbose=1
4 > EOF
4 > EOF
5
5
6 # Construct the following history tree:
6 # Construct the following history tree:
7 #
7 #
8 # @ 5:e1bb631146ca b1
8 # @ 5:e1bb631146ca b1
9 # |
9 # |
10 # o 4:a4fdb3b883c4 0:b608b9236435 b1
10 # o 4:a4fdb3b883c4 0:b608b9236435 b1
11 # |
11 # |
12 # | o 3:4b57d2520816 1:44592833ba9f
12 # | o 3:4b57d2520816 1:44592833ba9f
13 # | |
13 # | |
14 # | | o 2:063f31070f65
14 # | | o 2:063f31070f65
15 # | |/
15 # | |/
16 # | o 1:44592833ba9f
16 # | o 1:44592833ba9f
17 # |/
17 # |/
18 # o 0:b608b9236435
18 # o 0:b608b9236435
19
19
20 $ mkdir b1
20 $ mkdir b1
21 $ cd b1
21 $ cd b1
22 $ hg init
22 $ hg init
23 $ echo foo > foo
23 $ echo foo > foo
24 $ echo zero > a
24 $ echo zero > a
25 $ hg init sub
25 $ hg init sub
26 $ echo suba > sub/suba
26 $ echo suba > sub/suba
27 $ hg --cwd sub ci -Am addsuba
27 $ hg --cwd sub ci -Am addsuba
28 adding suba
28 adding suba
29 $ echo 'sub = sub' > .hgsub
29 $ echo 'sub = sub' > .hgsub
30 $ hg ci -qAm0
30 $ hg ci -qAm0
31 $ echo one > a ; hg ci -m1
31 $ echo one > a ; hg ci -m1
32 $ echo two > a ; hg ci -m2
32 $ echo two > a ; hg ci -m2
33 $ hg up -q 1
33 $ hg up -q 1
34 $ echo three > a ; hg ci -qm3
34 $ echo three > a ; hg ci -qm3
35 $ hg up -q 0
35 $ hg up -q 0
36 $ hg branch -q b1
36 $ hg branch -q b1
37 $ echo four > a ; hg ci -qm4
37 $ echo four > a ; hg ci -qm4
38 $ echo five > a ; hg ci -qm5
38 $ echo five > a ; hg ci -qm5
39
39
40 Initial repo state:
40 Initial repo state:
41
41
42 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
42 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
43 @ 5:ff252e8273df b1
43 @ 5:ff252e8273df b1
44 |
44 |
45 o 4:d047485b3896 0:60829823a42a b1
45 o 4:d047485b3896 0:60829823a42a b1
46 |
46 |
47 | o 3:6efa171f091b 1:0786582aa4b1
47 | o 3:6efa171f091b 1:0786582aa4b1
48 | |
48 | |
49 | | o 2:bd10386d478c
49 | | o 2:bd10386d478c
50 | |/
50 | |/
51 | o 1:0786582aa4b1
51 | o 1:0786582aa4b1
52 |/
52 |/
53 o 0:60829823a42a
53 o 0:60829823a42a
54
54
55
55
56 Make sure update doesn't assume b1 is a repository if invoked from outside:
56 Make sure update doesn't assume b1 is a repository if invoked from outside:
57
57
58 $ cd ..
58 $ cd ..
59 $ hg update b1
59 $ hg update b1
60 abort: no repository found in '$TESTTMP' (.hg not found)!
60 abort: no repository found in '$TESTTMP' (.hg not found)!
61 [255]
61 [255]
62 $ cd b1
62 $ cd b1
63
63
64 Test helper functions:
64 Test helper functions:
65
65
66 $ revtest () {
66 $ revtest () {
67 > msg=$1
67 > msg=$1
68 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
68 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
69 > startrev=$3
69 > startrev=$3
70 > targetrev=$4
70 > targetrev=$4
71 > opt=$5
71 > opt=$5
72 > hg up -qC $startrev
72 > hg up -qC $startrev
73 > test $dirtyflag = dirty && echo dirty > foo
73 > test $dirtyflag = dirty && echo dirty > foo
74 > test $dirtyflag = dirtysub && echo dirty > sub/suba
74 > test $dirtyflag = dirtysub && echo dirty > sub/suba
75 > hg up $opt $targetrev
75 > hg up $opt $targetrev
76 > hg parent --template 'parent={rev}\n'
76 > hg parent --template 'parent={rev}\n'
77 > hg stat -S
77 > hg stat -S
78 > }
78 > }
79
79
80 $ norevtest () {
80 $ norevtest () {
81 > msg=$1
81 > msg=$1
82 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
82 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
83 > startrev=$3
83 > startrev=$3
84 > opt=$4
84 > opt=$4
85 > hg up -qC $startrev
85 > hg up -qC $startrev
86 > test $dirtyflag = dirty && echo dirty > foo
86 > test $dirtyflag = dirty && echo dirty > foo
87 > test $dirtyflag = dirtysub && echo dirty > sub/suba
87 > test $dirtyflag = dirtysub && echo dirty > sub/suba
88 > hg up $opt
88 > hg up $opt
89 > hg parent --template 'parent={rev}\n'
89 > hg parent --template 'parent={rev}\n'
90 > hg stat -S
90 > hg stat -S
91 > }
91 > }
92
92
93 Test cases are documented in a table in the update function of merge.py.
93 Test cases are documented in a table in the update function of merge.py.
94 Cases are run as shown in that table, row by row.
94 Cases are run as shown in that table, row by row.
95
95
96 $ norevtest 'none clean linear' clean 4
96 $ norevtest 'none clean linear' clean 4
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 parent=5
98 parent=5
99
99
100 $ norevtest 'none clean same' clean 2
100 $ norevtest 'none clean same' clean 2
101 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 updated to "bd10386d478c: 2"
102 updated to "bd10386d478c: 2"
103 1 other heads for branch "default"
103 1 other heads for branch "default"
104 parent=2
104 parent=2
105
105
106
106
107 $ revtest 'none clean linear' clean 1 2
107 $ revtest 'none clean linear' clean 1 2
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 parent=2
109 parent=2
110
110
111 $ revtest 'none clean same' clean 2 3
111 $ revtest 'none clean same' clean 2 3
112 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 parent=3
113 parent=3
114
114
115 $ revtest 'none clean cross' clean 3 4
115 $ revtest 'none clean cross' clean 3 4
116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 parent=4
117 parent=4
118
118
119
119
120 $ revtest 'none dirty linear' dirty 1 2
120 $ revtest 'none dirty linear' dirty 1 2
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 parent=2
122 parent=2
123 M foo
123 M foo
124
124
125 $ revtest 'none dirtysub linear' dirtysub 1 2
125 $ revtest 'none dirtysub linear' dirtysub 1 2
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 parent=2
127 parent=2
128 M sub/suba
128 M sub/suba
129
129
130 $ revtest 'none dirty same' dirty 2 3
130 $ revtest 'none dirty same' dirty 2 3
131 abort: uncommitted changes
131 abort: uncommitted changes
132 (commit or update --clean to discard changes)
132 (commit or update --clean to discard changes)
133 parent=2
133 parent=2
134 M foo
134 M foo
135
135
136 $ revtest 'none dirtysub same' dirtysub 2 3
136 $ revtest 'none dirtysub same' dirtysub 2 3
137 abort: uncommitted changes
137 abort: uncommitted changes
138 (commit or update --clean to discard changes)
138 (commit or update --clean to discard changes)
139 parent=2
139 parent=2
140 M sub/suba
140 M sub/suba
141
141
142 $ revtest 'none dirty cross' dirty 3 4
142 $ revtest 'none dirty cross' dirty 3 4
143 abort: uncommitted changes
143 abort: uncommitted changes
144 (commit or update --clean to discard changes)
144 (commit or update --clean to discard changes)
145 parent=3
145 parent=3
146 M foo
146 M foo
147
147
148 $ norevtest 'none dirty cross' dirty 2
148 $ norevtest 'none dirty cross' dirty 2
149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 updated to "bd10386d478c: 2"
150 updated to "bd10386d478c: 2"
151 1 other heads for branch "default"
151 1 other heads for branch "default"
152 parent=2
152 parent=2
153 M foo
153 M foo
154
154
155 $ revtest 'none dirtysub cross' dirtysub 3 4
155 $ revtest 'none dirtysub cross' dirtysub 3 4
156 abort: uncommitted changes
156 abort: uncommitted changes
157 (commit or update --clean to discard changes)
157 (commit or update --clean to discard changes)
158 parent=3
158 parent=3
159 M sub/suba
159 M sub/suba
160
160
161 $ revtest '-C dirty linear' dirty 1 2 -C
161 $ revtest '-C dirty linear' dirty 1 2 -C
162 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 parent=2
163 parent=2
164
164
165 $ revtest '-c dirty linear' dirty 1 2 -c
165 $ revtest '-c dirty linear' dirty 1 2 -c
166 abort: uncommitted changes
166 abort: uncommitted changes
167 parent=1
167 parent=1
168 M foo
168 M foo
169
169
170 $ revtest '-m dirty linear' dirty 1 2 -m
170 $ revtest '-m dirty linear' dirty 1 2 -m
171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 parent=2
172 parent=2
173 M foo
173 M foo
174
174
175 $ revtest '-m dirty cross' dirty 3 4 -m
175 $ revtest '-m dirty cross' dirty 3 4 -m
176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
177 parent=4
177 parent=4
178 M foo
178 M foo
179
179
180 $ revtest '-c dirtysub linear' dirtysub 1 2 -c
180 $ revtest '-c dirtysub linear' dirtysub 1 2 -c
181 abort: uncommitted changes in subrepository "sub"
181 abort: uncommitted changes in subrepository "sub"
182 parent=1
182 parent=1
183 M sub/suba
183 M sub/suba
184
184
185 $ norevtest '-c clean same' clean 2 -c
185 $ norevtest '-c clean same' clean 2 -c
186 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 updated to "bd10386d478c: 2"
187 updated to "bd10386d478c: 2"
188 1 other heads for branch "default"
188 1 other heads for branch "default"
189 parent=2
189 parent=2
190
190
191 $ revtest '-cC dirty linear' dirty 1 2 -cC
191 $ revtest '-cC dirty linear' dirty 1 2 -cC
192 abort: can only specify one of -C/--clean, -c/--check, or -m/--merge
192 abort: can only specify one of -C/--clean, -c/--check, or -m/--merge
193 parent=1
193 parent=1
194 M foo
194 M foo
195
195
196 $ revtest '-mc dirty linear' dirty 1 2 -mc
196 $ revtest '-mc dirty linear' dirty 1 2 -mc
197 abort: can only specify one of -C/--clean, -c/--check, or -m/--merge
197 abort: can only specify one of -C/--clean, -c/--check, or -m/--merge
198 parent=1
198 parent=1
199 M foo
199 M foo
200
200
201 $ revtest '-mC dirty linear' dirty 1 2 -mC
201 $ revtest '-mC dirty linear' dirty 1 2 -mC
202 abort: can only specify one of -C/--clean, -c/--check, or -m/--merge
202 abort: can only specify one of -C/--clean, -c/--check, or -m/--merge
203 parent=1
203 parent=1
204 M foo
204 M foo
205
205
206 $ echo '[commands]' >> .hg/hgrc
206 $ echo '[commands]' >> .hg/hgrc
207 $ echo 'update.check = abort' >> .hg/hgrc
207 $ echo 'update.check = abort' >> .hg/hgrc
208
208
209 $ revtest 'none dirty linear' dirty 1 2
209 $ revtest 'none dirty linear' dirty 1 2
210 abort: uncommitted changes
210 abort: uncommitted changes
211 parent=1
211 parent=1
212 M foo
212 M foo
213
213
214 $ revtest 'none dirty linear' dirty 1 2 -c
214 $ revtest 'none dirty linear' dirty 1 2 -c
215 abort: uncommitted changes
215 abort: uncommitted changes
216 parent=1
216 parent=1
217 M foo
217 M foo
218
218
219 $ revtest 'none dirty linear' dirty 1 2 -C
219 $ revtest 'none dirty linear' dirty 1 2 -C
220 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
221 parent=2
221 parent=2
222
222
223 $ echo 'update.check = none' >> .hg/hgrc
223 $ echo 'update.check = none' >> .hg/hgrc
224
224
225 $ revtest 'none dirty cross' dirty 3 4
225 $ revtest 'none dirty cross' dirty 3 4
226 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 parent=4
227 parent=4
228 M foo
228 M foo
229
229
230 $ revtest 'none dirty linear' dirty 1 2
230 $ revtest 'none dirty linear' dirty 1 2
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 parent=2
232 parent=2
233 M foo
233 M foo
234
234
235 $ revtest 'none dirty linear' dirty 1 2 -c
235 $ revtest 'none dirty linear' dirty 1 2 -c
236 abort: uncommitted changes
236 abort: uncommitted changes
237 parent=1
237 parent=1
238 M foo
238 M foo
239
239
240 $ revtest 'none dirty linear' dirty 1 2 -C
240 $ revtest 'none dirty linear' dirty 1 2 -C
241 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 parent=2
242 parent=2
243
243
244 $ hg co -qC 3
244 $ hg co -qC 3
245 $ echo dirty >> a
245 $ echo dirty >> a
246 $ hg co --tool :merge3 4
246 $ hg co --tool :merge3 4
247 merging a
247 merging a
248 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
248 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
249 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
249 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
250 use 'hg resolve' to retry unresolved file merges
250 use 'hg resolve' to retry unresolved file merges
251 [1]
251 [1]
252 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
252 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
253 o 5:ff252e8273df b1
253 o 5:ff252e8273df b1
254 |
254 |
255 @ 4:d047485b3896 0:60829823a42a b1
255 @ 4:d047485b3896 0:60829823a42a b1
256 |
256 |
257 | o 3:6efa171f091b 1:0786582aa4b1
257 | % 3:6efa171f091b 1:0786582aa4b1
258 | |
258 | |
259 | | o 2:bd10386d478c
259 | | o 2:bd10386d478c
260 | |/
260 | |/
261 | o 1:0786582aa4b1
261 | o 1:0786582aa4b1
262 |/
262 |/
263 o 0:60829823a42a
263 o 0:60829823a42a
264
264
265 $ hg st
265 $ hg st
266 M a
266 M a
267 ? a.orig
267 ? a.orig
268 # Unresolved merge conflicts:
268 # Unresolved merge conflicts:
269 #
269 #
270 # a
270 # a
271 #
271 #
272 # To mark files as resolved: hg resolve --mark FILE
272 # To mark files as resolved: hg resolve --mark FILE
273
273
274 $ cat a
274 $ cat a
275 <<<<<<< working copy: 6efa171f091b - test: 3
275 <<<<<<< working copy: 6efa171f091b - test: 3
276 three
276 three
277 dirty
277 dirty
278 ||||||| base
278 ||||||| base
279 three
279 three
280 =======
280 =======
281 four
281 four
282 >>>>>>> destination: d047485b3896 b1 - test: 4
282 >>>>>>> destination: d047485b3896 b1 - test: 4
283 $ rm a.orig
283 $ rm a.orig
284
284
285 $ echo 'update.check = noconflict' >> .hg/hgrc
285 $ echo 'update.check = noconflict' >> .hg/hgrc
286
286
287 $ revtest 'none dirty cross' dirty 3 4
287 $ revtest 'none dirty cross' dirty 3 4
288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 parent=4
289 parent=4
290 M foo
290 M foo
291
291
292 $ revtest 'none dirty linear' dirty 1 2
292 $ revtest 'none dirty linear' dirty 1 2
293 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 parent=2
294 parent=2
295 M foo
295 M foo
296
296
297 $ revtest 'none dirty linear' dirty 1 2 -c
297 $ revtest 'none dirty linear' dirty 1 2 -c
298 abort: uncommitted changes
298 abort: uncommitted changes
299 parent=1
299 parent=1
300 M foo
300 M foo
301
301
302 $ revtest 'none dirty linear' dirty 1 2 -C
302 $ revtest 'none dirty linear' dirty 1 2 -C
303 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
303 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 parent=2
304 parent=2
305
305
306 Locally added file is allowed
306 Locally added file is allowed
307 $ hg up -qC 3
307 $ hg up -qC 3
308 $ echo a > bar
308 $ echo a > bar
309 $ hg add bar
309 $ hg add bar
310 $ hg up -q 4
310 $ hg up -q 4
311 $ hg st
311 $ hg st
312 A bar
312 A bar
313 $ hg forget bar
313 $ hg forget bar
314 $ rm bar
314 $ rm bar
315
315
316 Locally removed file is allowed
316 Locally removed file is allowed
317 $ hg up -qC 3
317 $ hg up -qC 3
318 $ hg rm foo
318 $ hg rm foo
319 $ hg up -q 4
319 $ hg up -q 4
320
320
321 File conflict is not allowed
321 File conflict is not allowed
322 $ hg up -qC 3
322 $ hg up -qC 3
323 $ echo dirty >> a
323 $ echo dirty >> a
324 $ hg up -q 4
324 $ hg up -q 4
325 abort: conflicting changes
325 abort: conflicting changes
326 (commit or update --clean to discard changes)
326 (commit or update --clean to discard changes)
327 [255]
327 [255]
328 $ hg up -m 4
328 $ hg up -m 4
329 merging a
329 merging a
330 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
330 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
331 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
331 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
332 use 'hg resolve' to retry unresolved file merges
332 use 'hg resolve' to retry unresolved file merges
333 [1]
333 [1]
334 $ rm a.orig
334 $ rm a.orig
335 $ hg status
335 $ hg status
336 M a
336 M a
337 # Unresolved merge conflicts:
337 # Unresolved merge conflicts:
338 #
338 #
339 # a
339 # a
340 #
340 #
341 # To mark files as resolved: hg resolve --mark FILE
341 # To mark files as resolved: hg resolve --mark FILE
342
342
343 $ hg resolve -l
343 $ hg resolve -l
344 U a
344 U a
345
345
346 Change/delete conflict is not allowed
346 Change/delete conflict is not allowed
347 $ hg up -qC 3
347 $ hg up -qC 3
348 $ hg rm foo
348 $ hg rm foo
349 $ hg up -q 4
349 $ hg up -q 4
350
350
351 Uses default value of "linear" when value is misspelled
351 Uses default value of "linear" when value is misspelled
352 $ echo 'update.check = linyar' >> .hg/hgrc
352 $ echo 'update.check = linyar' >> .hg/hgrc
353
353
354 $ revtest 'dirty cross' dirty 3 4
354 $ revtest 'dirty cross' dirty 3 4
355 abort: uncommitted changes
355 abort: uncommitted changes
356 (commit or update --clean to discard changes)
356 (commit or update --clean to discard changes)
357 parent=3
357 parent=3
358 M foo
358 M foo
359
359
360 Setup for later tests
360 Setup for later tests
361 $ revtest 'none dirty linear' dirty 1 2 -c
361 $ revtest 'none dirty linear' dirty 1 2 -c
362 abort: uncommitted changes
362 abort: uncommitted changes
363 parent=1
363 parent=1
364 M foo
364 M foo
365
365
366 $ cd ..
366 $ cd ..
367
367
368 Test updating to null revision
368 Test updating to null revision
369
369
370 $ hg init null-repo
370 $ hg init null-repo
371 $ cd null-repo
371 $ cd null-repo
372 $ echo a > a
372 $ echo a > a
373 $ hg add a
373 $ hg add a
374 $ hg ci -m a
374 $ hg ci -m a
375 $ hg up -qC 0
375 $ hg up -qC 0
376 $ echo b > b
376 $ echo b > b
377 $ hg add b
377 $ hg add b
378 $ hg up null
378 $ hg up null
379 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
379 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
380 $ hg st
380 $ hg st
381 A b
381 A b
382 $ hg up -q 0
382 $ hg up -q 0
383 $ hg st
383 $ hg st
384 A b
384 A b
385 $ hg up -qC null
385 $ hg up -qC null
386 $ hg st
386 $ hg st
387 ? b
387 ? b
388 $ cd ..
388 $ cd ..
389
389
390 Test updating with closed head
390 Test updating with closed head
391 ---------------------------------------------------------------------
391 ---------------------------------------------------------------------
392
392
393 $ hg clone -U -q b1 closed-heads
393 $ hg clone -U -q b1 closed-heads
394 $ cd closed-heads
394 $ cd closed-heads
395
395
396 Test updating if at least one non-closed branch head exists
396 Test updating if at least one non-closed branch head exists
397
397
398 if on the closed branch head:
398 if on the closed branch head:
399 - update to "."
399 - update to "."
400 - "updated to a closed branch head ...." message is displayed
400 - "updated to a closed branch head ...." message is displayed
401 - "N other heads for ...." message is displayed
401 - "N other heads for ...." message is displayed
402
402
403 $ hg update -q -C 3
403 $ hg update -q -C 3
404 $ hg commit --close-branch -m 6
404 $ hg commit --close-branch -m 6
405 $ norevtest "on closed branch head" clean 6
405 $ norevtest "on closed branch head" clean 6
406 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
407 no open descendant heads on branch "default", updating to a closed head
407 no open descendant heads on branch "default", updating to a closed head
408 (committing will reopen the head, use 'hg heads .' to see 1 other heads)
408 (committing will reopen the head, use 'hg heads .' to see 1 other heads)
409 parent=6
409 parent=6
410
410
411 if descendant non-closed branch head exists, and it is only one branch head:
411 if descendant non-closed branch head exists, and it is only one branch head:
412 - update to it, even if its revision is less than closed one
412 - update to it, even if its revision is less than closed one
413 - "N other heads for ...." message isn't displayed
413 - "N other heads for ...." message isn't displayed
414
414
415 $ norevtest "non-closed 2 should be chosen" clean 1
415 $ norevtest "non-closed 2 should be chosen" clean 1
416 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
417 parent=2
417 parent=2
418
418
419 if all descendant branch heads are closed, but there is another branch head:
419 if all descendant branch heads are closed, but there is another branch head:
420 - update to the tipmost descendant head
420 - update to the tipmost descendant head
421 - "updated to a closed branch head ...." message is displayed
421 - "updated to a closed branch head ...." message is displayed
422 - "N other heads for ...." message is displayed
422 - "N other heads for ...." message is displayed
423
423
424 $ norevtest "all descendant branch heads are closed" clean 3
424 $ norevtest "all descendant branch heads are closed" clean 3
425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 no open descendant heads on branch "default", updating to a closed head
426 no open descendant heads on branch "default", updating to a closed head
427 (committing will reopen the head, use 'hg heads .' to see 1 other heads)
427 (committing will reopen the head, use 'hg heads .' to see 1 other heads)
428 parent=6
428 parent=6
429
429
430 Test updating if all branch heads are closed
430 Test updating if all branch heads are closed
431
431
432 if on the closed branch head:
432 if on the closed branch head:
433 - update to "."
433 - update to "."
434 - "updated to a closed branch head ...." message is displayed
434 - "updated to a closed branch head ...." message is displayed
435 - "all heads of branch ...." message is displayed
435 - "all heads of branch ...." message is displayed
436
436
437 $ hg update -q -C 2
437 $ hg update -q -C 2
438 $ hg commit --close-branch -m 7
438 $ hg commit --close-branch -m 7
439 $ norevtest "all heads of branch default are closed" clean 6
439 $ norevtest "all heads of branch default are closed" clean 6
440 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
440 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
441 no open descendant heads on branch "default", updating to a closed head
441 no open descendant heads on branch "default", updating to a closed head
442 (committing will reopen branch "default")
442 (committing will reopen branch "default")
443 parent=6
443 parent=6
444
444
445 if not on the closed branch head:
445 if not on the closed branch head:
446 - update to the tipmost descendant (closed) head
446 - update to the tipmost descendant (closed) head
447 - "updated to a closed branch head ...." message is displayed
447 - "updated to a closed branch head ...." message is displayed
448 - "all heads of branch ...." message is displayed
448 - "all heads of branch ...." message is displayed
449
449
450 $ norevtest "all heads of branch default are closed" clean 1
450 $ norevtest "all heads of branch default are closed" clean 1
451 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
451 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 no open descendant heads on branch "default", updating to a closed head
452 no open descendant heads on branch "default", updating to a closed head
453 (committing will reopen branch "default")
453 (committing will reopen branch "default")
454 parent=7
454 parent=7
455
455
456 $ cd ..
456 $ cd ..
457
457
458 Test updating if "default" branch doesn't exist and no revision is
458 Test updating if "default" branch doesn't exist and no revision is
459 checked out (= "default" is used as current branch)
459 checked out (= "default" is used as current branch)
460
460
461 $ hg init no-default-branch
461 $ hg init no-default-branch
462 $ cd no-default-branch
462 $ cd no-default-branch
463
463
464 $ hg branch foobar
464 $ hg branch foobar
465 marked working directory as branch foobar
465 marked working directory as branch foobar
466 (branches are permanent and global, did you want a bookmark?)
466 (branches are permanent and global, did you want a bookmark?)
467 $ echo a > a
467 $ echo a > a
468 $ hg commit -m "#0" -A
468 $ hg commit -m "#0" -A
469 adding a
469 adding a
470 $ echo 1 >> a
470 $ echo 1 >> a
471 $ hg commit -m "#1"
471 $ hg commit -m "#1"
472 $ hg update -q 0
472 $ hg update -q 0
473 $ echo 3 >> a
473 $ echo 3 >> a
474 $ hg commit -m "#2"
474 $ hg commit -m "#2"
475 created new head
475 created new head
476 $ hg commit --close-branch -m "#3"
476 $ hg commit --close-branch -m "#3"
477
477
478 if there is at least one non-closed branch head:
478 if there is at least one non-closed branch head:
479 - update to the tipmost branch head
479 - update to the tipmost branch head
480
480
481 $ norevtest "non-closed 1 should be chosen" clean null
481 $ norevtest "non-closed 1 should be chosen" clean null
482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 parent=1
483 parent=1
484
484
485 if all branch heads are closed
485 if all branch heads are closed
486 - update to "tip"
486 - update to "tip"
487 - "updated to a closed branch head ...." message is displayed
487 - "updated to a closed branch head ...." message is displayed
488 - "all heads for branch "XXXX" are closed" message is displayed
488 - "all heads for branch "XXXX" are closed" message is displayed
489
489
490 $ hg update -q -C 1
490 $ hg update -q -C 1
491 $ hg commit --close-branch -m "#4"
491 $ hg commit --close-branch -m "#4"
492
492
493 $ norevtest "all branches are closed" clean null
493 $ norevtest "all branches are closed" clean null
494 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
495 no open descendant heads on branch "foobar", updating to a closed head
495 no open descendant heads on branch "foobar", updating to a closed head
496 (committing will reopen branch "foobar")
496 (committing will reopen branch "foobar")
497 parent=4
497 parent=4
498
498
499 $ cd ../b1
499 $ cd ../b1
500
500
501 Test obsolescence behavior
501 Test obsolescence behavior
502 ---------------------------------------------------------------------
502 ---------------------------------------------------------------------
503
503
504 successors should be taken in account when checking head destination
504 successors should be taken in account when checking head destination
505
505
506 $ cat << EOF >> $HGRCPATH
506 $ cat << EOF >> $HGRCPATH
507 > [ui]
507 > [ui]
508 > logtemplate={rev}:{node|short} {desc|firstline}
508 > logtemplate={rev}:{node|short} {desc|firstline}
509 > [experimental]
509 > [experimental]
510 > evolution.createmarkers=True
510 > evolution.createmarkers=True
511 > EOF
511 > EOF
512
512
513 Test no-argument update to a successor of an obsoleted changeset
513 Test no-argument update to a successor of an obsoleted changeset
514
514
515 $ hg log -G
515 $ hg log -G
516 o 5:ff252e8273df 5
516 o 5:ff252e8273df 5
517 |
517 |
518 o 4:d047485b3896 4
518 o 4:d047485b3896 4
519 |
519 |
520 | o 3:6efa171f091b 3
520 | o 3:6efa171f091b 3
521 | |
521 | |
522 | | o 2:bd10386d478c 2
522 | | o 2:bd10386d478c 2
523 | |/
523 | |/
524 | @ 1:0786582aa4b1 1
524 | @ 1:0786582aa4b1 1
525 |/
525 |/
526 o 0:60829823a42a 0
526 o 0:60829823a42a 0
527
527
528 $ hg book bm -r 3
528 $ hg book bm -r 3
529 $ hg status
529 $ hg status
530 M foo
530 M foo
531
531
532 We add simple obsolescence marker between 3 and 4 (indirect successors)
532 We add simple obsolescence marker between 3 and 4 (indirect successors)
533
533
534 $ hg id --debug -i -r 3
534 $ hg id --debug -i -r 3
535 6efa171f091b00a3c35edc15d48c52a498929953
535 6efa171f091b00a3c35edc15d48c52a498929953
536 $ hg id --debug -i -r 4
536 $ hg id --debug -i -r 4
537 d047485b3896813b2a624e86201983520f003206
537 d047485b3896813b2a624e86201983520f003206
538 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
538 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
539 1 new obsolescence markers
539 1 new obsolescence markers
540 obsoleted 1 changesets
540 obsoleted 1 changesets
541 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
541 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
542 1 new obsolescence markers
542 1 new obsolescence markers
543
543
544 Test that 5 is detected as a valid destination from 3 and also accepts moving
544 Test that 5 is detected as a valid destination from 3 and also accepts moving
545 the bookmark (issue4015)
545 the bookmark (issue4015)
546
546
547 $ hg up --quiet --hidden 3
547 $ hg up --quiet --hidden 3
548 $ hg up 5
548 $ hg up 5
549 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
549 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
550 $ hg book bm
550 $ hg book bm
551 moving bookmark 'bm' forward from 6efa171f091b
551 moving bookmark 'bm' forward from 6efa171f091b
552 $ hg bookmarks
552 $ hg bookmarks
553 * bm 5:ff252e8273df
553 * bm 5:ff252e8273df
554
554
555 Test that we abort before we warn about the hidden commit if the working
555 Test that we abort before we warn about the hidden commit if the working
556 directory is dirty
556 directory is dirty
557 $ echo conflict > a
557 $ echo conflict > a
558 $ hg up --hidden 3
558 $ hg up --hidden 3
559 abort: uncommitted changes
559 abort: uncommitted changes
560 (commit or update --clean to discard changes)
560 (commit or update --clean to discard changes)
561 [255]
561 [255]
562
562
563 Test that we still warn also when there are conflicts
563 Test that we still warn also when there are conflicts
564 $ hg up -m --hidden 3
564 $ hg up -m --hidden 3
565 merging a
565 merging a
566 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
566 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
567 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
567 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
568 use 'hg resolve' to retry unresolved file merges
568 use 'hg resolve' to retry unresolved file merges
569 (leaving bookmark bm)
569 (leaving bookmark bm)
570 updated to hidden changeset 6efa171f091b
570 updated to hidden changeset 6efa171f091b
571 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
571 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
572 [1]
572 [1]
573
573
574 Test that statuses are reported properly before and after merge resolution.
574 Test that statuses are reported properly before and after merge resolution.
575 $ rm a.orig
575 $ rm a.orig
576 $ hg resolve -l
576 $ hg resolve -l
577 U a
577 U a
578 $ hg status
578 $ hg status
579 M a
579 M a
580 M foo
580 M foo
581 # Unresolved merge conflicts:
581 # Unresolved merge conflicts:
582 #
582 #
583 # a
583 # a
584 #
584 #
585 # To mark files as resolved: hg resolve --mark FILE
585 # To mark files as resolved: hg resolve --mark FILE
586
586
587
587
588 $ hg revert -r . a
588 $ hg revert -r . a
589
589
590 $ rm a.orig
590 $ rm a.orig
591 $ hg resolve -l
591 $ hg resolve -l
592 U a
592 U a
593 $ hg status
593 $ hg status
594 M foo
594 M foo
595 # Unresolved merge conflicts:
595 # Unresolved merge conflicts:
596 #
596 #
597 # a
597 # a
598 #
598 #
599 # To mark files as resolved: hg resolve --mark FILE
599 # To mark files as resolved: hg resolve --mark FILE
600
600
601 $ hg status -Tjson
601 $ hg status -Tjson
602 [
602 [
603 {
603 {
604 "itemtype": "file",
604 "itemtype": "file",
605 "path": "foo",
605 "path": "foo",
606 "status": "M"
606 "status": "M"
607 },
607 },
608 {
608 {
609 "itemtype": "file",
609 "itemtype": "file",
610 "path": "a",
610 "path": "a",
611 "unresolved": true
611 "unresolved": true
612 }
612 }
613 ]
613 ]
614
614
615 $ hg resolve -m
615 $ hg resolve -m
616 (no more unresolved files)
616 (no more unresolved files)
617
617
618 $ hg resolve -l
618 $ hg resolve -l
619 R a
619 R a
620 $ hg status
620 $ hg status
621 M foo
621 M foo
622 # No unresolved merge conflicts.
622 # No unresolved merge conflicts.
623
623
624 $ hg status -Tjson
624 $ hg status -Tjson
625 [
625 [
626 {
626 {
627 "itemtype": "file",
627 "itemtype": "file",
628 "path": "foo",
628 "path": "foo",
629 "status": "M"
629 "status": "M"
630 }
630 }
631 ]
631 ]
632
632
633 Test that 4 is detected as the no-argument destination from 3 and also moves
633 Test that 4 is detected as the no-argument destination from 3 and also moves
634 the bookmark with it
634 the bookmark with it
635 $ hg up --quiet 0 # we should be able to update to 3 directly
635 $ hg up --quiet 0 # we should be able to update to 3 directly
636 $ hg status
636 $ hg status
637 M foo
637 M foo
638 $ hg up --quiet --hidden 3 # but not implemented yet.
638 $ hg up --quiet --hidden 3 # but not implemented yet.
639 updated to hidden changeset 6efa171f091b
639 updated to hidden changeset 6efa171f091b
640 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
640 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
641 $ hg book -f bm
641 $ hg book -f bm
642 $ hg up
642 $ hg up
643 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
643 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
644 updating bookmark bm
644 updating bookmark bm
645 $ hg book
645 $ hg book
646 * bm 4:d047485b3896
646 * bm 4:d047485b3896
647
647
648 Test that 5 is detected as a valid destination from 1
648 Test that 5 is detected as a valid destination from 1
649 $ hg up --quiet 0 # we should be able to update to 3 directly
649 $ hg up --quiet 0 # we should be able to update to 3 directly
650 $ hg up --quiet --hidden 3 # but not implemented yet.
650 $ hg up --quiet --hidden 3 # but not implemented yet.
651 updated to hidden changeset 6efa171f091b
651 updated to hidden changeset 6efa171f091b
652 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
652 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
653 $ hg up 5
653 $ hg up 5
654 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
654 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
655
655
656 Test that 5 is not detected as a valid destination from 2
656 Test that 5 is not detected as a valid destination from 2
657 $ hg up --quiet 0
657 $ hg up --quiet 0
658 $ hg up --quiet 2
658 $ hg up --quiet 2
659 $ hg up 5
659 $ hg up 5
660 abort: uncommitted changes
660 abort: uncommitted changes
661 (commit or update --clean to discard changes)
661 (commit or update --clean to discard changes)
662 [255]
662 [255]
663
663
664 Test that we don't crash when updating from a pruned changeset (i.e. has no
664 Test that we don't crash when updating from a pruned changeset (i.e. has no
665 successors). Behavior should probably be that we update to the first
665 successors). Behavior should probably be that we update to the first
666 non-obsolete parent but that will be decided later.
666 non-obsolete parent but that will be decided later.
667 $ hg id --debug -r 2
667 $ hg id --debug -r 2
668 bd10386d478cd5a9faf2e604114c8e6da62d3889
668 bd10386d478cd5a9faf2e604114c8e6da62d3889
669 $ hg up --quiet 0
669 $ hg up --quiet 0
670 $ hg up --quiet 2
670 $ hg up --quiet 2
671 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
671 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
672 1 new obsolescence markers
672 1 new obsolescence markers
673 obsoleted 1 changesets
673 obsoleted 1 changesets
674 $ hg up
674 $ hg up
675 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
675 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
676
676
677 Test experimental revset support
677 Test experimental revset support
678
678
679 $ hg log -r '_destupdate()'
679 $ hg log -r '_destupdate()'
680 2:bd10386d478c 2 (no-eol)
680 2:bd10386d478c 2 (no-eol)
681
681
682 Test that boolean flags allow --no-flag specification to override [defaults]
682 Test that boolean flags allow --no-flag specification to override [defaults]
683 $ cat >> $HGRCPATH <<EOF
683 $ cat >> $HGRCPATH <<EOF
684 > [defaults]
684 > [defaults]
685 > update = --check
685 > update = --check
686 > EOF
686 > EOF
687 $ hg co 2
687 $ hg co 2
688 abort: uncommitted changes
688 abort: uncommitted changes
689 [255]
689 [255]
690 $ hg co --no-check 2
690 $ hg co --no-check 2
691 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
691 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
General Comments 0
You need to be logged in to leave comments. Login now