Show More
@@ -1,107 +1,109 b'' | |||
|
1 | 1 | # -*- coding: UTF-8 -*- |
|
2 | 2 | # beautifygraph.py - improve graph output by using Unicode characters |
|
3 | 3 | # |
|
4 | 4 | # Copyright 2018 John Stiles <johnstiles@gmail.com> |
|
5 | 5 | # |
|
6 | 6 | # This software may be used and distributed according to the terms of the |
|
7 | 7 | # GNU General Public License version 2 or any later version. |
|
8 | 8 | |
|
9 | 9 | '''beautify log -G output by using Unicode characters (EXPERIMENTAL) |
|
10 | 10 | |
|
11 | 11 | A terminal with UTF-8 support and monospace narrow text are required. |
|
12 | 12 | ''' |
|
13 | 13 | |
|
14 | 14 | from __future__ import absolute_import |
|
15 | 15 | |
|
16 | 16 | from mercurial.i18n import _ |
|
17 | 17 | from mercurial import ( |
|
18 | 18 | encoding, |
|
19 | 19 | extensions, |
|
20 | 20 | graphmod, |
|
21 | 21 | pycompat, |
|
22 | 22 | templatekw, |
|
23 | 23 | ) |
|
24 | 24 | |
|
25 | 25 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
|
26 | 26 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
27 | 27 | # be specifying the version(s) of Mercurial they are tested with, or |
|
28 | 28 | # leave the attribute unspecified. |
|
29 | 29 | testedwith = b'ships-with-hg-core' |
|
30 | 30 | |
|
31 | 31 | |
|
32 | 32 | def prettyedge(before, edge, after): |
|
33 | 33 | if edge == b'~': |
|
34 | 34 | return b'\xE2\x95\xA7' # U+2567 β§ |
|
35 | 35 | if edge == b'/': |
|
36 | 36 | return b'\xE2\x95\xB1' # U+2571 β± |
|
37 | 37 | if edge == b'-': |
|
38 | 38 | return b'\xE2\x94\x80' # U+2500 β |
|
39 | 39 | if edge == b'|': |
|
40 | 40 | return b'\xE2\x94\x82' # U+2502 β |
|
41 | 41 | if edge == b':': |
|
42 | 42 | return b'\xE2\x94\x86' # U+2506 β |
|
43 | 43 | if edge == b'\\': |
|
44 | 44 | return b'\xE2\x95\xB2' # U+2572 β² |
|
45 | 45 | if edge == b'+': |
|
46 | 46 | if before == b' ' and not after == b' ': |
|
47 | 47 | return b'\xE2\x94\x9C' # U+251C β |
|
48 | 48 | if after == b' ' and not before == b' ': |
|
49 | 49 | return b'\xE2\x94\xA4' # U+2524 β€ |
|
50 | 50 | return b'\xE2\x94\xBC' # U+253C βΌ |
|
51 | 51 | return edge |
|
52 | 52 | |
|
53 | 53 | |
|
54 | 54 | def convertedges(line): |
|
55 | 55 | line = b' %s ' % line |
|
56 | 56 | pretty = [] |
|
57 | 57 | for idx in pycompat.xrange(len(line) - 2): |
|
58 | 58 | pretty.append( |
|
59 | 59 | prettyedge( |
|
60 | 60 | line[idx : idx + 1], |
|
61 | 61 | line[idx + 1 : idx + 2], |
|
62 | 62 | line[idx + 2 : idx + 3], |
|
63 | 63 | ) |
|
64 | 64 | ) |
|
65 | 65 | return b''.join(pretty) |
|
66 | 66 | |
|
67 | 67 | |
|
68 | 68 | def getprettygraphnode(orig, *args, **kwargs): |
|
69 | 69 | node = orig(*args, **kwargs) |
|
70 | 70 | if node == b'o': |
|
71 | 71 | return b'\xE2\x97\x8B' # U+25CB β |
|
72 | 72 | if node == b'@': |
|
73 | 73 | return b'\xE2\x97\x8D' # U+25CD β |
|
74 | if node == b'%': | |
|
75 | return b'\xE2\x97\x8D' # U+25CE β | |
|
74 | 76 | if node == b'*': |
|
75 | 77 | return b'\xE2\x88\x97' # U+2217 β |
|
76 | 78 | if node == b'x': |
|
77 | 79 | return b'\xE2\x97\x8C' # U+25CC β |
|
78 | 80 | if node == b'_': |
|
79 | 81 | return b'\xE2\x95\xA4' # U+2564 β€ |
|
80 | 82 | return node |
|
81 | 83 | |
|
82 | 84 | |
|
83 | 85 | def outputprettygraph(orig, ui, graph, *args, **kwargs): |
|
84 | 86 | (edges, text) = zip(*graph) |
|
85 | 87 | graph = zip([convertedges(e) for e in edges], text) |
|
86 | 88 | return orig(ui, graph, *args, **kwargs) |
|
87 | 89 | |
|
88 | 90 | |
|
89 | 91 | def extsetup(ui): |
|
90 | 92 | if ui.plain(b'graph'): |
|
91 | 93 | return |
|
92 | 94 | |
|
93 | 95 | if encoding.encoding != b'UTF-8': |
|
94 | 96 | ui.warn(_(b'beautifygraph: unsupported encoding, UTF-8 required\n')) |
|
95 | 97 | return |
|
96 | 98 | |
|
97 | 99 | if 'A' in encoding._wide: |
|
98 | 100 | ui.warn( |
|
99 | 101 | _( |
|
100 | 102 | b'beautifygraph: unsupported terminal settings, ' |
|
101 | 103 | b'monospace narrow text required\n' |
|
102 | 104 | ) |
|
103 | 105 | ) |
|
104 | 106 | return |
|
105 | 107 | |
|
106 | 108 | extensions.wrapfunction(graphmod, b'outputgraph', outputprettygraph) |
|
107 | 109 | extensions.wrapfunction(templatekw, b'getgraphnode', getprettygraphnode) |
@@ -1,940 +1,940 b'' | |||
|
1 | 1 | # hgweb/webutil.py - utility library for the web interface. |
|
2 | 2 | # |
|
3 | 3 | # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> |
|
4 | 4 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
|
5 | 5 | # |
|
6 | 6 | # This software may be used and distributed according to the terms of the |
|
7 | 7 | # GNU General Public License version 2 or any later version. |
|
8 | 8 | |
|
9 | 9 | from __future__ import absolute_import |
|
10 | 10 | |
|
11 | 11 | import copy |
|
12 | 12 | import difflib |
|
13 | 13 | import os |
|
14 | 14 | import re |
|
15 | 15 | |
|
16 | 16 | from ..i18n import _ |
|
17 | 17 | from ..node import hex, nullid, short |
|
18 | 18 | from ..pycompat import setattr |
|
19 | 19 | |
|
20 | 20 | from .common import ( |
|
21 | 21 | ErrorResponse, |
|
22 | 22 | HTTP_BAD_REQUEST, |
|
23 | 23 | HTTP_NOT_FOUND, |
|
24 | 24 | paritygen, |
|
25 | 25 | ) |
|
26 | 26 | |
|
27 | 27 | from .. import ( |
|
28 | 28 | context, |
|
29 | 29 | diffutil, |
|
30 | 30 | error, |
|
31 | 31 | match, |
|
32 | 32 | mdiff, |
|
33 | 33 | obsutil, |
|
34 | 34 | patch, |
|
35 | 35 | pathutil, |
|
36 | 36 | pycompat, |
|
37 | 37 | scmutil, |
|
38 | 38 | templatefilters, |
|
39 | 39 | templatekw, |
|
40 | 40 | templateutil, |
|
41 | 41 | ui as uimod, |
|
42 | 42 | util, |
|
43 | 43 | ) |
|
44 | 44 | |
|
45 | 45 | from ..utils import stringutil |
|
46 | 46 | |
|
47 | 47 | archivespecs = util.sortdict( |
|
48 | 48 | ( |
|
49 | 49 | (b'zip', (b'application/zip', b'zip', b'.zip', None)), |
|
50 | 50 | (b'gz', (b'application/x-gzip', b'tgz', b'.tar.gz', None)), |
|
51 | 51 | (b'bz2', (b'application/x-bzip2', b'tbz2', b'.tar.bz2', None)), |
|
52 | 52 | ) |
|
53 | 53 | ) |
|
54 | 54 | |
|
55 | 55 | |
|
56 | 56 | def archivelist(ui, nodeid, url=None): |
|
57 | 57 | allowed = ui.configlist(b'web', b'allow-archive', untrusted=True) |
|
58 | 58 | archives = [] |
|
59 | 59 | |
|
60 | 60 | for typ, spec in pycompat.iteritems(archivespecs): |
|
61 | 61 | if typ in allowed or ui.configbool( |
|
62 | 62 | b'web', b'allow' + typ, untrusted=True |
|
63 | 63 | ): |
|
64 | 64 | archives.append( |
|
65 | 65 | { |
|
66 | 66 | b'type': typ, |
|
67 | 67 | b'extension': spec[2], |
|
68 | 68 | b'node': nodeid, |
|
69 | 69 | b'url': url, |
|
70 | 70 | } |
|
71 | 71 | ) |
|
72 | 72 | |
|
73 | 73 | return templateutil.mappinglist(archives) |
|
74 | 74 | |
|
75 | 75 | |
|
76 | 76 | def up(p): |
|
77 | 77 | if p[0:1] != b"/": |
|
78 | 78 | p = b"/" + p |
|
79 | 79 | if p[-1:] == b"/": |
|
80 | 80 | p = p[:-1] |
|
81 | 81 | up = os.path.dirname(p) |
|
82 | 82 | if up == b"/": |
|
83 | 83 | return b"/" |
|
84 | 84 | return up + b"/" |
|
85 | 85 | |
|
86 | 86 | |
|
87 | 87 | def _navseq(step, firststep=None): |
|
88 | 88 | if firststep: |
|
89 | 89 | yield firststep |
|
90 | 90 | if firststep >= 20 and firststep <= 40: |
|
91 | 91 | firststep = 50 |
|
92 | 92 | yield firststep |
|
93 | 93 | assert step > 0 |
|
94 | 94 | assert firststep > 0 |
|
95 | 95 | while step <= firststep: |
|
96 | 96 | step *= 10 |
|
97 | 97 | while True: |
|
98 | 98 | yield 1 * step |
|
99 | 99 | yield 3 * step |
|
100 | 100 | step *= 10 |
|
101 | 101 | |
|
102 | 102 | |
|
103 | 103 | class revnav(object): |
|
104 | 104 | def __init__(self, repo): |
|
105 | 105 | """Navigation generation object |
|
106 | 106 | |
|
107 | 107 | :repo: repo object we generate nav for |
|
108 | 108 | """ |
|
109 | 109 | # used for hex generation |
|
110 | 110 | self._revlog = repo.changelog |
|
111 | 111 | |
|
112 | 112 | def __nonzero__(self): |
|
113 | 113 | """return True if any revision to navigate over""" |
|
114 | 114 | return self._first() is not None |
|
115 | 115 | |
|
116 | 116 | __bool__ = __nonzero__ |
|
117 | 117 | |
|
118 | 118 | def _first(self): |
|
119 | 119 | """return the minimum non-filtered changeset or None""" |
|
120 | 120 | try: |
|
121 | 121 | return next(iter(self._revlog)) |
|
122 | 122 | except StopIteration: |
|
123 | 123 | return None |
|
124 | 124 | |
|
125 | 125 | def hex(self, rev): |
|
126 | 126 | return hex(self._revlog.node(rev)) |
|
127 | 127 | |
|
128 | 128 | def gen(self, pos, pagelen, limit): |
|
129 | 129 | """computes label and revision id for navigation link |
|
130 | 130 | |
|
131 | 131 | :pos: is the revision relative to which we generate navigation. |
|
132 | 132 | :pagelen: the size of each navigation page |
|
133 | 133 | :limit: how far shall we link |
|
134 | 134 | |
|
135 | 135 | The return is: |
|
136 | 136 | - a single element mappinglist |
|
137 | 137 | - containing a dictionary with a `before` and `after` key |
|
138 | 138 | - values are dictionaries with `label` and `node` keys |
|
139 | 139 | """ |
|
140 | 140 | if not self: |
|
141 | 141 | # empty repo |
|
142 | 142 | return templateutil.mappinglist( |
|
143 | 143 | [ |
|
144 | 144 | { |
|
145 | 145 | b'before': templateutil.mappinglist([]), |
|
146 | 146 | b'after': templateutil.mappinglist([]), |
|
147 | 147 | }, |
|
148 | 148 | ] |
|
149 | 149 | ) |
|
150 | 150 | |
|
151 | 151 | targets = [] |
|
152 | 152 | for f in _navseq(1, pagelen): |
|
153 | 153 | if f > limit: |
|
154 | 154 | break |
|
155 | 155 | targets.append(pos + f) |
|
156 | 156 | targets.append(pos - f) |
|
157 | 157 | targets.sort() |
|
158 | 158 | |
|
159 | 159 | first = self._first() |
|
160 | 160 | navbefore = [{b'label': b'(%i)' % first, b'node': self.hex(first)}] |
|
161 | 161 | navafter = [] |
|
162 | 162 | for rev in targets: |
|
163 | 163 | if rev not in self._revlog: |
|
164 | 164 | continue |
|
165 | 165 | if pos < rev < limit: |
|
166 | 166 | navafter.append( |
|
167 | 167 | {b'label': b'+%d' % abs(rev - pos), b'node': self.hex(rev)} |
|
168 | 168 | ) |
|
169 | 169 | if 0 < rev < pos: |
|
170 | 170 | navbefore.append( |
|
171 | 171 | {b'label': b'-%d' % abs(rev - pos), b'node': self.hex(rev)} |
|
172 | 172 | ) |
|
173 | 173 | |
|
174 | 174 | navafter.append({b'label': b'tip', b'node': b'tip'}) |
|
175 | 175 | |
|
176 | 176 | # TODO: maybe this can be a scalar object supporting tomap() |
|
177 | 177 | return templateutil.mappinglist( |
|
178 | 178 | [ |
|
179 | 179 | { |
|
180 | 180 | b'before': templateutil.mappinglist(navbefore), |
|
181 | 181 | b'after': templateutil.mappinglist(navafter), |
|
182 | 182 | }, |
|
183 | 183 | ] |
|
184 | 184 | ) |
|
185 | 185 | |
|
186 | 186 | |
|
187 | 187 | class filerevnav(revnav): |
|
188 | 188 | def __init__(self, repo, path): |
|
189 | 189 | """Navigation generation object |
|
190 | 190 | |
|
191 | 191 | :repo: repo object we generate nav for |
|
192 | 192 | :path: path of the file we generate nav for |
|
193 | 193 | """ |
|
194 | 194 | # used for iteration |
|
195 | 195 | self._changelog = repo.unfiltered().changelog |
|
196 | 196 | # used for hex generation |
|
197 | 197 | self._revlog = repo.file(path) |
|
198 | 198 | |
|
199 | 199 | def hex(self, rev): |
|
200 | 200 | return hex(self._changelog.node(self._revlog.linkrev(rev))) |
|
201 | 201 | |
|
202 | 202 | |
|
203 | 203 | # TODO: maybe this can be a wrapper class for changectx/filectx list, which |
|
204 | 204 | # yields {'ctx': ctx} |
|
205 | 205 | def _ctxsgen(context, ctxs): |
|
206 | 206 | for s in ctxs: |
|
207 | 207 | d = { |
|
208 | 208 | b'node': s.hex(), |
|
209 | 209 | b'rev': s.rev(), |
|
210 | 210 | b'user': s.user(), |
|
211 | 211 | b'date': s.date(), |
|
212 | 212 | b'description': s.description(), |
|
213 | 213 | b'branch': s.branch(), |
|
214 | 214 | } |
|
215 | 215 | if util.safehasattr(s, b'path'): |
|
216 | 216 | d[b'file'] = s.path() |
|
217 | 217 | yield d |
|
218 | 218 | |
|
219 | 219 | |
|
220 | 220 | def _siblings(siblings=None, hiderev=None): |
|
221 | 221 | if siblings is None: |
|
222 | 222 | siblings = [] |
|
223 | 223 | siblings = [s for s in siblings if s.node() != nullid] |
|
224 | 224 | if len(siblings) == 1 and siblings[0].rev() == hiderev: |
|
225 | 225 | siblings = [] |
|
226 | 226 | return templateutil.mappinggenerator(_ctxsgen, args=(siblings,)) |
|
227 | 227 | |
|
228 | 228 | |
|
229 | 229 | def difffeatureopts(req, ui, section): |
|
230 | 230 | diffopts = diffutil.difffeatureopts( |
|
231 | 231 | ui, untrusted=True, section=section, whitespace=True |
|
232 | 232 | ) |
|
233 | 233 | |
|
234 | 234 | for k in ( |
|
235 | 235 | b'ignorews', |
|
236 | 236 | b'ignorewsamount', |
|
237 | 237 | b'ignorewseol', |
|
238 | 238 | b'ignoreblanklines', |
|
239 | 239 | ): |
|
240 | 240 | v = req.qsparams.get(k) |
|
241 | 241 | if v is not None: |
|
242 | 242 | v = stringutil.parsebool(v) |
|
243 | 243 | setattr(diffopts, k, v if v is not None else True) |
|
244 | 244 | |
|
245 | 245 | return diffopts |
|
246 | 246 | |
|
247 | 247 | |
|
248 | 248 | def annotate(req, fctx, ui): |
|
249 | 249 | diffopts = difffeatureopts(req, ui, b'annotate') |
|
250 | 250 | return fctx.annotate(follow=True, diffopts=diffopts) |
|
251 | 251 | |
|
252 | 252 | |
|
253 | 253 | def parents(ctx, hide=None): |
|
254 | 254 | if isinstance(ctx, context.basefilectx): |
|
255 | 255 | introrev = ctx.introrev() |
|
256 | 256 | if ctx.changectx().rev() != introrev: |
|
257 | 257 | return _siblings([ctx.repo()[introrev]], hide) |
|
258 | 258 | return _siblings(ctx.parents(), hide) |
|
259 | 259 | |
|
260 | 260 | |
|
261 | 261 | def children(ctx, hide=None): |
|
262 | 262 | return _siblings(ctx.children(), hide) |
|
263 | 263 | |
|
264 | 264 | |
|
265 | 265 | def renamelink(fctx): |
|
266 | 266 | r = fctx.renamed() |
|
267 | 267 | if r: |
|
268 | 268 | return templateutil.mappinglist([{b'file': r[0], b'node': hex(r[1])}]) |
|
269 | 269 | return templateutil.mappinglist([]) |
|
270 | 270 | |
|
271 | 271 | |
|
272 | 272 | def nodetagsdict(repo, node): |
|
273 | 273 | return templateutil.hybridlist(repo.nodetags(node), name=b'name') |
|
274 | 274 | |
|
275 | 275 | |
|
276 | 276 | def nodebookmarksdict(repo, node): |
|
277 | 277 | return templateutil.hybridlist(repo.nodebookmarks(node), name=b'name') |
|
278 | 278 | |
|
279 | 279 | |
|
280 | 280 | def nodebranchdict(repo, ctx): |
|
281 | 281 | branches = [] |
|
282 | 282 | branch = ctx.branch() |
|
283 | 283 | # If this is an empty repo, ctx.node() == nullid, |
|
284 | 284 | # ctx.branch() == 'default'. |
|
285 | 285 | try: |
|
286 | 286 | branchnode = repo.branchtip(branch) |
|
287 | 287 | except error.RepoLookupError: |
|
288 | 288 | branchnode = None |
|
289 | 289 | if branchnode == ctx.node(): |
|
290 | 290 | branches.append(branch) |
|
291 | 291 | return templateutil.hybridlist(branches, name=b'name') |
|
292 | 292 | |
|
293 | 293 | |
|
294 | 294 | def nodeinbranch(repo, ctx): |
|
295 | 295 | branches = [] |
|
296 | 296 | branch = ctx.branch() |
|
297 | 297 | try: |
|
298 | 298 | branchnode = repo.branchtip(branch) |
|
299 | 299 | except error.RepoLookupError: |
|
300 | 300 | branchnode = None |
|
301 | 301 | if branch != b'default' and branchnode != ctx.node(): |
|
302 | 302 | branches.append(branch) |
|
303 | 303 | return templateutil.hybridlist(branches, name=b'name') |
|
304 | 304 | |
|
305 | 305 | |
|
306 | 306 | def nodebranchnodefault(ctx): |
|
307 | 307 | branches = [] |
|
308 | 308 | branch = ctx.branch() |
|
309 | 309 | if branch != b'default': |
|
310 | 310 | branches.append(branch) |
|
311 | 311 | return templateutil.hybridlist(branches, name=b'name') |
|
312 | 312 | |
|
313 | 313 | |
|
314 | 314 | def _nodenamesgen(context, f, node, name): |
|
315 | 315 | for t in f(node): |
|
316 | 316 | yield {name: t} |
|
317 | 317 | |
|
318 | 318 | |
|
319 | 319 | def showtag(repo, t1, node=nullid): |
|
320 | 320 | args = (repo.nodetags, node, b'tag') |
|
321 | 321 | return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) |
|
322 | 322 | |
|
323 | 323 | |
|
324 | 324 | def showbookmark(repo, t1, node=nullid): |
|
325 | 325 | args = (repo.nodebookmarks, node, b'bookmark') |
|
326 | 326 | return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) |
|
327 | 327 | |
|
328 | 328 | |
|
329 | 329 | def branchentries(repo, stripecount, limit=0): |
|
330 | 330 | tips = [] |
|
331 | 331 | heads = repo.heads() |
|
332 | 332 | parity = paritygen(stripecount) |
|
333 | 333 | sortkey = lambda item: (not item[1], item[0].rev()) |
|
334 | 334 | |
|
335 | 335 | def entries(context): |
|
336 | 336 | count = 0 |
|
337 | 337 | if not tips: |
|
338 | 338 | for tag, hs, tip, closed in repo.branchmap().iterbranches(): |
|
339 | 339 | tips.append((repo[tip], closed)) |
|
340 | 340 | for ctx, closed in sorted(tips, key=sortkey, reverse=True): |
|
341 | 341 | if limit > 0 and count >= limit: |
|
342 | 342 | return |
|
343 | 343 | count += 1 |
|
344 | 344 | if closed: |
|
345 | 345 | status = b'closed' |
|
346 | 346 | elif ctx.node() not in heads: |
|
347 | 347 | status = b'inactive' |
|
348 | 348 | else: |
|
349 | 349 | status = b'open' |
|
350 | 350 | yield { |
|
351 | 351 | b'parity': next(parity), |
|
352 | 352 | b'branch': ctx.branch(), |
|
353 | 353 | b'status': status, |
|
354 | 354 | b'node': ctx.hex(), |
|
355 | 355 | b'date': ctx.date(), |
|
356 | 356 | } |
|
357 | 357 | |
|
358 | 358 | return templateutil.mappinggenerator(entries) |
|
359 | 359 | |
|
360 | 360 | |
|
361 | 361 | def cleanpath(repo, path): |
|
362 | 362 | path = path.lstrip(b'/') |
|
363 | 363 | auditor = pathutil.pathauditor(repo.root, realfs=False) |
|
364 | 364 | return pathutil.canonpath(repo.root, b'', path, auditor=auditor) |
|
365 | 365 | |
|
366 | 366 | |
|
367 | 367 | def changectx(repo, req): |
|
368 | 368 | changeid = b"tip" |
|
369 | 369 | if b'node' in req.qsparams: |
|
370 | 370 | changeid = req.qsparams[b'node'] |
|
371 | 371 | ipos = changeid.find(b':') |
|
372 | 372 | if ipos != -1: |
|
373 | 373 | changeid = changeid[(ipos + 1) :] |
|
374 | 374 | |
|
375 | 375 | return scmutil.revsymbol(repo, changeid) |
|
376 | 376 | |
|
377 | 377 | |
|
378 | 378 | def basechangectx(repo, req): |
|
379 | 379 | if b'node' in req.qsparams: |
|
380 | 380 | changeid = req.qsparams[b'node'] |
|
381 | 381 | ipos = changeid.find(b':') |
|
382 | 382 | if ipos != -1: |
|
383 | 383 | changeid = changeid[:ipos] |
|
384 | 384 | return scmutil.revsymbol(repo, changeid) |
|
385 | 385 | |
|
386 | 386 | return None |
|
387 | 387 | |
|
388 | 388 | |
|
389 | 389 | def filectx(repo, req): |
|
390 | 390 | if b'file' not in req.qsparams: |
|
391 | 391 | raise ErrorResponse(HTTP_NOT_FOUND, b'file not given') |
|
392 | 392 | path = cleanpath(repo, req.qsparams[b'file']) |
|
393 | 393 | if b'node' in req.qsparams: |
|
394 | 394 | changeid = req.qsparams[b'node'] |
|
395 | 395 | elif b'filenode' in req.qsparams: |
|
396 | 396 | changeid = req.qsparams[b'filenode'] |
|
397 | 397 | else: |
|
398 | 398 | raise ErrorResponse(HTTP_NOT_FOUND, b'node or filenode not given') |
|
399 | 399 | try: |
|
400 | 400 | fctx = scmutil.revsymbol(repo, changeid)[path] |
|
401 | 401 | except error.RepoError: |
|
402 | 402 | fctx = repo.filectx(path, fileid=changeid) |
|
403 | 403 | |
|
404 | 404 | return fctx |
|
405 | 405 | |
|
406 | 406 | |
|
407 | 407 | def linerange(req): |
|
408 | 408 | linerange = req.qsparams.getall(b'linerange') |
|
409 | 409 | if not linerange: |
|
410 | 410 | return None |
|
411 | 411 | if len(linerange) > 1: |
|
412 | 412 | raise ErrorResponse(HTTP_BAD_REQUEST, b'redundant linerange parameter') |
|
413 | 413 | try: |
|
414 | 414 | fromline, toline = map(int, linerange[0].split(b':', 1)) |
|
415 | 415 | except ValueError: |
|
416 | 416 | raise ErrorResponse(HTTP_BAD_REQUEST, b'invalid linerange parameter') |
|
417 | 417 | try: |
|
418 | 418 | return util.processlinerange(fromline, toline) |
|
419 | 419 | except error.ParseError as exc: |
|
420 | 420 | raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc)) |
|
421 | 421 | |
|
422 | 422 | |
|
423 | 423 | def formatlinerange(fromline, toline): |
|
424 | 424 | return b'%d:%d' % (fromline + 1, toline) |
|
425 | 425 | |
|
426 | 426 | |
|
427 | 427 | def _succsandmarkersgen(context, mapping): |
|
428 | 428 | repo = context.resource(mapping, b'repo') |
|
429 | 429 | itemmappings = templatekw.showsuccsandmarkers(context, mapping) |
|
430 | 430 | for item in itemmappings.tovalue(context, mapping): |
|
431 | 431 | item[b'successors'] = _siblings( |
|
432 | 432 | repo[successor] for successor in item[b'successors'] |
|
433 | 433 | ) |
|
434 | 434 | yield item |
|
435 | 435 | |
|
436 | 436 | |
|
437 | 437 | def succsandmarkers(context, mapping): |
|
438 | 438 | return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,)) |
|
439 | 439 | |
|
440 | 440 | |
|
441 | 441 | # teach templater succsandmarkers is switched to (context, mapping) API |
|
442 | 442 | succsandmarkers._requires = {b'repo', b'ctx'} |
|
443 | 443 | |
|
444 | 444 | |
|
445 | 445 | def _whyunstablegen(context, mapping): |
|
446 | 446 | repo = context.resource(mapping, b'repo') |
|
447 | 447 | ctx = context.resource(mapping, b'ctx') |
|
448 | 448 | |
|
449 | 449 | entries = obsutil.whyunstable(repo, ctx) |
|
450 | 450 | for entry in entries: |
|
451 | 451 | if entry.get(b'divergentnodes'): |
|
452 | 452 | entry[b'divergentnodes'] = _siblings(entry[b'divergentnodes']) |
|
453 | 453 | yield entry |
|
454 | 454 | |
|
455 | 455 | |
|
456 | 456 | def whyunstable(context, mapping): |
|
457 | 457 | return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,)) |
|
458 | 458 | |
|
459 | 459 | |
|
460 | 460 | whyunstable._requires = {b'repo', b'ctx'} |
|
461 | 461 | |
|
462 | 462 | |
|
463 | 463 | def commonentry(repo, ctx): |
|
464 | 464 | node = scmutil.binnode(ctx) |
|
465 | 465 | return { |
|
466 | 466 | # TODO: perhaps ctx.changectx() should be assigned if ctx is a |
|
467 | 467 | # filectx, but I'm not pretty sure if that would always work because |
|
468 | 468 | # fctx.parents() != fctx.changectx.parents() for example. |
|
469 | 469 | b'ctx': ctx, |
|
470 | 470 | b'rev': ctx.rev(), |
|
471 | 471 | b'node': hex(node), |
|
472 | 472 | b'author': ctx.user(), |
|
473 | 473 | b'desc': ctx.description(), |
|
474 | 474 | b'date': ctx.date(), |
|
475 | 475 | b'extra': ctx.extra(), |
|
476 | 476 | b'phase': ctx.phasestr(), |
|
477 | 477 | b'obsolete': ctx.obsolete(), |
|
478 | 478 | b'succsandmarkers': succsandmarkers, |
|
479 | 479 | b'instabilities': templateutil.hybridlist( |
|
480 | 480 | ctx.instabilities(), name=b'instability' |
|
481 | 481 | ), |
|
482 | 482 | b'whyunstable': whyunstable, |
|
483 | 483 | b'branch': nodebranchnodefault(ctx), |
|
484 | 484 | b'inbranch': nodeinbranch(repo, ctx), |
|
485 | 485 | b'branches': nodebranchdict(repo, ctx), |
|
486 | 486 | b'tags': nodetagsdict(repo, node), |
|
487 | 487 | b'bookmarks': nodebookmarksdict(repo, node), |
|
488 | 488 | b'parent': lambda context, mapping: parents(ctx), |
|
489 | 489 | b'child': lambda context, mapping: children(ctx), |
|
490 | 490 | } |
|
491 | 491 | |
|
492 | 492 | |
|
493 | 493 | def changelistentry(web, ctx): |
|
494 | 494 | '''Obtain a dictionary to be used for entries in a changelist. |
|
495 | 495 | |
|
496 | 496 | This function is called when producing items for the "entries" list passed |
|
497 | 497 | to the "shortlog" and "changelog" templates. |
|
498 | 498 | ''' |
|
499 | 499 | repo = web.repo |
|
500 | 500 | rev = ctx.rev() |
|
501 | 501 | n = scmutil.binnode(ctx) |
|
502 | 502 | showtags = showtag(repo, b'changelogtag', n) |
|
503 | 503 | files = listfilediffs(ctx.files(), n, web.maxfiles) |
|
504 | 504 | |
|
505 | 505 | entry = commonentry(repo, ctx) |
|
506 | 506 | entry.update( |
|
507 | 507 | { |
|
508 | 508 | b'allparents': lambda context, mapping: parents(ctx), |
|
509 | 509 | b'parent': lambda context, mapping: parents(ctx, rev - 1), |
|
510 | 510 | b'child': lambda context, mapping: children(ctx, rev + 1), |
|
511 | 511 | b'changelogtag': showtags, |
|
512 | 512 | b'files': files, |
|
513 | 513 | } |
|
514 | 514 | ) |
|
515 | 515 | return entry |
|
516 | 516 | |
|
517 | 517 | |
|
518 | 518 | def changelistentries(web, revs, maxcount, parityfn): |
|
519 | 519 | """Emit up to N records for an iterable of revisions.""" |
|
520 | 520 | repo = web.repo |
|
521 | 521 | |
|
522 | 522 | count = 0 |
|
523 | 523 | for rev in revs: |
|
524 | 524 | if count >= maxcount: |
|
525 | 525 | break |
|
526 | 526 | |
|
527 | 527 | count += 1 |
|
528 | 528 | |
|
529 | 529 | entry = changelistentry(web, repo[rev]) |
|
530 | 530 | entry[b'parity'] = next(parityfn) |
|
531 | 531 | |
|
532 | 532 | yield entry |
|
533 | 533 | |
|
534 | 534 | |
|
535 | 535 | def symrevorshortnode(req, ctx): |
|
536 | 536 | if b'node' in req.qsparams: |
|
537 | 537 | return templatefilters.revescape(req.qsparams[b'node']) |
|
538 | 538 | else: |
|
539 | 539 | return short(scmutil.binnode(ctx)) |
|
540 | 540 | |
|
541 | 541 | |
|
542 | 542 | def _listfilesgen(context, ctx, stripecount): |
|
543 | 543 | parity = paritygen(stripecount) |
|
544 | 544 | filesadded = ctx.filesadded() |
|
545 | 545 | for blockno, f in enumerate(ctx.files()): |
|
546 | 546 | if f not in ctx: |
|
547 | 547 | status = b'removed' |
|
548 | 548 | elif f in filesadded: |
|
549 | 549 | status = b'added' |
|
550 | 550 | else: |
|
551 | 551 | status = b'modified' |
|
552 | 552 | template = b'filenolink' if status == b'removed' else b'filenodelink' |
|
553 | 553 | yield context.process( |
|
554 | 554 | template, |
|
555 | 555 | { |
|
556 | 556 | b'node': ctx.hex(), |
|
557 | 557 | b'file': f, |
|
558 | 558 | b'blockno': blockno + 1, |
|
559 | 559 | b'parity': next(parity), |
|
560 | 560 | b'status': status, |
|
561 | 561 | }, |
|
562 | 562 | ) |
|
563 | 563 | |
|
564 | 564 | |
|
565 | 565 | def changesetentry(web, ctx): |
|
566 | 566 | '''Obtain a dictionary to be used to render the "changeset" template.''' |
|
567 | 567 | |
|
568 | 568 | showtags = showtag(web.repo, b'changesettag', scmutil.binnode(ctx)) |
|
569 | 569 | showbookmarks = showbookmark( |
|
570 | 570 | web.repo, b'changesetbookmark', scmutil.binnode(ctx) |
|
571 | 571 | ) |
|
572 | 572 | showbranch = nodebranchnodefault(ctx) |
|
573 | 573 | |
|
574 | 574 | basectx = basechangectx(web.repo, web.req) |
|
575 | 575 | if basectx is None: |
|
576 | 576 | basectx = ctx.p1() |
|
577 | 577 | |
|
578 | 578 | style = web.config(b'web', b'style') |
|
579 | 579 | if b'style' in web.req.qsparams: |
|
580 | 580 | style = web.req.qsparams[b'style'] |
|
581 | 581 | |
|
582 | 582 | diff = diffs(web, ctx, basectx, None, style) |
|
583 | 583 | |
|
584 | 584 | parity = paritygen(web.stripecount) |
|
585 | 585 | diffstatsgen = diffstatgen(web.repo.ui, ctx, basectx) |
|
586 | 586 | diffstats = diffstat(ctx, diffstatsgen, parity) |
|
587 | 587 | |
|
588 | 588 | return dict( |
|
589 | 589 | diff=diff, |
|
590 | 590 | symrev=symrevorshortnode(web.req, ctx), |
|
591 | 591 | basenode=basectx.hex(), |
|
592 | 592 | changesettag=showtags, |
|
593 | 593 | changesetbookmark=showbookmarks, |
|
594 | 594 | changesetbranch=showbranch, |
|
595 | 595 | files=templateutil.mappedgenerator( |
|
596 | 596 | _listfilesgen, args=(ctx, web.stripecount) |
|
597 | 597 | ), |
|
598 | 598 | diffsummary=lambda context, mapping: diffsummary(diffstatsgen), |
|
599 | 599 | diffstat=diffstats, |
|
600 | 600 | archives=web.archivelist(ctx.hex()), |
|
601 | 601 | **pycompat.strkwargs(commonentry(web.repo, ctx)) |
|
602 | 602 | ) |
|
603 | 603 | |
|
604 | 604 | |
|
605 | 605 | def _listfilediffsgen(context, files, node, max): |
|
606 | 606 | for f in files[:max]: |
|
607 | 607 | yield context.process(b'filedifflink', {b'node': hex(node), b'file': f}) |
|
608 | 608 | if len(files) > max: |
|
609 | 609 | yield context.process(b'fileellipses', {}) |
|
610 | 610 | |
|
611 | 611 | |
|
612 | 612 | def listfilediffs(files, node, max): |
|
613 | 613 | return templateutil.mappedgenerator( |
|
614 | 614 | _listfilediffsgen, args=(files, node, max) |
|
615 | 615 | ) |
|
616 | 616 | |
|
617 | 617 | |
|
618 | 618 | def _prettyprintdifflines(context, lines, blockno, lineidprefix): |
|
619 | 619 | for lineno, l in enumerate(lines, 1): |
|
620 | 620 | difflineno = b"%d.%d" % (blockno, lineno) |
|
621 | 621 | if l.startswith(b'+'): |
|
622 | 622 | ltype = b"difflineplus" |
|
623 | 623 | elif l.startswith(b'-'): |
|
624 | 624 | ltype = b"difflineminus" |
|
625 | 625 | elif l.startswith(b'@'): |
|
626 | 626 | ltype = b"difflineat" |
|
627 | 627 | else: |
|
628 | 628 | ltype = b"diffline" |
|
629 | 629 | yield context.process( |
|
630 | 630 | ltype, |
|
631 | 631 | { |
|
632 | 632 | b'line': l, |
|
633 | 633 | b'lineno': lineno, |
|
634 | 634 | b'lineid': lineidprefix + b"l%s" % difflineno, |
|
635 | 635 | b'linenumber': b"% 8s" % difflineno, |
|
636 | 636 | }, |
|
637 | 637 | ) |
|
638 | 638 | |
|
639 | 639 | |
|
640 | 640 | def _diffsgen( |
|
641 | 641 | context, |
|
642 | 642 | repo, |
|
643 | 643 | ctx, |
|
644 | 644 | basectx, |
|
645 | 645 | files, |
|
646 | 646 | style, |
|
647 | 647 | stripecount, |
|
648 | 648 | linerange, |
|
649 | 649 | lineidprefix, |
|
650 | 650 | ): |
|
651 | 651 | if files: |
|
652 | 652 | m = match.exact(files) |
|
653 | 653 | else: |
|
654 | 654 | m = match.always() |
|
655 | 655 | |
|
656 | 656 | diffopts = patch.diffopts(repo.ui, untrusted=True) |
|
657 | 657 | parity = paritygen(stripecount) |
|
658 | 658 | |
|
659 | 659 | diffhunks = patch.diffhunks(repo, basectx, ctx, m, opts=diffopts) |
|
660 | 660 | for blockno, (fctx1, fctx2, header, hunks) in enumerate(diffhunks, 1): |
|
661 | 661 | if style != b'raw': |
|
662 | 662 | header = header[1:] |
|
663 | 663 | lines = [h + b'\n' for h in header] |
|
664 | 664 | for hunkrange, hunklines in hunks: |
|
665 | 665 | if linerange is not None and hunkrange is not None: |
|
666 | 666 | s1, l1, s2, l2 = hunkrange |
|
667 | 667 | if not mdiff.hunkinrange((s2, l2), linerange): |
|
668 | 668 | continue |
|
669 | 669 | lines.extend(hunklines) |
|
670 | 670 | if lines: |
|
671 | 671 | l = templateutil.mappedgenerator( |
|
672 | 672 | _prettyprintdifflines, args=(lines, blockno, lineidprefix) |
|
673 | 673 | ) |
|
674 | 674 | yield { |
|
675 | 675 | b'parity': next(parity), |
|
676 | 676 | b'blockno': blockno, |
|
677 | 677 | b'lines': l, |
|
678 | 678 | } |
|
679 | 679 | |
|
680 | 680 | |
|
681 | 681 | def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=b''): |
|
682 | 682 | args = ( |
|
683 | 683 | web.repo, |
|
684 | 684 | ctx, |
|
685 | 685 | basectx, |
|
686 | 686 | files, |
|
687 | 687 | style, |
|
688 | 688 | web.stripecount, |
|
689 | 689 | linerange, |
|
690 | 690 | lineidprefix, |
|
691 | 691 | ) |
|
692 | 692 | return templateutil.mappinggenerator( |
|
693 | 693 | _diffsgen, args=args, name=b'diffblock' |
|
694 | 694 | ) |
|
695 | 695 | |
|
696 | 696 | |
|
697 | 697 | def _compline(type, leftlineno, leftline, rightlineno, rightline): |
|
698 | 698 | lineid = leftlineno and (b"l%d" % leftlineno) or b'' |
|
699 | 699 | lineid += rightlineno and (b"r%d" % rightlineno) or b'' |
|
700 | 700 | llno = b'%d' % leftlineno if leftlineno else b'' |
|
701 | 701 | rlno = b'%d' % rightlineno if rightlineno else b'' |
|
702 | 702 | return { |
|
703 | 703 | b'type': type, |
|
704 | 704 | b'lineid': lineid, |
|
705 | 705 | b'leftlineno': leftlineno, |
|
706 | 706 | b'leftlinenumber': b"% 6s" % llno, |
|
707 | 707 | b'leftline': leftline or b'', |
|
708 | 708 | b'rightlineno': rightlineno, |
|
709 | 709 | b'rightlinenumber': b"% 6s" % rlno, |
|
710 | 710 | b'rightline': rightline or b'', |
|
711 | 711 | } |
|
712 | 712 | |
|
713 | 713 | |
|
714 | 714 | def _getcompblockgen(context, leftlines, rightlines, opcodes): |
|
715 | 715 | for type, llo, lhi, rlo, rhi in opcodes: |
|
716 | 716 | type = pycompat.sysbytes(type) |
|
717 | 717 | len1 = lhi - llo |
|
718 | 718 | len2 = rhi - rlo |
|
719 | 719 | count = min(len1, len2) |
|
720 | 720 | for i in pycompat.xrange(count): |
|
721 | 721 | yield _compline( |
|
722 | 722 | type=type, |
|
723 | 723 | leftlineno=llo + i + 1, |
|
724 | 724 | leftline=leftlines[llo + i], |
|
725 | 725 | rightlineno=rlo + i + 1, |
|
726 | 726 | rightline=rightlines[rlo + i], |
|
727 | 727 | ) |
|
728 | 728 | if len1 > len2: |
|
729 | 729 | for i in pycompat.xrange(llo + count, lhi): |
|
730 | 730 | yield _compline( |
|
731 | 731 | type=type, |
|
732 | 732 | leftlineno=i + 1, |
|
733 | 733 | leftline=leftlines[i], |
|
734 | 734 | rightlineno=None, |
|
735 | 735 | rightline=None, |
|
736 | 736 | ) |
|
737 | 737 | elif len2 > len1: |
|
738 | 738 | for i in pycompat.xrange(rlo + count, rhi): |
|
739 | 739 | yield _compline( |
|
740 | 740 | type=type, |
|
741 | 741 | leftlineno=None, |
|
742 | 742 | leftline=None, |
|
743 | 743 | rightlineno=i + 1, |
|
744 | 744 | rightline=rightlines[i], |
|
745 | 745 | ) |
|
746 | 746 | |
|
747 | 747 | |
|
748 | 748 | def _getcompblock(leftlines, rightlines, opcodes): |
|
749 | 749 | args = (leftlines, rightlines, opcodes) |
|
750 | 750 | return templateutil.mappinggenerator( |
|
751 | 751 | _getcompblockgen, args=args, name=b'comparisonline' |
|
752 | 752 | ) |
|
753 | 753 | |
|
754 | 754 | |
|
755 | 755 | def _comparegen(context, contextnum, leftlines, rightlines): |
|
756 | 756 | '''Generator function that provides side-by-side comparison data.''' |
|
757 | 757 | s = difflib.SequenceMatcher(None, leftlines, rightlines) |
|
758 | 758 | if contextnum < 0: |
|
759 | 759 | l = _getcompblock(leftlines, rightlines, s.get_opcodes()) |
|
760 | 760 | yield {b'lines': l} |
|
761 | 761 | else: |
|
762 | 762 | for oc in s.get_grouped_opcodes(n=contextnum): |
|
763 | 763 | l = _getcompblock(leftlines, rightlines, oc) |
|
764 | 764 | yield {b'lines': l} |
|
765 | 765 | |
|
766 | 766 | |
|
767 | 767 | def compare(contextnum, leftlines, rightlines): |
|
768 | 768 | args = (contextnum, leftlines, rightlines) |
|
769 | 769 | return templateutil.mappinggenerator( |
|
770 | 770 | _comparegen, args=args, name=b'comparisonblock' |
|
771 | 771 | ) |
|
772 | 772 | |
|
773 | 773 | |
|
774 | 774 | def diffstatgen(ui, ctx, basectx): |
|
775 | 775 | '''Generator function that provides the diffstat data.''' |
|
776 | 776 | |
|
777 | 777 | diffopts = patch.diffopts(ui, {b'noprefix': False}) |
|
778 | 778 | stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx, opts=diffopts))) |
|
779 | 779 | maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats) |
|
780 | 780 | while True: |
|
781 | 781 | yield stats, maxname, maxtotal, addtotal, removetotal, binary |
|
782 | 782 | |
|
783 | 783 | |
|
784 | 784 | def diffsummary(statgen): |
|
785 | 785 | '''Return a short summary of the diff.''' |
|
786 | 786 | |
|
787 | 787 | stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen) |
|
788 | 788 | return _(b' %d files changed, %d insertions(+), %d deletions(-)\n') % ( |
|
789 | 789 | len(stats), |
|
790 | 790 | addtotal, |
|
791 | 791 | removetotal, |
|
792 | 792 | ) |
|
793 | 793 | |
|
794 | 794 | |
|
795 | 795 | def _diffstattmplgen(context, ctx, statgen, parity): |
|
796 | 796 | stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen) |
|
797 | 797 | files = ctx.files() |
|
798 | 798 | |
|
799 | 799 | def pct(i): |
|
800 | 800 | if maxtotal == 0: |
|
801 | 801 | return 0 |
|
802 | 802 | return (float(i) / maxtotal) * 100 |
|
803 | 803 | |
|
804 | 804 | fileno = 0 |
|
805 | 805 | for filename, adds, removes, isbinary in stats: |
|
806 | 806 | template = b'diffstatlink' if filename in files else b'diffstatnolink' |
|
807 | 807 | total = adds + removes |
|
808 | 808 | fileno += 1 |
|
809 | 809 | yield context.process( |
|
810 | 810 | template, |
|
811 | 811 | { |
|
812 | 812 | b'node': ctx.hex(), |
|
813 | 813 | b'file': filename, |
|
814 | 814 | b'fileno': fileno, |
|
815 | 815 | b'total': total, |
|
816 | 816 | b'addpct': pct(adds), |
|
817 | 817 | b'removepct': pct(removes), |
|
818 | 818 | b'parity': next(parity), |
|
819 | 819 | }, |
|
820 | 820 | ) |
|
821 | 821 | |
|
822 | 822 | |
|
823 | 823 | def diffstat(ctx, statgen, parity): |
|
824 | 824 | '''Return a diffstat template for each file in the diff.''' |
|
825 | 825 | args = (ctx, statgen, parity) |
|
826 | 826 | return templateutil.mappedgenerator(_diffstattmplgen, args=args) |
|
827 | 827 | |
|
828 | 828 | |
|
829 | 829 | class sessionvars(templateutil.wrapped): |
|
830 | 830 | def __init__(self, vars, start=b'?'): |
|
831 | 831 | self._start = start |
|
832 | 832 | self._vars = vars |
|
833 | 833 | |
|
834 | 834 | def __getitem__(self, key): |
|
835 | 835 | return self._vars[key] |
|
836 | 836 | |
|
837 | 837 | def __setitem__(self, key, value): |
|
838 | 838 | self._vars[key] = value |
|
839 | 839 | |
|
840 | 840 | def __copy__(self): |
|
841 | 841 | return sessionvars(copy.copy(self._vars), self._start) |
|
842 | 842 | |
|
843 | 843 | def contains(self, context, mapping, item): |
|
844 | 844 | item = templateutil.unwrapvalue(context, mapping, item) |
|
845 | 845 | return item in self._vars |
|
846 | 846 | |
|
847 | 847 | def getmember(self, context, mapping, key): |
|
848 | 848 | key = templateutil.unwrapvalue(context, mapping, key) |
|
849 | 849 | return self._vars.get(key) |
|
850 | 850 | |
|
851 | 851 | def getmin(self, context, mapping): |
|
852 | 852 | raise error.ParseError(_(b'not comparable')) |
|
853 | 853 | |
|
854 | 854 | def getmax(self, context, mapping): |
|
855 | 855 | raise error.ParseError(_(b'not comparable')) |
|
856 | 856 | |
|
857 | 857 | def filter(self, context, mapping, select): |
|
858 | 858 | # implement if necessary |
|
859 | 859 | raise error.ParseError(_(b'not filterable')) |
|
860 | 860 | |
|
861 | 861 | def itermaps(self, context): |
|
862 | 862 | separator = self._start |
|
863 | 863 | for key, value in sorted(pycompat.iteritems(self._vars)): |
|
864 | 864 | yield { |
|
865 | 865 | b'name': key, |
|
866 | 866 | b'value': pycompat.bytestr(value), |
|
867 | 867 | b'separator': separator, |
|
868 | 868 | } |
|
869 | 869 | separator = b'&' |
|
870 | 870 | |
|
871 | 871 | def join(self, context, mapping, sep): |
|
872 | 872 | # could be '{separator}{name}={value|urlescape}' |
|
873 | 873 | raise error.ParseError(_(b'not displayable without template')) |
|
874 | 874 | |
|
875 | 875 | def show(self, context, mapping): |
|
876 | 876 | return self.join(context, mapping, b'') |
|
877 | 877 | |
|
878 | 878 | def tobool(self, context, mapping): |
|
879 | 879 | return bool(self._vars) |
|
880 | 880 | |
|
881 | 881 | def tovalue(self, context, mapping): |
|
882 | 882 | return self._vars |
|
883 | 883 | |
|
884 | 884 | |
|
885 | 885 | class wsgiui(uimod.ui): |
|
886 | 886 | # default termwidth breaks under mod_wsgi |
|
887 | 887 | def termwidth(self): |
|
888 | 888 | return 80 |
|
889 | 889 | |
|
890 | 890 | |
|
891 | 891 | def getwebsubs(repo): |
|
892 | 892 | websubtable = [] |
|
893 | 893 | websubdefs = repo.ui.configitems(b'websub') |
|
894 | 894 | # we must maintain interhg backwards compatibility |
|
895 | 895 | websubdefs += repo.ui.configitems(b'interhg') |
|
896 | 896 | for key, pattern in websubdefs: |
|
897 | 897 | # grab the delimiter from the character after the "s" |
|
898 | 898 | unesc = pattern[1:2] |
|
899 | 899 | delim = stringutil.reescape(unesc) |
|
900 | 900 | |
|
901 | 901 | # identify portions of the pattern, taking care to avoid escaped |
|
902 | 902 | # delimiters. the replace format and flags are optional, but |
|
903 | 903 | # delimiters are required. |
|
904 | 904 | match = re.match( |
|
905 | 905 | br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$' |
|
906 | 906 | % (delim, delim, delim), |
|
907 | 907 | pattern, |
|
908 | 908 | ) |
|
909 | 909 | if not match: |
|
910 | 910 | repo.ui.warn( |
|
911 | 911 | _(b"websub: invalid pattern for %s: %s\n") % (key, pattern) |
|
912 | 912 | ) |
|
913 | 913 | continue |
|
914 | 914 | |
|
915 | 915 | # we need to unescape the delimiter for regexp and format |
|
916 | 916 | delim_re = re.compile(br'(?<!\\)\\%s' % delim) |
|
917 | 917 | regexp = delim_re.sub(unesc, match.group(1)) |
|
918 | 918 | format = delim_re.sub(unesc, match.group(2)) |
|
919 | 919 | |
|
920 | 920 | # the pattern allows for 6 regexp flags, so set them if necessary |
|
921 | 921 | flagin = match.group(3) |
|
922 | 922 | flags = 0 |
|
923 | 923 | if flagin: |
|
924 | 924 | for flag in pycompat.sysstr(flagin.upper()): |
|
925 | 925 | flags |= re.__dict__[flag] |
|
926 | 926 | |
|
927 | 927 | try: |
|
928 | 928 | regexp = re.compile(regexp, flags) |
|
929 | 929 | websubtable.append((regexp, format)) |
|
930 | 930 | except re.error: |
|
931 | 931 | repo.ui.warn( |
|
932 | 932 | _(b"websub: invalid regexp for %s: %s\n") % (key, regexp) |
|
933 | 933 | ) |
|
934 | 934 | return websubtable |
|
935 | 935 | |
|
936 | 936 | |
|
937 | 937 | def getgraphnode(repo, ctx): |
|
938 | 938 | return templatekw.getgraphnodecurrent( |
|
939 | repo, ctx | |
|
939 | repo, ctx, {} | |
|
940 | 940 | ) + templatekw.getgraphnodesymbol(ctx) |
@@ -1,1088 +1,1089 b'' | |||
|
1 | 1 | # logcmdutil.py - utility for log-like commands |
|
2 | 2 | # |
|
3 | 3 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
|
4 | 4 | # |
|
5 | 5 | # This software may be used and distributed according to the terms of the |
|
6 | 6 | # GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | from __future__ import absolute_import |
|
9 | 9 | |
|
10 | 10 | import itertools |
|
11 | 11 | import os |
|
12 | 12 | import posixpath |
|
13 | 13 | |
|
14 | 14 | from .i18n import _ |
|
15 | 15 | from .node import ( |
|
16 | 16 | nullid, |
|
17 | 17 | wdirid, |
|
18 | 18 | wdirrev, |
|
19 | 19 | ) |
|
20 | 20 | |
|
21 | 21 | from . import ( |
|
22 | 22 | dagop, |
|
23 | 23 | error, |
|
24 | 24 | formatter, |
|
25 | 25 | graphmod, |
|
26 | 26 | match as matchmod, |
|
27 | 27 | mdiff, |
|
28 | 28 | patch, |
|
29 | 29 | pathutil, |
|
30 | 30 | pycompat, |
|
31 | 31 | revset, |
|
32 | 32 | revsetlang, |
|
33 | 33 | scmutil, |
|
34 | 34 | smartset, |
|
35 | 35 | templatekw, |
|
36 | 36 | templater, |
|
37 | 37 | util, |
|
38 | 38 | ) |
|
39 | 39 | from .utils import ( |
|
40 | 40 | dateutil, |
|
41 | 41 | stringutil, |
|
42 | 42 | ) |
|
43 | 43 | |
|
44 | 44 | |
|
45 | 45 | if pycompat.TYPE_CHECKING: |
|
46 | 46 | from typing import ( |
|
47 | 47 | Any, |
|
48 | 48 | Optional, |
|
49 | 49 | Tuple, |
|
50 | 50 | ) |
|
51 | 51 | |
|
52 | 52 | for t in (Any, Optional, Tuple): |
|
53 | 53 | assert t |
|
54 | 54 | |
|
55 | 55 | |
|
56 | 56 | def getlimit(opts): |
|
57 | 57 | """get the log limit according to option -l/--limit""" |
|
58 | 58 | limit = opts.get(b'limit') |
|
59 | 59 | if limit: |
|
60 | 60 | try: |
|
61 | 61 | limit = int(limit) |
|
62 | 62 | except ValueError: |
|
63 | 63 | raise error.Abort(_(b'limit must be a positive integer')) |
|
64 | 64 | if limit <= 0: |
|
65 | 65 | raise error.Abort(_(b'limit must be positive')) |
|
66 | 66 | else: |
|
67 | 67 | limit = None |
|
68 | 68 | return limit |
|
69 | 69 | |
|
70 | 70 | |
|
71 | 71 | def diffordiffstat( |
|
72 | 72 | ui, |
|
73 | 73 | repo, |
|
74 | 74 | diffopts, |
|
75 | 75 | node1, |
|
76 | 76 | node2, |
|
77 | 77 | match, |
|
78 | 78 | changes=None, |
|
79 | 79 | stat=False, |
|
80 | 80 | fp=None, |
|
81 | 81 | graphwidth=0, |
|
82 | 82 | prefix=b'', |
|
83 | 83 | root=b'', |
|
84 | 84 | listsubrepos=False, |
|
85 | 85 | hunksfilterfn=None, |
|
86 | 86 | ): |
|
87 | 87 | '''show diff or diffstat.''' |
|
88 | 88 | ctx1 = repo[node1] |
|
89 | 89 | ctx2 = repo[node2] |
|
90 | 90 | if root: |
|
91 | 91 | relroot = pathutil.canonpath(repo.root, repo.getcwd(), root) |
|
92 | 92 | else: |
|
93 | 93 | relroot = b'' |
|
94 | 94 | copysourcematch = None |
|
95 | 95 | |
|
96 | 96 | def compose(f, g): |
|
97 | 97 | return lambda x: f(g(x)) |
|
98 | 98 | |
|
99 | 99 | def pathfn(f): |
|
100 | 100 | return posixpath.join(prefix, f) |
|
101 | 101 | |
|
102 | 102 | if relroot != b'': |
|
103 | 103 | # XXX relative roots currently don't work if the root is within a |
|
104 | 104 | # subrepo |
|
105 | 105 | uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) |
|
106 | 106 | uirelroot = uipathfn(pathfn(relroot)) |
|
107 | 107 | relroot += b'/' |
|
108 | 108 | for matchroot in match.files(): |
|
109 | 109 | if not matchroot.startswith(relroot): |
|
110 | 110 | ui.warn( |
|
111 | 111 | _(b'warning: %s not inside relative root %s\n') |
|
112 | 112 | % (uipathfn(pathfn(matchroot)), uirelroot) |
|
113 | 113 | ) |
|
114 | 114 | |
|
115 | 115 | relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path') |
|
116 | 116 | match = matchmod.intersectmatchers(match, relrootmatch) |
|
117 | 117 | copysourcematch = relrootmatch |
|
118 | 118 | |
|
119 | 119 | checkroot = repo.ui.configbool( |
|
120 | 120 | b'devel', b'all-warnings' |
|
121 | 121 | ) or repo.ui.configbool(b'devel', b'check-relroot') |
|
122 | 122 | |
|
123 | 123 | def relrootpathfn(f): |
|
124 | 124 | if checkroot and not f.startswith(relroot): |
|
125 | 125 | raise AssertionError( |
|
126 | 126 | b"file %s doesn't start with relroot %s" % (f, relroot) |
|
127 | 127 | ) |
|
128 | 128 | return f[len(relroot) :] |
|
129 | 129 | |
|
130 | 130 | pathfn = compose(relrootpathfn, pathfn) |
|
131 | 131 | |
|
132 | 132 | if stat: |
|
133 | 133 | diffopts = diffopts.copy(context=0, noprefix=False) |
|
134 | 134 | width = 80 |
|
135 | 135 | if not ui.plain(): |
|
136 | 136 | width = ui.termwidth() - graphwidth |
|
137 | 137 | # If an explicit --root was given, don't respect ui.relative-paths |
|
138 | 138 | if not relroot: |
|
139 | 139 | pathfn = compose(scmutil.getuipathfn(repo), pathfn) |
|
140 | 140 | |
|
141 | 141 | chunks = ctx2.diff( |
|
142 | 142 | ctx1, |
|
143 | 143 | match, |
|
144 | 144 | changes, |
|
145 | 145 | opts=diffopts, |
|
146 | 146 | pathfn=pathfn, |
|
147 | 147 | copysourcematch=copysourcematch, |
|
148 | 148 | hunksfilterfn=hunksfilterfn, |
|
149 | 149 | ) |
|
150 | 150 | |
|
151 | 151 | if fp is not None or ui.canwritewithoutlabels(): |
|
152 | 152 | out = fp or ui |
|
153 | 153 | if stat: |
|
154 | 154 | chunks = [patch.diffstat(util.iterlines(chunks), width=width)] |
|
155 | 155 | for chunk in util.filechunkiter(util.chunkbuffer(chunks)): |
|
156 | 156 | out.write(chunk) |
|
157 | 157 | else: |
|
158 | 158 | if stat: |
|
159 | 159 | chunks = patch.diffstatui(util.iterlines(chunks), width=width) |
|
160 | 160 | else: |
|
161 | 161 | chunks = patch.difflabel( |
|
162 | 162 | lambda chunks, **kwargs: chunks, chunks, opts=diffopts |
|
163 | 163 | ) |
|
164 | 164 | if ui.canbatchlabeledwrites(): |
|
165 | 165 | |
|
166 | 166 | def gen(): |
|
167 | 167 | for chunk, label in chunks: |
|
168 | 168 | yield ui.label(chunk, label=label) |
|
169 | 169 | |
|
170 | 170 | for chunk in util.filechunkiter(util.chunkbuffer(gen())): |
|
171 | 171 | ui.write(chunk) |
|
172 | 172 | else: |
|
173 | 173 | for chunk, label in chunks: |
|
174 | 174 | ui.write(chunk, label=label) |
|
175 | 175 | |
|
176 | 176 | for subpath, sub in scmutil.itersubrepos(ctx1, ctx2): |
|
177 | 177 | tempnode2 = node2 |
|
178 | 178 | try: |
|
179 | 179 | if node2 is not None: |
|
180 | 180 | tempnode2 = ctx2.substate[subpath][1] |
|
181 | 181 | except KeyError: |
|
182 | 182 | # A subrepo that existed in node1 was deleted between node1 and |
|
183 | 183 | # node2 (inclusive). Thus, ctx2's substate won't contain that |
|
184 | 184 | # subpath. The best we can do is to ignore it. |
|
185 | 185 | tempnode2 = None |
|
186 | 186 | submatch = matchmod.subdirmatcher(subpath, match) |
|
187 | 187 | subprefix = repo.wvfs.reljoin(prefix, subpath) |
|
188 | 188 | if listsubrepos or match.exact(subpath) or any(submatch.files()): |
|
189 | 189 | sub.diff( |
|
190 | 190 | ui, |
|
191 | 191 | diffopts, |
|
192 | 192 | tempnode2, |
|
193 | 193 | submatch, |
|
194 | 194 | changes=changes, |
|
195 | 195 | stat=stat, |
|
196 | 196 | fp=fp, |
|
197 | 197 | prefix=subprefix, |
|
198 | 198 | ) |
|
199 | 199 | |
|
200 | 200 | |
|
201 | 201 | class changesetdiffer(object): |
|
202 | 202 | """Generate diff of changeset with pre-configured filtering functions""" |
|
203 | 203 | |
|
204 | 204 | def _makefilematcher(self, ctx): |
|
205 | 205 | return scmutil.matchall(ctx.repo()) |
|
206 | 206 | |
|
207 | 207 | def _makehunksfilter(self, ctx): |
|
208 | 208 | return None |
|
209 | 209 | |
|
210 | 210 | def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False): |
|
211 | 211 | repo = ctx.repo() |
|
212 | 212 | node = ctx.node() |
|
213 | 213 | prev = ctx.p1().node() |
|
214 | 214 | diffordiffstat( |
|
215 | 215 | ui, |
|
216 | 216 | repo, |
|
217 | 217 | diffopts, |
|
218 | 218 | prev, |
|
219 | 219 | node, |
|
220 | 220 | match=self._makefilematcher(ctx), |
|
221 | 221 | stat=stat, |
|
222 | 222 | graphwidth=graphwidth, |
|
223 | 223 | hunksfilterfn=self._makehunksfilter(ctx), |
|
224 | 224 | ) |
|
225 | 225 | |
|
226 | 226 | |
|
227 | 227 | def changesetlabels(ctx): |
|
228 | 228 | labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()] |
|
229 | 229 | if ctx.obsolete(): |
|
230 | 230 | labels.append(b'changeset.obsolete') |
|
231 | 231 | if ctx.isunstable(): |
|
232 | 232 | labels.append(b'changeset.unstable') |
|
233 | 233 | for instability in ctx.instabilities(): |
|
234 | 234 | labels.append(b'instability.%s' % instability) |
|
235 | 235 | return b' '.join(labels) |
|
236 | 236 | |
|
237 | 237 | |
|
238 | 238 | class changesetprinter(object): |
|
239 | 239 | '''show changeset information when templating not requested.''' |
|
240 | 240 | |
|
241 | 241 | def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False): |
|
242 | 242 | self.ui = ui |
|
243 | 243 | self.repo = repo |
|
244 | 244 | self.buffered = buffered |
|
245 | 245 | self._differ = differ or changesetdiffer() |
|
246 | 246 | self._diffopts = patch.diffallopts(ui, diffopts) |
|
247 | 247 | self._includestat = diffopts and diffopts.get(b'stat') |
|
248 | 248 | self._includediff = diffopts and diffopts.get(b'patch') |
|
249 | 249 | self.header = {} |
|
250 | 250 | self.hunk = {} |
|
251 | 251 | self.lastheader = None |
|
252 | 252 | self.footer = None |
|
253 | 253 | self._columns = templatekw.getlogcolumns() |
|
254 | 254 | |
|
255 | 255 | def flush(self, ctx): |
|
256 | 256 | rev = ctx.rev() |
|
257 | 257 | if rev in self.header: |
|
258 | 258 | h = self.header[rev] |
|
259 | 259 | if h != self.lastheader: |
|
260 | 260 | self.lastheader = h |
|
261 | 261 | self.ui.write(h) |
|
262 | 262 | del self.header[rev] |
|
263 | 263 | if rev in self.hunk: |
|
264 | 264 | self.ui.write(self.hunk[rev]) |
|
265 | 265 | del self.hunk[rev] |
|
266 | 266 | |
|
267 | 267 | def close(self): |
|
268 | 268 | if self.footer: |
|
269 | 269 | self.ui.write(self.footer) |
|
270 | 270 | |
|
271 | 271 | def show(self, ctx, copies=None, **props): |
|
272 | 272 | props = pycompat.byteskwargs(props) |
|
273 | 273 | if self.buffered: |
|
274 | 274 | self.ui.pushbuffer(labeled=True) |
|
275 | 275 | self._show(ctx, copies, props) |
|
276 | 276 | self.hunk[ctx.rev()] = self.ui.popbuffer() |
|
277 | 277 | else: |
|
278 | 278 | self._show(ctx, copies, props) |
|
279 | 279 | |
|
280 | 280 | def _show(self, ctx, copies, props): |
|
281 | 281 | '''show a single changeset or file revision''' |
|
282 | 282 | changenode = ctx.node() |
|
283 | 283 | graphwidth = props.get(b'graphwidth', 0) |
|
284 | 284 | |
|
285 | 285 | if self.ui.quiet: |
|
286 | 286 | self.ui.write( |
|
287 | 287 | b"%s\n" % scmutil.formatchangeid(ctx), label=b'log.node' |
|
288 | 288 | ) |
|
289 | 289 | return |
|
290 | 290 | |
|
291 | 291 | columns = self._columns |
|
292 | 292 | self.ui.write( |
|
293 | 293 | columns[b'changeset'] % scmutil.formatchangeid(ctx), |
|
294 | 294 | label=changesetlabels(ctx), |
|
295 | 295 | ) |
|
296 | 296 | |
|
297 | 297 | # branches are shown first before any other names due to backwards |
|
298 | 298 | # compatibility |
|
299 | 299 | branch = ctx.branch() |
|
300 | 300 | # don't show the default branch name |
|
301 | 301 | if branch != b'default': |
|
302 | 302 | self.ui.write(columns[b'branch'] % branch, label=b'log.branch') |
|
303 | 303 | |
|
304 | 304 | for nsname, ns in pycompat.iteritems(self.repo.names): |
|
305 | 305 | # branches has special logic already handled above, so here we just |
|
306 | 306 | # skip it |
|
307 | 307 | if nsname == b'branches': |
|
308 | 308 | continue |
|
309 | 309 | # we will use the templatename as the color name since those two |
|
310 | 310 | # should be the same |
|
311 | 311 | for name in ns.names(self.repo, changenode): |
|
312 | 312 | self.ui.write(ns.logfmt % name, label=b'log.%s' % ns.colorname) |
|
313 | 313 | if self.ui.debugflag: |
|
314 | 314 | self.ui.write( |
|
315 | 315 | columns[b'phase'] % ctx.phasestr(), label=b'log.phase' |
|
316 | 316 | ) |
|
317 | 317 | for pctx in scmutil.meaningfulparents(self.repo, ctx): |
|
318 | 318 | label = b'log.parent changeset.%s' % pctx.phasestr() |
|
319 | 319 | self.ui.write( |
|
320 | 320 | columns[b'parent'] % scmutil.formatchangeid(pctx), label=label |
|
321 | 321 | ) |
|
322 | 322 | |
|
323 | 323 | if self.ui.debugflag: |
|
324 | 324 | mnode = ctx.manifestnode() |
|
325 | 325 | if mnode is None: |
|
326 | 326 | mnode = wdirid |
|
327 | 327 | mrev = wdirrev |
|
328 | 328 | else: |
|
329 | 329 | mrev = self.repo.manifestlog.rev(mnode) |
|
330 | 330 | self.ui.write( |
|
331 | 331 | columns[b'manifest'] |
|
332 | 332 | % scmutil.formatrevnode(self.ui, mrev, mnode), |
|
333 | 333 | label=b'ui.debug log.manifest', |
|
334 | 334 | ) |
|
335 | 335 | self.ui.write(columns[b'user'] % ctx.user(), label=b'log.user') |
|
336 | 336 | self.ui.write( |
|
337 | 337 | columns[b'date'] % dateutil.datestr(ctx.date()), label=b'log.date' |
|
338 | 338 | ) |
|
339 | 339 | |
|
340 | 340 | if ctx.isunstable(): |
|
341 | 341 | instabilities = ctx.instabilities() |
|
342 | 342 | self.ui.write( |
|
343 | 343 | columns[b'instability'] % b', '.join(instabilities), |
|
344 | 344 | label=b'log.instability', |
|
345 | 345 | ) |
|
346 | 346 | |
|
347 | 347 | elif ctx.obsolete(): |
|
348 | 348 | self._showobsfate(ctx) |
|
349 | 349 | |
|
350 | 350 | self._exthook(ctx) |
|
351 | 351 | |
|
352 | 352 | if self.ui.debugflag: |
|
353 | 353 | files = ctx.p1().status(ctx) |
|
354 | 354 | for key, value in zip( |
|
355 | 355 | [b'files', b'files+', b'files-'], |
|
356 | 356 | [files.modified, files.added, files.removed], |
|
357 | 357 | ): |
|
358 | 358 | if value: |
|
359 | 359 | self.ui.write( |
|
360 | 360 | columns[key] % b" ".join(value), |
|
361 | 361 | label=b'ui.debug log.files', |
|
362 | 362 | ) |
|
363 | 363 | elif ctx.files() and self.ui.verbose: |
|
364 | 364 | self.ui.write( |
|
365 | 365 | columns[b'files'] % b" ".join(ctx.files()), |
|
366 | 366 | label=b'ui.note log.files', |
|
367 | 367 | ) |
|
368 | 368 | if copies and self.ui.verbose: |
|
369 | 369 | copies = [b'%s (%s)' % c for c in copies] |
|
370 | 370 | self.ui.write( |
|
371 | 371 | columns[b'copies'] % b' '.join(copies), |
|
372 | 372 | label=b'ui.note log.copies', |
|
373 | 373 | ) |
|
374 | 374 | |
|
375 | 375 | extra = ctx.extra() |
|
376 | 376 | if extra and self.ui.debugflag: |
|
377 | 377 | for key, value in sorted(extra.items()): |
|
378 | 378 | self.ui.write( |
|
379 | 379 | columns[b'extra'] % (key, stringutil.escapestr(value)), |
|
380 | 380 | label=b'ui.debug log.extra', |
|
381 | 381 | ) |
|
382 | 382 | |
|
383 | 383 | description = ctx.description().strip() |
|
384 | 384 | if description: |
|
385 | 385 | if self.ui.verbose: |
|
386 | 386 | self.ui.write( |
|
387 | 387 | _(b"description:\n"), label=b'ui.note log.description' |
|
388 | 388 | ) |
|
389 | 389 | self.ui.write(description, label=b'ui.note log.description') |
|
390 | 390 | self.ui.write(b"\n\n") |
|
391 | 391 | else: |
|
392 | 392 | self.ui.write( |
|
393 | 393 | columns[b'summary'] % description.splitlines()[0], |
|
394 | 394 | label=b'log.summary', |
|
395 | 395 | ) |
|
396 | 396 | self.ui.write(b"\n") |
|
397 | 397 | |
|
398 | 398 | self._showpatch(ctx, graphwidth) |
|
399 | 399 | |
|
400 | 400 | def _showobsfate(self, ctx): |
|
401 | 401 | # TODO: do not depend on templater |
|
402 | 402 | tres = formatter.templateresources(self.repo.ui, self.repo) |
|
403 | 403 | t = formatter.maketemplater( |
|
404 | 404 | self.repo.ui, |
|
405 | 405 | b'{join(obsfate, "\n")}', |
|
406 | 406 | defaults=templatekw.keywords, |
|
407 | 407 | resources=tres, |
|
408 | 408 | ) |
|
409 | 409 | obsfate = t.renderdefault({b'ctx': ctx}).splitlines() |
|
410 | 410 | |
|
411 | 411 | if obsfate: |
|
412 | 412 | for obsfateline in obsfate: |
|
413 | 413 | self.ui.write( |
|
414 | 414 | self._columns[b'obsolete'] % obsfateline, |
|
415 | 415 | label=b'log.obsfate', |
|
416 | 416 | ) |
|
417 | 417 | |
|
418 | 418 | def _exthook(self, ctx): |
|
419 | 419 | '''empty method used by extension as a hook point |
|
420 | 420 | ''' |
|
421 | 421 | |
|
422 | 422 | def _showpatch(self, ctx, graphwidth=0): |
|
423 | 423 | if self._includestat: |
|
424 | 424 | self._differ.showdiff( |
|
425 | 425 | self.ui, ctx, self._diffopts, graphwidth, stat=True |
|
426 | 426 | ) |
|
427 | 427 | if self._includestat and self._includediff: |
|
428 | 428 | self.ui.write(b"\n") |
|
429 | 429 | if self._includediff: |
|
430 | 430 | self._differ.showdiff( |
|
431 | 431 | self.ui, ctx, self._diffopts, graphwidth, stat=False |
|
432 | 432 | ) |
|
433 | 433 | if self._includestat or self._includediff: |
|
434 | 434 | self.ui.write(b"\n") |
|
435 | 435 | |
|
436 | 436 | |
|
437 | 437 | class changesetformatter(changesetprinter): |
|
438 | 438 | """Format changeset information by generic formatter""" |
|
439 | 439 | |
|
440 | 440 | def __init__( |
|
441 | 441 | self, ui, repo, fm, differ=None, diffopts=None, buffered=False |
|
442 | 442 | ): |
|
443 | 443 | changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered) |
|
444 | 444 | self._diffopts = patch.difffeatureopts(ui, diffopts, git=True) |
|
445 | 445 | self._fm = fm |
|
446 | 446 | |
|
447 | 447 | def close(self): |
|
448 | 448 | self._fm.end() |
|
449 | 449 | |
|
450 | 450 | def _show(self, ctx, copies, props): |
|
451 | 451 | '''show a single changeset or file revision''' |
|
452 | 452 | fm = self._fm |
|
453 | 453 | fm.startitem() |
|
454 | 454 | fm.context(ctx=ctx) |
|
455 | 455 | fm.data(rev=scmutil.intrev(ctx), node=fm.hexfunc(scmutil.binnode(ctx))) |
|
456 | 456 | |
|
457 | 457 | datahint = fm.datahint() |
|
458 | 458 | if self.ui.quiet and not datahint: |
|
459 | 459 | return |
|
460 | 460 | |
|
461 | 461 | fm.data( |
|
462 | 462 | branch=ctx.branch(), |
|
463 | 463 | phase=ctx.phasestr(), |
|
464 | 464 | user=ctx.user(), |
|
465 | 465 | date=fm.formatdate(ctx.date()), |
|
466 | 466 | desc=ctx.description(), |
|
467 | 467 | bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'), |
|
468 | 468 | tags=fm.formatlist(ctx.tags(), name=b'tag'), |
|
469 | 469 | parents=fm.formatlist( |
|
470 | 470 | [fm.hexfunc(c.node()) for c in ctx.parents()], name=b'node' |
|
471 | 471 | ), |
|
472 | 472 | ) |
|
473 | 473 | |
|
474 | 474 | if self.ui.debugflag or b'manifest' in datahint: |
|
475 | 475 | fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid)) |
|
476 | 476 | if self.ui.debugflag or b'extra' in datahint: |
|
477 | 477 | fm.data(extra=fm.formatdict(ctx.extra())) |
|
478 | 478 | |
|
479 | 479 | if ( |
|
480 | 480 | self.ui.debugflag |
|
481 | 481 | or b'modified' in datahint |
|
482 | 482 | or b'added' in datahint |
|
483 | 483 | or b'removed' in datahint |
|
484 | 484 | ): |
|
485 | 485 | files = ctx.p1().status(ctx) |
|
486 | 486 | fm.data( |
|
487 | 487 | modified=fm.formatlist(files.modified, name=b'file'), |
|
488 | 488 | added=fm.formatlist(files.added, name=b'file'), |
|
489 | 489 | removed=fm.formatlist(files.removed, name=b'file'), |
|
490 | 490 | ) |
|
491 | 491 | |
|
492 | 492 | verbose = not self.ui.debugflag and self.ui.verbose |
|
493 | 493 | if verbose or b'files' in datahint: |
|
494 | 494 | fm.data(files=fm.formatlist(ctx.files(), name=b'file')) |
|
495 | 495 | if verbose and copies or b'copies' in datahint: |
|
496 | 496 | fm.data( |
|
497 | 497 | copies=fm.formatdict(copies or {}, key=b'name', value=b'source') |
|
498 | 498 | ) |
|
499 | 499 | |
|
500 | 500 | if self._includestat or b'diffstat' in datahint: |
|
501 | 501 | self.ui.pushbuffer() |
|
502 | 502 | self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True) |
|
503 | 503 | fm.data(diffstat=self.ui.popbuffer()) |
|
504 | 504 | if self._includediff or b'diff' in datahint: |
|
505 | 505 | self.ui.pushbuffer() |
|
506 | 506 | self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False) |
|
507 | 507 | fm.data(diff=self.ui.popbuffer()) |
|
508 | 508 | |
|
509 | 509 | |
|
510 | 510 | class changesettemplater(changesetprinter): |
|
511 | 511 | '''format changeset information. |
|
512 | 512 | |
|
513 | 513 | Note: there are a variety of convenience functions to build a |
|
514 | 514 | changesettemplater for common cases. See functions such as: |
|
515 | 515 | maketemplater, changesetdisplayer, buildcommittemplate, or other |
|
516 | 516 | functions that use changesest_templater. |
|
517 | 517 | ''' |
|
518 | 518 | |
|
519 | 519 | # Arguments before "buffered" used to be positional. Consider not |
|
520 | 520 | # adding/removing arguments before "buffered" to not break callers. |
|
521 | 521 | def __init__( |
|
522 | 522 | self, ui, repo, tmplspec, differ=None, diffopts=None, buffered=False |
|
523 | 523 | ): |
|
524 | 524 | changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered) |
|
525 | 525 | # tres is shared with _graphnodeformatter() |
|
526 | 526 | self._tresources = tres = formatter.templateresources(ui, repo) |
|
527 | 527 | self.t = formatter.loadtemplater( |
|
528 | 528 | ui, |
|
529 | 529 | tmplspec, |
|
530 | 530 | defaults=templatekw.keywords, |
|
531 | 531 | resources=tres, |
|
532 | 532 | cache=templatekw.defaulttempl, |
|
533 | 533 | ) |
|
534 | 534 | self._counter = itertools.count() |
|
535 | 535 | |
|
536 | 536 | self._tref = tmplspec.ref |
|
537 | 537 | self._parts = { |
|
538 | 538 | b'header': b'', |
|
539 | 539 | b'footer': b'', |
|
540 | 540 | tmplspec.ref: tmplspec.ref, |
|
541 | 541 | b'docheader': b'', |
|
542 | 542 | b'docfooter': b'', |
|
543 | 543 | b'separator': b'', |
|
544 | 544 | } |
|
545 | 545 | if tmplspec.mapfile: |
|
546 | 546 | # find correct templates for current mode, for backward |
|
547 | 547 | # compatibility with 'log -v/-q/--debug' using a mapfile |
|
548 | 548 | tmplmodes = [ |
|
549 | 549 | (True, b''), |
|
550 | 550 | (self.ui.verbose, b'_verbose'), |
|
551 | 551 | (self.ui.quiet, b'_quiet'), |
|
552 | 552 | (self.ui.debugflag, b'_debug'), |
|
553 | 553 | ] |
|
554 | 554 | for mode, postfix in tmplmodes: |
|
555 | 555 | for t in self._parts: |
|
556 | 556 | cur = t + postfix |
|
557 | 557 | if mode and cur in self.t: |
|
558 | 558 | self._parts[t] = cur |
|
559 | 559 | else: |
|
560 | 560 | partnames = [p for p in self._parts.keys() if p != tmplspec.ref] |
|
561 | 561 | m = formatter.templatepartsmap(tmplspec, self.t, partnames) |
|
562 | 562 | self._parts.update(m) |
|
563 | 563 | |
|
564 | 564 | if self._parts[b'docheader']: |
|
565 | 565 | self.ui.write(self.t.render(self._parts[b'docheader'], {})) |
|
566 | 566 | |
|
567 | 567 | def close(self): |
|
568 | 568 | if self._parts[b'docfooter']: |
|
569 | 569 | if not self.footer: |
|
570 | 570 | self.footer = b"" |
|
571 | 571 | self.footer += self.t.render(self._parts[b'docfooter'], {}) |
|
572 | 572 | return super(changesettemplater, self).close() |
|
573 | 573 | |
|
574 | 574 | def _show(self, ctx, copies, props): |
|
575 | 575 | '''show a single changeset or file revision''' |
|
576 | 576 | props = props.copy() |
|
577 | 577 | props[b'ctx'] = ctx |
|
578 | 578 | props[b'index'] = index = next(self._counter) |
|
579 | 579 | props[b'revcache'] = {b'copies': copies} |
|
580 | 580 | graphwidth = props.get(b'graphwidth', 0) |
|
581 | 581 | |
|
582 | 582 | # write separator, which wouldn't work well with the header part below |
|
583 | 583 | # since there's inherently a conflict between header (across items) and |
|
584 | 584 | # separator (per item) |
|
585 | 585 | if self._parts[b'separator'] and index > 0: |
|
586 | 586 | self.ui.write(self.t.render(self._parts[b'separator'], {})) |
|
587 | 587 | |
|
588 | 588 | # write header |
|
589 | 589 | if self._parts[b'header']: |
|
590 | 590 | h = self.t.render(self._parts[b'header'], props) |
|
591 | 591 | if self.buffered: |
|
592 | 592 | self.header[ctx.rev()] = h |
|
593 | 593 | else: |
|
594 | 594 | if self.lastheader != h: |
|
595 | 595 | self.lastheader = h |
|
596 | 596 | self.ui.write(h) |
|
597 | 597 | |
|
598 | 598 | # write changeset metadata, then patch if requested |
|
599 | 599 | key = self._parts[self._tref] |
|
600 | 600 | self.ui.write(self.t.render(key, props)) |
|
601 | 601 | self._exthook(ctx) |
|
602 | 602 | self._showpatch(ctx, graphwidth) |
|
603 | 603 | |
|
604 | 604 | if self._parts[b'footer']: |
|
605 | 605 | if not self.footer: |
|
606 | 606 | self.footer = self.t.render(self._parts[b'footer'], props) |
|
607 | 607 | |
|
608 | 608 | |
|
609 | 609 | def templatespec(tmpl, mapfile): |
|
610 | 610 | if pycompat.ispy3: |
|
611 | 611 | assert not isinstance(tmpl, str), b'tmpl must not be a str' |
|
612 | 612 | if mapfile: |
|
613 | 613 | return formatter.templatespec(b'changeset', tmpl, mapfile) |
|
614 | 614 | else: |
|
615 | 615 | return formatter.templatespec(b'', tmpl, None) |
|
616 | 616 | |
|
617 | 617 | |
|
618 | 618 | def _lookuptemplate(ui, tmpl, style): |
|
619 | 619 | """Find the template matching the given template spec or style |
|
620 | 620 | |
|
621 | 621 | See formatter.lookuptemplate() for details. |
|
622 | 622 | """ |
|
623 | 623 | |
|
624 | 624 | # ui settings |
|
625 | 625 | if not tmpl and not style: # template are stronger than style |
|
626 | 626 | tmpl = ui.config(b'ui', b'logtemplate') |
|
627 | 627 | if tmpl: |
|
628 | 628 | return templatespec(templater.unquotestring(tmpl), None) |
|
629 | 629 | else: |
|
630 | 630 | style = util.expandpath(ui.config(b'ui', b'style')) |
|
631 | 631 | |
|
632 | 632 | if not tmpl and style: |
|
633 | 633 | mapfile = style |
|
634 | 634 | if not os.path.split(mapfile)[0]: |
|
635 | 635 | mapname = templater.templatepath( |
|
636 | 636 | b'map-cmdline.' + mapfile |
|
637 | 637 | ) or templater.templatepath(mapfile) |
|
638 | 638 | if mapname: |
|
639 | 639 | mapfile = mapname |
|
640 | 640 | return templatespec(None, mapfile) |
|
641 | 641 | |
|
642 | 642 | return formatter.lookuptemplate(ui, b'changeset', tmpl) |
|
643 | 643 | |
|
644 | 644 | |
|
645 | 645 | def maketemplater(ui, repo, tmpl, buffered=False): |
|
646 | 646 | """Create a changesettemplater from a literal template 'tmpl' |
|
647 | 647 | byte-string.""" |
|
648 | 648 | spec = templatespec(tmpl, None) |
|
649 | 649 | return changesettemplater(ui, repo, spec, buffered=buffered) |
|
650 | 650 | |
|
651 | 651 | |
|
652 | 652 | def changesetdisplayer(ui, repo, opts, differ=None, buffered=False): |
|
653 | 653 | """show one changeset using template or regular display. |
|
654 | 654 | |
|
655 | 655 | Display format will be the first non-empty hit of: |
|
656 | 656 | 1. option 'template' |
|
657 | 657 | 2. option 'style' |
|
658 | 658 | 3. [ui] setting 'logtemplate' |
|
659 | 659 | 4. [ui] setting 'style' |
|
660 | 660 | If all of these values are either the unset or the empty string, |
|
661 | 661 | regular display via changesetprinter() is done. |
|
662 | 662 | """ |
|
663 | 663 | postargs = (differ, opts, buffered) |
|
664 | 664 | spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style')) |
|
665 | 665 | |
|
666 | 666 | # machine-readable formats have slightly different keyword set than |
|
667 | 667 | # plain templates, which are handled by changesetformatter. |
|
668 | 668 | # note that {b'pickle', b'debug'} can also be added to the list if needed. |
|
669 | 669 | if spec.ref in {b'cbor', b'json'}: |
|
670 | 670 | fm = ui.formatter(b'log', opts) |
|
671 | 671 | return changesetformatter(ui, repo, fm, *postargs) |
|
672 | 672 | |
|
673 | 673 | if not spec.ref and not spec.tmpl and not spec.mapfile: |
|
674 | 674 | return changesetprinter(ui, repo, *postargs) |
|
675 | 675 | |
|
676 | 676 | return changesettemplater(ui, repo, spec, *postargs) |
|
677 | 677 | |
|
678 | 678 | |
|
679 | 679 | def _makematcher(repo, revs, pats, opts): |
|
680 | 680 | """Build matcher and expanded patterns from log options |
|
681 | 681 | |
|
682 | 682 | If --follow, revs are the revisions to follow from. |
|
683 | 683 | |
|
684 | 684 | Returns (match, pats, slowpath) where |
|
685 | 685 | - match: a matcher built from the given pats and -I/-X opts |
|
686 | 686 | - pats: patterns used (globs are expanded on Windows) |
|
687 | 687 | - slowpath: True if patterns aren't as simple as scanning filelogs |
|
688 | 688 | """ |
|
689 | 689 | # pats/include/exclude are passed to match.match() directly in |
|
690 | 690 | # _matchfiles() revset but walkchangerevs() builds its matcher with |
|
691 | 691 | # scmutil.match(). The difference is input pats are globbed on |
|
692 | 692 | # platforms without shell expansion (windows). |
|
693 | 693 | wctx = repo[None] |
|
694 | 694 | match, pats = scmutil.matchandpats(wctx, pats, opts) |
|
695 | 695 | slowpath = match.anypats() or (not match.always() and opts.get(b'removed')) |
|
696 | 696 | if not slowpath: |
|
697 | 697 | follow = opts.get(b'follow') or opts.get(b'follow_first') |
|
698 | 698 | startctxs = [] |
|
699 | 699 | if follow and opts.get(b'rev'): |
|
700 | 700 | startctxs = [repo[r] for r in revs] |
|
701 | 701 | for f in match.files(): |
|
702 | 702 | if follow and startctxs: |
|
703 | 703 | # No idea if the path was a directory at that revision, so |
|
704 | 704 | # take the slow path. |
|
705 | 705 | if any(f not in c for c in startctxs): |
|
706 | 706 | slowpath = True |
|
707 | 707 | continue |
|
708 | 708 | elif follow and f not in wctx: |
|
709 | 709 | # If the file exists, it may be a directory, so let it |
|
710 | 710 | # take the slow path. |
|
711 | 711 | if os.path.exists(repo.wjoin(f)): |
|
712 | 712 | slowpath = True |
|
713 | 713 | continue |
|
714 | 714 | else: |
|
715 | 715 | raise error.Abort( |
|
716 | 716 | _( |
|
717 | 717 | b'cannot follow file not in parent ' |
|
718 | 718 | b'revision: "%s"' |
|
719 | 719 | ) |
|
720 | 720 | % f |
|
721 | 721 | ) |
|
722 | 722 | filelog = repo.file(f) |
|
723 | 723 | if not filelog: |
|
724 | 724 | # A zero count may be a directory or deleted file, so |
|
725 | 725 | # try to find matching entries on the slow path. |
|
726 | 726 | if follow: |
|
727 | 727 | raise error.Abort( |
|
728 | 728 | _(b'cannot follow nonexistent file: "%s"') % f |
|
729 | 729 | ) |
|
730 | 730 | slowpath = True |
|
731 | 731 | |
|
732 | 732 | # We decided to fall back to the slowpath because at least one |
|
733 | 733 | # of the paths was not a file. Check to see if at least one of them |
|
734 | 734 | # existed in history - in that case, we'll continue down the |
|
735 | 735 | # slowpath; otherwise, we can turn off the slowpath |
|
736 | 736 | if slowpath: |
|
737 | 737 | for path in match.files(): |
|
738 | 738 | if path == b'.' or path in repo.store: |
|
739 | 739 | break |
|
740 | 740 | else: |
|
741 | 741 | slowpath = False |
|
742 | 742 | |
|
743 | 743 | return match, pats, slowpath |
|
744 | 744 | |
|
745 | 745 | |
|
746 | 746 | def _fileancestors(repo, revs, match, followfirst): |
|
747 | 747 | fctxs = [] |
|
748 | 748 | for r in revs: |
|
749 | 749 | ctx = repo[r] |
|
750 | 750 | fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match)) |
|
751 | 751 | |
|
752 | 752 | # When displaying a revision with --patch --follow FILE, we have |
|
753 | 753 | # to know which file of the revision must be diffed. With |
|
754 | 754 | # --follow, we want the names of the ancestors of FILE in the |
|
755 | 755 | # revision, stored in "fcache". "fcache" is populated as a side effect |
|
756 | 756 | # of the graph traversal. |
|
757 | 757 | fcache = {} |
|
758 | 758 | |
|
759 | 759 | def filematcher(ctx): |
|
760 | 760 | return scmutil.matchfiles(repo, fcache.get(ctx.rev(), [])) |
|
761 | 761 | |
|
762 | 762 | def revgen(): |
|
763 | 763 | for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst): |
|
764 | 764 | fcache[rev] = [c.path() for c in cs] |
|
765 | 765 | yield rev |
|
766 | 766 | |
|
767 | 767 | return smartset.generatorset(revgen(), iterasc=False), filematcher |
|
768 | 768 | |
|
769 | 769 | |
|
770 | 770 | def _makenofollowfilematcher(repo, pats, opts): |
|
771 | 771 | '''hook for extensions to override the filematcher for non-follow cases''' |
|
772 | 772 | return None |
|
773 | 773 | |
|
774 | 774 | |
|
775 | 775 | _opt2logrevset = { |
|
776 | 776 | b'no_merges': (b'not merge()', None), |
|
777 | 777 | b'only_merges': (b'merge()', None), |
|
778 | 778 | b'_matchfiles': (None, b'_matchfiles(%ps)'), |
|
779 | 779 | b'date': (b'date(%s)', None), |
|
780 | 780 | b'branch': (b'branch(%s)', b'%lr'), |
|
781 | 781 | b'_patslog': (b'filelog(%s)', b'%lr'), |
|
782 | 782 | b'keyword': (b'keyword(%s)', b'%lr'), |
|
783 | 783 | b'prune': (b'ancestors(%s)', b'not %lr'), |
|
784 | 784 | b'user': (b'user(%s)', b'%lr'), |
|
785 | 785 | } |
|
786 | 786 | |
|
787 | 787 | |
|
788 | 788 | def _makerevset(repo, match, pats, slowpath, opts): |
|
789 | 789 | """Return a revset string built from log options and file patterns""" |
|
790 | 790 | opts = dict(opts) |
|
791 | 791 | # follow or not follow? |
|
792 | 792 | follow = opts.get(b'follow') or opts.get(b'follow_first') |
|
793 | 793 | |
|
794 | 794 | # branch and only_branch are really aliases and must be handled at |
|
795 | 795 | # the same time |
|
796 | 796 | opts[b'branch'] = opts.get(b'branch', []) + opts.get(b'only_branch', []) |
|
797 | 797 | opts[b'branch'] = [repo.lookupbranch(b) for b in opts[b'branch']] |
|
798 | 798 | |
|
799 | 799 | if slowpath: |
|
800 | 800 | # See walkchangerevs() slow path. |
|
801 | 801 | # |
|
802 | 802 | # pats/include/exclude cannot be represented as separate |
|
803 | 803 | # revset expressions as their filtering logic applies at file |
|
804 | 804 | # level. For instance "-I a -X b" matches a revision touching |
|
805 | 805 | # "a" and "b" while "file(a) and not file(b)" does |
|
806 | 806 | # not. Besides, filesets are evaluated against the working |
|
807 | 807 | # directory. |
|
808 | 808 | matchargs = [b'r:', b'd:relpath'] |
|
809 | 809 | for p in pats: |
|
810 | 810 | matchargs.append(b'p:' + p) |
|
811 | 811 | for p in opts.get(b'include', []): |
|
812 | 812 | matchargs.append(b'i:' + p) |
|
813 | 813 | for p in opts.get(b'exclude', []): |
|
814 | 814 | matchargs.append(b'x:' + p) |
|
815 | 815 | opts[b'_matchfiles'] = matchargs |
|
816 | 816 | elif not follow: |
|
817 | 817 | opts[b'_patslog'] = list(pats) |
|
818 | 818 | |
|
819 | 819 | expr = [] |
|
820 | 820 | for op, val in sorted(pycompat.iteritems(opts)): |
|
821 | 821 | if not val: |
|
822 | 822 | continue |
|
823 | 823 | if op not in _opt2logrevset: |
|
824 | 824 | continue |
|
825 | 825 | revop, listop = _opt2logrevset[op] |
|
826 | 826 | if revop and b'%' not in revop: |
|
827 | 827 | expr.append(revop) |
|
828 | 828 | elif not listop: |
|
829 | 829 | expr.append(revsetlang.formatspec(revop, val)) |
|
830 | 830 | else: |
|
831 | 831 | if revop: |
|
832 | 832 | val = [revsetlang.formatspec(revop, v) for v in val] |
|
833 | 833 | expr.append(revsetlang.formatspec(listop, val)) |
|
834 | 834 | |
|
835 | 835 | if expr: |
|
836 | 836 | expr = b'(' + b' and '.join(expr) + b')' |
|
837 | 837 | else: |
|
838 | 838 | expr = None |
|
839 | 839 | return expr |
|
840 | 840 | |
|
841 | 841 | |
|
842 | 842 | def _initialrevs(repo, opts): |
|
843 | 843 | """Return the initial set of revisions to be filtered or followed""" |
|
844 | 844 | follow = opts.get(b'follow') or opts.get(b'follow_first') |
|
845 | 845 | if opts.get(b'rev'): |
|
846 | 846 | revs = scmutil.revrange(repo, opts[b'rev']) |
|
847 | 847 | elif follow and repo.dirstate.p1() == nullid: |
|
848 | 848 | revs = smartset.baseset() |
|
849 | 849 | elif follow: |
|
850 | 850 | revs = repo.revs(b'.') |
|
851 | 851 | else: |
|
852 | 852 | revs = smartset.spanset(repo) |
|
853 | 853 | revs.reverse() |
|
854 | 854 | return revs |
|
855 | 855 | |
|
856 | 856 | |
|
857 | 857 | def getrevs(repo, pats, opts): |
|
858 | 858 | # type: (Any, Any, Any) -> Tuple[smartset.abstractsmartset, Optional[changesetdiffer]] |
|
859 | 859 | """Return (revs, differ) where revs is a smartset |
|
860 | 860 | |
|
861 | 861 | differ is a changesetdiffer with pre-configured file matcher. |
|
862 | 862 | """ |
|
863 | 863 | follow = opts.get(b'follow') or opts.get(b'follow_first') |
|
864 | 864 | followfirst = opts.get(b'follow_first') |
|
865 | 865 | limit = getlimit(opts) |
|
866 | 866 | revs = _initialrevs(repo, opts) |
|
867 | 867 | if not revs: |
|
868 | 868 | return smartset.baseset(), None |
|
869 | 869 | match, pats, slowpath = _makematcher(repo, revs, pats, opts) |
|
870 | 870 | filematcher = None |
|
871 | 871 | if follow: |
|
872 | 872 | if slowpath or match.always(): |
|
873 | 873 | revs = dagop.revancestors(repo, revs, followfirst=followfirst) |
|
874 | 874 | else: |
|
875 | 875 | revs, filematcher = _fileancestors(repo, revs, match, followfirst) |
|
876 | 876 | revs.reverse() |
|
877 | 877 | if filematcher is None: |
|
878 | 878 | filematcher = _makenofollowfilematcher(repo, pats, opts) |
|
879 | 879 | if filematcher is None: |
|
880 | 880 | |
|
881 | 881 | def filematcher(ctx): |
|
882 | 882 | return match |
|
883 | 883 | |
|
884 | 884 | expr = _makerevset(repo, match, pats, slowpath, opts) |
|
885 | 885 | if opts.get(b'graph'): |
|
886 | 886 | # User-specified revs might be unsorted, but don't sort before |
|
887 | 887 | # _makerevset because it might depend on the order of revs |
|
888 | 888 | if repo.ui.configbool(b'experimental', b'log.topo'): |
|
889 | 889 | if not revs.istopo(): |
|
890 | 890 | revs = dagop.toposort(revs, repo.changelog.parentrevs) |
|
891 | 891 | # TODO: try to iterate the set lazily |
|
892 | 892 | revs = revset.baseset(list(revs), istopo=True) |
|
893 | 893 | elif not (revs.isdescending() or revs.istopo()): |
|
894 | 894 | revs.sort(reverse=True) |
|
895 | 895 | if expr: |
|
896 | 896 | matcher = revset.match(None, expr) |
|
897 | 897 | revs = matcher(repo, revs) |
|
898 | 898 | if limit is not None: |
|
899 | 899 | revs = revs.slice(0, limit) |
|
900 | 900 | |
|
901 | 901 | differ = changesetdiffer() |
|
902 | 902 | differ._makefilematcher = filematcher |
|
903 | 903 | return revs, differ |
|
904 | 904 | |
|
905 | 905 | |
|
906 | 906 | def _parselinerangeopt(repo, opts): |
|
907 | 907 | """Parse --line-range log option and return a list of tuples (filename, |
|
908 | 908 | (fromline, toline)). |
|
909 | 909 | """ |
|
910 | 910 | linerangebyfname = [] |
|
911 | 911 | for pat in opts.get(b'line_range', []): |
|
912 | 912 | try: |
|
913 | 913 | pat, linerange = pat.rsplit(b',', 1) |
|
914 | 914 | except ValueError: |
|
915 | 915 | raise error.Abort(_(b'malformatted line-range pattern %s') % pat) |
|
916 | 916 | try: |
|
917 | 917 | fromline, toline = map(int, linerange.split(b':')) |
|
918 | 918 | except ValueError: |
|
919 | 919 | raise error.Abort(_(b"invalid line range for %s") % pat) |
|
920 | 920 | msg = _(b"line range pattern '%s' must match exactly one file") % pat |
|
921 | 921 | fname = scmutil.parsefollowlinespattern(repo, None, pat, msg) |
|
922 | 922 | linerangebyfname.append( |
|
923 | 923 | (fname, util.processlinerange(fromline, toline)) |
|
924 | 924 | ) |
|
925 | 925 | return linerangebyfname |
|
926 | 926 | |
|
927 | 927 | |
|
928 | 928 | def getlinerangerevs(repo, userrevs, opts): |
|
929 | 929 | """Return (revs, differ). |
|
930 | 930 | |
|
931 | 931 | "revs" are revisions obtained by processing "line-range" log options and |
|
932 | 932 | walking block ancestors of each specified file/line-range. |
|
933 | 933 | |
|
934 | 934 | "differ" is a changesetdiffer with pre-configured file matcher and hunks |
|
935 | 935 | filter. |
|
936 | 936 | """ |
|
937 | 937 | wctx = repo[None] |
|
938 | 938 | |
|
939 | 939 | # Two-levels map of "rev -> file ctx -> [line range]". |
|
940 | 940 | linerangesbyrev = {} |
|
941 | 941 | for fname, (fromline, toline) in _parselinerangeopt(repo, opts): |
|
942 | 942 | if fname not in wctx: |
|
943 | 943 | raise error.Abort( |
|
944 | 944 | _(b'cannot follow file not in parent revision: "%s"') % fname |
|
945 | 945 | ) |
|
946 | 946 | fctx = wctx.filectx(fname) |
|
947 | 947 | for fctx, linerange in dagop.blockancestors(fctx, fromline, toline): |
|
948 | 948 | rev = fctx.introrev() |
|
949 | 949 | if rev is None: |
|
950 | 950 | rev = wdirrev |
|
951 | 951 | if rev not in userrevs: |
|
952 | 952 | continue |
|
953 | 953 | linerangesbyrev.setdefault(rev, {}).setdefault( |
|
954 | 954 | fctx.path(), [] |
|
955 | 955 | ).append(linerange) |
|
956 | 956 | |
|
957 | 957 | def nofilterhunksfn(fctx, hunks): |
|
958 | 958 | return hunks |
|
959 | 959 | |
|
960 | 960 | def hunksfilter(ctx): |
|
961 | 961 | fctxlineranges = linerangesbyrev.get(scmutil.intrev(ctx)) |
|
962 | 962 | if fctxlineranges is None: |
|
963 | 963 | return nofilterhunksfn |
|
964 | 964 | |
|
965 | 965 | def filterfn(fctx, hunks): |
|
966 | 966 | lineranges = fctxlineranges.get(fctx.path()) |
|
967 | 967 | if lineranges is not None: |
|
968 | 968 | for hr, lines in hunks: |
|
969 | 969 | if hr is None: # binary |
|
970 | 970 | yield hr, lines |
|
971 | 971 | continue |
|
972 | 972 | if any(mdiff.hunkinrange(hr[2:], lr) for lr in lineranges): |
|
973 | 973 | yield hr, lines |
|
974 | 974 | else: |
|
975 | 975 | for hunk in hunks: |
|
976 | 976 | yield hunk |
|
977 | 977 | |
|
978 | 978 | return filterfn |
|
979 | 979 | |
|
980 | 980 | def filematcher(ctx): |
|
981 | 981 | files = list(linerangesbyrev.get(scmutil.intrev(ctx), [])) |
|
982 | 982 | return scmutil.matchfiles(repo, files) |
|
983 | 983 | |
|
984 | 984 | revs = sorted(linerangesbyrev, reverse=True) |
|
985 | 985 | |
|
986 | 986 | differ = changesetdiffer() |
|
987 | 987 | differ._makefilematcher = filematcher |
|
988 | 988 | differ._makehunksfilter = hunksfilter |
|
989 | 989 | return smartset.baseset(revs), differ |
|
990 | 990 | |
|
991 | 991 | |
|
992 | 992 | def _graphnodeformatter(ui, displayer): |
|
993 | 993 | spec = ui.config(b'ui', b'graphnodetemplate') |
|
994 | 994 | if not spec: |
|
995 | 995 | return templatekw.getgraphnode # fast path for "{graphnode}" |
|
996 | 996 | |
|
997 | 997 | spec = templater.unquotestring(spec) |
|
998 | 998 | if isinstance(displayer, changesettemplater): |
|
999 | 999 | # reuse cache of slow templates |
|
1000 | 1000 | tres = displayer._tresources |
|
1001 | 1001 | else: |
|
1002 | 1002 | tres = formatter.templateresources(ui) |
|
1003 | 1003 | templ = formatter.maketemplater( |
|
1004 | 1004 | ui, spec, defaults=templatekw.keywords, resources=tres |
|
1005 | 1005 | ) |
|
1006 | 1006 | |
|
1007 | def formatnode(repo, ctx): | |
|
1007 | def formatnode(repo, ctx, cache): | |
|
1008 | 1008 | props = {b'ctx': ctx, b'repo': repo} |
|
1009 | 1009 | return templ.renderdefault(props) |
|
1010 | 1010 | |
|
1011 | 1011 | return formatnode |
|
1012 | 1012 | |
|
1013 | 1013 | |
|
1014 | 1014 | def displaygraph(ui, repo, dag, displayer, edgefn, getcopies=None, props=None): |
|
1015 | 1015 | props = props or {} |
|
1016 | 1016 | formatnode = _graphnodeformatter(ui, displayer) |
|
1017 | 1017 | state = graphmod.asciistate() |
|
1018 | 1018 | styles = state.styles |
|
1019 | 1019 | |
|
1020 | 1020 | # only set graph styling if HGPLAIN is not set. |
|
1021 | 1021 | if ui.plain(b'graph'): |
|
1022 | 1022 | # set all edge styles to |, the default pre-3.8 behaviour |
|
1023 | 1023 | styles.update(dict.fromkeys(styles, b'|')) |
|
1024 | 1024 | else: |
|
1025 | 1025 | edgetypes = { |
|
1026 | 1026 | b'parent': graphmod.PARENT, |
|
1027 | 1027 | b'grandparent': graphmod.GRANDPARENT, |
|
1028 | 1028 | b'missing': graphmod.MISSINGPARENT, |
|
1029 | 1029 | } |
|
1030 | 1030 | for name, key in edgetypes.items(): |
|
1031 | 1031 | # experimental config: experimental.graphstyle.* |
|
1032 | 1032 | styles[key] = ui.config( |
|
1033 | 1033 | b'experimental', b'graphstyle.%s' % name, styles[key] |
|
1034 | 1034 | ) |
|
1035 | 1035 | if not styles[key]: |
|
1036 | 1036 | styles[key] = None |
|
1037 | 1037 | |
|
1038 | 1038 | # experimental config: experimental.graphshorten |
|
1039 | 1039 | state.graphshorten = ui.configbool(b'experimental', b'graphshorten') |
|
1040 | 1040 | |
|
1041 | formatnode_cache = {} | |
|
1041 | 1042 | for rev, type, ctx, parents in dag: |
|
1042 | char = formatnode(repo, ctx) | |
|
1043 | char = formatnode(repo, ctx, formatnode_cache) | |
|
1043 | 1044 | copies = getcopies(ctx) if getcopies else None |
|
1044 | 1045 | edges = edgefn(type, char, state, rev, parents) |
|
1045 | 1046 | firstedge = next(edges) |
|
1046 | 1047 | width = firstedge[2] |
|
1047 | 1048 | displayer.show( |
|
1048 | 1049 | ctx, copies=copies, graphwidth=width, **pycompat.strkwargs(props) |
|
1049 | 1050 | ) |
|
1050 | 1051 | lines = displayer.hunk.pop(rev).split(b'\n') |
|
1051 | 1052 | if not lines[-1]: |
|
1052 | 1053 | del lines[-1] |
|
1053 | 1054 | displayer.flush(ctx) |
|
1054 | 1055 | for type, char, width, coldata in itertools.chain([firstedge], edges): |
|
1055 | 1056 | graphmod.ascii(ui, state, type, char, lines, coldata) |
|
1056 | 1057 | lines = [] |
|
1057 | 1058 | displayer.close() |
|
1058 | 1059 | |
|
1059 | 1060 | |
|
1060 | 1061 | def displaygraphrevs(ui, repo, revs, displayer, getrenamed): |
|
1061 | 1062 | revdag = graphmod.dagwalker(repo, revs) |
|
1062 | 1063 | displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed) |
|
1063 | 1064 | |
|
1064 | 1065 | |
|
1065 | 1066 | def displayrevs(ui, repo, revs, displayer, getcopies): |
|
1066 | 1067 | for rev in revs: |
|
1067 | 1068 | ctx = repo[rev] |
|
1068 | 1069 | copies = getcopies(ctx) if getcopies else None |
|
1069 | 1070 | displayer.show(ctx, copies=copies) |
|
1070 | 1071 | displayer.flush(ctx) |
|
1071 | 1072 | displayer.close() |
|
1072 | 1073 | |
|
1073 | 1074 | |
|
1074 | 1075 | def checkunsupportedgraphflags(pats, opts): |
|
1075 | 1076 | for op in [b"newest_first"]: |
|
1076 | 1077 | if op in opts and opts[op]: |
|
1077 | 1078 | raise error.Abort( |
|
1078 | 1079 | _(b"-G/--graph option is incompatible with --%s") |
|
1079 | 1080 | % op.replace(b"_", b"-") |
|
1080 | 1081 | ) |
|
1081 | 1082 | |
|
1082 | 1083 | |
|
1083 | 1084 | def graphrevs(repo, nodes, opts): |
|
1084 | 1085 | limit = getlimit(opts) |
|
1085 | 1086 | nodes.reverse() |
|
1086 | 1087 | if limit is not None: |
|
1087 | 1088 | nodes = nodes[:limit] |
|
1088 | 1089 | return graphmod.nodes(repo, nodes) |
@@ -1,992 +1,1004 b'' | |||
|
1 | 1 | # templatekw.py - common changeset template keywords |
|
2 | 2 | # |
|
3 | 3 | # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> |
|
4 | 4 | # |
|
5 | 5 | # This software may be used and distributed according to the terms of the |
|
6 | 6 | # GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | from __future__ import absolute_import |
|
9 | 9 | |
|
10 | 10 | from .i18n import _ |
|
11 | 11 | from .node import ( |
|
12 | 12 | hex, |
|
13 | 13 | nullid, |
|
14 | 14 | wdirid, |
|
15 | 15 | wdirrev, |
|
16 | 16 | ) |
|
17 | 17 | |
|
18 | 18 | from . import ( |
|
19 | 19 | diffutil, |
|
20 | 20 | encoding, |
|
21 | 21 | error, |
|
22 | 22 | hbisect, |
|
23 | 23 | i18n, |
|
24 | 24 | obsutil, |
|
25 | 25 | patch, |
|
26 | 26 | pycompat, |
|
27 | 27 | registrar, |
|
28 | 28 | scmutil, |
|
29 | 29 | templateutil, |
|
30 | 30 | util, |
|
31 | 31 | ) |
|
32 | 32 | from .utils import stringutil |
|
33 | 33 | |
|
34 | 34 | _hybrid = templateutil.hybrid |
|
35 | 35 | hybriddict = templateutil.hybriddict |
|
36 | 36 | hybridlist = templateutil.hybridlist |
|
37 | 37 | compatdict = templateutil.compatdict |
|
38 | 38 | compatlist = templateutil.compatlist |
|
39 | 39 | _showcompatlist = templateutil._showcompatlist |
|
40 | 40 | |
|
41 | 41 | |
|
42 | 42 | def getlatesttags(context, mapping, pattern=None): |
|
43 | 43 | '''return date, distance and name for the latest tag of rev''' |
|
44 | 44 | repo = context.resource(mapping, b'repo') |
|
45 | 45 | ctx = context.resource(mapping, b'ctx') |
|
46 | 46 | cache = context.resource(mapping, b'cache') |
|
47 | 47 | |
|
48 | 48 | cachename = b'latesttags' |
|
49 | 49 | if pattern is not None: |
|
50 | 50 | cachename += b'-' + pattern |
|
51 | 51 | match = stringutil.stringmatcher(pattern)[2] |
|
52 | 52 | else: |
|
53 | 53 | match = util.always |
|
54 | 54 | |
|
55 | 55 | if cachename not in cache: |
|
56 | 56 | # Cache mapping from rev to a tuple with tag date, tag |
|
57 | 57 | # distance and tag name |
|
58 | 58 | cache[cachename] = {-1: (0, 0, [b'null'])} |
|
59 | 59 | latesttags = cache[cachename] |
|
60 | 60 | |
|
61 | 61 | rev = ctx.rev() |
|
62 | 62 | todo = [rev] |
|
63 | 63 | while todo: |
|
64 | 64 | rev = todo.pop() |
|
65 | 65 | if rev in latesttags: |
|
66 | 66 | continue |
|
67 | 67 | ctx = repo[rev] |
|
68 | 68 | tags = [ |
|
69 | 69 | t |
|
70 | 70 | for t in ctx.tags() |
|
71 | 71 | if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t)) |
|
72 | 72 | ] |
|
73 | 73 | if tags: |
|
74 | 74 | latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)] |
|
75 | 75 | continue |
|
76 | 76 | try: |
|
77 | 77 | ptags = [latesttags[p.rev()] for p in ctx.parents()] |
|
78 | 78 | if len(ptags) > 1: |
|
79 | 79 | if ptags[0][2] == ptags[1][2]: |
|
80 | 80 | # The tuples are laid out so the right one can be found by |
|
81 | 81 | # comparison in this case. |
|
82 | 82 | pdate, pdist, ptag = max(ptags) |
|
83 | 83 | else: |
|
84 | 84 | |
|
85 | 85 | def key(x): |
|
86 | 86 | tag = x[2][0] |
|
87 | 87 | if ctx.rev() is None: |
|
88 | 88 | # only() doesn't support wdir |
|
89 | 89 | prevs = [c.rev() for c in ctx.parents()] |
|
90 | 90 | changes = repo.revs(b'only(%ld, %s)', prevs, tag) |
|
91 | 91 | changessincetag = len(changes) + 1 |
|
92 | 92 | else: |
|
93 | 93 | changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag) |
|
94 | 94 | changessincetag = len(changes) |
|
95 | 95 | # Smallest number of changes since tag wins. Date is |
|
96 | 96 | # used as tiebreaker. |
|
97 | 97 | return [-changessincetag, x[0]] |
|
98 | 98 | |
|
99 | 99 | pdate, pdist, ptag = max(ptags, key=key) |
|
100 | 100 | else: |
|
101 | 101 | pdate, pdist, ptag = ptags[0] |
|
102 | 102 | except KeyError: |
|
103 | 103 | # Cache miss - recurse |
|
104 | 104 | todo.append(rev) |
|
105 | 105 | todo.extend(p.rev() for p in ctx.parents()) |
|
106 | 106 | continue |
|
107 | 107 | latesttags[rev] = pdate, pdist + 1, ptag |
|
108 | 108 | return latesttags[rev] |
|
109 | 109 | |
|
110 | 110 | |
|
111 | 111 | def getlogcolumns(): |
|
112 | 112 | """Return a dict of log column labels""" |
|
113 | 113 | _ = pycompat.identity # temporarily disable gettext |
|
114 | 114 | # i18n: column positioning for "hg log" |
|
115 | 115 | columns = _( |
|
116 | 116 | b'bookmark: %s\n' |
|
117 | 117 | b'branch: %s\n' |
|
118 | 118 | b'changeset: %s\n' |
|
119 | 119 | b'copies: %s\n' |
|
120 | 120 | b'date: %s\n' |
|
121 | 121 | b'extra: %s=%s\n' |
|
122 | 122 | b'files+: %s\n' |
|
123 | 123 | b'files-: %s\n' |
|
124 | 124 | b'files: %s\n' |
|
125 | 125 | b'instability: %s\n' |
|
126 | 126 | b'manifest: %s\n' |
|
127 | 127 | b'obsolete: %s\n' |
|
128 | 128 | b'parent: %s\n' |
|
129 | 129 | b'phase: %s\n' |
|
130 | 130 | b'summary: %s\n' |
|
131 | 131 | b'tag: %s\n' |
|
132 | 132 | b'user: %s\n' |
|
133 | 133 | ) |
|
134 | 134 | return dict( |
|
135 | 135 | zip( |
|
136 | 136 | [s.split(b':', 1)[0] for s in columns.splitlines()], |
|
137 | 137 | i18n._(columns).splitlines(True), |
|
138 | 138 | ) |
|
139 | 139 | ) |
|
140 | 140 | |
|
141 | 141 | |
|
142 | 142 | # basic internal templates |
|
143 | 143 | _changeidtmpl = b'{rev}:{node|formatnode}' |
|
144 | 144 | |
|
145 | 145 | # default templates internally used for rendering of lists |
|
146 | 146 | defaulttempl = { |
|
147 | 147 | b'parent': _changeidtmpl + b' ', |
|
148 | 148 | b'manifest': _changeidtmpl, |
|
149 | 149 | b'file_copy': b'{name} ({source})', |
|
150 | 150 | b'envvar': b'{key}={value}', |
|
151 | 151 | b'extra': b'{key}={value|stringescape}', |
|
152 | 152 | } |
|
153 | 153 | # filecopy is preserved for compatibility reasons |
|
154 | 154 | defaulttempl[b'filecopy'] = defaulttempl[b'file_copy'] |
|
155 | 155 | |
|
156 | 156 | # keywords are callables (see registrar.templatekeyword for details) |
|
157 | 157 | keywords = {} |
|
158 | 158 | templatekeyword = registrar.templatekeyword(keywords) |
|
159 | 159 | |
|
160 | 160 | |
|
161 | 161 | @templatekeyword(b'author', requires={b'ctx'}) |
|
162 | 162 | def showauthor(context, mapping): |
|
163 | 163 | """Alias for ``{user}``""" |
|
164 | 164 | return showuser(context, mapping) |
|
165 | 165 | |
|
166 | 166 | |
|
167 | 167 | @templatekeyword(b'bisect', requires={b'repo', b'ctx'}) |
|
168 | 168 | def showbisect(context, mapping): |
|
169 | 169 | """String. The changeset bisection status.""" |
|
170 | 170 | repo = context.resource(mapping, b'repo') |
|
171 | 171 | ctx = context.resource(mapping, b'ctx') |
|
172 | 172 | return hbisect.label(repo, ctx.node()) |
|
173 | 173 | |
|
174 | 174 | |
|
175 | 175 | @templatekeyword(b'branch', requires={b'ctx'}) |
|
176 | 176 | def showbranch(context, mapping): |
|
177 | 177 | """String. The name of the branch on which the changeset was |
|
178 | 178 | committed. |
|
179 | 179 | """ |
|
180 | 180 | ctx = context.resource(mapping, b'ctx') |
|
181 | 181 | return ctx.branch() |
|
182 | 182 | |
|
183 | 183 | |
|
184 | 184 | @templatekeyword(b'branches', requires={b'ctx'}) |
|
185 | 185 | def showbranches(context, mapping): |
|
186 | 186 | """List of strings. The name of the branch on which the |
|
187 | 187 | changeset was committed. Will be empty if the branch name was |
|
188 | 188 | default. (DEPRECATED) |
|
189 | 189 | """ |
|
190 | 190 | ctx = context.resource(mapping, b'ctx') |
|
191 | 191 | branch = ctx.branch() |
|
192 | 192 | if branch != b'default': |
|
193 | 193 | return compatlist( |
|
194 | 194 | context, mapping, b'branch', [branch], plural=b'branches' |
|
195 | 195 | ) |
|
196 | 196 | return compatlist(context, mapping, b'branch', [], plural=b'branches') |
|
197 | 197 | |
|
198 | 198 | |
|
199 | 199 | @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'}) |
|
200 | 200 | def showbookmarks(context, mapping): |
|
201 | 201 | """List of strings. Any bookmarks associated with the |
|
202 | 202 | changeset. Also sets 'active', the name of the active bookmark. |
|
203 | 203 | """ |
|
204 | 204 | repo = context.resource(mapping, b'repo') |
|
205 | 205 | ctx = context.resource(mapping, b'ctx') |
|
206 | 206 | bookmarks = ctx.bookmarks() |
|
207 | 207 | active = repo._activebookmark |
|
208 | 208 | makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active} |
|
209 | 209 | f = _showcompatlist(context, mapping, b'bookmark', bookmarks) |
|
210 | 210 | return _hybrid(f, bookmarks, makemap, pycompat.identity) |
|
211 | 211 | |
|
212 | 212 | |
|
213 | 213 | @templatekeyword(b'children', requires={b'ctx'}) |
|
214 | 214 | def showchildren(context, mapping): |
|
215 | 215 | """List of strings. The children of the changeset.""" |
|
216 | 216 | ctx = context.resource(mapping, b'ctx') |
|
217 | 217 | childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()] |
|
218 | 218 | return compatlist( |
|
219 | 219 | context, mapping, b'children', childrevs, element=b'child' |
|
220 | 220 | ) |
|
221 | 221 | |
|
222 | 222 | |
|
223 | 223 | # Deprecated, but kept alive for help generation a purpose. |
|
224 | 224 | @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'}) |
|
225 | 225 | def showcurrentbookmark(context, mapping): |
|
226 | 226 | """String. The active bookmark, if it is associated with the changeset. |
|
227 | 227 | (DEPRECATED)""" |
|
228 | 228 | return showactivebookmark(context, mapping) |
|
229 | 229 | |
|
230 | 230 | |
|
231 | 231 | @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'}) |
|
232 | 232 | def showactivebookmark(context, mapping): |
|
233 | 233 | """String. The active bookmark, if it is associated with the changeset.""" |
|
234 | 234 | repo = context.resource(mapping, b'repo') |
|
235 | 235 | ctx = context.resource(mapping, b'ctx') |
|
236 | 236 | active = repo._activebookmark |
|
237 | 237 | if active and active in ctx.bookmarks(): |
|
238 | 238 | return active |
|
239 | 239 | return b'' |
|
240 | 240 | |
|
241 | 241 | |
|
242 | 242 | @templatekeyword(b'date', requires={b'ctx'}) |
|
243 | 243 | def showdate(context, mapping): |
|
244 | 244 | """Date information. The date when the changeset was committed.""" |
|
245 | 245 | ctx = context.resource(mapping, b'ctx') |
|
246 | 246 | # the default string format is '<float(unixtime)><tzoffset>' because |
|
247 | 247 | # python-hglib splits date at decimal separator. |
|
248 | 248 | return templateutil.date(ctx.date(), showfmt=b'%d.0%d') |
|
249 | 249 | |
|
250 | 250 | |
|
251 | 251 | @templatekeyword(b'desc', requires={b'ctx'}) |
|
252 | 252 | def showdescription(context, mapping): |
|
253 | 253 | """String. The text of the changeset description.""" |
|
254 | 254 | ctx = context.resource(mapping, b'ctx') |
|
255 | 255 | s = ctx.description() |
|
256 | 256 | if isinstance(s, encoding.localstr): |
|
257 | 257 | # try hard to preserve utf-8 bytes |
|
258 | 258 | return encoding.tolocal(encoding.fromlocal(s).strip()) |
|
259 | 259 | elif isinstance(s, encoding.safelocalstr): |
|
260 | 260 | return encoding.safelocalstr(s.strip()) |
|
261 | 261 | else: |
|
262 | 262 | return s.strip() |
|
263 | 263 | |
|
264 | 264 | |
|
265 | 265 | @templatekeyword(b'diffstat', requires={b'ui', b'ctx'}) |
|
266 | 266 | def showdiffstat(context, mapping): |
|
267 | 267 | """String. Statistics of changes with the following format: |
|
268 | 268 | "modified files: +added/-removed lines" |
|
269 | 269 | """ |
|
270 | 270 | ui = context.resource(mapping, b'ui') |
|
271 | 271 | ctx = context.resource(mapping, b'ctx') |
|
272 | 272 | diffopts = diffutil.diffallopts(ui, {b'noprefix': False}) |
|
273 | 273 | diff = ctx.diff(opts=diffopts) |
|
274 | 274 | stats = patch.diffstatdata(util.iterlines(diff)) |
|
275 | 275 | maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats) |
|
276 | 276 | return b'%d: +%d/-%d' % (len(stats), adds, removes) |
|
277 | 277 | |
|
278 | 278 | |
|
279 | 279 | @templatekeyword(b'envvars', requires={b'ui'}) |
|
280 | 280 | def showenvvars(context, mapping): |
|
281 | 281 | """A dictionary of environment variables. (EXPERIMENTAL)""" |
|
282 | 282 | ui = context.resource(mapping, b'ui') |
|
283 | 283 | env = ui.exportableenviron() |
|
284 | 284 | env = util.sortdict((k, env[k]) for k in sorted(env)) |
|
285 | 285 | return compatdict(context, mapping, b'envvar', env, plural=b'envvars') |
|
286 | 286 | |
|
287 | 287 | |
|
288 | 288 | @templatekeyword(b'extras', requires={b'ctx'}) |
|
289 | 289 | def showextras(context, mapping): |
|
290 | 290 | """List of dicts with key, value entries of the 'extras' |
|
291 | 291 | field of this changeset.""" |
|
292 | 292 | ctx = context.resource(mapping, b'ctx') |
|
293 | 293 | extras = ctx.extra() |
|
294 | 294 | extras = util.sortdict((k, extras[k]) for k in sorted(extras)) |
|
295 | 295 | makemap = lambda k: {b'key': k, b'value': extras[k]} |
|
296 | 296 | c = [makemap(k) for k in extras] |
|
297 | 297 | f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras') |
|
298 | 298 | return _hybrid( |
|
299 | 299 | f, |
|
300 | 300 | extras, |
|
301 | 301 | makemap, |
|
302 | 302 | lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])), |
|
303 | 303 | ) |
|
304 | 304 | |
|
305 | 305 | |
|
306 | 306 | def _getfilestatus(context, mapping, listall=False): |
|
307 | 307 | ctx = context.resource(mapping, b'ctx') |
|
308 | 308 | revcache = context.resource(mapping, b'revcache') |
|
309 | 309 | if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall: |
|
310 | 310 | stat = ctx.p1().status( |
|
311 | 311 | ctx, listignored=listall, listclean=listall, listunknown=listall |
|
312 | 312 | ) |
|
313 | 313 | revcache[b'filestatus'] = stat |
|
314 | 314 | revcache[b'filestatusall'] = listall |
|
315 | 315 | return revcache[b'filestatus'] |
|
316 | 316 | |
|
317 | 317 | |
|
318 | 318 | def _getfilestatusmap(context, mapping, listall=False): |
|
319 | 319 | revcache = context.resource(mapping, b'revcache') |
|
320 | 320 | if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall: |
|
321 | 321 | stat = _getfilestatus(context, mapping, listall=listall) |
|
322 | 322 | revcache[b'filestatusmap'] = statmap = {} |
|
323 | 323 | for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat): |
|
324 | 324 | statmap.update((f, char) for f in files) |
|
325 | 325 | return revcache[b'filestatusmap'] # {path: statchar} |
|
326 | 326 | |
|
327 | 327 | |
|
328 | 328 | @templatekeyword( |
|
329 | 329 | b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'} |
|
330 | 330 | ) |
|
331 | 331 | def showfilecopies(context, mapping): |
|
332 | 332 | """List of strings. Files copied in this changeset with |
|
333 | 333 | their sources. |
|
334 | 334 | """ |
|
335 | 335 | repo = context.resource(mapping, b'repo') |
|
336 | 336 | ctx = context.resource(mapping, b'ctx') |
|
337 | 337 | cache = context.resource(mapping, b'cache') |
|
338 | 338 | copies = context.resource(mapping, b'revcache').get(b'copies') |
|
339 | 339 | if copies is None: |
|
340 | 340 | if b'getcopies' not in cache: |
|
341 | 341 | cache[b'getcopies'] = scmutil.getcopiesfn(repo) |
|
342 | 342 | getcopies = cache[b'getcopies'] |
|
343 | 343 | copies = getcopies(ctx) |
|
344 | 344 | return templateutil.compatfilecopiesdict( |
|
345 | 345 | context, mapping, b'file_copy', copies |
|
346 | 346 | ) |
|
347 | 347 | |
|
348 | 348 | |
|
349 | 349 | # showfilecopiesswitch() displays file copies only if copy records are |
|
350 | 350 | # provided before calling the templater, usually with a --copies |
|
351 | 351 | # command line switch. |
|
352 | 352 | @templatekeyword(b'file_copies_switch', requires={b'revcache'}) |
|
353 | 353 | def showfilecopiesswitch(context, mapping): |
|
354 | 354 | """List of strings. Like "file_copies" but displayed |
|
355 | 355 | only if the --copied switch is set. |
|
356 | 356 | """ |
|
357 | 357 | copies = context.resource(mapping, b'revcache').get(b'copies') or [] |
|
358 | 358 | return templateutil.compatfilecopiesdict( |
|
359 | 359 | context, mapping, b'file_copy', copies |
|
360 | 360 | ) |
|
361 | 361 | |
|
362 | 362 | |
|
363 | 363 | @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'}) |
|
364 | 364 | def showfileadds(context, mapping): |
|
365 | 365 | """List of strings. Files added by this changeset.""" |
|
366 | 366 | ctx = context.resource(mapping, b'ctx') |
|
367 | 367 | return templateutil.compatfileslist( |
|
368 | 368 | context, mapping, b'file_add', ctx.filesadded() |
|
369 | 369 | ) |
|
370 | 370 | |
|
371 | 371 | |
|
372 | 372 | @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'}) |
|
373 | 373 | def showfiledels(context, mapping): |
|
374 | 374 | """List of strings. Files removed by this changeset.""" |
|
375 | 375 | ctx = context.resource(mapping, b'ctx') |
|
376 | 376 | return templateutil.compatfileslist( |
|
377 | 377 | context, mapping, b'file_del', ctx.filesremoved() |
|
378 | 378 | ) |
|
379 | 379 | |
|
380 | 380 | |
|
381 | 381 | @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'}) |
|
382 | 382 | def showfilemods(context, mapping): |
|
383 | 383 | """List of strings. Files modified by this changeset.""" |
|
384 | 384 | ctx = context.resource(mapping, b'ctx') |
|
385 | 385 | return templateutil.compatfileslist( |
|
386 | 386 | context, mapping, b'file_mod', ctx.filesmodified() |
|
387 | 387 | ) |
|
388 | 388 | |
|
389 | 389 | |
|
390 | 390 | @templatekeyword(b'files', requires={b'ctx'}) |
|
391 | 391 | def showfiles(context, mapping): |
|
392 | 392 | """List of strings. All files modified, added, or removed by this |
|
393 | 393 | changeset. |
|
394 | 394 | """ |
|
395 | 395 | ctx = context.resource(mapping, b'ctx') |
|
396 | 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 | 400 | def showgraphnode(context, mapping): |
|
401 | 401 | """String. The character representing the changeset node in an ASCII |
|
402 | 402 | revision graph.""" |
|
403 | 403 | repo = context.resource(mapping, b'repo') |
|
404 | 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 | return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx) | |
|
409 | def getgraphnode(repo, ctx, cache): | |
|
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 | 414 | wpnodes = repo.dirstate.parents() |
|
414 | 415 | if wpnodes[1] == nullid: |
|
415 | 416 | wpnodes = wpnodes[:1] |
|
416 | 417 | if ctx.node() in wpnodes: |
|
417 | 418 | return b'@' |
|
418 | 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 | 431 | return b'' |
|
420 | 432 | |
|
421 | 433 | |
|
422 | 434 | def getgraphnodesymbol(ctx): |
|
423 | 435 | if ctx.obsolete(): |
|
424 | 436 | return b'x' |
|
425 | 437 | elif ctx.isunstable(): |
|
426 | 438 | return b'*' |
|
427 | 439 | elif ctx.closesbranch(): |
|
428 | 440 | return b'_' |
|
429 | 441 | else: |
|
430 | 442 | return b'o' |
|
431 | 443 | |
|
432 | 444 | |
|
433 | 445 | @templatekeyword(b'graphwidth', requires=()) |
|
434 | 446 | def showgraphwidth(context, mapping): |
|
435 | 447 | """Integer. The width of the graph drawn by 'log --graph' or zero.""" |
|
436 | 448 | # just hosts documentation; should be overridden by template mapping |
|
437 | 449 | return 0 |
|
438 | 450 | |
|
439 | 451 | |
|
440 | 452 | @templatekeyword(b'index', requires=()) |
|
441 | 453 | def showindex(context, mapping): |
|
442 | 454 | """Integer. The current iteration of the loop. (0 indexed)""" |
|
443 | 455 | # just hosts documentation; should be overridden by template mapping |
|
444 | 456 | raise error.Abort(_(b"can't use index in this context")) |
|
445 | 457 | |
|
446 | 458 | |
|
447 | 459 | @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'}) |
|
448 | 460 | def showlatesttag(context, mapping): |
|
449 | 461 | """List of strings. The global tags on the most recent globally |
|
450 | 462 | tagged ancestor of this changeset. If no such tags exist, the list |
|
451 | 463 | consists of the single string "null". |
|
452 | 464 | """ |
|
453 | 465 | return showlatesttags(context, mapping, None) |
|
454 | 466 | |
|
455 | 467 | |
|
456 | 468 | def showlatesttags(context, mapping, pattern): |
|
457 | 469 | """helper method for the latesttag keyword and function""" |
|
458 | 470 | latesttags = getlatesttags(context, mapping, pattern) |
|
459 | 471 | |
|
460 | 472 | # latesttag[0] is an implementation detail for sorting csets on different |
|
461 | 473 | # branches in a stable manner- it is the date the tagged cset was created, |
|
462 | 474 | # not the date the tag was created. Therefore it isn't made visible here. |
|
463 | 475 | makemap = lambda v: { |
|
464 | 476 | b'changes': _showchangessincetag, |
|
465 | 477 | b'distance': latesttags[1], |
|
466 | 478 | b'latesttag': v, # BC with {latesttag % '{latesttag}'} |
|
467 | 479 | b'tag': v, |
|
468 | 480 | } |
|
469 | 481 | |
|
470 | 482 | tags = latesttags[2] |
|
471 | 483 | f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':') |
|
472 | 484 | return _hybrid(f, tags, makemap, pycompat.identity) |
|
473 | 485 | |
|
474 | 486 | |
|
475 | 487 | @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'}) |
|
476 | 488 | def showlatesttagdistance(context, mapping): |
|
477 | 489 | """Integer. Longest path to the latest tag.""" |
|
478 | 490 | return getlatesttags(context, mapping)[1] |
|
479 | 491 | |
|
480 | 492 | |
|
481 | 493 | @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'}) |
|
482 | 494 | def showchangessincelatesttag(context, mapping): |
|
483 | 495 | """Integer. All ancestors not in the latest tag.""" |
|
484 | 496 | tag = getlatesttags(context, mapping)[2][0] |
|
485 | 497 | mapping = context.overlaymap(mapping, {b'tag': tag}) |
|
486 | 498 | return _showchangessincetag(context, mapping) |
|
487 | 499 | |
|
488 | 500 | |
|
489 | 501 | def _showchangessincetag(context, mapping): |
|
490 | 502 | repo = context.resource(mapping, b'repo') |
|
491 | 503 | ctx = context.resource(mapping, b'ctx') |
|
492 | 504 | offset = 0 |
|
493 | 505 | revs = [ctx.rev()] |
|
494 | 506 | tag = context.symbol(mapping, b'tag') |
|
495 | 507 | |
|
496 | 508 | # The only() revset doesn't currently support wdir() |
|
497 | 509 | if ctx.rev() is None: |
|
498 | 510 | offset = 1 |
|
499 | 511 | revs = [p.rev() for p in ctx.parents()] |
|
500 | 512 | |
|
501 | 513 | return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset |
|
502 | 514 | |
|
503 | 515 | |
|
504 | 516 | # teach templater latesttags.changes is switched to (context, mapping) API |
|
505 | 517 | _showchangessincetag._requires = {b'repo', b'ctx'} |
|
506 | 518 | |
|
507 | 519 | |
|
508 | 520 | @templatekeyword(b'manifest', requires={b'repo', b'ctx'}) |
|
509 | 521 | def showmanifest(context, mapping): |
|
510 | 522 | repo = context.resource(mapping, b'repo') |
|
511 | 523 | ctx = context.resource(mapping, b'ctx') |
|
512 | 524 | mnode = ctx.manifestnode() |
|
513 | 525 | if mnode is None: |
|
514 | 526 | mnode = wdirid |
|
515 | 527 | mrev = wdirrev |
|
516 | 528 | else: |
|
517 | 529 | mrev = repo.manifestlog.rev(mnode) |
|
518 | 530 | mhex = hex(mnode) |
|
519 | 531 | mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex}) |
|
520 | 532 | f = context.process(b'manifest', mapping) |
|
521 | 533 | return templateutil.hybriditem( |
|
522 | 534 | f, None, f, lambda x: {b'rev': mrev, b'node': mhex} |
|
523 | 535 | ) |
|
524 | 536 | |
|
525 | 537 | |
|
526 | 538 | @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'}) |
|
527 | 539 | def showobsfate(context, mapping): |
|
528 | 540 | # this function returns a list containing pre-formatted obsfate strings. |
|
529 | 541 | # |
|
530 | 542 | # This function will be replaced by templates fragments when we will have |
|
531 | 543 | # the verbosity templatekw available. |
|
532 | 544 | succsandmarkers = showsuccsandmarkers(context, mapping) |
|
533 | 545 | |
|
534 | 546 | ui = context.resource(mapping, b'ui') |
|
535 | 547 | repo = context.resource(mapping, b'repo') |
|
536 | 548 | values = [] |
|
537 | 549 | |
|
538 | 550 | for x in succsandmarkers.tovalue(context, mapping): |
|
539 | 551 | v = obsutil.obsfateprinter( |
|
540 | 552 | ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid |
|
541 | 553 | ) |
|
542 | 554 | values.append(v) |
|
543 | 555 | |
|
544 | 556 | return compatlist(context, mapping, b"fate", values) |
|
545 | 557 | |
|
546 | 558 | |
|
547 | 559 | def shownames(context, mapping, namespace): |
|
548 | 560 | """helper method to generate a template keyword for a namespace""" |
|
549 | 561 | repo = context.resource(mapping, b'repo') |
|
550 | 562 | ctx = context.resource(mapping, b'ctx') |
|
551 | 563 | ns = repo.names[namespace] |
|
552 | 564 | names = ns.names(repo, ctx.node()) |
|
553 | 565 | return compatlist( |
|
554 | 566 | context, mapping, ns.templatename, names, plural=namespace |
|
555 | 567 | ) |
|
556 | 568 | |
|
557 | 569 | |
|
558 | 570 | @templatekeyword(b'namespaces', requires={b'repo', b'ctx'}) |
|
559 | 571 | def shownamespaces(context, mapping): |
|
560 | 572 | """Dict of lists. Names attached to this changeset per |
|
561 | 573 | namespace.""" |
|
562 | 574 | repo = context.resource(mapping, b'repo') |
|
563 | 575 | ctx = context.resource(mapping, b'ctx') |
|
564 | 576 | |
|
565 | 577 | namespaces = util.sortdict() |
|
566 | 578 | |
|
567 | 579 | def makensmapfn(ns): |
|
568 | 580 | # 'name' for iterating over namespaces, templatename for local reference |
|
569 | 581 | return lambda v: {b'name': v, ns.templatename: v} |
|
570 | 582 | |
|
571 | 583 | for k, ns in pycompat.iteritems(repo.names): |
|
572 | 584 | names = ns.names(repo, ctx.node()) |
|
573 | 585 | f = _showcompatlist(context, mapping, b'name', names) |
|
574 | 586 | namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity) |
|
575 | 587 | |
|
576 | 588 | f = _showcompatlist(context, mapping, b'namespace', list(namespaces)) |
|
577 | 589 | |
|
578 | 590 | def makemap(ns): |
|
579 | 591 | return { |
|
580 | 592 | b'namespace': ns, |
|
581 | 593 | b'names': namespaces[ns], |
|
582 | 594 | b'builtin': repo.names[ns].builtin, |
|
583 | 595 | b'colorname': repo.names[ns].colorname, |
|
584 | 596 | } |
|
585 | 597 | |
|
586 | 598 | return _hybrid(f, namespaces, makemap, pycompat.identity) |
|
587 | 599 | |
|
588 | 600 | |
|
589 | 601 | @templatekeyword(b'negrev', requires={b'repo', b'ctx'}) |
|
590 | 602 | def shownegrev(context, mapping): |
|
591 | 603 | """Integer. The repository-local changeset negative revision number, |
|
592 | 604 | which counts in the opposite direction.""" |
|
593 | 605 | ctx = context.resource(mapping, b'ctx') |
|
594 | 606 | rev = ctx.rev() |
|
595 | 607 | if rev is None or rev < 0: # wdir() or nullrev? |
|
596 | 608 | return None |
|
597 | 609 | repo = context.resource(mapping, b'repo') |
|
598 | 610 | return rev - len(repo) |
|
599 | 611 | |
|
600 | 612 | |
|
601 | 613 | @templatekeyword(b'node', requires={b'ctx'}) |
|
602 | 614 | def shownode(context, mapping): |
|
603 | 615 | """String. The changeset identification hash, as a 40 hexadecimal |
|
604 | 616 | digit string. |
|
605 | 617 | """ |
|
606 | 618 | ctx = context.resource(mapping, b'ctx') |
|
607 | 619 | return ctx.hex() |
|
608 | 620 | |
|
609 | 621 | |
|
610 | 622 | @templatekeyword(b'obsolete', requires={b'ctx'}) |
|
611 | 623 | def showobsolete(context, mapping): |
|
612 | 624 | """String. Whether the changeset is obsolete. (EXPERIMENTAL)""" |
|
613 | 625 | ctx = context.resource(mapping, b'ctx') |
|
614 | 626 | if ctx.obsolete(): |
|
615 | 627 | return b'obsolete' |
|
616 | 628 | return b'' |
|
617 | 629 | |
|
618 | 630 | |
|
619 | 631 | @templatekeyword(b'path', requires={b'fctx'}) |
|
620 | 632 | def showpath(context, mapping): |
|
621 | 633 | """String. Repository-absolute path of the current file. (EXPERIMENTAL)""" |
|
622 | 634 | fctx = context.resource(mapping, b'fctx') |
|
623 | 635 | return fctx.path() |
|
624 | 636 | |
|
625 | 637 | |
|
626 | 638 | @templatekeyword(b'peerurls', requires={b'repo'}) |
|
627 | 639 | def showpeerurls(context, mapping): |
|
628 | 640 | """A dictionary of repository locations defined in the [paths] section |
|
629 | 641 | of your configuration file.""" |
|
630 | 642 | repo = context.resource(mapping, b'repo') |
|
631 | 643 | # see commands.paths() for naming of dictionary keys |
|
632 | 644 | paths = repo.ui.paths |
|
633 | 645 | urls = util.sortdict( |
|
634 | 646 | (k, p.rawloc) for k, p in sorted(pycompat.iteritems(paths)) |
|
635 | 647 | ) |
|
636 | 648 | |
|
637 | 649 | def makemap(k): |
|
638 | 650 | p = paths[k] |
|
639 | 651 | d = {b'name': k, b'url': p.rawloc} |
|
640 | 652 | d.update((o, v) for o, v in sorted(pycompat.iteritems(p.suboptions))) |
|
641 | 653 | return d |
|
642 | 654 | |
|
643 | 655 | return _hybrid(None, urls, makemap, lambda k: b'%s=%s' % (k, urls[k])) |
|
644 | 656 | |
|
645 | 657 | |
|
646 | 658 | @templatekeyword(b"predecessors", requires={b'repo', b'ctx'}) |
|
647 | 659 | def showpredecessors(context, mapping): |
|
648 | 660 | """Returns the list of the closest visible predecessors. (EXPERIMENTAL)""" |
|
649 | 661 | repo = context.resource(mapping, b'repo') |
|
650 | 662 | ctx = context.resource(mapping, b'ctx') |
|
651 | 663 | predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node())) |
|
652 | 664 | predecessors = pycompat.maplist(hex, predecessors) |
|
653 | 665 | |
|
654 | 666 | return _hybrid( |
|
655 | 667 | None, |
|
656 | 668 | predecessors, |
|
657 | 669 | lambda x: {b'ctx': repo[x]}, |
|
658 | 670 | lambda x: scmutil.formatchangeid(repo[x]), |
|
659 | 671 | ) |
|
660 | 672 | |
|
661 | 673 | |
|
662 | 674 | @templatekeyword(b'reporoot', requires={b'repo'}) |
|
663 | 675 | def showreporoot(context, mapping): |
|
664 | 676 | """String. The root directory of the current repository.""" |
|
665 | 677 | repo = context.resource(mapping, b'repo') |
|
666 | 678 | return repo.root |
|
667 | 679 | |
|
668 | 680 | |
|
669 | 681 | @templatekeyword(b'size', requires={b'fctx'}) |
|
670 | 682 | def showsize(context, mapping): |
|
671 | 683 | """Integer. Size of the current file in bytes. (EXPERIMENTAL)""" |
|
672 | 684 | fctx = context.resource(mapping, b'fctx') |
|
673 | 685 | return fctx.size() |
|
674 | 686 | |
|
675 | 687 | |
|
676 | 688 | # requires 'fctx' to denote {status} depends on (ctx, path) pair |
|
677 | 689 | @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'}) |
|
678 | 690 | def showstatus(context, mapping): |
|
679 | 691 | """String. Status code of the current file. (EXPERIMENTAL)""" |
|
680 | 692 | path = templateutil.runsymbol(context, mapping, b'path') |
|
681 | 693 | path = templateutil.stringify(context, mapping, path) |
|
682 | 694 | if not path: |
|
683 | 695 | return |
|
684 | 696 | statmap = _getfilestatusmap(context, mapping) |
|
685 | 697 | if path not in statmap: |
|
686 | 698 | statmap = _getfilestatusmap(context, mapping, listall=True) |
|
687 | 699 | return statmap.get(path) |
|
688 | 700 | |
|
689 | 701 | |
|
690 | 702 | @templatekeyword(b"successorssets", requires={b'repo', b'ctx'}) |
|
691 | 703 | def showsuccessorssets(context, mapping): |
|
692 | 704 | """Returns a string of sets of successors for a changectx. Format used |
|
693 | 705 | is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2 |
|
694 | 706 | while also diverged into ctx3. (EXPERIMENTAL)""" |
|
695 | 707 | repo = context.resource(mapping, b'repo') |
|
696 | 708 | ctx = context.resource(mapping, b'ctx') |
|
697 | 709 | if not ctx.obsolete(): |
|
698 | 710 | return b'' |
|
699 | 711 | |
|
700 | 712 | ssets = obsutil.successorssets(repo, ctx.node(), closest=True) |
|
701 | 713 | ssets = [[hex(n) for n in ss] for ss in ssets] |
|
702 | 714 | |
|
703 | 715 | data = [] |
|
704 | 716 | for ss in ssets: |
|
705 | 717 | h = _hybrid( |
|
706 | 718 | None, |
|
707 | 719 | ss, |
|
708 | 720 | lambda x: {b'ctx': repo[x]}, |
|
709 | 721 | lambda x: scmutil.formatchangeid(repo[x]), |
|
710 | 722 | ) |
|
711 | 723 | data.append(h) |
|
712 | 724 | |
|
713 | 725 | # Format the successorssets |
|
714 | 726 | def render(d): |
|
715 | 727 | return templateutil.stringify(context, mapping, d) |
|
716 | 728 | |
|
717 | 729 | def gen(data): |
|
718 | 730 | yield b"; ".join(render(d) for d in data) |
|
719 | 731 | |
|
720 | 732 | return _hybrid( |
|
721 | 733 | gen(data), data, lambda x: {b'successorset': x}, pycompat.identity |
|
722 | 734 | ) |
|
723 | 735 | |
|
724 | 736 | |
|
725 | 737 | @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'}) |
|
726 | 738 | def showsuccsandmarkers(context, mapping): |
|
727 | 739 | """Returns a list of dict for each final successor of ctx. The dict |
|
728 | 740 | contains successors node id in "successors" keys and the list of |
|
729 | 741 | obs-markers from ctx to the set of successors in "markers". |
|
730 | 742 | (EXPERIMENTAL) |
|
731 | 743 | """ |
|
732 | 744 | repo = context.resource(mapping, b'repo') |
|
733 | 745 | ctx = context.resource(mapping, b'ctx') |
|
734 | 746 | |
|
735 | 747 | values = obsutil.successorsandmarkers(repo, ctx) |
|
736 | 748 | |
|
737 | 749 | if values is None: |
|
738 | 750 | values = [] |
|
739 | 751 | |
|
740 | 752 | # Format successors and markers to avoid exposing binary to templates |
|
741 | 753 | data = [] |
|
742 | 754 | for i in values: |
|
743 | 755 | # Format successors |
|
744 | 756 | successors = i[b'successors'] |
|
745 | 757 | |
|
746 | 758 | successors = [hex(n) for n in successors] |
|
747 | 759 | successors = _hybrid( |
|
748 | 760 | None, |
|
749 | 761 | successors, |
|
750 | 762 | lambda x: {b'ctx': repo[x]}, |
|
751 | 763 | lambda x: scmutil.formatchangeid(repo[x]), |
|
752 | 764 | ) |
|
753 | 765 | |
|
754 | 766 | # Format markers |
|
755 | 767 | finalmarkers = [] |
|
756 | 768 | for m in i[b'markers']: |
|
757 | 769 | hexprec = hex(m[0]) |
|
758 | 770 | hexsucs = tuple(hex(n) for n in m[1]) |
|
759 | 771 | hexparents = None |
|
760 | 772 | if m[5] is not None: |
|
761 | 773 | hexparents = tuple(hex(n) for n in m[5]) |
|
762 | 774 | newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:] |
|
763 | 775 | finalmarkers.append(newmarker) |
|
764 | 776 | |
|
765 | 777 | data.append({b'successors': successors, b'markers': finalmarkers}) |
|
766 | 778 | |
|
767 | 779 | return templateutil.mappinglist(data) |
|
768 | 780 | |
|
769 | 781 | |
|
770 | 782 | @templatekeyword(b'p1', requires={b'ctx'}) |
|
771 | 783 | def showp1(context, mapping): |
|
772 | 784 | """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision |
|
773 | 785 | number, and ``{p1.node}`` for the identification hash.""" |
|
774 | 786 | ctx = context.resource(mapping, b'ctx') |
|
775 | 787 | return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl) |
|
776 | 788 | |
|
777 | 789 | |
|
778 | 790 | @templatekeyword(b'p2', requires={b'ctx'}) |
|
779 | 791 | def showp2(context, mapping): |
|
780 | 792 | """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision |
|
781 | 793 | number, and ``{p2.node}`` for the identification hash.""" |
|
782 | 794 | ctx = context.resource(mapping, b'ctx') |
|
783 | 795 | return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl) |
|
784 | 796 | |
|
785 | 797 | |
|
786 | 798 | @templatekeyword(b'p1rev', requires={b'ctx'}) |
|
787 | 799 | def showp1rev(context, mapping): |
|
788 | 800 | """Integer. The repository-local revision number of the changeset's |
|
789 | 801 | first parent, or -1 if the changeset has no parents. (DEPRECATED)""" |
|
790 | 802 | ctx = context.resource(mapping, b'ctx') |
|
791 | 803 | return ctx.p1().rev() |
|
792 | 804 | |
|
793 | 805 | |
|
794 | 806 | @templatekeyword(b'p2rev', requires={b'ctx'}) |
|
795 | 807 | def showp2rev(context, mapping): |
|
796 | 808 | """Integer. The repository-local revision number of the changeset's |
|
797 | 809 | second parent, or -1 if the changeset has no second parent. (DEPRECATED)""" |
|
798 | 810 | ctx = context.resource(mapping, b'ctx') |
|
799 | 811 | return ctx.p2().rev() |
|
800 | 812 | |
|
801 | 813 | |
|
802 | 814 | @templatekeyword(b'p1node', requires={b'ctx'}) |
|
803 | 815 | def showp1node(context, mapping): |
|
804 | 816 | """String. The identification hash of the changeset's first parent, |
|
805 | 817 | as a 40 digit hexadecimal string. If the changeset has no parents, all |
|
806 | 818 | digits are 0. (DEPRECATED)""" |
|
807 | 819 | ctx = context.resource(mapping, b'ctx') |
|
808 | 820 | return ctx.p1().hex() |
|
809 | 821 | |
|
810 | 822 | |
|
811 | 823 | @templatekeyword(b'p2node', requires={b'ctx'}) |
|
812 | 824 | def showp2node(context, mapping): |
|
813 | 825 | """String. The identification hash of the changeset's second |
|
814 | 826 | parent, as a 40 digit hexadecimal string. If the changeset has no second |
|
815 | 827 | parent, all digits are 0. (DEPRECATED)""" |
|
816 | 828 | ctx = context.resource(mapping, b'ctx') |
|
817 | 829 | return ctx.p2().hex() |
|
818 | 830 | |
|
819 | 831 | |
|
820 | 832 | @templatekeyword(b'parents', requires={b'repo', b'ctx'}) |
|
821 | 833 | def showparents(context, mapping): |
|
822 | 834 | """List of strings. The parents of the changeset in "rev:node" |
|
823 | 835 | format. If the changeset has only one "natural" parent (the predecessor |
|
824 | 836 | revision) nothing is shown.""" |
|
825 | 837 | repo = context.resource(mapping, b'repo') |
|
826 | 838 | ctx = context.resource(mapping, b'ctx') |
|
827 | 839 | pctxs = scmutil.meaningfulparents(repo, ctx) |
|
828 | 840 | prevs = [p.rev() for p in pctxs] |
|
829 | 841 | parents = [ |
|
830 | 842 | [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())] |
|
831 | 843 | for p in pctxs |
|
832 | 844 | ] |
|
833 | 845 | f = _showcompatlist(context, mapping, b'parent', parents) |
|
834 | 846 | return _hybrid( |
|
835 | 847 | f, |
|
836 | 848 | prevs, |
|
837 | 849 | lambda x: {b'ctx': repo[x]}, |
|
838 | 850 | lambda x: scmutil.formatchangeid(repo[x]), |
|
839 | 851 | keytype=int, |
|
840 | 852 | ) |
|
841 | 853 | |
|
842 | 854 | |
|
843 | 855 | @templatekeyword(b'phase', requires={b'ctx'}) |
|
844 | 856 | def showphase(context, mapping): |
|
845 | 857 | """String. The changeset phase name.""" |
|
846 | 858 | ctx = context.resource(mapping, b'ctx') |
|
847 | 859 | return ctx.phasestr() |
|
848 | 860 | |
|
849 | 861 | |
|
850 | 862 | @templatekeyword(b'phaseidx', requires={b'ctx'}) |
|
851 | 863 | def showphaseidx(context, mapping): |
|
852 | 864 | """Integer. The changeset phase index. (ADVANCED)""" |
|
853 | 865 | ctx = context.resource(mapping, b'ctx') |
|
854 | 866 | return ctx.phase() |
|
855 | 867 | |
|
856 | 868 | |
|
857 | 869 | @templatekeyword(b'rev', requires={b'ctx'}) |
|
858 | 870 | def showrev(context, mapping): |
|
859 | 871 | """Integer. The repository-local changeset revision number.""" |
|
860 | 872 | ctx = context.resource(mapping, b'ctx') |
|
861 | 873 | return scmutil.intrev(ctx) |
|
862 | 874 | |
|
863 | 875 | |
|
864 | 876 | def showrevslist(context, mapping, name, revs): |
|
865 | 877 | """helper to generate a list of revisions in which a mapped template will |
|
866 | 878 | be evaluated""" |
|
867 | 879 | repo = context.resource(mapping, b'repo') |
|
868 | 880 | # revs may be a smartset; don't compute it until f() has to be evaluated |
|
869 | 881 | def f(): |
|
870 | 882 | srevs = [b'%d' % r for r in revs] |
|
871 | 883 | return _showcompatlist(context, mapping, name, srevs) |
|
872 | 884 | |
|
873 | 885 | return _hybrid( |
|
874 | 886 | f, |
|
875 | 887 | revs, |
|
876 | 888 | lambda x: {name: x, b'ctx': repo[x]}, |
|
877 | 889 | pycompat.identity, |
|
878 | 890 | keytype=int, |
|
879 | 891 | ) |
|
880 | 892 | |
|
881 | 893 | |
|
882 | 894 | @templatekeyword(b'subrepos', requires={b'ctx'}) |
|
883 | 895 | def showsubrepos(context, mapping): |
|
884 | 896 | """List of strings. Updated subrepositories in the changeset.""" |
|
885 | 897 | ctx = context.resource(mapping, b'ctx') |
|
886 | 898 | substate = ctx.substate |
|
887 | 899 | if not substate: |
|
888 | 900 | return compatlist(context, mapping, b'subrepo', []) |
|
889 | 901 | psubstate = ctx.p1().substate or {} |
|
890 | 902 | subrepos = [] |
|
891 | 903 | for sub in substate: |
|
892 | 904 | if sub not in psubstate or substate[sub] != psubstate[sub]: |
|
893 | 905 | subrepos.append(sub) # modified or newly added in ctx |
|
894 | 906 | for sub in psubstate: |
|
895 | 907 | if sub not in substate: |
|
896 | 908 | subrepos.append(sub) # removed in ctx |
|
897 | 909 | return compatlist(context, mapping, b'subrepo', sorted(subrepos)) |
|
898 | 910 | |
|
899 | 911 | |
|
900 | 912 | # don't remove "showtags" definition, even though namespaces will put |
|
901 | 913 | # a helper function for "tags" keyword into "keywords" map automatically, |
|
902 | 914 | # because online help text is built without namespaces initialization |
|
903 | 915 | @templatekeyword(b'tags', requires={b'repo', b'ctx'}) |
|
904 | 916 | def showtags(context, mapping): |
|
905 | 917 | """List of strings. Any tags associated with the changeset.""" |
|
906 | 918 | return shownames(context, mapping, b'tags') |
|
907 | 919 | |
|
908 | 920 | |
|
909 | 921 | @templatekeyword(b'termwidth', requires={b'ui'}) |
|
910 | 922 | def showtermwidth(context, mapping): |
|
911 | 923 | """Integer. The width of the current terminal.""" |
|
912 | 924 | ui = context.resource(mapping, b'ui') |
|
913 | 925 | return ui.termwidth() |
|
914 | 926 | |
|
915 | 927 | |
|
916 | 928 | @templatekeyword(b'user', requires={b'ctx'}) |
|
917 | 929 | def showuser(context, mapping): |
|
918 | 930 | """String. The unmodified author of the changeset.""" |
|
919 | 931 | ctx = context.resource(mapping, b'ctx') |
|
920 | 932 | return ctx.user() |
|
921 | 933 | |
|
922 | 934 | |
|
923 | 935 | @templatekeyword(b'instabilities', requires={b'ctx'}) |
|
924 | 936 | def showinstabilities(context, mapping): |
|
925 | 937 | """List of strings. Evolution instabilities affecting the changeset. |
|
926 | 938 | (EXPERIMENTAL) |
|
927 | 939 | """ |
|
928 | 940 | ctx = context.resource(mapping, b'ctx') |
|
929 | 941 | return compatlist( |
|
930 | 942 | context, |
|
931 | 943 | mapping, |
|
932 | 944 | b'instability', |
|
933 | 945 | ctx.instabilities(), |
|
934 | 946 | plural=b'instabilities', |
|
935 | 947 | ) |
|
936 | 948 | |
|
937 | 949 | |
|
938 | 950 | @templatekeyword(b'verbosity', requires={b'ui'}) |
|
939 | 951 | def showverbosity(context, mapping): |
|
940 | 952 | """String. The current output verbosity in 'debug', 'quiet', 'verbose', |
|
941 | 953 | or ''.""" |
|
942 | 954 | ui = context.resource(mapping, b'ui') |
|
943 | 955 | # see logcmdutil.changesettemplater for priority of these flags |
|
944 | 956 | if ui.debugflag: |
|
945 | 957 | return b'debug' |
|
946 | 958 | elif ui.quiet: |
|
947 | 959 | return b'quiet' |
|
948 | 960 | elif ui.verbose: |
|
949 | 961 | return b'verbose' |
|
950 | 962 | return b'' |
|
951 | 963 | |
|
952 | 964 | |
|
953 | 965 | @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'}) |
|
954 | 966 | def showwhyunstable(context, mapping): |
|
955 | 967 | """List of dicts explaining all instabilities of a changeset. |
|
956 | 968 | (EXPERIMENTAL) |
|
957 | 969 | """ |
|
958 | 970 | repo = context.resource(mapping, b'repo') |
|
959 | 971 | ctx = context.resource(mapping, b'ctx') |
|
960 | 972 | |
|
961 | 973 | def formatnode(ctx): |
|
962 | 974 | return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) |
|
963 | 975 | |
|
964 | 976 | entries = obsutil.whyunstable(repo, ctx) |
|
965 | 977 | |
|
966 | 978 | for entry in entries: |
|
967 | 979 | if entry.get(b'divergentnodes'): |
|
968 | 980 | dnodes = entry[b'divergentnodes'] |
|
969 | 981 | dnhybrid = _hybrid( |
|
970 | 982 | None, |
|
971 | 983 | [dnode.hex() for dnode in dnodes], |
|
972 | 984 | lambda x: {b'ctx': repo[x]}, |
|
973 | 985 | lambda x: formatnode(repo[x]), |
|
974 | 986 | ) |
|
975 | 987 | entry[b'divergentnodes'] = dnhybrid |
|
976 | 988 | |
|
977 | 989 | tmpl = ( |
|
978 | 990 | b'{instability}:{if(divergentnodes, " ")}{divergentnodes} ' |
|
979 | 991 | b'{reason} {node|short}' |
|
980 | 992 | ) |
|
981 | 993 | return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n') |
|
982 | 994 | |
|
983 | 995 | |
|
984 | 996 | def loadkeyword(ui, extname, registrarobj): |
|
985 | 997 | """Load template keyword from specified registrarobj |
|
986 | 998 | """ |
|
987 | 999 | for name, func in pycompat.iteritems(registrarobj._table): |
|
988 | 1000 | keywords[name] = func |
|
989 | 1001 | |
|
990 | 1002 | |
|
991 | 1003 | # tell hggettext to extract docstrings from these functions: |
|
992 | 1004 | i18nfunctions = keywords.values() |
@@ -1,29 +1,34 b'' | |||
|
1 | 1 | == New Features == |
|
2 | 2 | |
|
3 | 3 | * `hg purge`/`hg clean` can now delete ignored files instead of |
|
4 | 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 | 12 | commits that are being merged, when there are conflicts. Also works |
|
8 | 13 | for conflicts caused by e.g. `hg graft`. |
|
9 | 14 | |
|
10 | 15 | |
|
11 | 16 | == New Experimental Features == |
|
12 | 17 | |
|
13 | 18 | |
|
14 | 19 | == Bug Fixes == |
|
15 | 20 | |
|
16 | 21 | |
|
17 | 22 | == Backwards Compatibility Changes == |
|
18 | 23 | |
|
19 | 24 | |
|
20 | 25 | == Internal API Changes == |
|
21 | 26 | |
|
22 | 27 | * The deprecated `ui.progress()` has now been deleted. Please use |
|
23 | 28 | `ui.makeprogress()` instead. |
|
24 | 29 | |
|
25 | 30 | * `hg.merge()` has lost its `abort` argument. Please call |
|
26 | 31 | `hg.abortmerge()` directly instead. |
|
27 | 32 | |
|
28 | 33 | * The `*others` argument of `cmdutil.check_incompatible_arguments()` |
|
29 | 34 | changed from being varargs argument to being a single collection. |
@@ -1,807 +1,807 b'' | |||
|
1 | 1 | $ hg init basic |
|
2 | 2 | $ cd basic |
|
3 | 3 | |
|
4 | 4 | should complain |
|
5 | 5 | |
|
6 | 6 | $ hg backout |
|
7 | 7 | abort: please specify a revision to backout |
|
8 | 8 | [255] |
|
9 | 9 | $ hg backout -r 0 0 |
|
10 | 10 | abort: please specify just one revision |
|
11 | 11 | [255] |
|
12 | 12 | |
|
13 | 13 | basic operation |
|
14 | 14 | (this also tests that editor is invoked if the commit message is not |
|
15 | 15 | specified explicitly) |
|
16 | 16 | |
|
17 | 17 | $ echo a > a |
|
18 | 18 | $ hg commit -d '0 0' -A -m a |
|
19 | 19 | adding a |
|
20 | 20 | $ echo b >> a |
|
21 | 21 | $ hg commit -d '1 0' -m b |
|
22 | 22 | |
|
23 | 23 | $ hg status --rev tip --rev "tip^1" |
|
24 | 24 | M a |
|
25 | 25 | $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true |
|
26 | 26 | reverting a |
|
27 | 27 | Backed out changeset a820f4f40a57 |
|
28 | 28 | |
|
29 | 29 | |
|
30 | 30 | HG: Enter commit message. Lines beginning with 'HG:' are removed. |
|
31 | 31 | HG: Leave message empty to abort commit. |
|
32 | 32 | HG: -- |
|
33 | 33 | HG: user: test |
|
34 | 34 | HG: branch 'default' |
|
35 | 35 | HG: changed a |
|
36 | 36 | changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57 |
|
37 | 37 | $ cat a |
|
38 | 38 | a |
|
39 | 39 | $ hg summary |
|
40 | 40 | parent: 2:2929462c3dff tip |
|
41 | 41 | Backed out changeset a820f4f40a57 |
|
42 | 42 | branch: default |
|
43 | 43 | commit: (clean) |
|
44 | 44 | update: (current) |
|
45 | 45 | phases: 3 draft |
|
46 | 46 | |
|
47 | 47 | commit option |
|
48 | 48 | |
|
49 | 49 | $ cd .. |
|
50 | 50 | $ hg init commit |
|
51 | 51 | $ cd commit |
|
52 | 52 | |
|
53 | 53 | $ echo tomatoes > a |
|
54 | 54 | $ hg add a |
|
55 | 55 | $ hg commit -d '0 0' -m tomatoes |
|
56 | 56 | |
|
57 | 57 | $ echo chair > b |
|
58 | 58 | $ hg add b |
|
59 | 59 | $ hg commit -d '1 0' -m chair |
|
60 | 60 | |
|
61 | 61 | $ echo grapes >> a |
|
62 | 62 | $ hg commit -d '2 0' -m grapes |
|
63 | 63 | |
|
64 | 64 | $ hg backout -d '4 0' 1 --tool=:fail |
|
65 | 65 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
66 | 66 | changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813 |
|
67 | 67 | $ hg summary |
|
68 | 68 | parent: 3:1c2161e97c0a tip |
|
69 | 69 | Backed out changeset 22cb4f70d813 |
|
70 | 70 | branch: default |
|
71 | 71 | commit: (clean) |
|
72 | 72 | update: (current) |
|
73 | 73 | phases: 4 draft |
|
74 | 74 | |
|
75 | 75 | $ echo ypples > a |
|
76 | 76 | $ hg commit -d '5 0' -m ypples |
|
77 | 77 | |
|
78 | 78 | $ hg backout -d '6 0' 2 --tool=:fail |
|
79 | 79 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
80 | 80 | use 'hg resolve' to retry unresolved file merges |
|
81 | 81 | [1] |
|
82 | 82 | $ hg summary |
|
83 | 83 | parent: 4:ed99997b793d tip |
|
84 | 84 | ypples |
|
85 | 85 | branch: default |
|
86 | 86 | commit: 1 unresolved (clean) |
|
87 | 87 | update: (current) |
|
88 | 88 | phases: 5 draft |
|
89 | 89 | $ hg log -G |
|
90 | 90 | @ changeset: 4:ed99997b793d |
|
91 | 91 | | tag: tip |
|
92 | 92 | | user: test |
|
93 | 93 | | date: Thu Jan 01 00:00:05 1970 +0000 |
|
94 | 94 | | summary: ypples |
|
95 | 95 | | |
|
96 | 96 | o changeset: 3:1c2161e97c0a |
|
97 | 97 | | user: test |
|
98 | 98 | | date: Thu Jan 01 00:00:04 1970 +0000 |
|
99 | 99 | | summary: Backed out changeset 22cb4f70d813 |
|
100 | 100 | | |
|
101 | 101 | o changeset: 2:a8c6e511cfee |
|
102 | 102 | | user: test |
|
103 | 103 | | date: Thu Jan 01 00:00:02 1970 +0000 |
|
104 | 104 | | summary: grapes |
|
105 | 105 | | |
|
106 |
|
|
|
106 | % changeset: 1:22cb4f70d813 | |
|
107 | 107 | | user: test |
|
108 | 108 | | date: Thu Jan 01 00:00:01 1970 +0000 |
|
109 | 109 | | summary: chair |
|
110 | 110 | | |
|
111 | 111 | o changeset: 0:a5cb2dde5805 |
|
112 | 112 | user: test |
|
113 | 113 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
114 | 114 | summary: tomatoes |
|
115 | 115 | |
|
116 | 116 | |
|
117 | 117 | file that was removed is recreated |
|
118 | 118 | (this also tests that editor is not invoked if the commit message is |
|
119 | 119 | specified explicitly) |
|
120 | 120 | |
|
121 | 121 | $ cd .. |
|
122 | 122 | $ hg init remove |
|
123 | 123 | $ cd remove |
|
124 | 124 | |
|
125 | 125 | $ echo content > a |
|
126 | 126 | $ hg commit -d '0 0' -A -m a |
|
127 | 127 | adding a |
|
128 | 128 | |
|
129 | 129 | $ hg rm a |
|
130 | 130 | $ hg commit -d '1 0' -m b |
|
131 | 131 | |
|
132 | 132 | $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372" |
|
133 | 133 | adding a |
|
134 | 134 | changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372 |
|
135 | 135 | $ cat a |
|
136 | 136 | content |
|
137 | 137 | $ hg summary |
|
138 | 138 | parent: 2:de31bdc76c0d tip |
|
139 | 139 | Backed out changeset 76862dcce372 |
|
140 | 140 | branch: default |
|
141 | 141 | commit: (clean) |
|
142 | 142 | update: (current) |
|
143 | 143 | phases: 3 draft |
|
144 | 144 | |
|
145 | 145 | backout of backout is as if nothing happened |
|
146 | 146 | |
|
147 | 147 | $ hg backout -d '3 0' --merge tip --tool=true |
|
148 | 148 | removing a |
|
149 | 149 | changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d |
|
150 | 150 | $ test -f a |
|
151 | 151 | [1] |
|
152 | 152 | $ hg summary |
|
153 | 153 | parent: 3:7f6d0f120113 tip |
|
154 | 154 | Backed out changeset de31bdc76c0d |
|
155 | 155 | branch: default |
|
156 | 156 | commit: (clean) |
|
157 | 157 | update: (current) |
|
158 | 158 | phases: 4 draft |
|
159 | 159 | |
|
160 | 160 | Test that 'hg rollback' restores dirstate just before opening |
|
161 | 161 | transaction: in-memory dirstate changes should be written into |
|
162 | 162 | '.hg/journal.dirstate' as expected. |
|
163 | 163 | |
|
164 | 164 | $ echo 'removed soon' > b |
|
165 | 165 | $ hg commit -A -d '4 0' -m 'prepare for subsequent removing' |
|
166 | 166 | adding b |
|
167 | 167 | $ echo 'newly added' > c |
|
168 | 168 | $ hg add c |
|
169 | 169 | $ hg remove b |
|
170 | 170 | $ hg commit -d '5 0' -m 'prepare for subsequent backout' |
|
171 | 171 | $ touch -t 200001010000 c |
|
172 | 172 | $ hg status -A |
|
173 | 173 | C c |
|
174 | 174 | $ hg debugstate --no-dates |
|
175 | 175 | n 644 12 set c |
|
176 | 176 | $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r . |
|
177 | 177 | removing c |
|
178 | 178 | adding b |
|
179 | 179 | changeset 6:4bfec048029d backs out changeset 5:fac0b729a654 |
|
180 | 180 | $ hg rollback -q |
|
181 | 181 | $ hg status -A |
|
182 | 182 | A b |
|
183 | 183 | R c |
|
184 | 184 | $ hg debugstate --no-dates |
|
185 | 185 | a 0 -1 unset b |
|
186 | 186 | r 0 0 set c |
|
187 | 187 | |
|
188 | 188 | across branch |
|
189 | 189 | |
|
190 | 190 | $ cd .. |
|
191 | 191 | $ hg init branch |
|
192 | 192 | $ cd branch |
|
193 | 193 | $ echo a > a |
|
194 | 194 | $ hg ci -Am0 |
|
195 | 195 | adding a |
|
196 | 196 | $ echo b > b |
|
197 | 197 | $ hg ci -Am1 |
|
198 | 198 | adding b |
|
199 | 199 | $ hg co -C 0 |
|
200 | 200 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
201 | 201 | $ hg summary |
|
202 | 202 | parent: 0:f7b1eb17ad24 |
|
203 | 203 | 0 |
|
204 | 204 | branch: default |
|
205 | 205 | commit: (clean) |
|
206 | 206 | update: 1 new changesets (update) |
|
207 | 207 | phases: 2 draft |
|
208 | 208 | |
|
209 | 209 | should fail |
|
210 | 210 | |
|
211 | 211 | $ hg backout 1 |
|
212 | 212 | abort: cannot backout change that is not an ancestor |
|
213 | 213 | [255] |
|
214 | 214 | $ echo c > c |
|
215 | 215 | $ hg ci -Am2 |
|
216 | 216 | adding c |
|
217 | 217 | created new head |
|
218 | 218 | $ hg summary |
|
219 | 219 | parent: 2:db815d6d32e6 tip |
|
220 | 220 | 2 |
|
221 | 221 | branch: default |
|
222 | 222 | commit: (clean) |
|
223 | 223 | update: 1 new changesets, 2 branch heads (merge) |
|
224 | 224 | phases: 3 draft |
|
225 | 225 | |
|
226 | 226 | should fail |
|
227 | 227 | |
|
228 | 228 | $ hg backout 1 |
|
229 | 229 | abort: cannot backout change that is not an ancestor |
|
230 | 230 | [255] |
|
231 | 231 | $ hg summary |
|
232 | 232 | parent: 2:db815d6d32e6 tip |
|
233 | 233 | 2 |
|
234 | 234 | branch: default |
|
235 | 235 | commit: (clean) |
|
236 | 236 | update: 1 new changesets, 2 branch heads (merge) |
|
237 | 237 | phases: 3 draft |
|
238 | 238 | |
|
239 | 239 | backout with merge |
|
240 | 240 | |
|
241 | 241 | $ cd .. |
|
242 | 242 | $ hg init merge |
|
243 | 243 | $ cd merge |
|
244 | 244 | |
|
245 | 245 | $ echo line 1 > a |
|
246 | 246 | $ echo line 2 >> a |
|
247 | 247 | $ hg commit -d '0 0' -A -m a |
|
248 | 248 | adding a |
|
249 | 249 | $ hg summary |
|
250 | 250 | parent: 0:59395513a13a tip |
|
251 | 251 | a |
|
252 | 252 | branch: default |
|
253 | 253 | commit: (clean) |
|
254 | 254 | update: (current) |
|
255 | 255 | phases: 1 draft |
|
256 | 256 | |
|
257 | 257 | remove line 1 |
|
258 | 258 | |
|
259 | 259 | $ echo line 2 > a |
|
260 | 260 | $ hg commit -d '1 0' -m b |
|
261 | 261 | |
|
262 | 262 | $ echo line 3 >> a |
|
263 | 263 | $ hg commit -d '2 0' -m c |
|
264 | 264 | |
|
265 | 265 | $ hg backout --merge -d '3 0' 1 --tool=true |
|
266 | 266 | reverting a |
|
267 | 267 | created new head |
|
268 | 268 | changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182 |
|
269 | 269 | merging with changeset 3:26b8ccb9ad91 |
|
270 | 270 | merging a |
|
271 | 271 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved |
|
272 | 272 | (branch merge, don't forget to commit) |
|
273 | 273 | $ hg commit -d '4 0' -m d |
|
274 | 274 | $ hg summary |
|
275 | 275 | parent: 4:c7df5e0b9c09 tip |
|
276 | 276 | d |
|
277 | 277 | branch: default |
|
278 | 278 | commit: (clean) |
|
279 | 279 | update: (current) |
|
280 | 280 | phases: 5 draft |
|
281 | 281 | |
|
282 | 282 | check line 1 is back |
|
283 | 283 | |
|
284 | 284 | $ cat a |
|
285 | 285 | line 1 |
|
286 | 286 | line 2 |
|
287 | 287 | line 3 |
|
288 | 288 | |
|
289 | 289 | Test visibility of in-memory dirstate changes outside transaction to |
|
290 | 290 | external hook process |
|
291 | 291 | |
|
292 | 292 | $ cat > $TESTTMP/checkvisibility.sh <<EOF |
|
293 | 293 | > echo "==== \$1:" |
|
294 | 294 | > hg parents --template "{rev}:{node|short}\n" |
|
295 | 295 | > echo "====" |
|
296 | 296 | > EOF |
|
297 | 297 | |
|
298 | 298 | "hg backout --merge REV1" at REV2 below implies steps below: |
|
299 | 299 | |
|
300 | 300 | (1) update to REV1 (REV2 => REV1) |
|
301 | 301 | (2) revert by REV1^1 |
|
302 | 302 | (3) commit backing out revision (REV3) |
|
303 | 303 | (4) update to REV2 (REV3 => REV2) |
|
304 | 304 | (5) merge with REV3 (REV2 => REV2, REV3) |
|
305 | 305 | |
|
306 | 306 | == test visibility to external preupdate hook |
|
307 | 307 | |
|
308 | 308 | $ hg update -q -C 2 |
|
309 | 309 | $ hg --config extensions.strip= strip 3 |
|
310 | 310 | saved backup bundle to * (glob) |
|
311 | 311 | |
|
312 | 312 | $ cat >> .hg/hgrc <<EOF |
|
313 | 313 | > [hooks] |
|
314 | 314 | > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate |
|
315 | 315 | > EOF |
|
316 | 316 | |
|
317 | 317 | ("-m" is needed to avoid writing dirstate changes out at other than |
|
318 | 318 | invocation of the hook to be examined) |
|
319 | 319 | |
|
320 | 320 | $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment' |
|
321 | 321 | ==== preupdate: |
|
322 | 322 | 2:6ea3f2a197a2 |
|
323 | 323 | ==== |
|
324 | 324 | reverting a |
|
325 | 325 | created new head |
|
326 | 326 | changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182 |
|
327 | 327 | ==== preupdate: |
|
328 | 328 | 3:d92a3f57f067 |
|
329 | 329 | ==== |
|
330 | 330 | merging with changeset 3:d92a3f57f067 |
|
331 | 331 | ==== preupdate: |
|
332 | 332 | 2:6ea3f2a197a2 |
|
333 | 333 | ==== |
|
334 | 334 | merging a |
|
335 | 335 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved |
|
336 | 336 | (branch merge, don't forget to commit) |
|
337 | 337 | |
|
338 | 338 | $ cat >> .hg/hgrc <<EOF |
|
339 | 339 | > [hooks] |
|
340 | 340 | > preupdate.visibility = |
|
341 | 341 | > EOF |
|
342 | 342 | |
|
343 | 343 | == test visibility to external update hook |
|
344 | 344 | |
|
345 | 345 | $ hg update -q -C 2 |
|
346 | 346 | $ hg --config extensions.strip= strip 3 |
|
347 | 347 | saved backup bundle to * (glob) |
|
348 | 348 | |
|
349 | 349 | $ cat >> .hg/hgrc <<EOF |
|
350 | 350 | > [hooks] |
|
351 | 351 | > update.visibility = sh $TESTTMP/checkvisibility.sh update |
|
352 | 352 | > EOF |
|
353 | 353 | |
|
354 | 354 | $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment' |
|
355 | 355 | ==== update: |
|
356 | 356 | 1:5a50a024c182 |
|
357 | 357 | ==== |
|
358 | 358 | reverting a |
|
359 | 359 | created new head |
|
360 | 360 | changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182 |
|
361 | 361 | ==== update: |
|
362 | 362 | 2:6ea3f2a197a2 |
|
363 | 363 | ==== |
|
364 | 364 | merging with changeset 3:d92a3f57f067 |
|
365 | 365 | merging a |
|
366 | 366 | ==== update: |
|
367 | 367 | 2:6ea3f2a197a2 |
|
368 | 368 | 3:d92a3f57f067 |
|
369 | 369 | ==== |
|
370 | 370 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved |
|
371 | 371 | (branch merge, don't forget to commit) |
|
372 | 372 | |
|
373 | 373 | $ cat >> .hg/hgrc <<EOF |
|
374 | 374 | > [hooks] |
|
375 | 375 | > update.visibility = |
|
376 | 376 | > EOF |
|
377 | 377 | |
|
378 | 378 | $ cd .. |
|
379 | 379 | |
|
380 | 380 | backout should not back out subsequent changesets |
|
381 | 381 | |
|
382 | 382 | $ hg init onecs |
|
383 | 383 | $ cd onecs |
|
384 | 384 | $ echo 1 > a |
|
385 | 385 | $ hg commit -d '0 0' -A -m a |
|
386 | 386 | adding a |
|
387 | 387 | $ echo 2 >> a |
|
388 | 388 | $ hg commit -d '1 0' -m b |
|
389 | 389 | $ echo 1 > b |
|
390 | 390 | $ hg commit -d '2 0' -A -m c |
|
391 | 391 | adding b |
|
392 | 392 | $ hg summary |
|
393 | 393 | parent: 2:882396649954 tip |
|
394 | 394 | c |
|
395 | 395 | branch: default |
|
396 | 396 | commit: (clean) |
|
397 | 397 | update: (current) |
|
398 | 398 | phases: 3 draft |
|
399 | 399 | |
|
400 | 400 | without --merge |
|
401 | 401 | $ hg backout --no-commit -d '3 0' 1 --tool=true |
|
402 | 402 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
403 | 403 | changeset 22bca4c721e5 backed out, don't forget to commit. |
|
404 | 404 | $ hg locate b |
|
405 | 405 | b |
|
406 | 406 | $ hg update -C tip |
|
407 | 407 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
408 | 408 | $ hg locate b |
|
409 | 409 | b |
|
410 | 410 | $ hg summary |
|
411 | 411 | parent: 2:882396649954 tip |
|
412 | 412 | c |
|
413 | 413 | branch: default |
|
414 | 414 | commit: (clean) |
|
415 | 415 | update: (current) |
|
416 | 416 | phases: 3 draft |
|
417 | 417 | |
|
418 | 418 | with --merge |
|
419 | 419 | $ hg backout --merge -d '3 0' 1 --tool=true |
|
420 | 420 | reverting a |
|
421 | 421 | created new head |
|
422 | 422 | changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5 |
|
423 | 423 | merging with changeset 3:3202beb76721 |
|
424 | 424 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
425 | 425 | (branch merge, don't forget to commit) |
|
426 | 426 | $ hg locate b |
|
427 | 427 | b |
|
428 | 428 | $ hg update -C tip |
|
429 | 429 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
430 | 430 | $ hg locate b |
|
431 | 431 | [1] |
|
432 | 432 | |
|
433 | 433 | $ cd .. |
|
434 | 434 | $ hg init m |
|
435 | 435 | $ cd m |
|
436 | 436 | $ echo a > a |
|
437 | 437 | $ hg commit -d '0 0' -A -m a |
|
438 | 438 | adding a |
|
439 | 439 | $ echo b > b |
|
440 | 440 | $ hg commit -d '1 0' -A -m b |
|
441 | 441 | adding b |
|
442 | 442 | $ echo c > c |
|
443 | 443 | $ hg commit -d '2 0' -A -m b |
|
444 | 444 | adding c |
|
445 | 445 | $ hg update 1 |
|
446 | 446 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
447 | 447 | $ echo d > d |
|
448 | 448 | $ hg commit -d '3 0' -A -m c |
|
449 | 449 | adding d |
|
450 | 450 | created new head |
|
451 | 451 | $ hg merge 2 |
|
452 | 452 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
453 | 453 | (branch merge, don't forget to commit) |
|
454 | 454 | $ hg commit -d '4 0' -A -m d |
|
455 | 455 | $ hg summary |
|
456 | 456 | parent: 4:b2f3bb92043e tip |
|
457 | 457 | d |
|
458 | 458 | branch: default |
|
459 | 459 | commit: (clean) |
|
460 | 460 | update: (current) |
|
461 | 461 | phases: 5 draft |
|
462 | 462 | |
|
463 | 463 | backout of merge should fail |
|
464 | 464 | |
|
465 | 465 | $ hg backout 4 |
|
466 | 466 | abort: cannot backout a merge changeset |
|
467 | 467 | [255] |
|
468 | 468 | |
|
469 | 469 | backout of merge with bad parent should fail |
|
470 | 470 | |
|
471 | 471 | $ hg backout --parent 0 4 |
|
472 | 472 | abort: cb9a9f314b8b is not a parent of b2f3bb92043e |
|
473 | 473 | [255] |
|
474 | 474 | |
|
475 | 475 | backout of non-merge with parent should fail |
|
476 | 476 | |
|
477 | 477 | $ hg backout --parent 0 3 |
|
478 | 478 | abort: cannot use --parent on non-merge changeset |
|
479 | 479 | [255] |
|
480 | 480 | |
|
481 | 481 | backout with valid parent should be ok |
|
482 | 482 | |
|
483 | 483 | $ hg backout -d '5 0' --parent 2 4 --tool=true |
|
484 | 484 | removing d |
|
485 | 485 | changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e |
|
486 | 486 | $ hg summary |
|
487 | 487 | parent: 5:10e5328c8435 tip |
|
488 | 488 | Backed out changeset b2f3bb92043e |
|
489 | 489 | branch: default |
|
490 | 490 | commit: (clean) |
|
491 | 491 | update: (current) |
|
492 | 492 | phases: 6 draft |
|
493 | 493 | |
|
494 | 494 | $ hg rollback |
|
495 | 495 | repository tip rolled back to revision 4 (undo commit) |
|
496 | 496 | working directory now based on revision 4 |
|
497 | 497 | $ hg update -C |
|
498 | 498 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
499 | 499 | $ hg summary |
|
500 | 500 | parent: 4:b2f3bb92043e tip |
|
501 | 501 | d |
|
502 | 502 | branch: default |
|
503 | 503 | commit: (clean) |
|
504 | 504 | update: (current) |
|
505 | 505 | phases: 5 draft |
|
506 | 506 | |
|
507 | 507 | $ hg backout -d '6 0' --parent 3 4 --tool=true |
|
508 | 508 | removing c |
|
509 | 509 | changeset 5:033590168430 backs out changeset 4:b2f3bb92043e |
|
510 | 510 | $ hg summary |
|
511 | 511 | parent: 5:033590168430 tip |
|
512 | 512 | Backed out changeset b2f3bb92043e |
|
513 | 513 | branch: default |
|
514 | 514 | commit: (clean) |
|
515 | 515 | update: (current) |
|
516 | 516 | phases: 6 draft |
|
517 | 517 | |
|
518 | 518 | $ cd .. |
|
519 | 519 | |
|
520 | 520 | named branches |
|
521 | 521 | |
|
522 | 522 | $ hg init named_branches |
|
523 | 523 | $ cd named_branches |
|
524 | 524 | |
|
525 | 525 | $ echo default > default |
|
526 | 526 | $ hg ci -d '0 0' -Am default |
|
527 | 527 | adding default |
|
528 | 528 | $ hg branch branch1 |
|
529 | 529 | marked working directory as branch branch1 |
|
530 | 530 | (branches are permanent and global, did you want a bookmark?) |
|
531 | 531 | $ echo branch1 > file1 |
|
532 | 532 | $ hg ci -d '1 0' -Am file1 |
|
533 | 533 | adding file1 |
|
534 | 534 | $ hg branch branch2 |
|
535 | 535 | marked working directory as branch branch2 |
|
536 | 536 | $ echo branch2 > file2 |
|
537 | 537 | $ hg ci -d '2 0' -Am file2 |
|
538 | 538 | adding file2 |
|
539 | 539 | |
|
540 | 540 | without --merge |
|
541 | 541 | $ hg backout --no-commit -r 1 --tool=true |
|
542 | 542 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
543 | 543 | changeset bf1602f437f3 backed out, don't forget to commit. |
|
544 | 544 | $ hg branch |
|
545 | 545 | branch2 |
|
546 | 546 | $ hg status -A |
|
547 | 547 | R file1 |
|
548 | 548 | C default |
|
549 | 549 | C file2 |
|
550 | 550 | $ hg summary |
|
551 | 551 | parent: 2:45bbcd363bf0 tip |
|
552 | 552 | file2 |
|
553 | 553 | branch: branch2 |
|
554 | 554 | commit: 1 removed |
|
555 | 555 | update: (current) |
|
556 | 556 | phases: 3 draft |
|
557 | 557 | |
|
558 | 558 | with --merge |
|
559 | 559 | (this also tests that editor is invoked if '--edit' is specified |
|
560 | 560 | explicitly regardless of '--message') |
|
561 | 561 | |
|
562 | 562 | $ hg update -qC |
|
563 | 563 | $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit |
|
564 | 564 | removing file1 |
|
565 | 565 | backout on branch1 |
|
566 | 566 | |
|
567 | 567 | |
|
568 | 568 | HG: Enter commit message. Lines beginning with 'HG:' are removed. |
|
569 | 569 | HG: Leave message empty to abort commit. |
|
570 | 570 | HG: -- |
|
571 | 571 | HG: user: test |
|
572 | 572 | HG: branch 'branch2' |
|
573 | 573 | HG: removed file1 |
|
574 | 574 | created new head |
|
575 | 575 | changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3 |
|
576 | 576 | merging with changeset 3:d4e8f6db59fb |
|
577 | 577 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
578 | 578 | (branch merge, don't forget to commit) |
|
579 | 579 | $ hg summary |
|
580 | 580 | parent: 2:45bbcd363bf0 |
|
581 | 581 | file2 |
|
582 | 582 | parent: 3:d4e8f6db59fb tip |
|
583 | 583 | backout on branch1 |
|
584 | 584 | branch: branch2 |
|
585 | 585 | commit: 1 removed (merge) |
|
586 | 586 | update: (current) |
|
587 | 587 | phases: 4 draft |
|
588 | 588 | $ hg update -q -C 2 |
|
589 | 589 | |
|
590 | 590 | on branch2 with branch1 not merged, so file1 should still exist: |
|
591 | 591 | |
|
592 | 592 | $ hg id |
|
593 | 593 | 45bbcd363bf0 (branch2) |
|
594 | 594 | $ hg st -A |
|
595 | 595 | C default |
|
596 | 596 | C file1 |
|
597 | 597 | C file2 |
|
598 | 598 | $ hg summary |
|
599 | 599 | parent: 2:45bbcd363bf0 |
|
600 | 600 | file2 |
|
601 | 601 | branch: branch2 |
|
602 | 602 | commit: (clean) |
|
603 | 603 | update: 1 new changesets, 2 branch heads (merge) |
|
604 | 604 | phases: 4 draft |
|
605 | 605 | |
|
606 | 606 | on branch2 with branch1 merged, so file1 should be gone: |
|
607 | 607 | |
|
608 | 608 | $ hg merge |
|
609 | 609 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
610 | 610 | (branch merge, don't forget to commit) |
|
611 | 611 | $ hg ci -d '4 0' -m 'merge backout of branch1' |
|
612 | 612 | $ hg id |
|
613 | 613 | d97a8500a969 (branch2) tip |
|
614 | 614 | $ hg st -A |
|
615 | 615 | C default |
|
616 | 616 | C file2 |
|
617 | 617 | $ hg summary |
|
618 | 618 | parent: 4:d97a8500a969 tip |
|
619 | 619 | merge backout of branch1 |
|
620 | 620 | branch: branch2 |
|
621 | 621 | commit: (clean) |
|
622 | 622 | update: (current) |
|
623 | 623 | phases: 5 draft |
|
624 | 624 | |
|
625 | 625 | on branch1, so no file1 and file2: |
|
626 | 626 | |
|
627 | 627 | $ hg co -C branch1 |
|
628 | 628 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
629 | 629 | $ hg id |
|
630 | 630 | bf1602f437f3 (branch1) |
|
631 | 631 | $ hg st -A |
|
632 | 632 | C default |
|
633 | 633 | C file1 |
|
634 | 634 | $ hg summary |
|
635 | 635 | parent: 1:bf1602f437f3 |
|
636 | 636 | file1 |
|
637 | 637 | branch: branch1 |
|
638 | 638 | commit: (clean) |
|
639 | 639 | update: (current) |
|
640 | 640 | phases: 5 draft |
|
641 | 641 | |
|
642 | 642 | $ cd .. |
|
643 | 643 | |
|
644 | 644 | backout of empty changeset (issue4190) |
|
645 | 645 | |
|
646 | 646 | $ hg init emptycommit |
|
647 | 647 | $ cd emptycommit |
|
648 | 648 | |
|
649 | 649 | $ touch file1 |
|
650 | 650 | $ hg ci -Aqm file1 |
|
651 | 651 | $ hg branch -q branch1 |
|
652 | 652 | $ hg ci -qm branch1 |
|
653 | 653 | $ hg backout -v 1 |
|
654 | 654 | resolving manifests |
|
655 | 655 | nothing changed |
|
656 | 656 | [1] |
|
657 | 657 | |
|
658 | 658 | $ cd .. |
|
659 | 659 | |
|
660 | 660 | |
|
661 | 661 | Test usage of `hg resolve` in case of conflict |
|
662 | 662 | (issue4163) |
|
663 | 663 | |
|
664 | 664 | $ hg init issue4163 |
|
665 | 665 | $ cd issue4163 |
|
666 | 666 | $ touch foo |
|
667 | 667 | $ hg add foo |
|
668 | 668 | $ cat > foo << EOF |
|
669 | 669 | > one |
|
670 | 670 | > two |
|
671 | 671 | > three |
|
672 | 672 | > four |
|
673 | 673 | > five |
|
674 | 674 | > six |
|
675 | 675 | > seven |
|
676 | 676 | > height |
|
677 | 677 | > nine |
|
678 | 678 | > ten |
|
679 | 679 | > EOF |
|
680 | 680 | $ hg ci -m 'initial' |
|
681 | 681 | $ cat > foo << EOF |
|
682 | 682 | > one |
|
683 | 683 | > two |
|
684 | 684 | > THREE |
|
685 | 685 | > four |
|
686 | 686 | > five |
|
687 | 687 | > six |
|
688 | 688 | > seven |
|
689 | 689 | > height |
|
690 | 690 | > nine |
|
691 | 691 | > ten |
|
692 | 692 | > EOF |
|
693 | 693 | $ hg ci -m 'capital three' |
|
694 | 694 | $ cat > foo << EOF |
|
695 | 695 | > one |
|
696 | 696 | > two |
|
697 | 697 | > THREE |
|
698 | 698 | > four |
|
699 | 699 | > five |
|
700 | 700 | > six |
|
701 | 701 | > seven |
|
702 | 702 | > height |
|
703 | 703 | > nine |
|
704 | 704 | > TEN |
|
705 | 705 | > EOF |
|
706 | 706 | $ hg ci -m 'capital ten' |
|
707 | 707 | $ hg backout -r 'desc("capital three")' --tool internal:fail |
|
708 | 708 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
709 | 709 | use 'hg resolve' to retry unresolved file merges |
|
710 | 710 | [1] |
|
711 | 711 | $ hg status |
|
712 | 712 | $ hg debugmergestate |
|
713 | 713 | * version 2 records |
|
714 | 714 | local: b71750c4b0fdf719734971e3ef90dbeab5919a2d |
|
715 | 715 | other: a30dd8addae3ce71b8667868478542bc417439e6 |
|
716 | 716 | file extras: foo (ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553) |
|
717 | 717 | file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33) |
|
718 | 718 | local path: foo (flags "") |
|
719 | 719 | ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708) |
|
720 | 720 | other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee) |
|
721 | 721 | $ mv .hg/merge/state2 .hg/merge/state2-moved |
|
722 | 722 | $ hg debugmergestate |
|
723 | 723 | * version 1 records |
|
724 | 724 | local: b71750c4b0fdf719734971e3ef90dbeab5919a2d |
|
725 | 725 | file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33) |
|
726 | 726 | local path: foo (flags "") |
|
727 | 727 | ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708) |
|
728 | 728 | other path: foo (node not stored in v1 format) |
|
729 | 729 | $ mv .hg/merge/state2-moved .hg/merge/state2 |
|
730 | 730 | $ hg resolve -l # still unresolved |
|
731 | 731 | U foo |
|
732 | 732 | $ hg summary |
|
733 | 733 | parent: 2:b71750c4b0fd tip |
|
734 | 734 | capital ten |
|
735 | 735 | branch: default |
|
736 | 736 | commit: 1 unresolved (clean) |
|
737 | 737 | update: (current) |
|
738 | 738 | phases: 3 draft |
|
739 | 739 | $ hg log -G |
|
740 | 740 | @ changeset: 2:b71750c4b0fd |
|
741 | 741 | | tag: tip |
|
742 | 742 | | user: test |
|
743 | 743 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
744 | 744 | | summary: capital ten |
|
745 | 745 | | |
|
746 | 746 | o changeset: 1:913609522437 |
|
747 | 747 | | user: test |
|
748 | 748 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
749 | 749 | | summary: capital three |
|
750 | 750 | | |
|
751 |
|
|
|
751 | % changeset: 0:a30dd8addae3 | |
|
752 | 752 | user: test |
|
753 | 753 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
754 | 754 | summary: initial |
|
755 | 755 | |
|
756 | 756 | $ hg resolve --all --debug |
|
757 | 757 | picked tool ':merge' for foo (binary False symlink False changedelete False) |
|
758 | 758 | merging foo |
|
759 | 759 | my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437 |
|
760 | 760 | premerge successful |
|
761 | 761 | (no more unresolved files) |
|
762 | 762 | continue: hg commit |
|
763 | 763 | $ hg status |
|
764 | 764 | M foo |
|
765 | 765 | ? foo.orig |
|
766 | 766 | $ hg resolve -l |
|
767 | 767 | R foo |
|
768 | 768 | $ hg summary |
|
769 | 769 | parent: 2:b71750c4b0fd tip |
|
770 | 770 | capital ten |
|
771 | 771 | branch: default |
|
772 | 772 | commit: 1 modified, 1 unknown |
|
773 | 773 | update: (current) |
|
774 | 774 | phases: 3 draft |
|
775 | 775 | $ cat foo |
|
776 | 776 | one |
|
777 | 777 | two |
|
778 | 778 | three |
|
779 | 779 | four |
|
780 | 780 | five |
|
781 | 781 | six |
|
782 | 782 | seven |
|
783 | 783 | height |
|
784 | 784 | nine |
|
785 | 785 | TEN |
|
786 | 786 | |
|
787 | 787 | --no-commit shouldn't commit |
|
788 | 788 | |
|
789 | 789 | $ hg init a |
|
790 | 790 | $ cd a |
|
791 | 791 | $ for i in 1 2 3; do |
|
792 | 792 | > touch $i |
|
793 | 793 | > hg ci -Am $i |
|
794 | 794 | > done |
|
795 | 795 | adding 1 |
|
796 | 796 | adding 2 |
|
797 | 797 | adding 3 |
|
798 | 798 | $ hg backout --no-commit . |
|
799 | 799 | removing 3 |
|
800 | 800 | changeset cccc23d9d68f backed out, don't forget to commit. |
|
801 | 801 | $ hg revert -aq |
|
802 | 802 | |
|
803 | 803 | --no-commit can't be used with --merge |
|
804 | 804 | |
|
805 | 805 | $ hg backout --merge --no-commit 2 |
|
806 | 806 | abort: cannot use --merge with --no-commit |
|
807 | 807 | [255] |
@@ -1,771 +1,771 b'' | |||
|
1 | 1 | #testcases abortcommand abortflag |
|
2 | 2 | |
|
3 | 3 | #if abortflag |
|
4 | 4 | $ cat >> $HGRCPATH <<EOF |
|
5 | 5 | > [alias] |
|
6 | 6 | > abort = graft --abort |
|
7 | 7 | > EOF |
|
8 | 8 | #endif |
|
9 | 9 | |
|
10 | 10 | |
|
11 | 11 | Testing the reading of old format graftstate file with newer mercurial |
|
12 | 12 | |
|
13 | 13 | $ hg init oldgraft |
|
14 | 14 | $ cd oldgraft |
|
15 | 15 | $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -Aqm "added "$ch; done; |
|
16 | 16 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
17 | 17 | @ 2:8be98ac1a569 added c |
|
18 | 18 | | |
|
19 | 19 | o 1:80e6d2c47cfe added b |
|
20 | 20 | | |
|
21 | 21 | o 0:f7ad41964313 added a |
|
22 | 22 | |
|
23 | 23 | $ hg up 0 |
|
24 | 24 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
25 | 25 | $ echo bar > b |
|
26 | 26 | $ hg add b |
|
27 | 27 | $ hg ci -m "bar to b" |
|
28 | 28 | created new head |
|
29 | 29 | $ hg graft -r 1 -r 2 |
|
30 | 30 | grafting 1:80e6d2c47cfe "added b" |
|
31 | 31 | merging b |
|
32 | 32 | warning: conflicts while merging b! (edit, then use 'hg resolve --mark') |
|
33 | 33 | abort: unresolved conflicts, can't continue |
|
34 | 34 | (use 'hg resolve' and 'hg graft --continue') |
|
35 | 35 | [255] |
|
36 | 36 | |
|
37 | 37 | Writing the nodes in old format to graftstate |
|
38 | 38 | |
|
39 | 39 | $ hg log -r 1 -r 2 -T '{node}\n' > .hg/graftstate |
|
40 | 40 | $ echo foo > b |
|
41 | 41 | $ hg resolve -m |
|
42 | 42 | (no more unresolved files) |
|
43 | 43 | continue: hg graft --continue |
|
44 | 44 | $ hg graft --continue |
|
45 | 45 | grafting 1:80e6d2c47cfe "added b" |
|
46 | 46 | grafting 2:8be98ac1a569 "added c" |
|
47 | 47 | |
|
48 | 48 | Testing that --user is preserved during conflicts and value is reused while |
|
49 | 49 | running `hg graft --continue` |
|
50 | 50 | |
|
51 | 51 | $ hg log -G |
|
52 | 52 | @ changeset: 5:711e9fa999f1 |
|
53 | 53 | | tag: tip |
|
54 | 54 | | user: test |
|
55 | 55 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
56 | 56 | | summary: added c |
|
57 | 57 | | |
|
58 | 58 | o changeset: 4:e5ad7353b408 |
|
59 | 59 | | user: test |
|
60 | 60 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
61 | 61 | | summary: added b |
|
62 | 62 | | |
|
63 | 63 | o changeset: 3:9e887f7a939c |
|
64 | 64 | | parent: 0:f7ad41964313 |
|
65 | 65 | | user: test |
|
66 | 66 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
67 | 67 | | summary: bar to b |
|
68 | 68 | | |
|
69 | 69 | | o changeset: 2:8be98ac1a569 |
|
70 | 70 | | | user: test |
|
71 | 71 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
72 | 72 | | | summary: added c |
|
73 | 73 | | | |
|
74 | 74 | | o changeset: 1:80e6d2c47cfe |
|
75 | 75 | |/ user: test |
|
76 | 76 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
77 | 77 | | summary: added b |
|
78 | 78 | | |
|
79 | 79 | o changeset: 0:f7ad41964313 |
|
80 | 80 | user: test |
|
81 | 81 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
82 | 82 | summary: added a |
|
83 | 83 | |
|
84 | 84 | |
|
85 | 85 | $ hg up '.^^' |
|
86 | 86 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
87 | 87 | |
|
88 | 88 | $ hg graft -r 1 -r 2 --user batman |
|
89 | 89 | grafting 1:80e6d2c47cfe "added b" |
|
90 | 90 | merging b |
|
91 | 91 | warning: conflicts while merging b! (edit, then use 'hg resolve --mark') |
|
92 | 92 | abort: unresolved conflicts, can't continue |
|
93 | 93 | (use 'hg resolve' and 'hg graft --continue') |
|
94 | 94 | [255] |
|
95 | 95 | |
|
96 | 96 | $ echo wat > b |
|
97 | 97 | $ hg resolve -m |
|
98 | 98 | (no more unresolved files) |
|
99 | 99 | continue: hg graft --continue |
|
100 | 100 | |
|
101 | 101 | $ hg graft --continue |
|
102 | 102 | grafting 1:80e6d2c47cfe "added b" |
|
103 | 103 | grafting 2:8be98ac1a569 "added c" |
|
104 | 104 | |
|
105 | 105 | $ hg log -Gr 3:: |
|
106 | 106 | @ changeset: 7:11a36ffaacf2 |
|
107 | 107 | | tag: tip |
|
108 | 108 | | user: batman |
|
109 | 109 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
110 | 110 | | summary: added c |
|
111 | 111 | | |
|
112 | 112 | o changeset: 6:76803afc6511 |
|
113 | 113 | | parent: 3:9e887f7a939c |
|
114 | 114 | | user: batman |
|
115 | 115 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
116 | 116 | | summary: added b |
|
117 | 117 | | |
|
118 | 118 | | o changeset: 5:711e9fa999f1 |
|
119 | 119 | | | user: test |
|
120 | 120 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
121 | 121 | | | summary: added c |
|
122 | 122 | | | |
|
123 | 123 | | o changeset: 4:e5ad7353b408 |
|
124 | 124 | |/ user: test |
|
125 | 125 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
126 | 126 | | summary: added b |
|
127 | 127 | | |
|
128 | 128 | o changeset: 3:9e887f7a939c |
|
129 | 129 | | parent: 0:f7ad41964313 |
|
130 | 130 | ~ user: test |
|
131 | 131 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
132 | 132 | summary: bar to b |
|
133 | 133 | |
|
134 | 134 | Test that --date is preserved and reused in `hg graft --continue` |
|
135 | 135 | |
|
136 | 136 | $ hg up '.^^' |
|
137 | 137 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
138 | 138 | $ hg graft -r 1 -r 2 --date '1234560000 120' |
|
139 | 139 | grafting 1:80e6d2c47cfe "added b" |
|
140 | 140 | merging b |
|
141 | 141 | warning: conflicts while merging b! (edit, then use 'hg resolve --mark') |
|
142 | 142 | abort: unresolved conflicts, can't continue |
|
143 | 143 | (use 'hg resolve' and 'hg graft --continue') |
|
144 | 144 | [255] |
|
145 | 145 | |
|
146 | 146 | $ echo foobar > b |
|
147 | 147 | $ hg resolve -m |
|
148 | 148 | (no more unresolved files) |
|
149 | 149 | continue: hg graft --continue |
|
150 | 150 | $ hg graft --continue |
|
151 | 151 | grafting 1:80e6d2c47cfe "added b" |
|
152 | 152 | grafting 2:8be98ac1a569 "added c" |
|
153 | 153 | |
|
154 | 154 | $ hg log -Gr '.^^::.' |
|
155 | 155 | @ changeset: 9:1896b76e007a |
|
156 | 156 | | tag: tip |
|
157 | 157 | | user: test |
|
158 | 158 | | date: Fri Feb 13 21:18:00 2009 -0002 |
|
159 | 159 | | summary: added c |
|
160 | 160 | | |
|
161 | 161 | o changeset: 8:ce2b4f1632af |
|
162 | 162 | | parent: 3:9e887f7a939c |
|
163 | 163 | | user: test |
|
164 | 164 | | date: Fri Feb 13 21:18:00 2009 -0002 |
|
165 | 165 | | summary: added b |
|
166 | 166 | | |
|
167 | 167 | o changeset: 3:9e887f7a939c |
|
168 | 168 | | parent: 0:f7ad41964313 |
|
169 | 169 | ~ user: test |
|
170 | 170 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
171 | 171 | summary: bar to b |
|
172 | 172 | |
|
173 | 173 | Test that --log is preserved and reused in `hg graft --continue` |
|
174 | 174 | |
|
175 | 175 | $ hg up '.^^' |
|
176 | 176 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
177 | 177 | $ hg graft -r 1 -r 2 --log |
|
178 | 178 | grafting 1:80e6d2c47cfe "added b" |
|
179 | 179 | merging b |
|
180 | 180 | warning: conflicts while merging b! (edit, then use 'hg resolve --mark') |
|
181 | 181 | abort: unresolved conflicts, can't continue |
|
182 | 182 | (use 'hg resolve' and 'hg graft --continue') |
|
183 | 183 | [255] |
|
184 | 184 | |
|
185 | 185 | $ echo foobar > b |
|
186 | 186 | $ hg resolve -m |
|
187 | 187 | (no more unresolved files) |
|
188 | 188 | continue: hg graft --continue |
|
189 | 189 | |
|
190 | 190 | $ hg graft --continue |
|
191 | 191 | grafting 1:80e6d2c47cfe "added b" |
|
192 | 192 | grafting 2:8be98ac1a569 "added c" |
|
193 | 193 | |
|
194 | 194 | $ hg log -GT "{rev}:{node|short} {desc}" -r '.^^::.' |
|
195 | 195 | @ 11:30c1050a58b2 added c |
|
196 | 196 | | (grafted from 8be98ac1a56990c2d9ca6861041b8390af7bd6f3) |
|
197 | 197 | o 10:ec7eda2313e2 added b |
|
198 | 198 | | (grafted from 80e6d2c47cfe5b3185519568327a17a061c7efb6) |
|
199 | 199 | o 3:9e887f7a939c bar to b |
|
200 | 200 | | |
|
201 | 201 | ~ |
|
202 | 202 | |
|
203 | 203 | $ cd .. |
|
204 | 204 | |
|
205 | 205 | Testing the --stop flag of `hg graft` which stops the interrupted graft |
|
206 | 206 | |
|
207 | 207 | $ hg init stopgraft |
|
208 | 208 | $ cd stopgraft |
|
209 | 209 | $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done; |
|
210 | 210 | |
|
211 | 211 | $ hg log -G |
|
212 | 212 | @ changeset: 3:9150fe93bec6 |
|
213 | 213 | | tag: tip |
|
214 | 214 | | user: test |
|
215 | 215 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
216 | 216 | | summary: added d |
|
217 | 217 | | |
|
218 | 218 | o changeset: 2:155349b645be |
|
219 | 219 | | user: test |
|
220 | 220 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
221 | 221 | | summary: added c |
|
222 | 222 | | |
|
223 | 223 | o changeset: 1:5f6d8a4bf34a |
|
224 | 224 | | user: test |
|
225 | 225 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
226 | 226 | | summary: added b |
|
227 | 227 | | |
|
228 | 228 | o changeset: 0:9092f1db7931 |
|
229 | 229 | user: test |
|
230 | 230 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
231 | 231 | summary: added a |
|
232 | 232 | |
|
233 | 233 | $ hg up '.^^' |
|
234 | 234 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
235 | 235 | |
|
236 | 236 | $ echo foo > d |
|
237 | 237 | $ hg ci -Aqm "added foo to d" |
|
238 | 238 | |
|
239 | 239 | $ hg graft --stop |
|
240 | 240 | abort: no interrupted graft found |
|
241 | 241 | [255] |
|
242 | 242 | |
|
243 | 243 | $ hg graft -r 3 |
|
244 | 244 | grafting 3:9150fe93bec6 "added d" |
|
245 | 245 | merging d |
|
246 | 246 | warning: conflicts while merging d! (edit, then use 'hg resolve --mark') |
|
247 | 247 | abort: unresolved conflicts, can't continue |
|
248 | 248 | (use 'hg resolve' and 'hg graft --continue') |
|
249 | 249 | [255] |
|
250 | 250 | |
|
251 | 251 | $ hg graft --stop --continue |
|
252 | 252 | abort: cannot use '--continue' and '--stop' together |
|
253 | 253 | [255] |
|
254 | 254 | |
|
255 | 255 | $ hg graft --stop -U |
|
256 | 256 | abort: cannot specify any other flag with '--stop' |
|
257 | 257 | [255] |
|
258 | 258 | $ hg graft --stop --rev 4 |
|
259 | 259 | abort: cannot specify any other flag with '--stop' |
|
260 | 260 | [255] |
|
261 | 261 | $ hg graft --stop --log |
|
262 | 262 | abort: cannot specify any other flag with '--stop' |
|
263 | 263 | [255] |
|
264 | 264 | |
|
265 | 265 | $ hg graft --stop |
|
266 | 266 | stopped the interrupted graft |
|
267 | 267 | working directory is now at a0deacecd59d |
|
268 | 268 | |
|
269 | 269 | $ hg diff |
|
270 | 270 | |
|
271 | 271 | $ hg log -Gr '.' |
|
272 | 272 | @ changeset: 4:a0deacecd59d |
|
273 | 273 | | tag: tip |
|
274 | 274 | ~ parent: 1:5f6d8a4bf34a |
|
275 | 275 | user: test |
|
276 | 276 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
277 | 277 | summary: added foo to d |
|
278 | 278 | |
|
279 | 279 | $ hg graft -r 2 -r 3 |
|
280 | 280 | grafting 2:155349b645be "added c" |
|
281 | 281 | grafting 3:9150fe93bec6 "added d" |
|
282 | 282 | merging d |
|
283 | 283 | warning: conflicts while merging d! (edit, then use 'hg resolve --mark') |
|
284 | 284 | abort: unresolved conflicts, can't continue |
|
285 | 285 | (use 'hg resolve' and 'hg graft --continue') |
|
286 | 286 | [255] |
|
287 | 287 | |
|
288 | 288 | $ hg graft --stop |
|
289 | 289 | stopped the interrupted graft |
|
290 | 290 | working directory is now at 75b447541a9e |
|
291 | 291 | |
|
292 | 292 | $ hg diff |
|
293 | 293 | |
|
294 | 294 | $ hg log -G -T "{rev}:{node|short} {desc}" |
|
295 | 295 | @ 5:75b447541a9e added c |
|
296 | 296 | | |
|
297 | 297 | o 4:a0deacecd59d added foo to d |
|
298 | 298 | | |
|
299 | 299 | | o 3:9150fe93bec6 added d |
|
300 | 300 | | | |
|
301 | 301 | | o 2:155349b645be added c |
|
302 | 302 | |/ |
|
303 | 303 | o 1:5f6d8a4bf34a added b |
|
304 | 304 | | |
|
305 | 305 | o 0:9092f1db7931 added a |
|
306 | 306 | |
|
307 | 307 | $ cd .. |
|
308 | 308 | |
|
309 | 309 | Testing the --abort flag for `hg graft` which aborts and rollback to state |
|
310 | 310 | before the graft |
|
311 | 311 | |
|
312 | 312 | $ hg init abortgraft |
|
313 | 313 | $ cd abortgraft |
|
314 | 314 | $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done; |
|
315 | 315 | |
|
316 | 316 | $ hg up '.^^' |
|
317 | 317 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
318 | 318 | |
|
319 | 319 | $ echo x > x |
|
320 | 320 | $ hg ci -Aqm "added x" |
|
321 | 321 | $ hg up '.^' |
|
322 | 322 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
323 | 323 | $ echo foo > c |
|
324 | 324 | $ hg ci -Aqm "added foo to c" |
|
325 | 325 | |
|
326 | 326 | $ hg log -GT "{rev}:{node|short} {desc}" |
|
327 | 327 | @ 5:36b793615f78 added foo to c |
|
328 | 328 | | |
|
329 | 329 | | o 4:863a25e1a9ea added x |
|
330 | 330 | |/ |
|
331 | 331 | | o 3:9150fe93bec6 added d |
|
332 | 332 | | | |
|
333 | 333 | | o 2:155349b645be added c |
|
334 | 334 | |/ |
|
335 | 335 | o 1:5f6d8a4bf34a added b |
|
336 | 336 | | |
|
337 | 337 | o 0:9092f1db7931 added a |
|
338 | 338 | |
|
339 | 339 | $ hg up 9150fe93bec6 |
|
340 | 340 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
341 | 341 | |
|
342 | 342 | $ hg abort |
|
343 | 343 | abort: no interrupted graft to abort (abortflag !) |
|
344 | 344 | abort: no operation in progress (abortcommand !) |
|
345 | 345 | [255] |
|
346 | 346 | |
|
347 | 347 | when stripping is required |
|
348 | 348 | $ hg graft -r 4 -r 5 |
|
349 | 349 | grafting 4:863a25e1a9ea "added x" |
|
350 | 350 | grafting 5:36b793615f78 "added foo to c" (tip) |
|
351 | 351 | merging c |
|
352 | 352 | warning: conflicts while merging c! (edit, then use 'hg resolve --mark') |
|
353 | 353 | abort: unresolved conflicts, can't continue |
|
354 | 354 | (use 'hg resolve' and 'hg graft --continue') |
|
355 | 355 | [255] |
|
356 | 356 | |
|
357 | 357 | $ hg graft --continue --abort |
|
358 | 358 | abort: cannot use '--continue' and '--abort' together |
|
359 | 359 | [255] |
|
360 | 360 | |
|
361 | 361 | $ hg graft --abort --stop |
|
362 | 362 | abort: cannot use '--abort' and '--stop' together |
|
363 | 363 | [255] |
|
364 | 364 | |
|
365 | 365 | $ hg graft --abort --currentuser |
|
366 | 366 | abort: cannot specify any other flag with '--abort' |
|
367 | 367 | [255] |
|
368 | 368 | |
|
369 | 369 | $ hg graft --abort --edit |
|
370 | 370 | abort: cannot specify any other flag with '--abort' |
|
371 | 371 | [255] |
|
372 | 372 | |
|
373 | 373 | #if abortcommand |
|
374 | 374 | when in dry-run mode |
|
375 | 375 | $ hg abort --dry-run |
|
376 | 376 | graft in progress, will be aborted |
|
377 | 377 | #endif |
|
378 | 378 | |
|
379 | 379 | $ hg abort |
|
380 | 380 | graft aborted |
|
381 | 381 | working directory is now at 9150fe93bec6 |
|
382 | 382 | $ hg log -GT "{rev}:{node|short} {desc}" |
|
383 | 383 | o 5:36b793615f78 added foo to c |
|
384 | 384 | | |
|
385 | 385 | | o 4:863a25e1a9ea added x |
|
386 | 386 | |/ |
|
387 | 387 | | @ 3:9150fe93bec6 added d |
|
388 | 388 | | | |
|
389 | 389 | | o 2:155349b645be added c |
|
390 | 390 | |/ |
|
391 | 391 | o 1:5f6d8a4bf34a added b |
|
392 | 392 | | |
|
393 | 393 | o 0:9092f1db7931 added a |
|
394 | 394 | |
|
395 | 395 | when stripping is not required |
|
396 | 396 | $ hg graft -r 5 |
|
397 | 397 | grafting 5:36b793615f78 "added foo to c" (tip) |
|
398 | 398 | merging c |
|
399 | 399 | warning: conflicts while merging c! (edit, then use 'hg resolve --mark') |
|
400 | 400 | abort: unresolved conflicts, can't continue |
|
401 | 401 | (use 'hg resolve' and 'hg graft --continue') |
|
402 | 402 | [255] |
|
403 | 403 | |
|
404 | 404 | $ hg abort |
|
405 | 405 | graft aborted |
|
406 | 406 | working directory is now at 9150fe93bec6 |
|
407 | 407 | $ hg log -GT "{rev}:{node|short} {desc}" |
|
408 | 408 | o 5:36b793615f78 added foo to c |
|
409 | 409 | | |
|
410 | 410 | | o 4:863a25e1a9ea added x |
|
411 | 411 | |/ |
|
412 | 412 | | @ 3:9150fe93bec6 added d |
|
413 | 413 | | | |
|
414 | 414 | | o 2:155349b645be added c |
|
415 | 415 | |/ |
|
416 | 416 | o 1:5f6d8a4bf34a added b |
|
417 | 417 | | |
|
418 | 418 | o 0:9092f1db7931 added a |
|
419 | 419 | |
|
420 | 420 | when some of the changesets became public |
|
421 | 421 | |
|
422 | 422 | $ hg graft -r 4 -r 5 |
|
423 | 423 | grafting 4:863a25e1a9ea "added x" |
|
424 | 424 | grafting 5:36b793615f78 "added foo to c" (tip) |
|
425 | 425 | merging c |
|
426 | 426 | warning: conflicts while merging c! (edit, then use 'hg resolve --mark') |
|
427 | 427 | abort: unresolved conflicts, can't continue |
|
428 | 428 | (use 'hg resolve' and 'hg graft --continue') |
|
429 | 429 | [255] |
|
430 | 430 | |
|
431 | 431 | $ hg log -GT "{rev}:{node|short} {desc}" |
|
432 | 432 | @ 6:6ec71c037d94 added x |
|
433 | 433 | | |
|
434 |
| |
|
|
434 | | % 5:36b793615f78 added foo to c | |
|
435 | 435 | | | |
|
436 | 436 | | | o 4:863a25e1a9ea added x |
|
437 | 437 | | |/ |
|
438 | 438 | o | 3:9150fe93bec6 added d |
|
439 | 439 | | | |
|
440 | 440 | o | 2:155349b645be added c |
|
441 | 441 | |/ |
|
442 | 442 | o 1:5f6d8a4bf34a added b |
|
443 | 443 | | |
|
444 | 444 | o 0:9092f1db7931 added a |
|
445 | 445 | |
|
446 | 446 | $ hg phase -r 6 --public |
|
447 | 447 | |
|
448 | 448 | $ hg abort |
|
449 | 449 | cannot clean up public changesets 6ec71c037d94 |
|
450 | 450 | graft aborted |
|
451 | 451 | working directory is now at 6ec71c037d94 |
|
452 | 452 | |
|
453 | 453 | when we created new changesets on top of existing one |
|
454 | 454 | |
|
455 | 455 | $ hg up '.^^' |
|
456 | 456 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
457 | 457 | $ echo y > y |
|
458 | 458 | $ hg ci -Aqm "added y" |
|
459 | 459 | $ echo z > z |
|
460 | 460 | $ hg ci -Aqm "added z" |
|
461 | 461 | |
|
462 | 462 | $ hg up 3 |
|
463 | 463 | 1 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
464 | 464 | $ hg log -GT "{rev}:{node|short} {desc}" |
|
465 | 465 | o 8:637f9e9bbfd4 added z |
|
466 | 466 | | |
|
467 | 467 | o 7:123221671fd4 added y |
|
468 | 468 | | |
|
469 | 469 | | o 6:6ec71c037d94 added x |
|
470 | 470 | | | |
|
471 | 471 | | | o 5:36b793615f78 added foo to c |
|
472 | 472 | | | | |
|
473 | 473 | | | | o 4:863a25e1a9ea added x |
|
474 | 474 | | | |/ |
|
475 | 475 | | @ | 3:9150fe93bec6 added d |
|
476 | 476 | |/ / |
|
477 | 477 | o / 2:155349b645be added c |
|
478 | 478 | |/ |
|
479 | 479 | o 1:5f6d8a4bf34a added b |
|
480 | 480 | | |
|
481 | 481 | o 0:9092f1db7931 added a |
|
482 | 482 | |
|
483 | 483 | $ hg graft -r 8 -r 7 -r 5 |
|
484 | 484 | grafting 8:637f9e9bbfd4 "added z" (tip) |
|
485 | 485 | grafting 7:123221671fd4 "added y" |
|
486 | 486 | grafting 5:36b793615f78 "added foo to c" |
|
487 | 487 | merging c |
|
488 | 488 | warning: conflicts while merging c! (edit, then use 'hg resolve --mark') |
|
489 | 489 | abort: unresolved conflicts, can't continue |
|
490 | 490 | (use 'hg resolve' and 'hg graft --continue') |
|
491 | 491 | [255] |
|
492 | 492 | |
|
493 | 493 | $ cd .. |
|
494 | 494 | $ hg init pullrepo |
|
495 | 495 | $ cd pullrepo |
|
496 | 496 | $ cat >> .hg/hgrc <<EOF |
|
497 | 497 | > [phases] |
|
498 | 498 | > publish=False |
|
499 | 499 | > EOF |
|
500 | 500 | $ hg pull ../abortgraft --config phases.publish=False |
|
501 | 501 | pulling from ../abortgraft |
|
502 | 502 | requesting all changes |
|
503 | 503 | adding changesets |
|
504 | 504 | adding manifests |
|
505 | 505 | adding file changes |
|
506 | 506 | added 11 changesets with 9 changes to 8 files (+4 heads) |
|
507 | 507 | new changesets 9092f1db7931:6b98ff0062dd (6 drafts) |
|
508 | 508 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
509 | 509 | $ hg up 9 |
|
510 | 510 | 5 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
511 | 511 | $ echo w > w |
|
512 | 512 | $ hg ci -Aqm "added w" --config phases.publish=False |
|
513 | 513 | |
|
514 | 514 | $ cd ../abortgraft |
|
515 | 515 | $ hg pull ../pullrepo |
|
516 | 516 | pulling from ../pullrepo |
|
517 | 517 | searching for changes |
|
518 | 518 | adding changesets |
|
519 | 519 | adding manifests |
|
520 | 520 | adding file changes |
|
521 | 521 | added 1 changesets with 1 changes to 1 files (+1 heads) |
|
522 | 522 | new changesets 311dfc6cf3bf (1 drafts) |
|
523 | 523 | (run 'hg heads .' to see heads, 'hg merge' to merge) |
|
524 | 524 | |
|
525 | 525 | $ hg abort |
|
526 | 526 | new changesets detected on destination branch, can't strip |
|
527 | 527 | graft aborted |
|
528 | 528 | working directory is now at 6b98ff0062dd |
|
529 | 529 | |
|
530 | 530 | $ cd .. |
|
531 | 531 | |
|
532 | 532 | ============================ |
|
533 | 533 | Testing --no-commit option:| |
|
534 | 534 | ============================ |
|
535 | 535 | |
|
536 | 536 | $ hg init nocommit |
|
537 | 537 | $ cd nocommit |
|
538 | 538 | $ echo a > a |
|
539 | 539 | $ hg ci -qAma |
|
540 | 540 | $ echo b > b |
|
541 | 541 | $ hg ci -qAmb |
|
542 | 542 | $ hg up -q 0 |
|
543 | 543 | $ echo c > c |
|
544 | 544 | $ hg ci -qAmc |
|
545 | 545 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
546 | 546 | @ 2:d36c0562f908 c |
|
547 | 547 | | |
|
548 | 548 | | o 1:d2ae7f538514 b |
|
549 | 549 | |/ |
|
550 | 550 | o 0:cb9a9f314b8b a |
|
551 | 551 | |
|
552 | 552 | |
|
553 | 553 | Check reporting when --no-commit used with non-applicable options: |
|
554 | 554 | |
|
555 | 555 | $ hg graft 1 --no-commit -e |
|
556 | 556 | abort: cannot specify --no-commit and --edit together |
|
557 | 557 | [255] |
|
558 | 558 | |
|
559 | 559 | $ hg graft 1 --no-commit --log |
|
560 | 560 | abort: cannot specify --no-commit and --log together |
|
561 | 561 | [255] |
|
562 | 562 | |
|
563 | 563 | $ hg graft 1 --no-commit -D |
|
564 | 564 | abort: cannot specify --no-commit and --currentdate together |
|
565 | 565 | [255] |
|
566 | 566 | |
|
567 | 567 | Test --no-commit is working: |
|
568 | 568 | $ hg graft 1 --no-commit |
|
569 | 569 | grafting 1:d2ae7f538514 "b" |
|
570 | 570 | |
|
571 | 571 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
572 | 572 | @ 2:d36c0562f908 c |
|
573 | 573 | | |
|
574 | 574 | | o 1:d2ae7f538514 b |
|
575 | 575 | |/ |
|
576 | 576 | o 0:cb9a9f314b8b a |
|
577 | 577 | |
|
578 | 578 | |
|
579 | 579 | $ hg diff |
|
580 | 580 | diff -r d36c0562f908 b |
|
581 | 581 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 |
|
582 | 582 | +++ b/b Thu Jan 01 00:00:00 1970 +0000 |
|
583 | 583 | @@ -0,0 +1,1 @@ |
|
584 | 584 | +b |
|
585 | 585 | |
|
586 | 586 | Prepare wrdir to check --no-commit is resepected after --continue: |
|
587 | 587 | |
|
588 | 588 | $ hg up -qC |
|
589 | 589 | $ echo A>a |
|
590 | 590 | $ hg ci -qm "A in file a" |
|
591 | 591 | $ hg up -q 1 |
|
592 | 592 | $ echo B>a |
|
593 | 593 | $ hg ci -qm "B in file a" |
|
594 | 594 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
595 | 595 | @ 4:2aa9ad1006ff B in file a |
|
596 | 596 | | |
|
597 | 597 | | o 3:09e253b87e17 A in file a |
|
598 | 598 | | | |
|
599 | 599 | | o 2:d36c0562f908 c |
|
600 | 600 | | | |
|
601 | 601 | o | 1:d2ae7f538514 b |
|
602 | 602 | |/ |
|
603 | 603 | o 0:cb9a9f314b8b a |
|
604 | 604 | |
|
605 | 605 | |
|
606 | 606 | $ hg graft 3 --no-commit |
|
607 | 607 | grafting 3:09e253b87e17 "A in file a" |
|
608 | 608 | merging a |
|
609 | 609 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') |
|
610 | 610 | abort: unresolved conflicts, can't continue |
|
611 | 611 | (use 'hg resolve' and 'hg graft --continue') |
|
612 | 612 | [255] |
|
613 | 613 | |
|
614 | 614 | Resolve conflict: |
|
615 | 615 | $ echo A>a |
|
616 | 616 | $ hg resolve --mark |
|
617 | 617 | (no more unresolved files) |
|
618 | 618 | continue: hg graft --continue |
|
619 | 619 | |
|
620 | 620 | $ hg graft --continue |
|
621 | 621 | grafting 3:09e253b87e17 "A in file a" |
|
622 | 622 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
623 | 623 | @ 4:2aa9ad1006ff B in file a |
|
624 | 624 | | |
|
625 |
| |
|
|
625 | | % 3:09e253b87e17 A in file a | |
|
626 | 626 | | | |
|
627 | 627 | | o 2:d36c0562f908 c |
|
628 | 628 | | | |
|
629 | 629 | o | 1:d2ae7f538514 b |
|
630 | 630 | |/ |
|
631 | 631 | o 0:cb9a9f314b8b a |
|
632 | 632 | |
|
633 | 633 | $ hg diff |
|
634 | 634 | diff -r 2aa9ad1006ff a |
|
635 | 635 | --- a/a Thu Jan 01 00:00:00 1970 +0000 |
|
636 | 636 | +++ b/a Thu Jan 01 00:00:00 1970 +0000 |
|
637 | 637 | @@ -1,1 +1,1 @@ |
|
638 | 638 | -B |
|
639 | 639 | +A |
|
640 | 640 | |
|
641 | 641 | $ hg up -qC |
|
642 | 642 | |
|
643 | 643 | Check --no-commit is resepected when passed with --continue: |
|
644 | 644 | |
|
645 | 645 | $ hg graft 3 |
|
646 | 646 | grafting 3:09e253b87e17 "A in file a" |
|
647 | 647 | merging a |
|
648 | 648 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') |
|
649 | 649 | abort: unresolved conflicts, can't continue |
|
650 | 650 | (use 'hg resolve' and 'hg graft --continue') |
|
651 | 651 | [255] |
|
652 | 652 | |
|
653 | 653 | Resolve conflict: |
|
654 | 654 | $ echo A>a |
|
655 | 655 | $ hg resolve --mark |
|
656 | 656 | (no more unresolved files) |
|
657 | 657 | continue: hg graft --continue |
|
658 | 658 | |
|
659 | 659 | $ hg graft --continue --no-commit |
|
660 | 660 | grafting 3:09e253b87e17 "A in file a" |
|
661 | 661 | $ hg diff |
|
662 | 662 | diff -r 2aa9ad1006ff a |
|
663 | 663 | --- a/a Thu Jan 01 00:00:00 1970 +0000 |
|
664 | 664 | +++ b/a Thu Jan 01 00:00:00 1970 +0000 |
|
665 | 665 | @@ -1,1 +1,1 @@ |
|
666 | 666 | -B |
|
667 | 667 | +A |
|
668 | 668 | |
|
669 | 669 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
670 | 670 | @ 4:2aa9ad1006ff B in file a |
|
671 | 671 | | |
|
672 |
| |
|
|
672 | | % 3:09e253b87e17 A in file a | |
|
673 | 673 | | | |
|
674 | 674 | | o 2:d36c0562f908 c |
|
675 | 675 | | | |
|
676 | 676 | o | 1:d2ae7f538514 b |
|
677 | 677 | |/ |
|
678 | 678 | o 0:cb9a9f314b8b a |
|
679 | 679 | |
|
680 | 680 | $ hg up -qC |
|
681 | 681 | |
|
682 | 682 | Test --no-commit when graft multiple revisions: |
|
683 | 683 | When there is conflict: |
|
684 | 684 | $ hg graft -r "2::3" --no-commit |
|
685 | 685 | grafting 2:d36c0562f908 "c" |
|
686 | 686 | grafting 3:09e253b87e17 "A in file a" |
|
687 | 687 | merging a |
|
688 | 688 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') |
|
689 | 689 | abort: unresolved conflicts, can't continue |
|
690 | 690 | (use 'hg resolve' and 'hg graft --continue') |
|
691 | 691 | [255] |
|
692 | 692 | |
|
693 | 693 | $ echo A>a |
|
694 | 694 | $ hg resolve --mark |
|
695 | 695 | (no more unresolved files) |
|
696 | 696 | continue: hg graft --continue |
|
697 | 697 | $ hg graft --continue |
|
698 | 698 | grafting 3:09e253b87e17 "A in file a" |
|
699 | 699 | $ hg diff |
|
700 | 700 | diff -r 2aa9ad1006ff a |
|
701 | 701 | --- a/a Thu Jan 01 00:00:00 1970 +0000 |
|
702 | 702 | +++ b/a Thu Jan 01 00:00:00 1970 +0000 |
|
703 | 703 | @@ -1,1 +1,1 @@ |
|
704 | 704 | -B |
|
705 | 705 | +A |
|
706 | 706 | diff -r 2aa9ad1006ff c |
|
707 | 707 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 |
|
708 | 708 | +++ b/c Thu Jan 01 00:00:00 1970 +0000 |
|
709 | 709 | @@ -0,0 +1,1 @@ |
|
710 | 710 | +c |
|
711 | 711 | |
|
712 | 712 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
713 | 713 | @ 4:2aa9ad1006ff B in file a |
|
714 | 714 | | |
|
715 |
| |
|
|
715 | | % 3:09e253b87e17 A in file a | |
|
716 | 716 | | | |
|
717 | 717 | | o 2:d36c0562f908 c |
|
718 | 718 | | | |
|
719 | 719 | o | 1:d2ae7f538514 b |
|
720 | 720 | |/ |
|
721 | 721 | o 0:cb9a9f314b8b a |
|
722 | 722 | |
|
723 | 723 | $ hg up -qC |
|
724 | 724 | |
|
725 | 725 | When there is no conflict: |
|
726 | 726 | $ echo d>d |
|
727 | 727 | $ hg add d -q |
|
728 | 728 | $ hg ci -qmd |
|
729 | 729 | $ hg up 3 -q |
|
730 | 730 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
731 | 731 | o 5:baefa8927fc0 d |
|
732 | 732 | | |
|
733 | 733 | o 4:2aa9ad1006ff B in file a |
|
734 | 734 | | |
|
735 | 735 | | @ 3:09e253b87e17 A in file a |
|
736 | 736 | | | |
|
737 | 737 | | o 2:d36c0562f908 c |
|
738 | 738 | | | |
|
739 | 739 | o | 1:d2ae7f538514 b |
|
740 | 740 | |/ |
|
741 | 741 | o 0:cb9a9f314b8b a |
|
742 | 742 | |
|
743 | 743 | |
|
744 | 744 | $ hg graft -r 1 -r 5 --no-commit |
|
745 | 745 | grafting 1:d2ae7f538514 "b" |
|
746 | 746 | grafting 5:baefa8927fc0 "d" (tip) |
|
747 | 747 | $ hg diff |
|
748 | 748 | diff -r 09e253b87e17 b |
|
749 | 749 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 |
|
750 | 750 | +++ b/b Thu Jan 01 00:00:00 1970 +0000 |
|
751 | 751 | @@ -0,0 +1,1 @@ |
|
752 | 752 | +b |
|
753 | 753 | diff -r 09e253b87e17 d |
|
754 | 754 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 |
|
755 | 755 | +++ b/d Thu Jan 01 00:00:00 1970 +0000 |
|
756 | 756 | @@ -0,0 +1,1 @@ |
|
757 | 757 | +d |
|
758 | 758 | $ hg log -GT "{rev}:{node|short} {desc}\n" |
|
759 | 759 | o 5:baefa8927fc0 d |
|
760 | 760 | | |
|
761 | 761 | o 4:2aa9ad1006ff B in file a |
|
762 | 762 | | |
|
763 | 763 | | @ 3:09e253b87e17 A in file a |
|
764 | 764 | | | |
|
765 | 765 | | o 2:d36c0562f908 c |
|
766 | 766 | | | |
|
767 | 767 | o | 1:d2ae7f538514 b |
|
768 | 768 | |/ |
|
769 | 769 | o 0:cb9a9f314b8b a |
|
770 | 770 | |
|
771 | 771 | $ cd .. |
@@ -1,776 +1,776 b'' | |||
|
1 | 1 | $ cat >> $HGRCPATH <<EOF |
|
2 | 2 | > [extensions] |
|
3 | 3 | > rebase= |
|
4 | 4 | > mq= |
|
5 | 5 | > drawdag=$TESTDIR/drawdag.py |
|
6 | 6 | > |
|
7 | 7 | > [phases] |
|
8 | 8 | > publish=False |
|
9 | 9 | > |
|
10 | 10 | > [alias] |
|
11 | 11 | > tglog = log -G --template "{rev}: {node|short} '{desc}' {branches}\n" |
|
12 | 12 | > tglogp = log -G --template "{rev}: {node|short} {phase} '{desc}' {branches}\n" |
|
13 | 13 | > EOF |
|
14 | 14 | |
|
15 | 15 | Highest phase of source commits is used: |
|
16 | 16 | |
|
17 | 17 | $ hg init phase |
|
18 | 18 | $ cd phase |
|
19 | 19 | $ hg debugdrawdag << 'EOF' |
|
20 | 20 | > D |
|
21 | 21 | > | |
|
22 | 22 | > F C |
|
23 | 23 | > | | |
|
24 | 24 | > E B |
|
25 | 25 | > |/ |
|
26 | 26 | > A |
|
27 | 27 | > EOF |
|
28 | 28 | |
|
29 | 29 | $ hg phase --force --secret D |
|
30 | 30 | |
|
31 | 31 | $ cat > $TESTTMP/editor.sh <<EOF |
|
32 | 32 | > echo "==== before editing" |
|
33 | 33 | > cat \$1 |
|
34 | 34 | > echo "====" |
|
35 | 35 | > echo "edited manually" >> \$1 |
|
36 | 36 | > EOF |
|
37 | 37 | $ HGEDITOR="sh $TESTTMP/editor.sh" hg rebase --collapse --keepbranches -e --source B --dest F |
|
38 | 38 | rebasing 1:112478962961 "B" (B) |
|
39 | 39 | rebasing 3:26805aba1e60 "C" (C) |
|
40 | 40 | rebasing 5:f585351a92f8 "D" (D tip) |
|
41 | 41 | ==== before editing |
|
42 | 42 | Collapsed revision |
|
43 | 43 | * B |
|
44 | 44 | * C |
|
45 | 45 | * D |
|
46 | 46 | |
|
47 | 47 | |
|
48 | 48 | HG: Enter commit message. Lines beginning with 'HG:' are removed. |
|
49 | 49 | HG: Leave message empty to abort commit. |
|
50 | 50 | HG: -- |
|
51 | 51 | HG: user: test |
|
52 | 52 | HG: branch 'default' |
|
53 | 53 | HG: added B |
|
54 | 54 | HG: added C |
|
55 | 55 | HG: added D |
|
56 | 56 | ==== |
|
57 | 57 | saved backup bundle to $TESTTMP/phase/.hg/strip-backup/112478962961-cb2a9b47-rebase.hg |
|
58 | 58 | |
|
59 | 59 | $ hg tglogp |
|
60 | 60 | o 3: 92fa5f5fe108 secret 'Collapsed revision |
|
61 | 61 | | * B |
|
62 | 62 | | * C |
|
63 | 63 | | * D |
|
64 | 64 | | |
|
65 | 65 | | |
|
66 | 66 | | edited manually' |
|
67 | 67 | o 2: 64a8289d2492 draft 'F' |
|
68 | 68 | | |
|
69 | 69 | o 1: 7fb047a69f22 draft 'E' |
|
70 | 70 | | |
|
71 | 71 | o 0: 426bada5c675 draft 'A' |
|
72 | 72 | |
|
73 | 73 | $ hg manifest --rev tip |
|
74 | 74 | A |
|
75 | 75 | B |
|
76 | 76 | C |
|
77 | 77 | D |
|
78 | 78 | E |
|
79 | 79 | F |
|
80 | 80 | |
|
81 | 81 | $ cd .. |
|
82 | 82 | |
|
83 | 83 | |
|
84 | 84 | Merge gets linearized: |
|
85 | 85 | |
|
86 | 86 | $ hg init linearized-merge |
|
87 | 87 | $ cd linearized-merge |
|
88 | 88 | |
|
89 | 89 | $ hg debugdrawdag << 'EOF' |
|
90 | 90 | > F D |
|
91 | 91 | > |/| |
|
92 | 92 | > C B |
|
93 | 93 | > |/ |
|
94 | 94 | > A |
|
95 | 95 | > EOF |
|
96 | 96 | |
|
97 | 97 | $ hg phase --force --secret D |
|
98 | 98 | $ hg rebase --source B --collapse --dest F |
|
99 | 99 | rebasing 1:112478962961 "B" (B) |
|
100 | 100 | rebasing 3:4e4f9194f9f1 "D" (D) |
|
101 | 101 | saved backup bundle to $TESTTMP/linearized-merge/.hg/strip-backup/112478962961-e389075b-rebase.hg |
|
102 | 102 | |
|
103 | 103 | $ hg tglog |
|
104 | 104 | o 3: 5bdc08b7da2b 'Collapsed revision |
|
105 | 105 | | * B |
|
106 | 106 | | * D' |
|
107 | 107 | o 2: afc707c82df0 'F' |
|
108 | 108 | | |
|
109 | 109 | o 1: dc0947a82db8 'C' |
|
110 | 110 | | |
|
111 | 111 | o 0: 426bada5c675 'A' |
|
112 | 112 | |
|
113 | 113 | $ hg manifest --rev tip |
|
114 | 114 | A |
|
115 | 115 | B |
|
116 | 116 | C |
|
117 | 117 | F |
|
118 | 118 | |
|
119 | 119 | $ cd .. |
|
120 | 120 | |
|
121 | 121 | Custom message: |
|
122 | 122 | |
|
123 | 123 | $ hg init message |
|
124 | 124 | $ cd message |
|
125 | 125 | |
|
126 | 126 | $ hg debugdrawdag << 'EOF' |
|
127 | 127 | > C |
|
128 | 128 | > | |
|
129 | 129 | > D B |
|
130 | 130 | > |/ |
|
131 | 131 | > A |
|
132 | 132 | > EOF |
|
133 | 133 | |
|
134 | 134 | |
|
135 | 135 | $ hg rebase --base B -m 'custom message' |
|
136 | 136 | abort: message can only be specified with collapse |
|
137 | 137 | [255] |
|
138 | 138 | |
|
139 | 139 | $ cat > $TESTTMP/checkeditform.sh <<EOF |
|
140 | 140 | > env | grep HGEDITFORM |
|
141 | 141 | > true |
|
142 | 142 | > EOF |
|
143 | 143 | $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --source B --collapse -m 'custom message' -e --dest D |
|
144 | 144 | rebasing 1:112478962961 "B" (B) |
|
145 | 145 | rebasing 3:26805aba1e60 "C" (C tip) |
|
146 | 146 | HGEDITFORM=rebase.collapse |
|
147 | 147 | saved backup bundle to $TESTTMP/message/.hg/strip-backup/112478962961-f4131707-rebase.hg |
|
148 | 148 | |
|
149 | 149 | $ hg tglog |
|
150 | 150 | o 2: 2f197b9a08f3 'custom message' |
|
151 | 151 | | |
|
152 | 152 | o 1: b18e25de2cf5 'D' |
|
153 | 153 | | |
|
154 | 154 | o 0: 426bada5c675 'A' |
|
155 | 155 | |
|
156 | 156 | $ hg manifest --rev tip |
|
157 | 157 | A |
|
158 | 158 | B |
|
159 | 159 | C |
|
160 | 160 | D |
|
161 | 161 | |
|
162 | 162 | $ cd .. |
|
163 | 163 | |
|
164 | 164 | Rebase and collapse - more than one external (fail): |
|
165 | 165 | |
|
166 | 166 | $ hg init multiple-external-parents |
|
167 | 167 | $ cd multiple-external-parents |
|
168 | 168 | |
|
169 | 169 | $ hg debugdrawdag << 'EOF' |
|
170 | 170 | > G |
|
171 | 171 | > |\ |
|
172 | 172 | > | F |
|
173 | 173 | > | | |
|
174 | 174 | > D E |
|
175 | 175 | > |\| |
|
176 | 176 | > H C B |
|
177 | 177 | > \|/ |
|
178 | 178 | > A |
|
179 | 179 | > EOF |
|
180 | 180 | |
|
181 | 181 | $ hg rebase -s C --dest H --collapse |
|
182 | 182 | abort: unable to collapse on top of 3, there is more than one external parent: 1, 6 |
|
183 | 183 | [255] |
|
184 | 184 | |
|
185 | 185 | Rebase and collapse - E onto H: |
|
186 | 186 | |
|
187 | 187 | $ hg rebase -s E --dest I --collapse # root (E) is not a merge |
|
188 | 188 | abort: unknown revision 'I'! |
|
189 | 189 | [255] |
|
190 | 190 | |
|
191 | 191 | $ hg tglog |
|
192 | 192 | o 7: 64e264db77f0 'G' |
|
193 | 193 | |\ |
|
194 | 194 | | o 6: 11abe3fb10b8 'F' |
|
195 | 195 | | | |
|
196 | 196 | | o 5: 49cb92066bfd 'E' |
|
197 | 197 | | | |
|
198 | 198 | o | 4: 4e4f9194f9f1 'D' |
|
199 | 199 | |\| |
|
200 | 200 | | | o 3: 575c4b5ec114 'H' |
|
201 | 201 | | | | |
|
202 | 202 | o---+ 2: dc0947a82db8 'C' |
|
203 | 203 | / / |
|
204 | 204 | o / 1: 112478962961 'B' |
|
205 | 205 | |/ |
|
206 | 206 | o 0: 426bada5c675 'A' |
|
207 | 207 | |
|
208 | 208 | $ hg manifest --rev tip |
|
209 | 209 | A |
|
210 | 210 | B |
|
211 | 211 | C |
|
212 | 212 | E |
|
213 | 213 | F |
|
214 | 214 | |
|
215 | 215 | $ cd .. |
|
216 | 216 | |
|
217 | 217 | |
|
218 | 218 | |
|
219 | 219 | |
|
220 | 220 | Test that branchheads cache is updated correctly when doing a strip in which |
|
221 | 221 | the parent of the ancestor node to be stripped does not become a head and also, |
|
222 | 222 | the parent of a node that is a child of the node stripped becomes a head (node |
|
223 | 223 | 3). The code is now much simpler and we could just test a simpler scenario |
|
224 | 224 | We keep it the test this way in case new complexity is injected. |
|
225 | 225 | |
|
226 | 226 | Create repo b: |
|
227 | 227 | |
|
228 | 228 | $ hg init branch-heads |
|
229 | 229 | $ cd branch-heads |
|
230 | 230 | |
|
231 | 231 | $ hg debugdrawdag << 'EOF' |
|
232 | 232 | > G |
|
233 | 233 | > |\ |
|
234 | 234 | > | F |
|
235 | 235 | > | | |
|
236 | 236 | > D E |
|
237 | 237 | > |\| |
|
238 | 238 | > H C B |
|
239 | 239 | > \|/ |
|
240 | 240 | > A |
|
241 | 241 | > EOF |
|
242 | 242 | |
|
243 | 243 | $ hg heads --template="{rev}:{node} {branch}\n" |
|
244 | 244 | 7:64e264db77f061f16d9132b70c5a58e2461fb630 default |
|
245 | 245 | 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default |
|
246 | 246 | |
|
247 | 247 | $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served |
|
248 | 248 | 64e264db77f061f16d9132b70c5a58e2461fb630 7 |
|
249 | 249 | 575c4b5ec114d64b681d33f8792853568bfb2b2c o default |
|
250 | 250 | 64e264db77f061f16d9132b70c5a58e2461fb630 o default |
|
251 | 251 | |
|
252 | 252 | $ hg strip 4 |
|
253 | 253 | saved backup bundle to $TESTTMP/branch-heads/.hg/strip-backup/4e4f9194f9f1-5ec4b5e6-backup.hg |
|
254 | 254 | |
|
255 | 255 | $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served |
|
256 | 256 | 11abe3fb10b8689b560681094b17fe161871d043 5 |
|
257 | 257 | dc0947a82db884575bb76ea10ac97b08536bfa03 o default |
|
258 | 258 | 575c4b5ec114d64b681d33f8792853568bfb2b2c o default |
|
259 | 259 | 11abe3fb10b8689b560681094b17fe161871d043 o default |
|
260 | 260 | |
|
261 | 261 | $ hg heads --template="{rev}:{node} {branch}\n" |
|
262 | 262 | 5:11abe3fb10b8689b560681094b17fe161871d043 default |
|
263 | 263 | 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default |
|
264 | 264 | 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default |
|
265 | 265 | |
|
266 | 266 | $ cd .. |
|
267 | 267 | |
|
268 | 268 | |
|
269 | 269 | |
|
270 | 270 | Preserves external parent |
|
271 | 271 | |
|
272 | 272 | $ hg init external-parent |
|
273 | 273 | $ cd external-parent |
|
274 | 274 | |
|
275 | 275 | $ hg debugdrawdag << 'EOF' |
|
276 | 276 | > H |
|
277 | 277 | > |\ |
|
278 | 278 | > | G |
|
279 | 279 | > | | |
|
280 | 280 | > | F # F/E = F\n |
|
281 | 281 | > | | |
|
282 | 282 | > D E # D/D = D\n |
|
283 | 283 | > |\| |
|
284 | 284 | > I C B |
|
285 | 285 | > \|/ |
|
286 | 286 | > A |
|
287 | 287 | > EOF |
|
288 | 288 | |
|
289 | 289 | $ hg rebase -s F --dest I --collapse # root (F) is not a merge |
|
290 | 290 | rebasing 6:c82b08f646f1 "F" (F) |
|
291 | 291 | file 'E' was deleted in local [dest] but was modified in other [source]. |
|
292 | 292 | You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved. |
|
293 | 293 | What do you want to do? u |
|
294 | 294 | unresolved conflicts (see hg resolve, then hg rebase --continue) |
|
295 | 295 | [1] |
|
296 | 296 | |
|
297 | 297 | $ echo F > E |
|
298 | 298 | $ hg resolve -m |
|
299 | 299 | (no more unresolved files) |
|
300 | 300 | continue: hg rebase --continue |
|
301 | 301 | $ hg rebase -c |
|
302 | 302 | rebasing 6:c82b08f646f1 "F" (F) |
|
303 | 303 | rebasing 7:a6db7fa104e1 "G" (G) |
|
304 | 304 | rebasing 8:e1d201b72d91 "H" (H tip) |
|
305 | 305 | saved backup bundle to $TESTTMP/external-parent/.hg/strip-backup/c82b08f646f1-f2721fbf-rebase.hg |
|
306 | 306 | |
|
307 | 307 | $ hg tglog |
|
308 | 308 | o 6: 681daa3e686d 'Collapsed revision |
|
309 | 309 | |\ * F |
|
310 | 310 | | | * G |
|
311 | 311 | | | * H' |
|
312 | 312 | | | o 5: 49cb92066bfd 'E' |
|
313 | 313 | | | | |
|
314 | 314 | | o | 4: 09143c0bf13e 'D' |
|
315 | 315 | | |\| |
|
316 | 316 | o | | 3: 08ebfeb61bac 'I' |
|
317 | 317 | | | | |
|
318 | 318 | | o | 2: dc0947a82db8 'C' |
|
319 | 319 | |/ / |
|
320 | 320 | | o 1: 112478962961 'B' |
|
321 | 321 | |/ |
|
322 | 322 | o 0: 426bada5c675 'A' |
|
323 | 323 | |
|
324 | 324 | $ hg manifest --rev tip |
|
325 | 325 | A |
|
326 | 326 | C |
|
327 | 327 | D |
|
328 | 328 | E |
|
329 | 329 | F |
|
330 | 330 | G |
|
331 | 331 | I |
|
332 | 332 | |
|
333 | 333 | $ hg up tip -q |
|
334 | 334 | $ cat E |
|
335 | 335 | F |
|
336 | 336 | |
|
337 | 337 | $ cd .. |
|
338 | 338 | |
|
339 | 339 | Rebasing from multiple bases: |
|
340 | 340 | |
|
341 | 341 | $ hg init multiple-bases |
|
342 | 342 | $ cd multiple-bases |
|
343 | 343 | $ hg debugdrawdag << 'EOF' |
|
344 | 344 | > C B |
|
345 | 345 | > D |/ |
|
346 | 346 | > |/ |
|
347 | 347 | > A |
|
348 | 348 | > EOF |
|
349 | 349 | $ hg rebase --collapse -r 'B+C' -d D |
|
350 | 350 | rebasing 1:fc2b737bb2e5 "B" (B) |
|
351 | 351 | rebasing 2:dc0947a82db8 "C" (C) |
|
352 | 352 | saved backup bundle to $TESTTMP/multiple-bases/.hg/strip-backup/dc0947a82db8-b0c1a7ea-rebase.hg |
|
353 | 353 | $ hg tglog |
|
354 | 354 | o 2: 2127ae44d291 'Collapsed revision |
|
355 | 355 | | * B |
|
356 | 356 | | * C' |
|
357 | 357 | o 1: b18e25de2cf5 'D' |
|
358 | 358 | | |
|
359 | 359 | o 0: 426bada5c675 'A' |
|
360 | 360 | |
|
361 | 361 | $ cd .. |
|
362 | 362 | |
|
363 | 363 | With non-contiguous commits: |
|
364 | 364 | |
|
365 | 365 | $ hg init non-contiguous |
|
366 | 366 | $ cd non-contiguous |
|
367 | 367 | $ cat >> .hg/hgrc <<EOF |
|
368 | 368 | > [experimental] |
|
369 | 369 | > evolution=all |
|
370 | 370 | > EOF |
|
371 | 371 | |
|
372 | 372 | $ hg debugdrawdag << 'EOF' |
|
373 | 373 | > F |
|
374 | 374 | > | |
|
375 | 375 | > E |
|
376 | 376 | > | |
|
377 | 377 | > D |
|
378 | 378 | > | |
|
379 | 379 | > C |
|
380 | 380 | > | |
|
381 | 381 | > B G |
|
382 | 382 | > |/ |
|
383 | 383 | > A |
|
384 | 384 | > EOF |
|
385 | 385 | |
|
386 | 386 | BROKEN: should be allowed |
|
387 | 387 | $ hg rebase --collapse -r 'B+D+F' -d G |
|
388 | 388 | abort: unable to collapse on top of 2, there is more than one external parent: 3, 5 |
|
389 | 389 | [255] |
|
390 | 390 | $ cd .. |
|
391 | 391 | |
|
392 | 392 | |
|
393 | 393 | $ hg init multiple-external-parents-2 |
|
394 | 394 | $ cd multiple-external-parents-2 |
|
395 | 395 | $ hg debugdrawdag << 'EOF' |
|
396 | 396 | > D G |
|
397 | 397 | > |\ /| |
|
398 | 398 | > B C E F |
|
399 | 399 | > \| |/ |
|
400 | 400 | > \ H / |
|
401 | 401 | > \|/ |
|
402 | 402 | > A |
|
403 | 403 | > EOF |
|
404 | 404 | |
|
405 | 405 | $ hg rebase --collapse -d H -s 'B+F' |
|
406 | 406 | abort: unable to collapse on top of 5, there is more than one external parent: 1, 3 |
|
407 | 407 | [255] |
|
408 | 408 | $ cd .. |
|
409 | 409 | |
|
410 | 410 | With internal merge: |
|
411 | 411 | |
|
412 | 412 | $ hg init internal-merge |
|
413 | 413 | $ cd internal-merge |
|
414 | 414 | |
|
415 | 415 | $ hg debugdrawdag << 'EOF' |
|
416 | 416 | > E |
|
417 | 417 | > |\ |
|
418 | 418 | > C D |
|
419 | 419 | > |/ |
|
420 | 420 | > F B |
|
421 | 421 | > |/ |
|
422 | 422 | > A |
|
423 | 423 | > EOF |
|
424 | 424 | |
|
425 | 425 | |
|
426 | 426 | $ hg rebase -s B --collapse --dest F |
|
427 | 427 | rebasing 1:112478962961 "B" (B) |
|
428 | 428 | rebasing 3:26805aba1e60 "C" (C) |
|
429 | 429 | rebasing 4:be0ef73c17ad "D" (D) |
|
430 | 430 | rebasing 5:02c4367d6973 "E" (E tip) |
|
431 | 431 | saved backup bundle to $TESTTMP/internal-merge/.hg/strip-backup/112478962961-1dfb057b-rebase.hg |
|
432 | 432 | |
|
433 | 433 | $ hg tglog |
|
434 | 434 | o 2: c0512a1797b0 'Collapsed revision |
|
435 | 435 | | * B |
|
436 | 436 | | * C |
|
437 | 437 | | * D |
|
438 | 438 | | * E' |
|
439 | 439 | o 1: 8908a377a434 'F' |
|
440 | 440 | | |
|
441 | 441 | o 0: 426bada5c675 'A' |
|
442 | 442 | |
|
443 | 443 | $ hg manifest --rev tip |
|
444 | 444 | A |
|
445 | 445 | B |
|
446 | 446 | C |
|
447 | 447 | D |
|
448 | 448 | F |
|
449 | 449 | $ cd .. |
|
450 | 450 | |
|
451 | 451 | Interactions between collapse and keepbranches |
|
452 | 452 | $ hg init e |
|
453 | 453 | $ cd e |
|
454 | 454 | $ echo 'a' > a |
|
455 | 455 | $ hg ci -Am 'A' |
|
456 | 456 | adding a |
|
457 | 457 | |
|
458 | 458 | $ hg branch 'one' |
|
459 | 459 | marked working directory as branch one |
|
460 | 460 | (branches are permanent and global, did you want a bookmark?) |
|
461 | 461 | $ echo 'b' > b |
|
462 | 462 | $ hg ci -Am 'B' |
|
463 | 463 | adding b |
|
464 | 464 | |
|
465 | 465 | $ hg branch 'two' |
|
466 | 466 | marked working directory as branch two |
|
467 | 467 | $ echo 'c' > c |
|
468 | 468 | $ hg ci -Am 'C' |
|
469 | 469 | adding c |
|
470 | 470 | |
|
471 | 471 | $ hg up -q 0 |
|
472 | 472 | $ echo 'd' > d |
|
473 | 473 | $ hg ci -Am 'D' |
|
474 | 474 | adding d |
|
475 | 475 | |
|
476 | 476 | $ hg tglog |
|
477 | 477 | @ 3: 41acb9dca9eb 'D' |
|
478 | 478 | | |
|
479 | 479 | | o 2: 8ac4a08debf1 'C' two |
|
480 | 480 | | | |
|
481 | 481 | | o 1: 1ba175478953 'B' one |
|
482 | 482 | |/ |
|
483 | 483 | o 0: 1994f17a630e 'A' |
|
484 | 484 | |
|
485 | 485 | $ hg rebase --keepbranches --collapse -s 1 -d 3 |
|
486 | 486 | abort: cannot collapse multiple named branches |
|
487 | 487 | [255] |
|
488 | 488 | |
|
489 | 489 | $ cd .. |
|
490 | 490 | |
|
491 | 491 | Rebase, collapse and copies |
|
492 | 492 | |
|
493 | 493 | $ hg init copies |
|
494 | 494 | $ cd copies |
|
495 | 495 | $ hg unbundle "$TESTDIR/bundles/renames.hg" |
|
496 | 496 | adding changesets |
|
497 | 497 | adding manifests |
|
498 | 498 | adding file changes |
|
499 | 499 | added 4 changesets with 11 changes to 7 files (+1 heads) |
|
500 | 500 | new changesets f447d5abf5ea:338e84e2e558 (4 drafts) |
|
501 | 501 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
502 | 502 | $ hg up -q tip |
|
503 | 503 | $ hg tglog |
|
504 | 504 | @ 3: 338e84e2e558 'move2' |
|
505 | 505 | | |
|
506 | 506 | o 2: 6e7340ee38c0 'move1' |
|
507 | 507 | | |
|
508 | 508 | | o 1: 1352765a01d4 'change' |
|
509 | 509 | |/ |
|
510 | 510 | o 0: f447d5abf5ea 'add' |
|
511 | 511 | |
|
512 | 512 | $ hg rebase --collapse -d 1 |
|
513 | 513 | rebasing 2:6e7340ee38c0 "move1" |
|
514 | 514 | merging a and d to d |
|
515 | 515 | merging b and e to e |
|
516 | 516 | merging c and f to f |
|
517 | 517 | rebasing 3:338e84e2e558 "move2" (tip) |
|
518 | 518 | merging f and c to c |
|
519 | 519 | merging e and g to g |
|
520 | 520 | saved backup bundle to $TESTTMP/copies/.hg/strip-backup/6e7340ee38c0-ef8ef003-rebase.hg |
|
521 | 521 | $ hg st |
|
522 | 522 | $ hg st --copies --change tip |
|
523 | 523 | A d |
|
524 | 524 | a |
|
525 | 525 | A g |
|
526 | 526 | b |
|
527 | 527 | R b |
|
528 | 528 | $ hg up tip -q |
|
529 | 529 | $ cat c |
|
530 | 530 | c |
|
531 | 531 | c |
|
532 | 532 | $ cat d |
|
533 | 533 | a |
|
534 | 534 | a |
|
535 | 535 | $ cat g |
|
536 | 536 | b |
|
537 | 537 | b |
|
538 | 538 | $ hg log -r . --template "{file_copies}\n" |
|
539 | 539 | d (a)g (b) |
|
540 | 540 | |
|
541 | 541 | Test collapsing a middle revision in-place |
|
542 | 542 | |
|
543 | 543 | $ hg tglog |
|
544 | 544 | @ 2: 64b456429f67 'Collapsed revision |
|
545 | 545 | | * move1 |
|
546 | 546 | | * move2' |
|
547 | 547 | o 1: 1352765a01d4 'change' |
|
548 | 548 | | |
|
549 | 549 | o 0: f447d5abf5ea 'add' |
|
550 | 550 | |
|
551 | 551 | $ hg rebase --collapse -r 1 -d 0 |
|
552 | 552 | abort: cannot rebase changeset with children |
|
553 | 553 | (use --keep to keep original changesets) |
|
554 | 554 | [255] |
|
555 | 555 | |
|
556 | 556 | Test collapsing in place |
|
557 | 557 | |
|
558 | 558 | $ hg rebase --collapse -b . -d 0 |
|
559 | 559 | rebasing 1:1352765a01d4 "change" |
|
560 | 560 | rebasing 2:64b456429f67 "Collapsed revision" (tip) |
|
561 | 561 | saved backup bundle to $TESTTMP/copies/.hg/strip-backup/1352765a01d4-45a352ea-rebase.hg |
|
562 | 562 | $ hg st --change tip --copies |
|
563 | 563 | M a |
|
564 | 564 | M c |
|
565 | 565 | A d |
|
566 | 566 | a |
|
567 | 567 | A g |
|
568 | 568 | b |
|
569 | 569 | R b |
|
570 | 570 | $ hg up tip -q |
|
571 | 571 | $ cat a |
|
572 | 572 | a |
|
573 | 573 | a |
|
574 | 574 | $ cat c |
|
575 | 575 | c |
|
576 | 576 | c |
|
577 | 577 | $ cat d |
|
578 | 578 | a |
|
579 | 579 | a |
|
580 | 580 | $ cat g |
|
581 | 581 | b |
|
582 | 582 | b |
|
583 | 583 | $ cd .. |
|
584 | 584 | |
|
585 | 585 | |
|
586 | 586 | Test stripping a revision with another child |
|
587 | 587 | |
|
588 | 588 | $ hg init f |
|
589 | 589 | $ cd f |
|
590 | 590 | |
|
591 | 591 | $ hg debugdrawdag << 'EOF' |
|
592 | 592 | > C B |
|
593 | 593 | > |/ |
|
594 | 594 | > A |
|
595 | 595 | > EOF |
|
596 | 596 | |
|
597 | 597 | $ hg heads --template="{rev}:{node} {branch}: {desc}\n" |
|
598 | 598 | 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default: C |
|
599 | 599 | 1:112478962961147124edd43549aedd1a335e44bf default: B |
|
600 | 600 | |
|
601 | 601 | $ hg strip C |
|
602 | 602 | saved backup bundle to $TESTTMP/f/.hg/strip-backup/dc0947a82db8-d21b92a4-backup.hg |
|
603 | 603 | |
|
604 | 604 | $ hg tglog |
|
605 | 605 | o 1: 112478962961 'B' |
|
606 | 606 | | |
|
607 | 607 | o 0: 426bada5c675 'A' |
|
608 | 608 | |
|
609 | 609 | |
|
610 | 610 | |
|
611 | 611 | $ hg heads --template="{rev}:{node} {branch}: {desc}\n" |
|
612 | 612 | 1:112478962961147124edd43549aedd1a335e44bf default: B |
|
613 | 613 | |
|
614 | 614 | $ cd .. |
|
615 | 615 | |
|
616 | 616 | Test collapsing changes that add then remove a file |
|
617 | 617 | |
|
618 | 618 | $ hg init collapseaddremove |
|
619 | 619 | $ cd collapseaddremove |
|
620 | 620 | |
|
621 | 621 | $ touch base |
|
622 | 622 | $ hg commit -Am base |
|
623 | 623 | adding base |
|
624 | 624 | $ touch a |
|
625 | 625 | $ hg commit -Am a |
|
626 | 626 | adding a |
|
627 | 627 | $ hg rm a |
|
628 | 628 | $ touch b |
|
629 | 629 | $ hg commit -Am b |
|
630 | 630 | adding b |
|
631 | 631 | $ hg book foo |
|
632 | 632 | $ hg rebase -d 0 -r "1::2" --collapse -m collapsed |
|
633 | 633 | rebasing 1:6d8d9f24eec3 "a" |
|
634 | 634 | rebasing 2:1cc73eca5ecc "b" (foo tip) |
|
635 | 635 | saved backup bundle to $TESTTMP/collapseaddremove/.hg/strip-backup/6d8d9f24eec3-77d3b6e2-rebase.hg |
|
636 | 636 | $ hg log -G --template "{rev}: '{desc}' {bookmarks}" |
|
637 | 637 | @ 1: 'collapsed' foo |
|
638 | 638 | | |
|
639 | 639 | o 0: 'base' |
|
640 | 640 | |
|
641 | 641 | $ hg manifest --rev tip |
|
642 | 642 | b |
|
643 | 643 | base |
|
644 | 644 | |
|
645 | 645 | $ cd .. |
|
646 | 646 | |
|
647 | 647 | Test that rebase --collapse will remember message after |
|
648 | 648 | running into merge conflict and invoking rebase --continue. |
|
649 | 649 | |
|
650 | 650 | $ hg init collapse_remember_message |
|
651 | 651 | $ cd collapse_remember_message |
|
652 | 652 | $ hg debugdrawdag << 'EOF' |
|
653 | 653 | > C B # B/A = B\n |
|
654 | 654 | > |/ # C/A = C\n |
|
655 | 655 | > A |
|
656 | 656 | > EOF |
|
657 | 657 | $ hg rebase --collapse -m "new message" -b B -d C |
|
658 | 658 | rebasing 1:81e5401e4d37 "B" (B) |
|
659 | 659 | merging A |
|
660 | 660 | warning: conflicts while merging A! (edit, then use 'hg resolve --mark') |
|
661 | 661 | unresolved conflicts (see hg resolve, then hg rebase --continue) |
|
662 | 662 | [1] |
|
663 | 663 | $ rm A.orig |
|
664 | 664 | $ hg resolve --mark A |
|
665 | 665 | (no more unresolved files) |
|
666 | 666 | continue: hg rebase --continue |
|
667 | 667 | $ hg rebase --continue |
|
668 | 668 | rebasing 1:81e5401e4d37 "B" (B) |
|
669 | 669 | saved backup bundle to $TESTTMP/collapse_remember_message/.hg/strip-backup/81e5401e4d37-96c3dd30-rebase.hg |
|
670 | 670 | $ hg log |
|
671 | 671 | changeset: 2:17186933e123 |
|
672 | 672 | tag: tip |
|
673 | 673 | user: test |
|
674 | 674 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
675 | 675 | summary: new message |
|
676 | 676 | |
|
677 | 677 | changeset: 1:043039e9df84 |
|
678 | 678 | tag: C |
|
679 | 679 | user: test |
|
680 | 680 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
681 | 681 | summary: C |
|
682 | 682 | |
|
683 | 683 | changeset: 0:426bada5c675 |
|
684 | 684 | tag: A |
|
685 | 685 | user: test |
|
686 | 686 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
687 | 687 | summary: A |
|
688 | 688 | |
|
689 | 689 | $ cd .. |
|
690 | 690 | |
|
691 | 691 | Test aborted editor on final message |
|
692 | 692 | |
|
693 | 693 | $ HGMERGE=:merge3 |
|
694 | 694 | $ export HGMERGE |
|
695 | 695 | $ hg init aborted-editor |
|
696 | 696 | $ cd aborted-editor |
|
697 | 697 | $ hg debugdrawdag << 'EOF' |
|
698 | 698 | > C # D/A = D\n |
|
699 | 699 | > | # C/A = C\n |
|
700 | 700 | > B D # B/A = B\n |
|
701 | 701 | > |/ # A/A = A\n |
|
702 | 702 | > A |
|
703 | 703 | > EOF |
|
704 | 704 | $ hg rebase --collapse -t internal:merge3 -s B -d D |
|
705 | 705 | rebasing 1:f899f3910ce7 "B" (B) |
|
706 | 706 | merging A |
|
707 | 707 | warning: conflicts while merging A! (edit, then use 'hg resolve --mark') |
|
708 | 708 | unresolved conflicts (see hg resolve, then hg rebase --continue) |
|
709 | 709 | [1] |
|
710 | 710 | $ hg tglog |
|
711 | 711 | o 3: 63668d570d21 'C' |
|
712 | 712 | | |
|
713 | 713 | | @ 2: 82b8abf9c185 'D' |
|
714 | 714 | | | |
|
715 | 715 | @ | 1: f899f3910ce7 'B' |
|
716 | 716 | |/ |
|
717 | 717 | o 0: 4a2df7238c3b 'A' |
|
718 | 718 | |
|
719 | 719 | $ cat A |
|
720 | 720 | <<<<<<< dest: 82b8abf9c185 D - test: D |
|
721 | 721 | D |
|
722 | 722 | ||||||| base |
|
723 | 723 | A |
|
724 | 724 | ======= |
|
725 | 725 | B |
|
726 | 726 | >>>>>>> source: f899f3910ce7 B - test: B |
|
727 | 727 | $ echo BC > A |
|
728 | 728 | $ hg resolve -m |
|
729 | 729 | (no more unresolved files) |
|
730 | 730 | continue: hg rebase --continue |
|
731 | 731 | $ hg rebase --continue |
|
732 | 732 | rebasing 1:f899f3910ce7 "B" (B) |
|
733 | 733 | rebasing 3:63668d570d21 "C" (C tip) |
|
734 | 734 | merging A |
|
735 | 735 | warning: conflicts while merging A! (edit, then use 'hg resolve --mark') |
|
736 | 736 | unresolved conflicts (see hg resolve, then hg rebase --continue) |
|
737 | 737 | [1] |
|
738 | 738 | $ hg tglog |
|
739 | 739 | @ 3: 63668d570d21 'C' |
|
740 | 740 | | |
|
741 | 741 | | @ 2: 82b8abf9c185 'D' |
|
742 | 742 | | | |
|
743 | 743 | o | 1: f899f3910ce7 'B' |
|
744 | 744 | |/ |
|
745 | 745 | o 0: 4a2df7238c3b 'A' |
|
746 | 746 | |
|
747 | 747 | $ cat A |
|
748 | 748 | <<<<<<< dest: 82b8abf9c185 D - test: D |
|
749 | 749 | BC |
|
750 | 750 | ||||||| base |
|
751 | 751 | B |
|
752 | 752 | ======= |
|
753 | 753 | C |
|
754 | 754 | >>>>>>> source: 63668d570d21 C tip - test: C |
|
755 | 755 | $ echo BD > A |
|
756 | 756 | $ hg resolve -m |
|
757 | 757 | (no more unresolved files) |
|
758 | 758 | continue: hg rebase --continue |
|
759 | 759 | $ HGEDITOR=false hg rebase --continue --config ui.interactive=1 |
|
760 | 760 | already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185 |
|
761 | 761 | rebasing 3:63668d570d21 "C" (C tip) |
|
762 | 762 | abort: edit failed: false exited with status 1 |
|
763 | 763 | [255] |
|
764 | 764 | $ hg tglog |
|
765 |
|
|
|
765 | % 3: 63668d570d21 'C' | |
|
766 | 766 | | |
|
767 | 767 | | @ 2: 82b8abf9c185 'D' |
|
768 | 768 | | | |
|
769 | 769 | o | 1: f899f3910ce7 'B' |
|
770 | 770 | |/ |
|
771 | 771 | o 0: 4a2df7238c3b 'A' |
|
772 | 772 | |
|
773 | 773 | $ hg rebase --continue |
|
774 | 774 | already rebased 1:f899f3910ce7 "B" (B) as 82b8abf9c185 |
|
775 | 775 | already rebased 3:63668d570d21 "C" (C tip) as 82b8abf9c185 |
|
776 | 776 | saved backup bundle to $TESTTMP/aborted-editor/.hg/strip-backup/f899f3910ce7-7cab5e15-rebase.hg |
@@ -1,1407 +1,1407 b'' | |||
|
1 | 1 | $ echo "[extensions]" >> $HGRCPATH |
|
2 | 2 | $ echo "strip=" >> $HGRCPATH |
|
3 | 3 | $ echo "drawdag=$TESTDIR/drawdag.py" >> $HGRCPATH |
|
4 | 4 | |
|
5 | 5 | $ restore() { |
|
6 | 6 | > hg unbundle -q .hg/strip-backup/* |
|
7 | 7 | > rm .hg/strip-backup/* |
|
8 | 8 | > } |
|
9 | 9 | $ teststrip() { |
|
10 | 10 | > hg up -C $1 |
|
11 | 11 | > echo % before update $1, strip $2 |
|
12 | 12 | > hg log -G -T '{rev}:{node}' |
|
13 | 13 | > hg --traceback strip $2 |
|
14 | 14 | > echo % after update $1, strip $2 |
|
15 | 15 | > hg log -G -T '{rev}:{node}' |
|
16 | 16 | > restore |
|
17 | 17 | > } |
|
18 | 18 | |
|
19 | 19 | $ hg init test |
|
20 | 20 | $ cd test |
|
21 | 21 | |
|
22 | 22 | $ echo foo > bar |
|
23 | 23 | $ hg ci -Ama |
|
24 | 24 | adding bar |
|
25 | 25 | |
|
26 | 26 | $ echo more >> bar |
|
27 | 27 | $ hg ci -Amb |
|
28 | 28 | |
|
29 | 29 | $ echo blah >> bar |
|
30 | 30 | $ hg ci -Amc |
|
31 | 31 | |
|
32 | 32 | $ hg up 1 |
|
33 | 33 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
34 | 34 | $ echo blah >> bar |
|
35 | 35 | $ hg ci -Amd |
|
36 | 36 | created new head |
|
37 | 37 | |
|
38 | 38 | $ echo final >> bar |
|
39 | 39 | $ hg ci -Ame |
|
40 | 40 | |
|
41 | 41 | $ hg log |
|
42 | 42 | changeset: 4:443431ffac4f |
|
43 | 43 | tag: tip |
|
44 | 44 | user: test |
|
45 | 45 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
46 | 46 | summary: e |
|
47 | 47 | |
|
48 | 48 | changeset: 3:65bd5f99a4a3 |
|
49 | 49 | parent: 1:ef3a871183d7 |
|
50 | 50 | user: test |
|
51 | 51 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
52 | 52 | summary: d |
|
53 | 53 | |
|
54 | 54 | changeset: 2:264128213d29 |
|
55 | 55 | user: test |
|
56 | 56 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
57 | 57 | summary: c |
|
58 | 58 | |
|
59 | 59 | changeset: 1:ef3a871183d7 |
|
60 | 60 | user: test |
|
61 | 61 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
62 | 62 | summary: b |
|
63 | 63 | |
|
64 | 64 | changeset: 0:9ab35a2d17cb |
|
65 | 65 | user: test |
|
66 | 66 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
67 | 67 | summary: a |
|
68 | 68 | |
|
69 | 69 | |
|
70 | 70 | $ teststrip 4 4 |
|
71 | 71 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
72 | 72 | % before update 4, strip 4 |
|
73 | 73 | @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
74 | 74 | | |
|
75 | 75 | o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
76 | 76 | | |
|
77 | 77 | | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
78 | 78 | |/ |
|
79 | 79 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
80 | 80 | | |
|
81 | 81 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
82 | 82 | |
|
83 | 83 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
84 | 84 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
85 | 85 | % after update 4, strip 4 |
|
86 | 86 | @ 3:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
87 | 87 | | |
|
88 | 88 | | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
89 | 89 | |/ |
|
90 | 90 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
91 | 91 | | |
|
92 | 92 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
93 | 93 | |
|
94 | 94 | $ teststrip 4 3 |
|
95 | 95 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
96 | 96 | % before update 4, strip 3 |
|
97 | 97 | @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
98 | 98 | | |
|
99 | 99 | o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
100 | 100 | | |
|
101 | 101 | | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
102 | 102 | |/ |
|
103 | 103 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
104 | 104 | | |
|
105 | 105 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
106 | 106 | |
|
107 | 107 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
108 | 108 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
109 | 109 | % after update 4, strip 3 |
|
110 | 110 | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
111 | 111 | | |
|
112 | 112 | @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
113 | 113 | | |
|
114 | 114 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
115 | 115 | |
|
116 | 116 | $ teststrip 1 4 |
|
117 | 117 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
118 | 118 | % before update 1, strip 4 |
|
119 | 119 | o 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
120 | 120 | | |
|
121 | 121 | o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
122 | 122 | | |
|
123 | 123 | | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
124 | 124 | |/ |
|
125 | 125 | @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
126 | 126 | | |
|
127 | 127 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
128 | 128 | |
|
129 | 129 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
130 | 130 | % after update 1, strip 4 |
|
131 | 131 | o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
132 | 132 | | |
|
133 | 133 | | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
134 | 134 | |/ |
|
135 | 135 | @ 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
136 | 136 | | |
|
137 | 137 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
138 | 138 | |
|
139 | 139 | $ teststrip 4 2 |
|
140 | 140 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
141 | 141 | % before update 4, strip 2 |
|
142 | 142 | @ 4:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
143 | 143 | | |
|
144 | 144 | o 3:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
145 | 145 | | |
|
146 | 146 | | o 2:264128213d290d868c54642d13aeaa3675551a78 |
|
147 | 147 | |/ |
|
148 | 148 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
149 | 149 | | |
|
150 | 150 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
151 | 151 | |
|
152 | 152 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
153 | 153 | % after update 4, strip 2 |
|
154 | 154 | @ 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
155 | 155 | | |
|
156 | 156 | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
157 | 157 | | |
|
158 | 158 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
159 | 159 | | |
|
160 | 160 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
161 | 161 | |
|
162 | 162 | $ teststrip 4 1 |
|
163 | 163 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
164 | 164 | % before update 4, strip 1 |
|
165 | 165 | @ 4:264128213d290d868c54642d13aeaa3675551a78 |
|
166 | 166 | | |
|
167 | 167 | | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
168 | 168 | | | |
|
169 | 169 | | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
170 | 170 | |/ |
|
171 | 171 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
172 | 172 | | |
|
173 | 173 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
174 | 174 | |
|
175 | 175 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
176 | 176 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
177 | 177 | % after update 4, strip 1 |
|
178 | 178 | @ 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
179 | 179 | |
|
180 | 180 | $ teststrip null 4 |
|
181 | 181 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
182 | 182 | % before update null, strip 4 |
|
183 | 183 | o 4:264128213d290d868c54642d13aeaa3675551a78 |
|
184 | 184 | | |
|
185 | 185 | | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
186 | 186 | | | |
|
187 | 187 | | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
188 | 188 | |/ |
|
189 | 189 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
190 | 190 | | |
|
191 | 191 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
192 | 192 | |
|
193 | 193 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
194 | 194 | % after update null, strip 4 |
|
195 | 195 | o 3:443431ffac4f5b5a19b0b6c298a21b7ba736bcce |
|
196 | 196 | | |
|
197 | 197 | o 2:65bd5f99a4a376cdea23a1153f07856b0d881d64 |
|
198 | 198 | | |
|
199 | 199 | o 1:ef3a871183d7199c541cc140218298bbfcc6c28a |
|
200 | 200 | | |
|
201 | 201 | o 0:9ab35a2d17cb64271241ea881efcc19dd953215b |
|
202 | 202 | |
|
203 | 203 | |
|
204 | 204 | $ hg log |
|
205 | 205 | changeset: 4:264128213d29 |
|
206 | 206 | tag: tip |
|
207 | 207 | parent: 1:ef3a871183d7 |
|
208 | 208 | user: test |
|
209 | 209 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
210 | 210 | summary: c |
|
211 | 211 | |
|
212 | 212 | changeset: 3:443431ffac4f |
|
213 | 213 | user: test |
|
214 | 214 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
215 | 215 | summary: e |
|
216 | 216 | |
|
217 | 217 | changeset: 2:65bd5f99a4a3 |
|
218 | 218 | user: test |
|
219 | 219 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
220 | 220 | summary: d |
|
221 | 221 | |
|
222 | 222 | changeset: 1:ef3a871183d7 |
|
223 | 223 | user: test |
|
224 | 224 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
225 | 225 | summary: b |
|
226 | 226 | |
|
227 | 227 | changeset: 0:9ab35a2d17cb |
|
228 | 228 | user: test |
|
229 | 229 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
230 | 230 | summary: a |
|
231 | 231 | |
|
232 | 232 | $ hg up -C 4 |
|
233 | 233 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
234 | 234 | $ hg parents |
|
235 | 235 | changeset: 4:264128213d29 |
|
236 | 236 | tag: tip |
|
237 | 237 | parent: 1:ef3a871183d7 |
|
238 | 238 | user: test |
|
239 | 239 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
240 | 240 | summary: c |
|
241 | 241 | |
|
242 | 242 | |
|
243 | 243 | $ hg --traceback strip 4 |
|
244 | 244 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
245 | 245 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg |
|
246 | 246 | $ hg parents |
|
247 | 247 | changeset: 1:ef3a871183d7 |
|
248 | 248 | user: test |
|
249 | 249 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
250 | 250 | summary: b |
|
251 | 251 | |
|
252 | 252 | $ hg debugbundle .hg/strip-backup/* |
|
253 | 253 | Stream params: {Compression: BZ} |
|
254 | 254 | changegroup -- {nbchanges: 1, version: 02} (mandatory: True) |
|
255 | 255 | 264128213d290d868c54642d13aeaa3675551a78 |
|
256 | 256 | cache:rev-branch-cache -- {} (mandatory: False) |
|
257 | 257 | phase-heads -- {} (mandatory: True) |
|
258 | 258 | 264128213d290d868c54642d13aeaa3675551a78 draft |
|
259 | 259 | $ hg unbundle .hg/strip-backup/* |
|
260 | 260 | adding changesets |
|
261 | 261 | adding manifests |
|
262 | 262 | adding file changes |
|
263 | 263 | added 1 changesets with 0 changes to 1 files (+1 heads) |
|
264 | 264 | new changesets 264128213d29 (1 drafts) |
|
265 | 265 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
266 | 266 | $ rm .hg/strip-backup/* |
|
267 | 267 | $ hg log --graph |
|
268 | 268 | o changeset: 4:264128213d29 |
|
269 | 269 | | tag: tip |
|
270 | 270 | | parent: 1:ef3a871183d7 |
|
271 | 271 | | user: test |
|
272 | 272 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
273 | 273 | | summary: c |
|
274 | 274 | | |
|
275 | 275 | | o changeset: 3:443431ffac4f |
|
276 | 276 | | | user: test |
|
277 | 277 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
278 | 278 | | | summary: e |
|
279 | 279 | | | |
|
280 | 280 | | o changeset: 2:65bd5f99a4a3 |
|
281 | 281 | |/ user: test |
|
282 | 282 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
283 | 283 | | summary: d |
|
284 | 284 | | |
|
285 | 285 | @ changeset: 1:ef3a871183d7 |
|
286 | 286 | | user: test |
|
287 | 287 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
288 | 288 | | summary: b |
|
289 | 289 | | |
|
290 | 290 | o changeset: 0:9ab35a2d17cb |
|
291 | 291 | user: test |
|
292 | 292 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
293 | 293 | summary: a |
|
294 | 294 | |
|
295 | 295 | $ hg up -C 2 |
|
296 | 296 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
297 | 297 | $ hg merge 4 |
|
298 | 298 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
299 | 299 | (branch merge, don't forget to commit) |
|
300 | 300 | |
|
301 | 301 | before strip of merge parent |
|
302 | 302 | |
|
303 | 303 | $ hg parents |
|
304 | 304 | changeset: 2:65bd5f99a4a3 |
|
305 | 305 | user: test |
|
306 | 306 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
307 | 307 | summary: d |
|
308 | 308 | |
|
309 | 309 | changeset: 4:264128213d29 |
|
310 | 310 | tag: tip |
|
311 | 311 | parent: 1:ef3a871183d7 |
|
312 | 312 | user: test |
|
313 | 313 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
314 | 314 | summary: c |
|
315 | 315 | |
|
316 | 316 | ##strip not allowed with merge in progress |
|
317 | 317 | $ hg strip 4 |
|
318 | 318 | abort: outstanding uncommitted merge |
|
319 | 319 | (use 'hg commit' or 'hg merge --abort') |
|
320 | 320 | [255] |
|
321 | 321 | ##strip allowed --force with merge in progress |
|
322 | 322 | $ hg strip 4 --force |
|
323 | 323 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
324 | 324 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
325 | 325 | |
|
326 | 326 | after strip of merge parent |
|
327 | 327 | |
|
328 | 328 | $ hg parents |
|
329 | 329 | changeset: 1:ef3a871183d7 |
|
330 | 330 | user: test |
|
331 | 331 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
332 | 332 | summary: b |
|
333 | 333 | |
|
334 | 334 | $ restore |
|
335 | 335 | |
|
336 | 336 | $ hg up |
|
337 | 337 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
338 | 338 | updated to "264128213d29: c" |
|
339 | 339 | 1 other heads for branch "default" |
|
340 | 340 | $ hg log -G |
|
341 | 341 | @ changeset: 4:264128213d29 |
|
342 | 342 | | tag: tip |
|
343 | 343 | | parent: 1:ef3a871183d7 |
|
344 | 344 | | user: test |
|
345 | 345 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
346 | 346 | | summary: c |
|
347 | 347 | | |
|
348 | 348 | | o changeset: 3:443431ffac4f |
|
349 | 349 | | | user: test |
|
350 | 350 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
351 | 351 | | | summary: e |
|
352 | 352 | | | |
|
353 | 353 | | o changeset: 2:65bd5f99a4a3 |
|
354 | 354 | |/ user: test |
|
355 | 355 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
356 | 356 | | summary: d |
|
357 | 357 | | |
|
358 | 358 | o changeset: 1:ef3a871183d7 |
|
359 | 359 | | user: test |
|
360 | 360 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
361 | 361 | | summary: b |
|
362 | 362 | | |
|
363 | 363 | o changeset: 0:9ab35a2d17cb |
|
364 | 364 | user: test |
|
365 | 365 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
366 | 366 | summary: a |
|
367 | 367 | |
|
368 | 368 | |
|
369 | 369 | 2 is parent of 3, only one strip should happen |
|
370 | 370 | |
|
371 | 371 | $ hg strip "roots(2)" 3 |
|
372 | 372 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
373 | 373 | $ hg log -G |
|
374 | 374 | @ changeset: 2:264128213d29 |
|
375 | 375 | | tag: tip |
|
376 | 376 | | user: test |
|
377 | 377 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
378 | 378 | | summary: c |
|
379 | 379 | | |
|
380 | 380 | o changeset: 1:ef3a871183d7 |
|
381 | 381 | | user: test |
|
382 | 382 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
383 | 383 | | summary: b |
|
384 | 384 | | |
|
385 | 385 | o changeset: 0:9ab35a2d17cb |
|
386 | 386 | user: test |
|
387 | 387 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
388 | 388 | summary: a |
|
389 | 389 | |
|
390 | 390 | $ restore |
|
391 | 391 | $ hg log -G |
|
392 | 392 | o changeset: 4:443431ffac4f |
|
393 | 393 | | tag: tip |
|
394 | 394 | | user: test |
|
395 | 395 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
396 | 396 | | summary: e |
|
397 | 397 | | |
|
398 | 398 | o changeset: 3:65bd5f99a4a3 |
|
399 | 399 | | parent: 1:ef3a871183d7 |
|
400 | 400 | | user: test |
|
401 | 401 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
402 | 402 | | summary: d |
|
403 | 403 | | |
|
404 | 404 | | @ changeset: 2:264128213d29 |
|
405 | 405 | |/ user: test |
|
406 | 406 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
407 | 407 | | summary: c |
|
408 | 408 | | |
|
409 | 409 | o changeset: 1:ef3a871183d7 |
|
410 | 410 | | user: test |
|
411 | 411 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
412 | 412 | | summary: b |
|
413 | 413 | | |
|
414 | 414 | o changeset: 0:9ab35a2d17cb |
|
415 | 415 | user: test |
|
416 | 416 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
417 | 417 | summary: a |
|
418 | 418 | |
|
419 | 419 | Failed hook while applying "saveheads" bundle. |
|
420 | 420 | |
|
421 | 421 | $ hg strip 2 --config hooks.pretxnchangegroup.bad=false |
|
422 | 422 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
423 | 423 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
424 | 424 | transaction abort! |
|
425 | 425 | rollback completed |
|
426 | 426 | strip failed, backup bundle stored in '$TESTTMP/test/.hg/strip-backup/*-backup.hg' (glob) |
|
427 | 427 | strip failed, unrecovered changes stored in '$TESTTMP/test/.hg/strip-backup/*-temp.hg' (glob) |
|
428 | 428 | (fix the problem, then recover the changesets with "hg unbundle '$TESTTMP/test/.hg/strip-backup/*-temp.hg'") (glob) |
|
429 | 429 | abort: pretxnchangegroup.bad hook exited with status 1 |
|
430 | 430 | [255] |
|
431 | 431 | $ restore |
|
432 | 432 | $ hg log -G |
|
433 | 433 | o changeset: 4:443431ffac4f |
|
434 | 434 | | tag: tip |
|
435 | 435 | | user: test |
|
436 | 436 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
437 | 437 | | summary: e |
|
438 | 438 | | |
|
439 | 439 | o changeset: 3:65bd5f99a4a3 |
|
440 | 440 | | parent: 1:ef3a871183d7 |
|
441 | 441 | | user: test |
|
442 | 442 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
443 | 443 | | summary: d |
|
444 | 444 | | |
|
445 | 445 | | o changeset: 2:264128213d29 |
|
446 | 446 | |/ user: test |
|
447 | 447 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
448 | 448 | | summary: c |
|
449 | 449 | | |
|
450 | 450 | @ changeset: 1:ef3a871183d7 |
|
451 | 451 | | user: test |
|
452 | 452 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
453 | 453 | | summary: b |
|
454 | 454 | | |
|
455 | 455 | o changeset: 0:9ab35a2d17cb |
|
456 | 456 | user: test |
|
457 | 457 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
458 | 458 | summary: a |
|
459 | 459 | |
|
460 | 460 | |
|
461 | 461 | 2 different branches: 2 strips |
|
462 | 462 | |
|
463 | 463 | $ hg strip 2 4 |
|
464 | 464 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
465 | 465 | $ hg log -G |
|
466 | 466 | o changeset: 2:65bd5f99a4a3 |
|
467 | 467 | | tag: tip |
|
468 | 468 | | user: test |
|
469 | 469 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
470 | 470 | | summary: d |
|
471 | 471 | | |
|
472 | 472 | @ changeset: 1:ef3a871183d7 |
|
473 | 473 | | user: test |
|
474 | 474 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
475 | 475 | | summary: b |
|
476 | 476 | | |
|
477 | 477 | o changeset: 0:9ab35a2d17cb |
|
478 | 478 | user: test |
|
479 | 479 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
480 | 480 | summary: a |
|
481 | 481 | |
|
482 | 482 | $ restore |
|
483 | 483 | |
|
484 | 484 | 2 different branches and a common ancestor: 1 strip |
|
485 | 485 | |
|
486 | 486 | $ hg strip 1 "2|4" |
|
487 | 487 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
488 | 488 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
489 | 489 | $ restore |
|
490 | 490 | |
|
491 | 491 | verify fncache is kept up-to-date |
|
492 | 492 | |
|
493 | 493 | $ touch a |
|
494 | 494 | $ hg ci -qAm a |
|
495 | 495 | #if repofncache |
|
496 | 496 | $ cat .hg/store/fncache | sort |
|
497 | 497 | data/a.i |
|
498 | 498 | data/bar.i |
|
499 | 499 | #endif |
|
500 | 500 | |
|
501 | 501 | $ hg strip tip |
|
502 | 502 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
503 | 503 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
504 | 504 | #if repofncache |
|
505 | 505 | $ cat .hg/store/fncache |
|
506 | 506 | data/bar.i |
|
507 | 507 | #endif |
|
508 | 508 | |
|
509 | 509 | stripping an empty revset |
|
510 | 510 | |
|
511 | 511 | $ hg strip "1 and not 1" |
|
512 | 512 | abort: empty revision set |
|
513 | 513 | [255] |
|
514 | 514 | |
|
515 | 515 | remove branchy history for qimport tests |
|
516 | 516 | |
|
517 | 517 | $ hg strip 3 |
|
518 | 518 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
519 | 519 | |
|
520 | 520 | |
|
521 | 521 | strip of applied mq should cleanup status file |
|
522 | 522 | |
|
523 | 523 | $ echo "mq=" >> $HGRCPATH |
|
524 | 524 | $ hg up -C 3 |
|
525 | 525 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
526 | 526 | $ echo fooagain >> bar |
|
527 | 527 | $ hg ci -mf |
|
528 | 528 | $ hg qimport -r tip:2 |
|
529 | 529 | |
|
530 | 530 | applied patches before strip |
|
531 | 531 | |
|
532 | 532 | $ hg qapplied |
|
533 | 533 | d |
|
534 | 534 | e |
|
535 | 535 | f |
|
536 | 536 | |
|
537 | 537 | stripping revision in queue |
|
538 | 538 | |
|
539 | 539 | $ hg strip 3 |
|
540 | 540 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
541 | 541 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
542 | 542 | |
|
543 | 543 | applied patches after stripping rev in queue |
|
544 | 544 | |
|
545 | 545 | $ hg qapplied |
|
546 | 546 | d |
|
547 | 547 | |
|
548 | 548 | stripping ancestor of queue |
|
549 | 549 | |
|
550 | 550 | $ hg strip 1 |
|
551 | 551 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
552 | 552 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
553 | 553 | |
|
554 | 554 | applied patches after stripping ancestor of queue |
|
555 | 555 | |
|
556 | 556 | $ hg qapplied |
|
557 | 557 | |
|
558 | 558 | Verify strip protects against stripping wc parent when there are uncommitted mods |
|
559 | 559 | |
|
560 | 560 | $ echo b > b |
|
561 | 561 | $ echo bb > bar |
|
562 | 562 | $ hg add b |
|
563 | 563 | $ hg ci -m 'b' |
|
564 | 564 | $ hg log --graph |
|
565 | 565 | @ changeset: 1:76dcf9fab855 |
|
566 | 566 | | tag: tip |
|
567 | 567 | | user: test |
|
568 | 568 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
569 | 569 | | summary: b |
|
570 | 570 | | |
|
571 | 571 | o changeset: 0:9ab35a2d17cb |
|
572 | 572 | user: test |
|
573 | 573 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
574 | 574 | summary: a |
|
575 | 575 | |
|
576 | 576 | $ hg up 0 |
|
577 | 577 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
578 | 578 | $ echo c > bar |
|
579 | 579 | $ hg up -t false |
|
580 | 580 | merging bar |
|
581 | 581 | merging bar failed! |
|
582 | 582 | 1 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
583 | 583 | use 'hg resolve' to retry unresolved file merges |
|
584 | 584 | [1] |
|
585 | 585 | $ hg sum |
|
586 | 586 | parent: 1:76dcf9fab855 tip |
|
587 | 587 | b |
|
588 | 588 | branch: default |
|
589 | 589 | commit: 1 modified, 1 unknown, 1 unresolved |
|
590 | 590 | update: (current) |
|
591 | 591 | phases: 2 draft |
|
592 | 592 | mq: 3 unapplied |
|
593 | 593 | |
|
594 | 594 | $ hg log --graph |
|
595 | 595 | @ changeset: 1:76dcf9fab855 |
|
596 | 596 | | tag: tip |
|
597 | 597 | | user: test |
|
598 | 598 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
599 | 599 | | summary: b |
|
600 | 600 | | |
|
601 |
|
|
|
601 | % changeset: 0:9ab35a2d17cb | |
|
602 | 602 | user: test |
|
603 | 603 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
604 | 604 | summary: a |
|
605 | 605 | |
|
606 | 606 | $ echo c > b |
|
607 | 607 | $ hg strip tip |
|
608 | 608 | abort: uncommitted changes |
|
609 | 609 | [255] |
|
610 | 610 | $ hg strip tip --keep |
|
611 | 611 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
612 | 612 | $ hg log --graph |
|
613 | 613 | @ changeset: 0:9ab35a2d17cb |
|
614 | 614 | tag: tip |
|
615 | 615 | user: test |
|
616 | 616 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
617 | 617 | summary: a |
|
618 | 618 | |
|
619 | 619 | $ hg status |
|
620 | 620 | M bar |
|
621 | 621 | ? b |
|
622 | 622 | ? bar.orig |
|
623 | 623 | |
|
624 | 624 | $ rm bar.orig |
|
625 | 625 | $ hg sum |
|
626 | 626 | parent: 0:9ab35a2d17cb tip |
|
627 | 627 | a |
|
628 | 628 | branch: default |
|
629 | 629 | commit: 1 modified, 1 unknown |
|
630 | 630 | update: (current) |
|
631 | 631 | phases: 1 draft |
|
632 | 632 | mq: 3 unapplied |
|
633 | 633 | |
|
634 | 634 | Strip adds, removes, modifies with --keep |
|
635 | 635 | |
|
636 | 636 | $ touch b |
|
637 | 637 | $ hg add b |
|
638 | 638 | $ hg commit -mb |
|
639 | 639 | $ touch c |
|
640 | 640 | |
|
641 | 641 | ... with a clean working dir |
|
642 | 642 | |
|
643 | 643 | $ hg add c |
|
644 | 644 | $ hg rm bar |
|
645 | 645 | $ hg commit -mc |
|
646 | 646 | $ hg status |
|
647 | 647 | $ hg strip --keep tip |
|
648 | 648 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
649 | 649 | $ hg status |
|
650 | 650 | ! bar |
|
651 | 651 | ? c |
|
652 | 652 | |
|
653 | 653 | ... with a dirty working dir |
|
654 | 654 | |
|
655 | 655 | $ hg add c |
|
656 | 656 | $ hg rm bar |
|
657 | 657 | $ hg commit -mc |
|
658 | 658 | $ hg status |
|
659 | 659 | $ echo b > b |
|
660 | 660 | $ echo d > d |
|
661 | 661 | $ hg strip --keep tip |
|
662 | 662 | saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) |
|
663 | 663 | $ hg status |
|
664 | 664 | M b |
|
665 | 665 | ! bar |
|
666 | 666 | ? c |
|
667 | 667 | ? d |
|
668 | 668 | |
|
669 | 669 | ... after updating the dirstate |
|
670 | 670 | $ hg add c |
|
671 | 671 | $ hg commit -mc |
|
672 | 672 | $ hg rm c |
|
673 | 673 | $ hg commit -mc |
|
674 | 674 | $ hg strip --keep '.^' -q |
|
675 | 675 | $ cd .. |
|
676 | 676 | |
|
677 | 677 | stripping many nodes on a complex graph (issue3299) |
|
678 | 678 | |
|
679 | 679 | $ hg init issue3299 |
|
680 | 680 | $ cd issue3299 |
|
681 | 681 | $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a' |
|
682 | 682 | $ hg strip 'not ancestors(x)' |
|
683 | 683 | saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob) |
|
684 | 684 | |
|
685 | 685 | test hg strip -B bookmark |
|
686 | 686 | |
|
687 | 687 | $ cd .. |
|
688 | 688 | $ hg init bookmarks |
|
689 | 689 | $ cd bookmarks |
|
690 | 690 | $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b<m+2:d<2.:e<m+1:f' |
|
691 | 691 | $ hg bookmark -r 'a' 'todelete' |
|
692 | 692 | $ hg bookmark -r 'b' 'B' |
|
693 | 693 | $ hg bookmark -r 'b' 'nostrip' |
|
694 | 694 | $ hg bookmark -r 'c' 'delete' |
|
695 | 695 | $ hg bookmark -r 'd' 'multipledelete1' |
|
696 | 696 | $ hg bookmark -r 'e' 'multipledelete2' |
|
697 | 697 | $ hg bookmark -r 'f' 'singlenode1' |
|
698 | 698 | $ hg bookmark -r 'f' 'singlenode2' |
|
699 | 699 | $ hg up -C todelete |
|
700 | 700 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
701 | 701 | (activating bookmark todelete) |
|
702 | 702 | $ hg strip -B nostrip |
|
703 | 703 | bookmark 'nostrip' deleted |
|
704 | 704 | abort: empty revision set |
|
705 | 705 | [255] |
|
706 | 706 | $ hg strip -B todelete |
|
707 | 707 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
708 | 708 | saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob) |
|
709 | 709 | bookmark 'todelete' deleted |
|
710 | 710 | $ hg id -ir dcbb326fdec2 |
|
711 | 711 | abort: unknown revision 'dcbb326fdec2'! |
|
712 | 712 | [255] |
|
713 | 713 | $ hg id -ir d62d843c9a01 |
|
714 | 714 | d62d843c9a01 |
|
715 | 715 | $ hg bookmarks |
|
716 | 716 | B 9:ff43616e5d0f |
|
717 | 717 | delete 6:2702dd0c91e7 |
|
718 | 718 | multipledelete1 11:e46a4836065c |
|
719 | 719 | multipledelete2 12:b4594d867745 |
|
720 | 720 | singlenode1 13:43227190fef8 |
|
721 | 721 | singlenode2 13:43227190fef8 |
|
722 | 722 | $ hg strip -B multipledelete1 -B multipledelete2 |
|
723 | 723 | saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/e46a4836065c-89ec65c2-backup.hg |
|
724 | 724 | bookmark 'multipledelete1' deleted |
|
725 | 725 | bookmark 'multipledelete2' deleted |
|
726 | 726 | $ hg id -ir e46a4836065c |
|
727 | 727 | abort: unknown revision 'e46a4836065c'! |
|
728 | 728 | [255] |
|
729 | 729 | $ hg id -ir b4594d867745 |
|
730 | 730 | abort: unknown revision 'b4594d867745'! |
|
731 | 731 | [255] |
|
732 | 732 | $ hg strip -B singlenode1 -B singlenode2 |
|
733 | 733 | saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/43227190fef8-8da858f2-backup.hg |
|
734 | 734 | bookmark 'singlenode1' deleted |
|
735 | 735 | bookmark 'singlenode2' deleted |
|
736 | 736 | $ hg id -ir 43227190fef8 |
|
737 | 737 | abort: unknown revision '43227190fef8'! |
|
738 | 738 | [255] |
|
739 | 739 | $ hg strip -B unknownbookmark |
|
740 | 740 | abort: bookmark 'unknownbookmark' not found |
|
741 | 741 | [255] |
|
742 | 742 | $ hg strip -B unknownbookmark1 -B unknownbookmark2 |
|
743 | 743 | abort: bookmark 'unknownbookmark1,unknownbookmark2' not found |
|
744 | 744 | [255] |
|
745 | 745 | $ hg strip -B delete -B unknownbookmark |
|
746 | 746 | abort: bookmark 'unknownbookmark' not found |
|
747 | 747 | [255] |
|
748 | 748 | $ hg strip -B delete |
|
749 | 749 | saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob) |
|
750 | 750 | bookmark 'delete' deleted |
|
751 | 751 | $ hg id -ir 6:2702dd0c91e7 |
|
752 | 752 | abort: unknown revision '2702dd0c91e7'! |
|
753 | 753 | [255] |
|
754 | 754 | $ hg update B |
|
755 | 755 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
756 | 756 | (activating bookmark B) |
|
757 | 757 | $ echo a > a |
|
758 | 758 | $ hg add a |
|
759 | 759 | $ hg strip -B B |
|
760 | 760 | abort: uncommitted changes |
|
761 | 761 | [255] |
|
762 | 762 | $ hg bookmarks |
|
763 | 763 | * B 6:ff43616e5d0f |
|
764 | 764 | |
|
765 | 765 | Make sure no one adds back a -b option: |
|
766 | 766 | |
|
767 | 767 | $ hg strip -b tip |
|
768 | 768 | hg strip: option -b not recognized |
|
769 | 769 | hg strip [-k] [-f] [-B bookmark] [-r] REV... |
|
770 | 770 | |
|
771 | 771 | strip changesets and all their descendants from the repository |
|
772 | 772 | |
|
773 | 773 | (use 'hg help -e strip' to show help for the strip extension) |
|
774 | 774 | |
|
775 | 775 | options ([+] can be repeated): |
|
776 | 776 | |
|
777 | 777 | -r --rev REV [+] strip specified revision (optional, can specify |
|
778 | 778 | revisions without this option) |
|
779 | 779 | -f --force force removal of changesets, discard uncommitted |
|
780 | 780 | changes (no backup) |
|
781 | 781 | --no-backup do not save backup bundle |
|
782 | 782 | -k --keep do not modify working directory during strip |
|
783 | 783 | -B --bookmark BOOKMARK [+] remove revs only reachable from given bookmark |
|
784 | 784 | --mq operate on patch repository |
|
785 | 785 | |
|
786 | 786 | (use 'hg strip -h' to show more help) |
|
787 | 787 | [255] |
|
788 | 788 | |
|
789 | 789 | $ cd .. |
|
790 | 790 | |
|
791 | 791 | Verify bundles don't get overwritten: |
|
792 | 792 | |
|
793 | 793 | $ hg init doublebundle |
|
794 | 794 | $ cd doublebundle |
|
795 | 795 | $ touch a |
|
796 | 796 | $ hg commit -Aqm a |
|
797 | 797 | $ touch b |
|
798 | 798 | $ hg commit -Aqm b |
|
799 | 799 | $ hg strip -r 0 |
|
800 | 800 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
801 | 801 | saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-e68910bd-backup.hg |
|
802 | 802 | $ ls .hg/strip-backup |
|
803 | 803 | 3903775176ed-e68910bd-backup.hg |
|
804 | 804 | #if repobundlerepo |
|
805 | 805 | $ hg pull -q -r 3903775176ed .hg/strip-backup/3903775176ed-e68910bd-backup.hg |
|
806 | 806 | $ hg strip -r 0 |
|
807 | 807 | saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-54390173-backup.hg |
|
808 | 808 | $ ls .hg/strip-backup |
|
809 | 809 | 3903775176ed-54390173-backup.hg |
|
810 | 810 | 3903775176ed-e68910bd-backup.hg |
|
811 | 811 | #endif |
|
812 | 812 | $ cd .. |
|
813 | 813 | |
|
814 | 814 | Test that we only bundle the stripped changesets (issue4736) |
|
815 | 815 | ------------------------------------------------------------ |
|
816 | 816 | |
|
817 | 817 | initialization (previous repo is empty anyway) |
|
818 | 818 | |
|
819 | 819 | $ hg init issue4736 |
|
820 | 820 | $ cd issue4736 |
|
821 | 821 | $ echo a > a |
|
822 | 822 | $ hg add a |
|
823 | 823 | $ hg commit -m commitA |
|
824 | 824 | $ echo b > b |
|
825 | 825 | $ hg add b |
|
826 | 826 | $ hg commit -m commitB |
|
827 | 827 | $ echo c > c |
|
828 | 828 | $ hg add c |
|
829 | 829 | $ hg commit -m commitC |
|
830 | 830 | $ hg up 'desc(commitB)' |
|
831 | 831 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
832 | 832 | $ echo d > d |
|
833 | 833 | $ hg add d |
|
834 | 834 | $ hg commit -m commitD |
|
835 | 835 | created new head |
|
836 | 836 | $ hg up 'desc(commitC)' |
|
837 | 837 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
838 | 838 | $ hg merge 'desc(commitD)' |
|
839 | 839 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
840 | 840 | (branch merge, don't forget to commit) |
|
841 | 841 | $ hg ci -m 'mergeCD' |
|
842 | 842 | $ hg log -G |
|
843 | 843 | @ changeset: 4:d8db9d137221 |
|
844 | 844 | |\ tag: tip |
|
845 | 845 | | | parent: 2:5c51d8d6557d |
|
846 | 846 | | | parent: 3:6625a5168474 |
|
847 | 847 | | | user: test |
|
848 | 848 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
849 | 849 | | | summary: mergeCD |
|
850 | 850 | | | |
|
851 | 851 | | o changeset: 3:6625a5168474 |
|
852 | 852 | | | parent: 1:eca11cf91c71 |
|
853 | 853 | | | user: test |
|
854 | 854 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
855 | 855 | | | summary: commitD |
|
856 | 856 | | | |
|
857 | 857 | o | changeset: 2:5c51d8d6557d |
|
858 | 858 | |/ user: test |
|
859 | 859 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
860 | 860 | | summary: commitC |
|
861 | 861 | | |
|
862 | 862 | o changeset: 1:eca11cf91c71 |
|
863 | 863 | | user: test |
|
864 | 864 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
865 | 865 | | summary: commitB |
|
866 | 866 | | |
|
867 | 867 | o changeset: 0:105141ef12d0 |
|
868 | 868 | user: test |
|
869 | 869 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
870 | 870 | summary: commitA |
|
871 | 871 | |
|
872 | 872 | |
|
873 | 873 | Check bundle behavior: |
|
874 | 874 | |
|
875 | 875 | $ hg bundle -r 'desc(mergeCD)' --base 'desc(commitC)' ../issue4736.hg |
|
876 | 876 | 2 changesets found |
|
877 | 877 | #if repobundlerepo |
|
878 | 878 | $ hg log -r 'bundle()' -R ../issue4736.hg |
|
879 | 879 | changeset: 3:6625a5168474 |
|
880 | 880 | parent: 1:eca11cf91c71 |
|
881 | 881 | user: test |
|
882 | 882 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
883 | 883 | summary: commitD |
|
884 | 884 | |
|
885 | 885 | changeset: 4:d8db9d137221 |
|
886 | 886 | tag: tip |
|
887 | 887 | parent: 2:5c51d8d6557d |
|
888 | 888 | parent: 3:6625a5168474 |
|
889 | 889 | user: test |
|
890 | 890 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
891 | 891 | summary: mergeCD |
|
892 | 892 | |
|
893 | 893 | #endif |
|
894 | 894 | |
|
895 | 895 | check strip behavior |
|
896 | 896 | |
|
897 | 897 | $ hg --config extensions.strip= strip 'desc(commitD)' --debug |
|
898 | 898 | resolving manifests |
|
899 | 899 | branchmerge: False, force: True, partial: False |
|
900 | 900 | ancestor: d8db9d137221+, local: d8db9d137221+, remote: eca11cf91c71 |
|
901 | 901 | c: other deleted -> r |
|
902 | 902 | removing c |
|
903 | 903 | d: other deleted -> r |
|
904 | 904 | removing d |
|
905 | 905 | starting 4 threads for background file closing (?) |
|
906 | 906 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
907 | 907 | 2 changesets found |
|
908 | 908 | list of changesets: |
|
909 | 909 | 6625a516847449b6f0fa3737b9ba56e9f0f3032c |
|
910 | 910 | d8db9d1372214336d2b5570f20ee468d2c72fa8b |
|
911 | 911 | bundle2-output-bundle: "HG20", (1 params) 3 parts total |
|
912 | 912 | bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload |
|
913 | 913 | bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload |
|
914 | 914 | bundle2-output-part: "phase-heads" 24 bytes payload |
|
915 | 915 | saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/6625a5168474-345bb43d-backup.hg |
|
916 | 916 | updating the branch cache |
|
917 | 917 | invalid branch cache (served): tip differs |
|
918 | 918 | $ hg log -G |
|
919 | 919 | o changeset: 2:5c51d8d6557d |
|
920 | 920 | | tag: tip |
|
921 | 921 | | user: test |
|
922 | 922 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
923 | 923 | | summary: commitC |
|
924 | 924 | | |
|
925 | 925 | @ changeset: 1:eca11cf91c71 |
|
926 | 926 | | user: test |
|
927 | 927 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
928 | 928 | | summary: commitB |
|
929 | 929 | | |
|
930 | 930 | o changeset: 0:105141ef12d0 |
|
931 | 931 | user: test |
|
932 | 932 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
933 | 933 | summary: commitA |
|
934 | 934 | |
|
935 | 935 | |
|
936 | 936 | strip backup content |
|
937 | 937 | |
|
938 | 938 | #if repobundlerepo |
|
939 | 939 | $ hg log -r 'bundle()' -R .hg/strip-backup/6625a5168474-*-backup.hg |
|
940 | 940 | changeset: 3:6625a5168474 |
|
941 | 941 | parent: 1:eca11cf91c71 |
|
942 | 942 | user: test |
|
943 | 943 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
944 | 944 | summary: commitD |
|
945 | 945 | |
|
946 | 946 | changeset: 4:d8db9d137221 |
|
947 | 947 | tag: tip |
|
948 | 948 | parent: 2:5c51d8d6557d |
|
949 | 949 | parent: 3:6625a5168474 |
|
950 | 950 | user: test |
|
951 | 951 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
952 | 952 | summary: mergeCD |
|
953 | 953 | |
|
954 | 954 | |
|
955 | 955 | #endif |
|
956 | 956 | |
|
957 | 957 | Check that the phase cache is properly invalidated after a strip with bookmark. |
|
958 | 958 | |
|
959 | 959 | $ cat > ../stripstalephasecache.py << EOF |
|
960 | 960 | > from mercurial import extensions, localrepo |
|
961 | 961 | > def transactioncallback(orig, repo, desc, *args, **kwargs): |
|
962 | 962 | > def test(transaction): |
|
963 | 963 | > # observe cache inconsistency |
|
964 | 964 | > try: |
|
965 | 965 | > [repo.changelog.node(r) for r in repo.revs(b"not public()")] |
|
966 | 966 | > except IndexError: |
|
967 | 967 | > repo.ui.status(b"Index error!\n") |
|
968 | 968 | > transaction = orig(repo, desc, *args, **kwargs) |
|
969 | 969 | > # warm up the phase cache |
|
970 | 970 | > list(repo.revs(b"not public()")) |
|
971 | 971 | > if desc != b'strip': |
|
972 | 972 | > transaction.addpostclose(b"phase invalidation test", test) |
|
973 | 973 | > return transaction |
|
974 | 974 | > def extsetup(ui): |
|
975 | 975 | > extensions.wrapfunction(localrepo.localrepository, b"transaction", |
|
976 | 976 | > transactioncallback) |
|
977 | 977 | > EOF |
|
978 | 978 | $ hg up -C 2 |
|
979 | 979 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
980 | 980 | $ echo k > k |
|
981 | 981 | $ hg add k |
|
982 | 982 | $ hg commit -m commitK |
|
983 | 983 | $ echo l > l |
|
984 | 984 | $ hg add l |
|
985 | 985 | $ hg commit -m commitL |
|
986 | 986 | $ hg book -r tip blah |
|
987 | 987 | $ hg strip ".^" --config extensions.crash=$TESTTMP/stripstalephasecache.py |
|
988 | 988 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
989 | 989 | saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/8f0b4384875c-4fa10deb-backup.hg |
|
990 | 990 | $ hg up -C 1 |
|
991 | 991 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
992 | 992 | |
|
993 | 993 | Error during post-close callback of the strip transaction |
|
994 | 994 | (They should be gracefully handled and reported) |
|
995 | 995 | |
|
996 | 996 | $ cat > ../crashstrip.py << EOF |
|
997 | 997 | > from mercurial import error |
|
998 | 998 | > def reposetup(ui, repo): |
|
999 | 999 | > class crashstriprepo(repo.__class__): |
|
1000 | 1000 | > def transaction(self, desc, *args, **kwargs): |
|
1001 | 1001 | > tr = super(crashstriprepo, self).transaction(desc, *args, **kwargs) |
|
1002 | 1002 | > if desc == b'strip': |
|
1003 | 1003 | > def crash(tra): raise error.Abort(b'boom') |
|
1004 | 1004 | > tr.addpostclose(b'crash', crash) |
|
1005 | 1005 | > return tr |
|
1006 | 1006 | > repo.__class__ = crashstriprepo |
|
1007 | 1007 | > EOF |
|
1008 | 1008 | $ hg strip tip --config extensions.crash=$TESTTMP/crashstrip.py |
|
1009 | 1009 | saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/5c51d8d6557d-70daef06-backup.hg |
|
1010 | 1010 | strip failed, backup bundle stored in '$TESTTMP/issue4736/.hg/strip-backup/5c51d8d6557d-70daef06-backup.hg' |
|
1011 | 1011 | abort: boom |
|
1012 | 1012 | [255] |
|
1013 | 1013 | |
|
1014 | 1014 | test stripping a working directory parent doesn't switch named branches |
|
1015 | 1015 | |
|
1016 | 1016 | $ hg log -G |
|
1017 | 1017 | @ changeset: 1:eca11cf91c71 |
|
1018 | 1018 | | tag: tip |
|
1019 | 1019 | | user: test |
|
1020 | 1020 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1021 | 1021 | | summary: commitB |
|
1022 | 1022 | | |
|
1023 | 1023 | o changeset: 0:105141ef12d0 |
|
1024 | 1024 | user: test |
|
1025 | 1025 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1026 | 1026 | summary: commitA |
|
1027 | 1027 | |
|
1028 | 1028 | |
|
1029 | 1029 | $ hg branch new-branch |
|
1030 | 1030 | marked working directory as branch new-branch |
|
1031 | 1031 | (branches are permanent and global, did you want a bookmark?) |
|
1032 | 1032 | $ hg ci -m "start new branch" |
|
1033 | 1033 | $ echo 'foo' > foo.txt |
|
1034 | 1034 | $ hg ci -Aqm foo |
|
1035 | 1035 | $ hg up default |
|
1036 | 1036 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1037 | 1037 | $ echo 'bar' > bar.txt |
|
1038 | 1038 | $ hg ci -Aqm bar |
|
1039 | 1039 | $ hg up new-branch |
|
1040 | 1040 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1041 | 1041 | $ hg merge default |
|
1042 | 1042 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1043 | 1043 | (branch merge, don't forget to commit) |
|
1044 | 1044 | $ hg log -G |
|
1045 | 1045 | @ changeset: 4:35358f982181 |
|
1046 | 1046 | | tag: tip |
|
1047 | 1047 | | parent: 1:eca11cf91c71 |
|
1048 | 1048 | | user: test |
|
1049 | 1049 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1050 | 1050 | | summary: bar |
|
1051 | 1051 | | |
|
1052 | 1052 | | @ changeset: 3:f62c6c09b707 |
|
1053 | 1053 | | | branch: new-branch |
|
1054 | 1054 | | | user: test |
|
1055 | 1055 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1056 | 1056 | | | summary: foo |
|
1057 | 1057 | | | |
|
1058 | 1058 | | o changeset: 2:b1d33a8cadd9 |
|
1059 | 1059 | |/ branch: new-branch |
|
1060 | 1060 | | user: test |
|
1061 | 1061 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1062 | 1062 | | summary: start new branch |
|
1063 | 1063 | | |
|
1064 | 1064 | o changeset: 1:eca11cf91c71 |
|
1065 | 1065 | | user: test |
|
1066 | 1066 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1067 | 1067 | | summary: commitB |
|
1068 | 1068 | | |
|
1069 | 1069 | o changeset: 0:105141ef12d0 |
|
1070 | 1070 | user: test |
|
1071 | 1071 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1072 | 1072 | summary: commitA |
|
1073 | 1073 | |
|
1074 | 1074 | |
|
1075 | 1075 | $ hg strip --force -r 35358f982181 |
|
1076 | 1076 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1077 | 1077 | saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-50d992d4-backup.hg |
|
1078 | 1078 | $ hg log -G |
|
1079 | 1079 | @ changeset: 3:f62c6c09b707 |
|
1080 | 1080 | | branch: new-branch |
|
1081 | 1081 | | tag: tip |
|
1082 | 1082 | | user: test |
|
1083 | 1083 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1084 | 1084 | | summary: foo |
|
1085 | 1085 | | |
|
1086 | 1086 | o changeset: 2:b1d33a8cadd9 |
|
1087 | 1087 | | branch: new-branch |
|
1088 | 1088 | | user: test |
|
1089 | 1089 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1090 | 1090 | | summary: start new branch |
|
1091 | 1091 | | |
|
1092 | 1092 | o changeset: 1:eca11cf91c71 |
|
1093 | 1093 | | user: test |
|
1094 | 1094 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1095 | 1095 | | summary: commitB |
|
1096 | 1096 | | |
|
1097 | 1097 | o changeset: 0:105141ef12d0 |
|
1098 | 1098 | user: test |
|
1099 | 1099 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1100 | 1100 | summary: commitA |
|
1101 | 1101 | |
|
1102 | 1102 | |
|
1103 | 1103 | $ hg up default |
|
1104 | 1104 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1105 | 1105 | $ echo 'bar' > bar.txt |
|
1106 | 1106 | $ hg ci -Aqm bar |
|
1107 | 1107 | $ hg up new-branch |
|
1108 | 1108 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1109 | 1109 | $ hg merge default |
|
1110 | 1110 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1111 | 1111 | (branch merge, don't forget to commit) |
|
1112 | 1112 | $ hg ci -m merge |
|
1113 | 1113 | $ hg log -G |
|
1114 | 1114 | @ changeset: 5:4cf5e92caec2 |
|
1115 | 1115 | |\ branch: new-branch |
|
1116 | 1116 | | | tag: tip |
|
1117 | 1117 | | | parent: 3:f62c6c09b707 |
|
1118 | 1118 | | | parent: 4:35358f982181 |
|
1119 | 1119 | | | user: test |
|
1120 | 1120 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1121 | 1121 | | | summary: merge |
|
1122 | 1122 | | | |
|
1123 | 1123 | | o changeset: 4:35358f982181 |
|
1124 | 1124 | | | parent: 1:eca11cf91c71 |
|
1125 | 1125 | | | user: test |
|
1126 | 1126 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1127 | 1127 | | | summary: bar |
|
1128 | 1128 | | | |
|
1129 | 1129 | o | changeset: 3:f62c6c09b707 |
|
1130 | 1130 | | | branch: new-branch |
|
1131 | 1131 | | | user: test |
|
1132 | 1132 | | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1133 | 1133 | | | summary: foo |
|
1134 | 1134 | | | |
|
1135 | 1135 | o | changeset: 2:b1d33a8cadd9 |
|
1136 | 1136 | |/ branch: new-branch |
|
1137 | 1137 | | user: test |
|
1138 | 1138 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1139 | 1139 | | summary: start new branch |
|
1140 | 1140 | | |
|
1141 | 1141 | o changeset: 1:eca11cf91c71 |
|
1142 | 1142 | | user: test |
|
1143 | 1143 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1144 | 1144 | | summary: commitB |
|
1145 | 1145 | | |
|
1146 | 1146 | o changeset: 0:105141ef12d0 |
|
1147 | 1147 | user: test |
|
1148 | 1148 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1149 | 1149 | summary: commitA |
|
1150 | 1150 | |
|
1151 | 1151 | |
|
1152 | 1152 | $ hg strip -r 35358f982181 |
|
1153 | 1153 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1154 | 1154 | saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg |
|
1155 | 1155 | $ hg log -G |
|
1156 | 1156 | @ changeset: 3:f62c6c09b707 |
|
1157 | 1157 | | branch: new-branch |
|
1158 | 1158 | | tag: tip |
|
1159 | 1159 | | user: test |
|
1160 | 1160 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1161 | 1161 | | summary: foo |
|
1162 | 1162 | | |
|
1163 | 1163 | o changeset: 2:b1d33a8cadd9 |
|
1164 | 1164 | | branch: new-branch |
|
1165 | 1165 | | user: test |
|
1166 | 1166 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1167 | 1167 | | summary: start new branch |
|
1168 | 1168 | | |
|
1169 | 1169 | o changeset: 1:eca11cf91c71 |
|
1170 | 1170 | | user: test |
|
1171 | 1171 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1172 | 1172 | | summary: commitB |
|
1173 | 1173 | | |
|
1174 | 1174 | o changeset: 0:105141ef12d0 |
|
1175 | 1175 | user: test |
|
1176 | 1176 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1177 | 1177 | summary: commitA |
|
1178 | 1178 | |
|
1179 | 1179 | |
|
1180 | 1180 | $ hg unbundle -u $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg |
|
1181 | 1181 | adding changesets |
|
1182 | 1182 | adding manifests |
|
1183 | 1183 | adding file changes |
|
1184 | 1184 | added 2 changesets with 1 changes to 1 files |
|
1185 | 1185 | new changesets 35358f982181:4cf5e92caec2 (2 drafts) |
|
1186 | 1186 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1187 | 1187 | |
|
1188 | 1188 | $ hg strip -k -r 35358f982181 |
|
1189 | 1189 | saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/35358f982181-a6f020aa-backup.hg |
|
1190 | 1190 | $ hg log -G |
|
1191 | 1191 | @ changeset: 3:f62c6c09b707 |
|
1192 | 1192 | | branch: new-branch |
|
1193 | 1193 | | tag: tip |
|
1194 | 1194 | | user: test |
|
1195 | 1195 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1196 | 1196 | | summary: foo |
|
1197 | 1197 | | |
|
1198 | 1198 | o changeset: 2:b1d33a8cadd9 |
|
1199 | 1199 | | branch: new-branch |
|
1200 | 1200 | | user: test |
|
1201 | 1201 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1202 | 1202 | | summary: start new branch |
|
1203 | 1203 | | |
|
1204 | 1204 | o changeset: 1:eca11cf91c71 |
|
1205 | 1205 | | user: test |
|
1206 | 1206 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1207 | 1207 | | summary: commitB |
|
1208 | 1208 | | |
|
1209 | 1209 | o changeset: 0:105141ef12d0 |
|
1210 | 1210 | user: test |
|
1211 | 1211 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
1212 | 1212 | summary: commitA |
|
1213 | 1213 | |
|
1214 | 1214 | $ hg diff |
|
1215 | 1215 | diff -r f62c6c09b707 bar.txt |
|
1216 | 1216 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 |
|
1217 | 1217 | +++ b/bar.txt Thu Jan 01 00:00:00 1970 +0000 |
|
1218 | 1218 | @@ -0,0 +1,1 @@ |
|
1219 | 1219 | +bar |
|
1220 | 1220 | |
|
1221 | 1221 | Use delayedstrip to strip inside a transaction |
|
1222 | 1222 | |
|
1223 | 1223 | $ cd $TESTTMP |
|
1224 | 1224 | $ hg init delayedstrip |
|
1225 | 1225 | $ cd delayedstrip |
|
1226 | 1226 | $ hg debugdrawdag <<'EOS' |
|
1227 | 1227 | > D |
|
1228 | 1228 | > | |
|
1229 | 1229 | > C F H # Commit on top of "I", |
|
1230 | 1230 | > | |/| # Strip B+D+I+E+G+H+Z |
|
1231 | 1231 | > I B E G |
|
1232 | 1232 | > \|/ |
|
1233 | 1233 | > A Z |
|
1234 | 1234 | > EOS |
|
1235 | 1235 | $ cp -R . ../scmutilcleanup |
|
1236 | 1236 | |
|
1237 | 1237 | $ hg up -C I |
|
1238 | 1238 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1239 | 1239 | $ echo 3 >> I |
|
1240 | 1240 | $ cat > $TESTTMP/delayedstrip.py <<EOF |
|
1241 | 1241 | > from __future__ import absolute_import |
|
1242 | 1242 | > from mercurial import commands, registrar, repair |
|
1243 | 1243 | > cmdtable = {} |
|
1244 | 1244 | > command = registrar.command(cmdtable) |
|
1245 | 1245 | > @command(b'testdelayedstrip') |
|
1246 | 1246 | > def testdelayedstrip(ui, repo): |
|
1247 | 1247 | > def getnodes(expr): |
|
1248 | 1248 | > return [repo.changelog.node(r) for r in repo.revs(expr)] |
|
1249 | 1249 | > with repo.wlock(): |
|
1250 | 1250 | > with repo.lock(): |
|
1251 | 1251 | > with repo.transaction(b'delayedstrip'): |
|
1252 | 1252 | > repair.delayedstrip(ui, repo, getnodes(b'B+I+Z+D+E'), b'J') |
|
1253 | 1253 | > repair.delayedstrip(ui, repo, getnodes(b'G+H+Z'), b'I') |
|
1254 | 1254 | > commands.commit(ui, repo, message=b'J', date=b'0 0') |
|
1255 | 1255 | > EOF |
|
1256 | 1256 | $ hg testdelayedstrip --config extensions.t=$TESTTMP/delayedstrip.py |
|
1257 | 1257 | warning: orphaned descendants detected, not stripping 08ebfeb61bac, 112478962961, 7fb047a69f22 |
|
1258 | 1258 | saved backup bundle to $TESTTMP/delayedstrip/.hg/strip-backup/f585351a92f8-17475721-I.hg |
|
1259 | 1259 | |
|
1260 | 1260 | $ hg log -G -T '{rev}:{node|short} {desc}' -r 'sort(all(), topo)' |
|
1261 | 1261 | @ 6:2f2d51af6205 J |
|
1262 | 1262 | | |
|
1263 | 1263 | o 3:08ebfeb61bac I |
|
1264 | 1264 | | |
|
1265 | 1265 | | o 5:64a8289d2492 F |
|
1266 | 1266 | | | |
|
1267 | 1267 | | o 2:7fb047a69f22 E |
|
1268 | 1268 | |/ |
|
1269 | 1269 | | o 4:26805aba1e60 C |
|
1270 | 1270 | | | |
|
1271 | 1271 | | o 1:112478962961 B |
|
1272 | 1272 | |/ |
|
1273 | 1273 | o 0:426bada5c675 A |
|
1274 | 1274 | |
|
1275 | 1275 | Test high-level scmutil.cleanupnodes API |
|
1276 | 1276 | |
|
1277 | 1277 | $ cd $TESTTMP/scmutilcleanup |
|
1278 | 1278 | $ hg debugdrawdag <<'EOS' |
|
1279 | 1279 | > D2 F2 G2 # D2, F2, G2 are replacements for D, F, G |
|
1280 | 1280 | > | | | |
|
1281 | 1281 | > C H G |
|
1282 | 1282 | > EOS |
|
1283 | 1283 | $ for i in B C D F G I Z; do |
|
1284 | 1284 | > hg bookmark -i -r $i b-$i |
|
1285 | 1285 | > done |
|
1286 | 1286 | $ hg bookmark -i -r E 'b-F@divergent1' |
|
1287 | 1287 | $ hg bookmark -i -r H 'b-F@divergent2' |
|
1288 | 1288 | $ hg bookmark -i -r G 'b-F@divergent3' |
|
1289 | 1289 | $ cp -R . ../scmutilcleanup.obsstore |
|
1290 | 1290 | |
|
1291 | 1291 | $ cat > $TESTTMP/scmutilcleanup.py <<EOF |
|
1292 | 1292 | > from mercurial import registrar, scmutil |
|
1293 | 1293 | > cmdtable = {} |
|
1294 | 1294 | > command = registrar.command(cmdtable) |
|
1295 | 1295 | > @command(b'testnodescleanup') |
|
1296 | 1296 | > def testnodescleanup(ui, repo): |
|
1297 | 1297 | > def nodes(expr): |
|
1298 | 1298 | > return [repo.changelog.node(r) for r in repo.revs(expr)] |
|
1299 | 1299 | > def node(expr): |
|
1300 | 1300 | > return nodes(expr)[0] |
|
1301 | 1301 | > with repo.wlock(): |
|
1302 | 1302 | > with repo.lock(): |
|
1303 | 1303 | > with repo.transaction(b'delayedstrip'): |
|
1304 | 1304 | > mapping = {node(b'F'): [node(b'F2')], |
|
1305 | 1305 | > node(b'D'): [node(b'D2')], |
|
1306 | 1306 | > node(b'G'): [node(b'G2')]} |
|
1307 | 1307 | > scmutil.cleanupnodes(repo, mapping, b'replace') |
|
1308 | 1308 | > scmutil.cleanupnodes(repo, nodes(b'((B::)+I+Z)-D2-obsolete()'), |
|
1309 | 1309 | > b'replace') |
|
1310 | 1310 | > EOF |
|
1311 | 1311 | $ hg testnodescleanup --config extensions.t=$TESTTMP/scmutilcleanup.py |
|
1312 | 1312 | warning: orphaned descendants detected, not stripping 112478962961, 1fc8102cda62, 26805aba1e60 |
|
1313 | 1313 | saved backup bundle to $TESTTMP/scmutilcleanup/.hg/strip-backup/f585351a92f8-73fb7c03-replace.hg |
|
1314 | 1314 | |
|
1315 | 1315 | $ hg log -G -T '{rev}:{node|short} {desc} {bookmarks}' -r 'sort(all(), topo)' |
|
1316 | 1316 | o 8:1473d4b996d1 G2 b-F@divergent3 b-G |
|
1317 | 1317 | | |
|
1318 | 1318 | | o 7:d11b3456a873 F2 b-F |
|
1319 | 1319 | | | |
|
1320 | 1320 | | o 5:5cb05ba470a7 H |
|
1321 | 1321 | |/| |
|
1322 | 1322 | | o 3:7fb047a69f22 E b-F@divergent1 |
|
1323 | 1323 | | | |
|
1324 | 1324 | | | o 6:7c78f703e465 D2 b-D |
|
1325 | 1325 | | | | |
|
1326 | 1326 | | | o 4:26805aba1e60 C |
|
1327 | 1327 | | | | |
|
1328 | 1328 | | | o 2:112478962961 B |
|
1329 | 1329 | | |/ |
|
1330 | 1330 | o | 1:1fc8102cda62 G |
|
1331 | 1331 | / |
|
1332 | 1332 | o 0:426bada5c675 A b-B b-C b-I |
|
1333 | 1333 | |
|
1334 | 1334 | $ hg bookmark |
|
1335 | 1335 | b-B 0:426bada5c675 |
|
1336 | 1336 | b-C 0:426bada5c675 |
|
1337 | 1337 | b-D 6:7c78f703e465 |
|
1338 | 1338 | b-F 7:d11b3456a873 |
|
1339 | 1339 | b-F@divergent1 3:7fb047a69f22 |
|
1340 | 1340 | b-F@divergent3 8:1473d4b996d1 |
|
1341 | 1341 | b-G 8:1473d4b996d1 |
|
1342 | 1342 | b-I 0:426bada5c675 |
|
1343 | 1343 | b-Z -1:000000000000 |
|
1344 | 1344 | |
|
1345 | 1345 | Test the above using obsstore "by the way". Not directly related to strip, but |
|
1346 | 1346 | we have reusable code here |
|
1347 | 1347 | |
|
1348 | 1348 | $ cd $TESTTMP/scmutilcleanup.obsstore |
|
1349 | 1349 | $ cat >> .hg/hgrc <<EOF |
|
1350 | 1350 | > [experimental] |
|
1351 | 1351 | > evolution=true |
|
1352 | 1352 | > evolution.track-operation=1 |
|
1353 | 1353 | > EOF |
|
1354 | 1354 | |
|
1355 | 1355 | $ hg testnodescleanup --config extensions.t=$TESTTMP/scmutilcleanup.py |
|
1356 | 1356 | 4 new orphan changesets |
|
1357 | 1357 | |
|
1358 | 1358 | $ rm .hg/localtags |
|
1359 | 1359 | $ hg log -G -T '{rev}:{node|short} {desc} {bookmarks}' -r 'sort(all(), topo)' |
|
1360 | 1360 | * 12:1473d4b996d1 G2 b-F@divergent3 b-G |
|
1361 | 1361 | | |
|
1362 | 1362 | | * 11:d11b3456a873 F2 b-F |
|
1363 | 1363 | | | |
|
1364 | 1364 | | * 8:5cb05ba470a7 H |
|
1365 | 1365 | |/| |
|
1366 | 1366 | | o 4:7fb047a69f22 E b-F@divergent1 |
|
1367 | 1367 | | | |
|
1368 | 1368 | | | * 10:7c78f703e465 D2 b-D |
|
1369 | 1369 | | | | |
|
1370 | 1370 | | | x 6:26805aba1e60 C |
|
1371 | 1371 | | | | |
|
1372 | 1372 | | | x 3:112478962961 B |
|
1373 | 1373 | | |/ |
|
1374 | 1374 | x | 1:1fc8102cda62 G |
|
1375 | 1375 | / |
|
1376 | 1376 | o 0:426bada5c675 A b-B b-C b-I |
|
1377 | 1377 | |
|
1378 | 1378 | $ hg debugobsolete |
|
1379 | 1379 | 1fc8102cda6204549f031015641606ccf5513ec3 1473d4b996d1d1b121de6b39fab6a04fbf9d873e 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'replace', 'user': 'test'} |
|
1380 | 1380 | 64a8289d249234b9886244d379f15e6b650b28e3 d11b3456a873daec7c7bc53e5622e8df6d741bd2 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'replace', 'user': 'test'} |
|
1381 | 1381 | f585351a92f85104bff7c284233c338b10eb1df7 7c78f703e465d73102cc8780667ce269c5208a40 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '9', 'operation': 'replace', 'user': 'test'} |
|
1382 | 1382 | 48b9aae0607f43ff110d84e6883c151942add5ab 0 {0000000000000000000000000000000000000000} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'} |
|
1383 | 1383 | 112478962961147124edd43549aedd1a335e44bf 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'} |
|
1384 | 1384 | 08ebfeb61bac6e3f12079de774d285a0d6689eba 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'} |
|
1385 | 1385 | 26805aba1e600a82e93661149f2313866a221a7b 0 {112478962961147124edd43549aedd1a335e44bf} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'replace', 'user': 'test'} |
|
1386 | 1386 | $ cd .. |
|
1387 | 1387 | |
|
1388 | 1388 | Test that obsmarkers are restored even when not using generaldelta |
|
1389 | 1389 | |
|
1390 | 1390 | $ hg --config format.usegeneraldelta=no init issue5678 |
|
1391 | 1391 | $ cd issue5678 |
|
1392 | 1392 | $ cat >> .hg/hgrc <<EOF |
|
1393 | 1393 | > [experimental] |
|
1394 | 1394 | > evolution=true |
|
1395 | 1395 | > EOF |
|
1396 | 1396 | $ echo a > a |
|
1397 | 1397 | $ hg ci -Aqm a |
|
1398 | 1398 | $ hg ci --amend -m a2 |
|
1399 | 1399 | $ hg debugobsolete |
|
1400 | 1400 | cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'} |
|
1401 | 1401 | $ hg strip . |
|
1402 | 1402 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1403 | 1403 | saved backup bundle to $TESTTMP/issue5678/.hg/strip-backup/489bac576828-bef27e14-backup.hg |
|
1404 | 1404 | $ hg unbundle -q .hg/strip-backup/* |
|
1405 | 1405 | $ hg debugobsolete |
|
1406 | 1406 | cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'} |
|
1407 | 1407 | $ cd .. |
@@ -1,691 +1,691 b'' | |||
|
1 | 1 | $ cat >> $HGRCPATH <<EOF |
|
2 | 2 | > [commands] |
|
3 | 3 | > status.verbose=1 |
|
4 | 4 | > EOF |
|
5 | 5 | |
|
6 | 6 | # Construct the following history tree: |
|
7 | 7 | # |
|
8 | 8 | # @ 5:e1bb631146ca b1 |
|
9 | 9 | # | |
|
10 | 10 | # o 4:a4fdb3b883c4 0:b608b9236435 b1 |
|
11 | 11 | # | |
|
12 | 12 | # | o 3:4b57d2520816 1:44592833ba9f |
|
13 | 13 | # | | |
|
14 | 14 | # | | o 2:063f31070f65 |
|
15 | 15 | # | |/ |
|
16 | 16 | # | o 1:44592833ba9f |
|
17 | 17 | # |/ |
|
18 | 18 | # o 0:b608b9236435 |
|
19 | 19 | |
|
20 | 20 | $ mkdir b1 |
|
21 | 21 | $ cd b1 |
|
22 | 22 | $ hg init |
|
23 | 23 | $ echo foo > foo |
|
24 | 24 | $ echo zero > a |
|
25 | 25 | $ hg init sub |
|
26 | 26 | $ echo suba > sub/suba |
|
27 | 27 | $ hg --cwd sub ci -Am addsuba |
|
28 | 28 | adding suba |
|
29 | 29 | $ echo 'sub = sub' > .hgsub |
|
30 | 30 | $ hg ci -qAm0 |
|
31 | 31 | $ echo one > a ; hg ci -m1 |
|
32 | 32 | $ echo two > a ; hg ci -m2 |
|
33 | 33 | $ hg up -q 1 |
|
34 | 34 | $ echo three > a ; hg ci -qm3 |
|
35 | 35 | $ hg up -q 0 |
|
36 | 36 | $ hg branch -q b1 |
|
37 | 37 | $ echo four > a ; hg ci -qm4 |
|
38 | 38 | $ echo five > a ; hg ci -qm5 |
|
39 | 39 | |
|
40 | 40 | Initial repo state: |
|
41 | 41 | |
|
42 | 42 | $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n' |
|
43 | 43 | @ 5:ff252e8273df b1 |
|
44 | 44 | | |
|
45 | 45 | o 4:d047485b3896 0:60829823a42a b1 |
|
46 | 46 | | |
|
47 | 47 | | o 3:6efa171f091b 1:0786582aa4b1 |
|
48 | 48 | | | |
|
49 | 49 | | | o 2:bd10386d478c |
|
50 | 50 | | |/ |
|
51 | 51 | | o 1:0786582aa4b1 |
|
52 | 52 | |/ |
|
53 | 53 | o 0:60829823a42a |
|
54 | 54 | |
|
55 | 55 | |
|
56 | 56 | Make sure update doesn't assume b1 is a repository if invoked from outside: |
|
57 | 57 | |
|
58 | 58 | $ cd .. |
|
59 | 59 | $ hg update b1 |
|
60 | 60 | abort: no repository found in '$TESTTMP' (.hg not found)! |
|
61 | 61 | [255] |
|
62 | 62 | $ cd b1 |
|
63 | 63 | |
|
64 | 64 | Test helper functions: |
|
65 | 65 | |
|
66 | 66 | $ revtest () { |
|
67 | 67 | > msg=$1 |
|
68 | 68 | > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub' |
|
69 | 69 | > startrev=$3 |
|
70 | 70 | > targetrev=$4 |
|
71 | 71 | > opt=$5 |
|
72 | 72 | > hg up -qC $startrev |
|
73 | 73 | > test $dirtyflag = dirty && echo dirty > foo |
|
74 | 74 | > test $dirtyflag = dirtysub && echo dirty > sub/suba |
|
75 | 75 | > hg up $opt $targetrev |
|
76 | 76 | > hg parent --template 'parent={rev}\n' |
|
77 | 77 | > hg stat -S |
|
78 | 78 | > } |
|
79 | 79 | |
|
80 | 80 | $ norevtest () { |
|
81 | 81 | > msg=$1 |
|
82 | 82 | > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub' |
|
83 | 83 | > startrev=$3 |
|
84 | 84 | > opt=$4 |
|
85 | 85 | > hg up -qC $startrev |
|
86 | 86 | > test $dirtyflag = dirty && echo dirty > foo |
|
87 | 87 | > test $dirtyflag = dirtysub && echo dirty > sub/suba |
|
88 | 88 | > hg up $opt |
|
89 | 89 | > hg parent --template 'parent={rev}\n' |
|
90 | 90 | > hg stat -S |
|
91 | 91 | > } |
|
92 | 92 | |
|
93 | 93 | Test cases are documented in a table in the update function of merge.py. |
|
94 | 94 | Cases are run as shown in that table, row by row. |
|
95 | 95 | |
|
96 | 96 | $ norevtest 'none clean linear' clean 4 |
|
97 | 97 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
98 | 98 | parent=5 |
|
99 | 99 | |
|
100 | 100 | $ norevtest 'none clean same' clean 2 |
|
101 | 101 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
102 | 102 | updated to "bd10386d478c: 2" |
|
103 | 103 | 1 other heads for branch "default" |
|
104 | 104 | parent=2 |
|
105 | 105 | |
|
106 | 106 | |
|
107 | 107 | $ revtest 'none clean linear' clean 1 2 |
|
108 | 108 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
109 | 109 | parent=2 |
|
110 | 110 | |
|
111 | 111 | $ revtest 'none clean same' clean 2 3 |
|
112 | 112 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
113 | 113 | parent=3 |
|
114 | 114 | |
|
115 | 115 | $ revtest 'none clean cross' clean 3 4 |
|
116 | 116 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
117 | 117 | parent=4 |
|
118 | 118 | |
|
119 | 119 | |
|
120 | 120 | $ revtest 'none dirty linear' dirty 1 2 |
|
121 | 121 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
122 | 122 | parent=2 |
|
123 | 123 | M foo |
|
124 | 124 | |
|
125 | 125 | $ revtest 'none dirtysub linear' dirtysub 1 2 |
|
126 | 126 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
127 | 127 | parent=2 |
|
128 | 128 | M sub/suba |
|
129 | 129 | |
|
130 | 130 | $ revtest 'none dirty same' dirty 2 3 |
|
131 | 131 | abort: uncommitted changes |
|
132 | 132 | (commit or update --clean to discard changes) |
|
133 | 133 | parent=2 |
|
134 | 134 | M foo |
|
135 | 135 | |
|
136 | 136 | $ revtest 'none dirtysub same' dirtysub 2 3 |
|
137 | 137 | abort: uncommitted changes |
|
138 | 138 | (commit or update --clean to discard changes) |
|
139 | 139 | parent=2 |
|
140 | 140 | M sub/suba |
|
141 | 141 | |
|
142 | 142 | $ revtest 'none dirty cross' dirty 3 4 |
|
143 | 143 | abort: uncommitted changes |
|
144 | 144 | (commit or update --clean to discard changes) |
|
145 | 145 | parent=3 |
|
146 | 146 | M foo |
|
147 | 147 | |
|
148 | 148 | $ norevtest 'none dirty cross' dirty 2 |
|
149 | 149 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
150 | 150 | updated to "bd10386d478c: 2" |
|
151 | 151 | 1 other heads for branch "default" |
|
152 | 152 | parent=2 |
|
153 | 153 | M foo |
|
154 | 154 | |
|
155 | 155 | $ revtest 'none dirtysub cross' dirtysub 3 4 |
|
156 | 156 | abort: uncommitted changes |
|
157 | 157 | (commit or update --clean to discard changes) |
|
158 | 158 | parent=3 |
|
159 | 159 | M sub/suba |
|
160 | 160 | |
|
161 | 161 | $ revtest '-C dirty linear' dirty 1 2 -C |
|
162 | 162 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
163 | 163 | parent=2 |
|
164 | 164 | |
|
165 | 165 | $ revtest '-c dirty linear' dirty 1 2 -c |
|
166 | 166 | abort: uncommitted changes |
|
167 | 167 | parent=1 |
|
168 | 168 | M foo |
|
169 | 169 | |
|
170 | 170 | $ revtest '-m dirty linear' dirty 1 2 -m |
|
171 | 171 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
172 | 172 | parent=2 |
|
173 | 173 | M foo |
|
174 | 174 | |
|
175 | 175 | $ revtest '-m dirty cross' dirty 3 4 -m |
|
176 | 176 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
177 | 177 | parent=4 |
|
178 | 178 | M foo |
|
179 | 179 | |
|
180 | 180 | $ revtest '-c dirtysub linear' dirtysub 1 2 -c |
|
181 | 181 | abort: uncommitted changes in subrepository "sub" |
|
182 | 182 | parent=1 |
|
183 | 183 | M sub/suba |
|
184 | 184 | |
|
185 | 185 | $ norevtest '-c clean same' clean 2 -c |
|
186 | 186 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
187 | 187 | updated to "bd10386d478c: 2" |
|
188 | 188 | 1 other heads for branch "default" |
|
189 | 189 | parent=2 |
|
190 | 190 | |
|
191 | 191 | $ revtest '-cC dirty linear' dirty 1 2 -cC |
|
192 | 192 | abort: can only specify one of -C/--clean, -c/--check, or -m/--merge |
|
193 | 193 | parent=1 |
|
194 | 194 | M foo |
|
195 | 195 | |
|
196 | 196 | $ revtest '-mc dirty linear' dirty 1 2 -mc |
|
197 | 197 | abort: can only specify one of -C/--clean, -c/--check, or -m/--merge |
|
198 | 198 | parent=1 |
|
199 | 199 | M foo |
|
200 | 200 | |
|
201 | 201 | $ revtest '-mC dirty linear' dirty 1 2 -mC |
|
202 | 202 | abort: can only specify one of -C/--clean, -c/--check, or -m/--merge |
|
203 | 203 | parent=1 |
|
204 | 204 | M foo |
|
205 | 205 | |
|
206 | 206 | $ echo '[commands]' >> .hg/hgrc |
|
207 | 207 | $ echo 'update.check = abort' >> .hg/hgrc |
|
208 | 208 | |
|
209 | 209 | $ revtest 'none dirty linear' dirty 1 2 |
|
210 | 210 | abort: uncommitted changes |
|
211 | 211 | parent=1 |
|
212 | 212 | M foo |
|
213 | 213 | |
|
214 | 214 | $ revtest 'none dirty linear' dirty 1 2 -c |
|
215 | 215 | abort: uncommitted changes |
|
216 | 216 | parent=1 |
|
217 | 217 | M foo |
|
218 | 218 | |
|
219 | 219 | $ revtest 'none dirty linear' dirty 1 2 -C |
|
220 | 220 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
221 | 221 | parent=2 |
|
222 | 222 | |
|
223 | 223 | $ echo 'update.check = none' >> .hg/hgrc |
|
224 | 224 | |
|
225 | 225 | $ revtest 'none dirty cross' dirty 3 4 |
|
226 | 226 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
227 | 227 | parent=4 |
|
228 | 228 | M foo |
|
229 | 229 | |
|
230 | 230 | $ revtest 'none dirty linear' dirty 1 2 |
|
231 | 231 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
232 | 232 | parent=2 |
|
233 | 233 | M foo |
|
234 | 234 | |
|
235 | 235 | $ revtest 'none dirty linear' dirty 1 2 -c |
|
236 | 236 | abort: uncommitted changes |
|
237 | 237 | parent=1 |
|
238 | 238 | M foo |
|
239 | 239 | |
|
240 | 240 | $ revtest 'none dirty linear' dirty 1 2 -C |
|
241 | 241 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
242 | 242 | parent=2 |
|
243 | 243 | |
|
244 | 244 | $ hg co -qC 3 |
|
245 | 245 | $ echo dirty >> a |
|
246 | 246 | $ hg co --tool :merge3 4 |
|
247 | 247 | merging a |
|
248 | 248 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') |
|
249 | 249 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
250 | 250 | use 'hg resolve' to retry unresolved file merges |
|
251 | 251 | [1] |
|
252 | 252 | $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n' |
|
253 | 253 | o 5:ff252e8273df b1 |
|
254 | 254 | | |
|
255 | 255 | @ 4:d047485b3896 0:60829823a42a b1 |
|
256 | 256 | | |
|
257 |
| |
|
|
257 | | % 3:6efa171f091b 1:0786582aa4b1 | |
|
258 | 258 | | | |
|
259 | 259 | | | o 2:bd10386d478c |
|
260 | 260 | | |/ |
|
261 | 261 | | o 1:0786582aa4b1 |
|
262 | 262 | |/ |
|
263 | 263 | o 0:60829823a42a |
|
264 | 264 | |
|
265 | 265 | $ hg st |
|
266 | 266 | M a |
|
267 | 267 | ? a.orig |
|
268 | 268 | # Unresolved merge conflicts: |
|
269 | 269 | # |
|
270 | 270 | # a |
|
271 | 271 | # |
|
272 | 272 | # To mark files as resolved: hg resolve --mark FILE |
|
273 | 273 | |
|
274 | 274 | $ cat a |
|
275 | 275 | <<<<<<< working copy: 6efa171f091b - test: 3 |
|
276 | 276 | three |
|
277 | 277 | dirty |
|
278 | 278 | ||||||| base |
|
279 | 279 | three |
|
280 | 280 | ======= |
|
281 | 281 | four |
|
282 | 282 | >>>>>>> destination: d047485b3896 b1 - test: 4 |
|
283 | 283 | $ rm a.orig |
|
284 | 284 | |
|
285 | 285 | $ echo 'update.check = noconflict' >> .hg/hgrc |
|
286 | 286 | |
|
287 | 287 | $ revtest 'none dirty cross' dirty 3 4 |
|
288 | 288 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
289 | 289 | parent=4 |
|
290 | 290 | M foo |
|
291 | 291 | |
|
292 | 292 | $ revtest 'none dirty linear' dirty 1 2 |
|
293 | 293 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
294 | 294 | parent=2 |
|
295 | 295 | M foo |
|
296 | 296 | |
|
297 | 297 | $ revtest 'none dirty linear' dirty 1 2 -c |
|
298 | 298 | abort: uncommitted changes |
|
299 | 299 | parent=1 |
|
300 | 300 | M foo |
|
301 | 301 | |
|
302 | 302 | $ revtest 'none dirty linear' dirty 1 2 -C |
|
303 | 303 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
304 | 304 | parent=2 |
|
305 | 305 | |
|
306 | 306 | Locally added file is allowed |
|
307 | 307 | $ hg up -qC 3 |
|
308 | 308 | $ echo a > bar |
|
309 | 309 | $ hg add bar |
|
310 | 310 | $ hg up -q 4 |
|
311 | 311 | $ hg st |
|
312 | 312 | A bar |
|
313 | 313 | $ hg forget bar |
|
314 | 314 | $ rm bar |
|
315 | 315 | |
|
316 | 316 | Locally removed file is allowed |
|
317 | 317 | $ hg up -qC 3 |
|
318 | 318 | $ hg rm foo |
|
319 | 319 | $ hg up -q 4 |
|
320 | 320 | |
|
321 | 321 | File conflict is not allowed |
|
322 | 322 | $ hg up -qC 3 |
|
323 | 323 | $ echo dirty >> a |
|
324 | 324 | $ hg up -q 4 |
|
325 | 325 | abort: conflicting changes |
|
326 | 326 | (commit or update --clean to discard changes) |
|
327 | 327 | [255] |
|
328 | 328 | $ hg up -m 4 |
|
329 | 329 | merging a |
|
330 | 330 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') |
|
331 | 331 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
332 | 332 | use 'hg resolve' to retry unresolved file merges |
|
333 | 333 | [1] |
|
334 | 334 | $ rm a.orig |
|
335 | 335 | $ hg status |
|
336 | 336 | M a |
|
337 | 337 | # Unresolved merge conflicts: |
|
338 | 338 | # |
|
339 | 339 | # a |
|
340 | 340 | # |
|
341 | 341 | # To mark files as resolved: hg resolve --mark FILE |
|
342 | 342 | |
|
343 | 343 | $ hg resolve -l |
|
344 | 344 | U a |
|
345 | 345 | |
|
346 | 346 | Change/delete conflict is not allowed |
|
347 | 347 | $ hg up -qC 3 |
|
348 | 348 | $ hg rm foo |
|
349 | 349 | $ hg up -q 4 |
|
350 | 350 | |
|
351 | 351 | Uses default value of "linear" when value is misspelled |
|
352 | 352 | $ echo 'update.check = linyar' >> .hg/hgrc |
|
353 | 353 | |
|
354 | 354 | $ revtest 'dirty cross' dirty 3 4 |
|
355 | 355 | abort: uncommitted changes |
|
356 | 356 | (commit or update --clean to discard changes) |
|
357 | 357 | parent=3 |
|
358 | 358 | M foo |
|
359 | 359 | |
|
360 | 360 | Setup for later tests |
|
361 | 361 | $ revtest 'none dirty linear' dirty 1 2 -c |
|
362 | 362 | abort: uncommitted changes |
|
363 | 363 | parent=1 |
|
364 | 364 | M foo |
|
365 | 365 | |
|
366 | 366 | $ cd .. |
|
367 | 367 | |
|
368 | 368 | Test updating to null revision |
|
369 | 369 | |
|
370 | 370 | $ hg init null-repo |
|
371 | 371 | $ cd null-repo |
|
372 | 372 | $ echo a > a |
|
373 | 373 | $ hg add a |
|
374 | 374 | $ hg ci -m a |
|
375 | 375 | $ hg up -qC 0 |
|
376 | 376 | $ echo b > b |
|
377 | 377 | $ hg add b |
|
378 | 378 | $ hg up null |
|
379 | 379 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
380 | 380 | $ hg st |
|
381 | 381 | A b |
|
382 | 382 | $ hg up -q 0 |
|
383 | 383 | $ hg st |
|
384 | 384 | A b |
|
385 | 385 | $ hg up -qC null |
|
386 | 386 | $ hg st |
|
387 | 387 | ? b |
|
388 | 388 | $ cd .. |
|
389 | 389 | |
|
390 | 390 | Test updating with closed head |
|
391 | 391 | --------------------------------------------------------------------- |
|
392 | 392 | |
|
393 | 393 | $ hg clone -U -q b1 closed-heads |
|
394 | 394 | $ cd closed-heads |
|
395 | 395 | |
|
396 | 396 | Test updating if at least one non-closed branch head exists |
|
397 | 397 | |
|
398 | 398 | if on the closed branch head: |
|
399 | 399 | - update to "." |
|
400 | 400 | - "updated to a closed branch head ...." message is displayed |
|
401 | 401 | - "N other heads for ...." message is displayed |
|
402 | 402 | |
|
403 | 403 | $ hg update -q -C 3 |
|
404 | 404 | $ hg commit --close-branch -m 6 |
|
405 | 405 | $ norevtest "on closed branch head" clean 6 |
|
406 | 406 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
407 | 407 | no open descendant heads on branch "default", updating to a closed head |
|
408 | 408 | (committing will reopen the head, use 'hg heads .' to see 1 other heads) |
|
409 | 409 | parent=6 |
|
410 | 410 | |
|
411 | 411 | if descendant non-closed branch head exists, and it is only one branch head: |
|
412 | 412 | - update to it, even if its revision is less than closed one |
|
413 | 413 | - "N other heads for ...." message isn't displayed |
|
414 | 414 | |
|
415 | 415 | $ norevtest "non-closed 2 should be chosen" clean 1 |
|
416 | 416 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
417 | 417 | parent=2 |
|
418 | 418 | |
|
419 | 419 | if all descendant branch heads are closed, but there is another branch head: |
|
420 | 420 | - update to the tipmost descendant head |
|
421 | 421 | - "updated to a closed branch head ...." message is displayed |
|
422 | 422 | - "N other heads for ...." message is displayed |
|
423 | 423 | |
|
424 | 424 | $ norevtest "all descendant branch heads are closed" clean 3 |
|
425 | 425 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
426 | 426 | no open descendant heads on branch "default", updating to a closed head |
|
427 | 427 | (committing will reopen the head, use 'hg heads .' to see 1 other heads) |
|
428 | 428 | parent=6 |
|
429 | 429 | |
|
430 | 430 | Test updating if all branch heads are closed |
|
431 | 431 | |
|
432 | 432 | if on the closed branch head: |
|
433 | 433 | - update to "." |
|
434 | 434 | - "updated to a closed branch head ...." message is displayed |
|
435 | 435 | - "all heads of branch ...." message is displayed |
|
436 | 436 | |
|
437 | 437 | $ hg update -q -C 2 |
|
438 | 438 | $ hg commit --close-branch -m 7 |
|
439 | 439 | $ norevtest "all heads of branch default are closed" clean 6 |
|
440 | 440 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
441 | 441 | no open descendant heads on branch "default", updating to a closed head |
|
442 | 442 | (committing will reopen branch "default") |
|
443 | 443 | parent=6 |
|
444 | 444 | |
|
445 | 445 | if not on the closed branch head: |
|
446 | 446 | - update to the tipmost descendant (closed) head |
|
447 | 447 | - "updated to a closed branch head ...." message is displayed |
|
448 | 448 | - "all heads of branch ...." message is displayed |
|
449 | 449 | |
|
450 | 450 | $ norevtest "all heads of branch default are closed" clean 1 |
|
451 | 451 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
452 | 452 | no open descendant heads on branch "default", updating to a closed head |
|
453 | 453 | (committing will reopen branch "default") |
|
454 | 454 | parent=7 |
|
455 | 455 | |
|
456 | 456 | $ cd .. |
|
457 | 457 | |
|
458 | 458 | Test updating if "default" branch doesn't exist and no revision is |
|
459 | 459 | checked out (= "default" is used as current branch) |
|
460 | 460 | |
|
461 | 461 | $ hg init no-default-branch |
|
462 | 462 | $ cd no-default-branch |
|
463 | 463 | |
|
464 | 464 | $ hg branch foobar |
|
465 | 465 | marked working directory as branch foobar |
|
466 | 466 | (branches are permanent and global, did you want a bookmark?) |
|
467 | 467 | $ echo a > a |
|
468 | 468 | $ hg commit -m "#0" -A |
|
469 | 469 | adding a |
|
470 | 470 | $ echo 1 >> a |
|
471 | 471 | $ hg commit -m "#1" |
|
472 | 472 | $ hg update -q 0 |
|
473 | 473 | $ echo 3 >> a |
|
474 | 474 | $ hg commit -m "#2" |
|
475 | 475 | created new head |
|
476 | 476 | $ hg commit --close-branch -m "#3" |
|
477 | 477 | |
|
478 | 478 | if there is at least one non-closed branch head: |
|
479 | 479 | - update to the tipmost branch head |
|
480 | 480 | |
|
481 | 481 | $ norevtest "non-closed 1 should be chosen" clean null |
|
482 | 482 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
483 | 483 | parent=1 |
|
484 | 484 | |
|
485 | 485 | if all branch heads are closed |
|
486 | 486 | - update to "tip" |
|
487 | 487 | - "updated to a closed branch head ...." message is displayed |
|
488 | 488 | - "all heads for branch "XXXX" are closed" message is displayed |
|
489 | 489 | |
|
490 | 490 | $ hg update -q -C 1 |
|
491 | 491 | $ hg commit --close-branch -m "#4" |
|
492 | 492 | |
|
493 | 493 | $ norevtest "all branches are closed" clean null |
|
494 | 494 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
495 | 495 | no open descendant heads on branch "foobar", updating to a closed head |
|
496 | 496 | (committing will reopen branch "foobar") |
|
497 | 497 | parent=4 |
|
498 | 498 | |
|
499 | 499 | $ cd ../b1 |
|
500 | 500 | |
|
501 | 501 | Test obsolescence behavior |
|
502 | 502 | --------------------------------------------------------------------- |
|
503 | 503 | |
|
504 | 504 | successors should be taken in account when checking head destination |
|
505 | 505 | |
|
506 | 506 | $ cat << EOF >> $HGRCPATH |
|
507 | 507 | > [ui] |
|
508 | 508 | > logtemplate={rev}:{node|short} {desc|firstline} |
|
509 | 509 | > [experimental] |
|
510 | 510 | > evolution.createmarkers=True |
|
511 | 511 | > EOF |
|
512 | 512 | |
|
513 | 513 | Test no-argument update to a successor of an obsoleted changeset |
|
514 | 514 | |
|
515 | 515 | $ hg log -G |
|
516 | 516 | o 5:ff252e8273df 5 |
|
517 | 517 | | |
|
518 | 518 | o 4:d047485b3896 4 |
|
519 | 519 | | |
|
520 | 520 | | o 3:6efa171f091b 3 |
|
521 | 521 | | | |
|
522 | 522 | | | o 2:bd10386d478c 2 |
|
523 | 523 | | |/ |
|
524 | 524 | | @ 1:0786582aa4b1 1 |
|
525 | 525 | |/ |
|
526 | 526 | o 0:60829823a42a 0 |
|
527 | 527 | |
|
528 | 528 | $ hg book bm -r 3 |
|
529 | 529 | $ hg status |
|
530 | 530 | M foo |
|
531 | 531 | |
|
532 | 532 | We add simple obsolescence marker between 3 and 4 (indirect successors) |
|
533 | 533 | |
|
534 | 534 | $ hg id --debug -i -r 3 |
|
535 | 535 | 6efa171f091b00a3c35edc15d48c52a498929953 |
|
536 | 536 | $ hg id --debug -i -r 4 |
|
537 | 537 | d047485b3896813b2a624e86201983520f003206 |
|
538 | 538 | $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
|
539 | 539 | 1 new obsolescence markers |
|
540 | 540 | obsoleted 1 changesets |
|
541 | 541 | $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206 |
|
542 | 542 | 1 new obsolescence markers |
|
543 | 543 | |
|
544 | 544 | Test that 5 is detected as a valid destination from 3 and also accepts moving |
|
545 | 545 | the bookmark (issue4015) |
|
546 | 546 | |
|
547 | 547 | $ hg up --quiet --hidden 3 |
|
548 | 548 | $ hg up 5 |
|
549 | 549 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
550 | 550 | $ hg book bm |
|
551 | 551 | moving bookmark 'bm' forward from 6efa171f091b |
|
552 | 552 | $ hg bookmarks |
|
553 | 553 | * bm 5:ff252e8273df |
|
554 | 554 | |
|
555 | 555 | Test that we abort before we warn about the hidden commit if the working |
|
556 | 556 | directory is dirty |
|
557 | 557 | $ echo conflict > a |
|
558 | 558 | $ hg up --hidden 3 |
|
559 | 559 | abort: uncommitted changes |
|
560 | 560 | (commit or update --clean to discard changes) |
|
561 | 561 | [255] |
|
562 | 562 | |
|
563 | 563 | Test that we still warn also when there are conflicts |
|
564 | 564 | $ hg up -m --hidden 3 |
|
565 | 565 | merging a |
|
566 | 566 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') |
|
567 | 567 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
568 | 568 | use 'hg resolve' to retry unresolved file merges |
|
569 | 569 | (leaving bookmark bm) |
|
570 | 570 | updated to hidden changeset 6efa171f091b |
|
571 | 571 | (hidden revision '6efa171f091b' was rewritten as: d047485b3896) |
|
572 | 572 | [1] |
|
573 | 573 | |
|
574 | 574 | Test that statuses are reported properly before and after merge resolution. |
|
575 | 575 | $ rm a.orig |
|
576 | 576 | $ hg resolve -l |
|
577 | 577 | U a |
|
578 | 578 | $ hg status |
|
579 | 579 | M a |
|
580 | 580 | M foo |
|
581 | 581 | # Unresolved merge conflicts: |
|
582 | 582 | # |
|
583 | 583 | # a |
|
584 | 584 | # |
|
585 | 585 | # To mark files as resolved: hg resolve --mark FILE |
|
586 | 586 | |
|
587 | 587 | |
|
588 | 588 | $ hg revert -r . a |
|
589 | 589 | |
|
590 | 590 | $ rm a.orig |
|
591 | 591 | $ hg resolve -l |
|
592 | 592 | U a |
|
593 | 593 | $ hg status |
|
594 | 594 | M foo |
|
595 | 595 | # Unresolved merge conflicts: |
|
596 | 596 | # |
|
597 | 597 | # a |
|
598 | 598 | # |
|
599 | 599 | # To mark files as resolved: hg resolve --mark FILE |
|
600 | 600 | |
|
601 | 601 | $ hg status -Tjson |
|
602 | 602 | [ |
|
603 | 603 | { |
|
604 | 604 | "itemtype": "file", |
|
605 | 605 | "path": "foo", |
|
606 | 606 | "status": "M" |
|
607 | 607 | }, |
|
608 | 608 | { |
|
609 | 609 | "itemtype": "file", |
|
610 | 610 | "path": "a", |
|
611 | 611 | "unresolved": true |
|
612 | 612 | } |
|
613 | 613 | ] |
|
614 | 614 | |
|
615 | 615 | $ hg resolve -m |
|
616 | 616 | (no more unresolved files) |
|
617 | 617 | |
|
618 | 618 | $ hg resolve -l |
|
619 | 619 | R a |
|
620 | 620 | $ hg status |
|
621 | 621 | M foo |
|
622 | 622 | # No unresolved merge conflicts. |
|
623 | 623 | |
|
624 | 624 | $ hg status -Tjson |
|
625 | 625 | [ |
|
626 | 626 | { |
|
627 | 627 | "itemtype": "file", |
|
628 | 628 | "path": "foo", |
|
629 | 629 | "status": "M" |
|
630 | 630 | } |
|
631 | 631 | ] |
|
632 | 632 | |
|
633 | 633 | Test that 4 is detected as the no-argument destination from 3 and also moves |
|
634 | 634 | the bookmark with it |
|
635 | 635 | $ hg up --quiet 0 # we should be able to update to 3 directly |
|
636 | 636 | $ hg status |
|
637 | 637 | M foo |
|
638 | 638 | $ hg up --quiet --hidden 3 # but not implemented yet. |
|
639 | 639 | updated to hidden changeset 6efa171f091b |
|
640 | 640 | (hidden revision '6efa171f091b' was rewritten as: d047485b3896) |
|
641 | 641 | $ hg book -f bm |
|
642 | 642 | $ hg up |
|
643 | 643 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
644 | 644 | updating bookmark bm |
|
645 | 645 | $ hg book |
|
646 | 646 | * bm 4:d047485b3896 |
|
647 | 647 | |
|
648 | 648 | Test that 5 is detected as a valid destination from 1 |
|
649 | 649 | $ hg up --quiet 0 # we should be able to update to 3 directly |
|
650 | 650 | $ hg up --quiet --hidden 3 # but not implemented yet. |
|
651 | 651 | updated to hidden changeset 6efa171f091b |
|
652 | 652 | (hidden revision '6efa171f091b' was rewritten as: d047485b3896) |
|
653 | 653 | $ hg up 5 |
|
654 | 654 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
655 | 655 | |
|
656 | 656 | Test that 5 is not detected as a valid destination from 2 |
|
657 | 657 | $ hg up --quiet 0 |
|
658 | 658 | $ hg up --quiet 2 |
|
659 | 659 | $ hg up 5 |
|
660 | 660 | abort: uncommitted changes |
|
661 | 661 | (commit or update --clean to discard changes) |
|
662 | 662 | [255] |
|
663 | 663 | |
|
664 | 664 | Test that we don't crash when updating from a pruned changeset (i.e. has no |
|
665 | 665 | successors). Behavior should probably be that we update to the first |
|
666 | 666 | non-obsolete parent but that will be decided later. |
|
667 | 667 | $ hg id --debug -r 2 |
|
668 | 668 | bd10386d478cd5a9faf2e604114c8e6da62d3889 |
|
669 | 669 | $ hg up --quiet 0 |
|
670 | 670 | $ hg up --quiet 2 |
|
671 | 671 | $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889 |
|
672 | 672 | 1 new obsolescence markers |
|
673 | 673 | obsoleted 1 changesets |
|
674 | 674 | $ hg up |
|
675 | 675 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
676 | 676 | |
|
677 | 677 | Test experimental revset support |
|
678 | 678 | |
|
679 | 679 | $ hg log -r '_destupdate()' |
|
680 | 680 | 2:bd10386d478c 2 (no-eol) |
|
681 | 681 | |
|
682 | 682 | Test that boolean flags allow --no-flag specification to override [defaults] |
|
683 | 683 | $ cat >> $HGRCPATH <<EOF |
|
684 | 684 | > [defaults] |
|
685 | 685 | > update = --check |
|
686 | 686 | > EOF |
|
687 | 687 | $ hg co 2 |
|
688 | 688 | abort: uncommitted changes |
|
689 | 689 | [255] |
|
690 | 690 | $ hg co --no-check 2 |
|
691 | 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