##// END OF EJS Templates
show: use consistent (and possibly shorter) node lengths...
Gregory Szorc -
r34192:e6b5e732 default
parent child Browse files
Show More
@@ -1,439 +1,465 b''
1 1 # show.py - Extension implementing `hg show`
2 2 #
3 3 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.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 """unified command to show various repository information (EXPERIMENTAL)
9 9
10 10 This extension provides the :hg:`show` command, which provides a central
11 11 command for displaying commonly-accessed repository data and views of that
12 12 data.
13 13
14 14 The following config options can influence operation.
15 15
16 16 ``commands``
17 17 ------------
18 18
19 19 ``show.aliasprefix``
20 20 List of strings that will register aliases for views. e.g. ``s`` will
21 21 effectively set config options ``alias.s<view> = show <view>`` for all
22 22 views. i.e. `hg swork` would execute `hg show work`.
23 23
24 24 Aliases that would conflict with existing registrations will not be
25 25 performed.
26 26 """
27 27
28 28 from __future__ import absolute_import
29 29
30 30 from mercurial.i18n import _
31 31 from mercurial.node import nullrev
32 32 from mercurial import (
33 33 cmdutil,
34 34 commands,
35 35 destutil,
36 36 error,
37 37 formatter,
38 38 graphmod,
39 39 phases,
40 40 pycompat,
41 41 registrar,
42 42 revset,
43 43 revsetlang,
44 44 )
45 45
46 46 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
47 47 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
48 48 # be specifying the version(s) of Mercurial they are tested with, or
49 49 # leave the attribute unspecified.
50 50 testedwith = 'ships-with-hg-core'
51 51
52 52 cmdtable = {}
53 53 command = registrar.command(cmdtable)
54 54 revsetpredicate = registrar.revsetpredicate()
55 55
56 56 class showcmdfunc(registrar._funcregistrarbase):
57 57 """Register a function to be invoked for an `hg show <thing>`."""
58 58
59 59 # Used by _formatdoc().
60 60 _docformat = '%s -- %s'
61 61
62 62 def _extrasetup(self, name, func, fmtopic=None, csettopic=None):
63 63 """Called with decorator arguments to register a show view.
64 64
65 65 ``name`` is the sub-command name.
66 66
67 67 ``func`` is the function being decorated.
68 68
69 69 ``fmtopic`` is the topic in the style that will be rendered for
70 70 this view.
71 71
72 72 ``csettopic`` is the topic in the style to be used for a changeset
73 73 printer.
74 74
75 75 If ``fmtopic`` is specified, the view function will receive a
76 76 formatter instance. If ``csettopic`` is specified, the view
77 77 function will receive a changeset printer.
78 78 """
79 79 func._fmtopic = fmtopic
80 80 func._csettopic = csettopic
81 81
82 82 showview = showcmdfunc()
83 83
84 84 @command('show', [
85 85 # TODO: Switch this template flag to use cmdutil.formatteropts if
86 86 # 'hg show' becomes stable before --template/-T is stable. For now,
87 87 # we are putting it here without the '(EXPERIMENTAL)' flag because it
88 88 # is an important part of the 'hg show' user experience and the entire
89 89 # 'hg show' experience is experimental.
90 90 ('T', 'template', '', ('display with template'), _('TEMPLATE')),
91 91 ], _('VIEW'))
92 92 def show(ui, repo, view=None, template=None):
93 93 """show various repository information
94 94
95 95 A requested view of repository data is displayed.
96 96
97 97 If no view is requested, the list of available views is shown and the
98 98 command aborts.
99 99
100 100 .. note::
101 101
102 102 There are no backwards compatibility guarantees for the output of this
103 103 command. Output may change in any future Mercurial release.
104 104
105 105 Consumers wanting stable command output should specify a template via
106 106 ``-T/--template``.
107 107
108 108 List of available views:
109 109 """
110 110 if ui.plain() and not template:
111 111 hint = _('invoke with -T/--template to control output format')
112 112 raise error.Abort(_('must specify a template in plain mode'), hint=hint)
113 113
114 114 views = showview._table
115 115
116 116 if not view:
117 117 ui.pager('show')
118 118 # TODO consider using formatter here so available views can be
119 119 # rendered to custom format.
120 120 ui.write(_('available views:\n'))
121 121 ui.write('\n')
122 122
123 123 for name, func in sorted(views.items()):
124 124 ui.write(('%s\n') % func.__doc__)
125 125
126 126 ui.write('\n')
127 127 raise error.Abort(_('no view requested'),
128 128 hint=_('use "hg show VIEW" to choose a view'))
129 129
130 130 # TODO use same logic as dispatch to perform prefix matching.
131 131 if view not in views:
132 132 raise error.Abort(_('unknown view: %s') % view,
133 133 hint=_('run "hg show" to see available views'))
134 134
135 135 template = template or 'show'
136 136
137 137 fn = views[view]
138 138 ui.pager('show')
139 139
140 140 if fn._fmtopic:
141 141 fmtopic = 'show%s' % fn._fmtopic
142 142 with ui.formatter(fmtopic, {'template': template}) as fm:
143 143 return fn(ui, repo, fm)
144 144 elif fn._csettopic:
145 145 ref = 'show%s' % fn._csettopic
146 146 spec = formatter.lookuptemplate(ui, ref, template)
147 147 displayer = cmdutil.changeset_templater(ui, repo, spec, buffered=True)
148 148 return fn(ui, repo, displayer)
149 149 else:
150 150 return fn(ui, repo)
151 151
152 152 @showview('bookmarks', fmtopic='bookmarks')
153 153 def showbookmarks(ui, repo, fm):
154 154 """bookmarks and their associated changeset"""
155 155 marks = repo._bookmarks
156 156 if not len(marks):
157 157 # This is a bit hacky. Ideally, templates would have a way to
158 158 # specify an empty output, but we shouldn't corrupt JSON while
159 159 # waiting for this functionality.
160 160 if not isinstance(fm, formatter.jsonformatter):
161 161 ui.write(_('(no bookmarks set)\n'))
162 162 return
163 163
164 revs = [repo[node].rev() for node in marks.values()]
164 165 active = repo._activebookmark
165 166 longestname = max(len(b) for b in marks)
166 # TODO consider exposing longest shortest(node).
167 nodelen = longestshortest(repo, revs)
167 168
168 169 for bm, node in sorted(marks.items()):
169 170 fm.startitem()
170 171 fm.context(ctx=repo[node])
171 172 fm.write('bookmark', '%s', bm)
172 173 fm.write('node', fm.hexfunc(node), fm.hexfunc(node))
173 174 fm.data(active=bm == active,
174 175 longestbookmarklen=longestname,
175 nodelen=5)
176 nodelen=nodelen)
176 177
177 178 @showview('stack', csettopic='stack')
178 179 def showstack(ui, repo, displayer):
179 180 """current line of work"""
180 181 wdirctx = repo['.']
181 182 if wdirctx.rev() == nullrev:
182 183 raise error.Abort(_('stack view only available when there is a '
183 184 'working directory'))
184 185
185 186 if wdirctx.phase() == phases.public:
186 187 ui.write(_('(empty stack; working directory parent is a published '
187 188 'changeset)\n'))
188 189 return
189 190
190 191 # TODO extract "find stack" into a function to facilitate
191 192 # customization and reuse.
192 193
193 194 baserev = destutil.stackbase(ui, repo)
194 195 basectx = None
195 196
196 197 if baserev is None:
197 198 baserev = wdirctx.rev()
198 199 stackrevs = {wdirctx.rev()}
199 200 else:
200 201 stackrevs = set(repo.revs('%d::.', baserev))
201 202
202 203 ctx = repo[baserev]
203 204 if ctx.p1().rev() != nullrev:
204 205 basectx = ctx.p1()
205 206
206 207 # And relevant descendants.
207 208 branchpointattip = False
208 209 cl = repo.changelog
209 210
210 211 for rev in cl.descendants([wdirctx.rev()]):
211 212 ctx = repo[rev]
212 213
213 214 # Will only happen if . is public.
214 215 if ctx.phase() == phases.public:
215 216 break
216 217
217 218 stackrevs.add(ctx.rev())
218 219
219 220 # ctx.children() within a function iterating on descandants
220 221 # potentially has severe performance concerns because revlog.children()
221 222 # iterates over all revisions after ctx's node. However, the number of
222 223 # draft changesets should be a reasonably small number. So even if
223 224 # this is quadratic, the perf impact should be minimal.
224 225 if len(ctx.children()) > 1:
225 226 branchpointattip = True
226 227 break
227 228
228 229 stackrevs = list(sorted(stackrevs, reverse=True))
229 230
230 231 # Find likely target heads for the current stack. These are likely
231 232 # merge or rebase targets.
232 233 if basectx:
233 234 # TODO make this customizable?
234 235 newheads = set(repo.revs('heads(%d::) - %ld - not public()',
235 236 basectx.rev(), stackrevs))
236 237 else:
237 238 newheads = set()
238 239
240 allrevs = set(stackrevs) | newheads | set([baserev])
241 nodelen = longestshortest(repo, allrevs)
242
239 243 try:
240 244 cmdutil.findcmd('rebase', commands.table)
241 245 haverebase = True
242 246 except (error.AmbiguousCommand, error.UnknownCommand):
243 247 haverebase = False
244 248
245 249 # TODO use templating.
246 250 # TODO consider using graphmod. But it may not be necessary given
247 251 # our simplicity and the customizations required.
248 252 # TODO use proper graph symbols from graphmod
249 253
250 shortesttmpl = formatter.maketemplater(ui, '{shortest(node, 5)}')
254 shortesttmpl = formatter.maketemplater(ui, '{shortest(node, %d)}' % nodelen)
251 255 def shortest(ctx):
252 256 return shortesttmpl.render({'ctx': ctx, 'node': ctx.hex()})
253 257
254 258 # We write out new heads to aid in DAG awareness and to help with decision
255 259 # making on how the stack should be reconciled with commits made since the
256 260 # branch point.
257 261 if newheads:
258 262 # Calculate distance from base so we can render the count and so we can
259 263 # sort display order by commit distance.
260 264 revdistance = {}
261 265 for head in newheads:
262 266 # There is some redundancy in DAG traversal here and therefore
263 267 # room to optimize.
264 268 ancestors = cl.ancestors([head], stoprev=basectx.rev())
265 269 revdistance[head] = len(list(ancestors))
266 270
267 271 sourcectx = repo[stackrevs[-1]]
268 272
269 273 sortedheads = sorted(newheads, key=lambda x: revdistance[x],
270 274 reverse=True)
271 275
272 276 for i, rev in enumerate(sortedheads):
273 277 ctx = repo[rev]
274 278
275 279 if i:
276 280 ui.write(': ')
277 281 else:
278 282 ui.write(' ')
279 283
280 284 ui.write(('o '))
281 displayer.show(ctx, nodelen=5)
285 displayer.show(ctx, nodelen=nodelen)
282 286 displayer.flush(ctx)
283 287 ui.write('\n')
284 288
285 289 if i:
286 290 ui.write(':/')
287 291 else:
288 292 ui.write(' /')
289 293
290 294 ui.write(' (')
291 295 ui.write(_('%d commits ahead') % revdistance[rev],
292 296 label='stack.commitdistance')
293 297
294 298 if haverebase:
295 299 # TODO may be able to omit --source in some scenarios
296 300 ui.write('; ')
297 301 ui.write(('hg rebase --source %s --dest %s' % (
298 302 shortest(sourcectx), shortest(ctx))),
299 303 label='stack.rebasehint')
300 304
301 305 ui.write(')\n')
302 306
303 307 ui.write(':\n: ')
304 308 ui.write(_('(stack head)\n'), label='stack.label')
305 309
306 310 if branchpointattip:
307 311 ui.write(' \\ / ')
308 312 ui.write(_('(multiple children)\n'), label='stack.label')
309 313 ui.write(' |\n')
310 314
311 315 for rev in stackrevs:
312 316 ctx = repo[rev]
313 317 symbol = '@' if rev == wdirctx.rev() else 'o'
314 318
315 319 if newheads:
316 320 ui.write(': ')
317 321 else:
318 322 ui.write(' ')
319 323
320 324 ui.write(symbol, ' ')
321 displayer.show(ctx, nodelen=5)
325 displayer.show(ctx, nodelen=nodelen)
322 326 displayer.flush(ctx)
323 327 ui.write('\n')
324 328
325 329 # TODO display histedit hint?
326 330
327 331 if basectx:
328 332 # Vertically and horizontally separate stack base from parent
329 333 # to reinforce stack boundary.
330 334 if newheads:
331 335 ui.write(':/ ')
332 336 else:
333 337 ui.write(' / ')
334 338
335 339 ui.write(_('(stack base)'), '\n', label='stack.label')
336 340 ui.write(('o '))
337 341
338 displayer.show(basectx, nodelen=5)
342 displayer.show(basectx, nodelen=nodelen)
339 343 displayer.flush(basectx)
340 344 ui.write('\n')
341 345
342 346 @revsetpredicate('_underway([commitage[, headage]])')
343 347 def underwayrevset(repo, subset, x):
344 348 args = revset.getargsdict(x, 'underway', 'commitage headage')
345 349 if 'commitage' not in args:
346 350 args['commitage'] = None
347 351 if 'headage' not in args:
348 352 args['headage'] = None
349 353
350 354 # We assume callers of this revset add a topographical sort on the
351 355 # result. This means there is no benefit to making the revset lazy
352 356 # since the topographical sort needs to consume all revs.
353 357 #
354 358 # With this in mind, we build up the set manually instead of constructing
355 359 # a complex revset. This enables faster execution.
356 360
357 361 # Mutable changesets (non-public) are the most important changesets
358 362 # to return. ``not public()`` will also pull in obsolete changesets if
359 363 # there is a non-obsolete changeset with obsolete ancestors. This is
360 364 # why we exclude obsolete changesets from this query.
361 365 rs = 'not public() and not obsolete()'
362 366 rsargs = []
363 367 if args['commitage']:
364 368 rs += ' and date(%s)'
365 369 rsargs.append(revsetlang.getstring(args['commitage'],
366 370 _('commitage requires a string')))
367 371
368 372 mutable = repo.revs(rs, *rsargs)
369 373 relevant = revset.baseset(mutable)
370 374
371 375 # Add parents of mutable changesets to provide context.
372 376 relevant += repo.revs('parents(%ld)', mutable)
373 377
374 378 # We also pull in (public) heads if they a) aren't closing a branch
375 379 # b) are recent.
376 380 rs = 'head() and not closed()'
377 381 rsargs = []
378 382 if args['headage']:
379 383 rs += ' and date(%s)'
380 384 rsargs.append(revsetlang.getstring(args['headage'],
381 385 _('headage requires a string')))
382 386
383 387 relevant += repo.revs(rs, *rsargs)
384 388
385 389 # Add working directory parent.
386 390 wdirrev = repo['.'].rev()
387 391 if wdirrev != nullrev:
388 392 relevant += revset.baseset({wdirrev})
389 393
390 394 return subset & relevant
391 395
392 396 @showview('work', csettopic='work')
393 397 def showwork(ui, repo, displayer):
394 398 """changesets that aren't finished"""
395 399 # TODO support date-based limiting when calling revset.
396 400 revs = repo.revs('sort(_underway(), topo)')
401 nodelen = longestshortest(repo, revs)
397 402
398 403 revdag = graphmod.dagwalker(repo, revs)
399 404
400 405 ui.setconfig('experimental', 'graphshorten', True)
401 406 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges,
402 props={'nodelen': 5})
407 props={'nodelen': nodelen})
403 408
404 409 def extsetup(ui):
405 410 # Alias `hg <prefix><view>` to `hg show <view>`.
406 411 for prefix in ui.configlist('commands', 'show.aliasprefix'):
407 412 for view in showview._table:
408 413 name = '%s%s' % (prefix, view)
409 414
410 415 choice, allcommands = cmdutil.findpossible(name, commands.table,
411 416 strict=True)
412 417
413 418 # This alias is already a command name. Don't set it.
414 419 if name in choice:
415 420 continue
416 421
417 422 # Same for aliases.
418 423 if ui.config('alias', name):
419 424 continue
420 425
421 426 ui.setconfig('alias', name, 'show %s' % view, source='show')
422 427
428 def longestshortest(repo, revs, minlen=4):
429 """Return the length of the longest shortest node to identify revisions.
430
431 The result of this function can be used with the ``shortest()`` template
432 function to ensure that a value is unique and unambiguous for a given
433 set of nodes.
434
435 The number of revisions in the repo is taken into account to prevent
436 a numeric node prefix from conflicting with an integer revision number.
437 If we fail to do this, a value of e.g. ``10023`` could mean either
438 revision 10023 or node ``10023abc...``.
439 """
440 tmpl = formatter.maketemplater(repo.ui, '{shortest(node, %d)}' % minlen)
441 lens = [minlen]
442 for rev in revs:
443 ctx = repo[rev]
444 shortest = tmpl.render({'ctx': ctx, 'node': ctx.hex()})
445 lens.append(len(shortest))
446
447 return max(lens)
448
423 449 # Adjust the docstring of the show command so it shows all registered views.
424 450 # This is a bit hacky because it runs at the end of module load. When moved
425 451 # into core or when another extension wants to provide a view, we'll need
426 452 # to do this more robustly.
427 453 # TODO make this more robust.
428 454 def _updatedocstring():
429 455 longest = max(map(len, showview._table.keys()))
430 456 entries = []
431 457 for key in sorted(showview._table.keys()):
432 458 entries.append(pycompat.sysstr(' %s %s' % (
433 459 key.ljust(longest), showview._table[key]._origdoc)))
434 460
435 461 cmdtable['show'][0].__doc__ = pycompat.sysstr('%s\n\n%s\n ') % (
436 462 cmdtable['show'][0].__doc__.rstrip(),
437 463 pycompat.sysstr('\n\n').join(entries))
438 464
439 465 _updatedocstring()
@@ -1,220 +1,220 b''
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [extensions]
3 3 > show =
4 4 > EOF
5 5
6 6 $ hg init repo0
7 7 $ cd repo0
8 8
9 9 Empty repo / no checkout results in error
10 10
11 11 $ hg show stack
12 12 abort: stack view only available when there is a working directory
13 13 [255]
14 14
15 15 Stack displays single draft changeset as root revision
16 16
17 17 $ echo 0 > foo
18 18 $ hg -q commit -A -m 'commit 0'
19 19 $ hg show stack
20 @ 9f171 commit 0
20 @ 9f17 commit 0
21 21
22 22 Stack displays multiple draft changesets
23 23
24 24 $ echo 1 > foo
25 25 $ hg commit -m 'commit 1'
26 26 $ echo 2 > foo
27 27 $ hg commit -m 'commit 2'
28 28 $ echo 3 > foo
29 29 $ hg commit -m 'commit 3'
30 30 $ echo 4 > foo
31 31 $ hg commit -m 'commit 4'
32 32 $ hg show stack
33 @ 2737b commit 4
34 o d1a69 commit 3
35 o 128c8 commit 2
36 o 181cc commit 1
37 o 9f171 commit 0
33 @ 2737 commit 4
34 o d1a6 commit 3
35 o 128c commit 2
36 o 181c commit 1
37 o 9f17 commit 0
38 38
39 39 Public parent of draft base is displayed, separated from stack
40 40
41 41 $ hg phase --public -r 0
42 42 $ hg show stack
43 @ 2737b commit 4
44 o d1a69 commit 3
45 o 128c8 commit 2
46 o 181cc commit 1
43 @ 2737 commit 4
44 o d1a6 commit 3
45 o 128c commit 2
46 o 181c commit 1
47 47 / (stack base)
48 o 9f171 commit 0
48 o 9f17 commit 0
49 49
50 50 $ hg phase --public -r 1
51 51 $ hg show stack
52 @ 2737b commit 4
53 o d1a69 commit 3
54 o 128c8 commit 2
52 @ 2737 commit 4
53 o d1a6 commit 3
54 o 128c commit 2
55 55 / (stack base)
56 o 181cc commit 1
56 o 181c commit 1
57 57
58 58 Draft descendants are shown
59 59
60 60 $ hg -q up 2
61 61 $ hg show stack
62 o 2737b commit 4
63 o d1a69 commit 3
64 @ 128c8 commit 2
62 o 2737 commit 4
63 o d1a6 commit 3
64 @ 128c commit 2
65 65 / (stack base)
66 o 181cc commit 1
66 o 181c commit 1
67 67
68 68 $ hg -q up 3
69 69 $ hg show stack
70 o 2737b commit 4
71 @ d1a69 commit 3
72 o 128c8 commit 2
70 o 2737 commit 4
71 @ d1a6 commit 3
72 o 128c commit 2
73 73 / (stack base)
74 o 181cc commit 1
74 o 181c commit 1
75 75
76 76 working dir on public changeset should display special message
77 77
78 78 $ hg -q up 1
79 79 $ hg show stack
80 80 (empty stack; working directory parent is a published changeset)
81 81
82 82 Branch point in descendants displayed at top of graph
83 83
84 84 $ hg -q up 3
85 85 $ echo b > foo
86 86 $ hg commit -m 'commit 5 (new dag branch)'
87 87 created new head
88 88 $ hg -q up 2
89 89 $ hg show stack
90 90 \ / (multiple children)
91 91 |
92 o d1a69 commit 3
93 @ 128c8 commit 2
92 o d1a6 commit 3
93 @ 128c commit 2
94 94 / (stack base)
95 o 181cc commit 1
95 o 181c commit 1
96 96
97 97 $ cd ..
98 98
99 99 Base is stopped at merges
100 100
101 101 $ hg init merge-base
102 102 $ cd merge-base
103 103 $ echo 0 > foo
104 104 $ hg -q commit -A -m initial
105 105 $ echo h1 > foo
106 106 $ hg commit -m 'head 1'
107 107 $ hg -q up 0
108 108 $ echo h2 > foo
109 109 $ hg -q commit -m 'head 2'
110 110 $ hg phase --public -r 0:tip
111 111 $ hg -q up 1
112 112 $ hg merge -t :local 2
113 113 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
114 114 (branch merge, don't forget to commit)
115 115 $ hg commit -m 'merge heads'
116 116
117 117 TODO doesn't yet handle case where wdir is a draft merge
118 118
119 119 $ hg show stack
120 @ 8ee90 merge heads
120 @ 8ee9 merge heads
121 121 / (stack base)
122 o 59478 head 1
122 o 5947 head 1
123 123
124 124 $ echo d1 > foo
125 125 $ hg commit -m 'draft 1'
126 126 $ echo d2 > foo
127 127 $ hg commit -m 'draft 2'
128 128
129 129 $ hg show stack
130 @ 430d5 draft 2
131 o 787b1 draft 1
130 @ 430d draft 2
131 o 787b draft 1
132 132 / (stack base)
133 o 8ee90 merge heads
133 o 8ee9 merge heads
134 134
135 135 $ cd ..
136 136
137 137 Now move on to stacks when there are more commits after the base branchpoint
138 138
139 139 $ hg init public-rebase
140 140 $ cd public-rebase
141 141 $ echo 0 > foo
142 142 $ hg -q commit -A -m 'base'
143 143 $ hg phase --public -r .
144 144 $ echo d1 > foo
145 145 $ hg commit -m 'draft 1'
146 146 $ echo d2 > foo
147 147 $ hg commit -m 'draft 2'
148 148 $ hg -q up 0
149 149 $ echo 1 > foo
150 150 $ hg commit -m 'new 1'
151 151 created new head
152 152 $ echo 2 > foo
153 153 $ hg commit -m 'new 2'
154 154 $ hg -q up 2
155 155
156 156 Newer draft heads don't impact output
157 157
158 158 $ hg show stack
159 @ eaffc draft 2
160 o 2b218 draft 1
159 @ eaff draft 2
160 o 2b21 draft 1
161 161 / (stack base)
162 o b66bb base
162 o b66b base
163 163
164 164 Newer public heads are rendered
165 165
166 166 $ hg phase --public -r '::tip'
167 167
168 168 $ hg show stack
169 o baa4b new 2
169 o baa4 new 2
170 170 / (2 commits ahead)
171 171 :
172 172 : (stack head)
173 : @ eaffc draft 2
174 : o 2b218 draft 1
173 : @ eaff draft 2
174 : o 2b21 draft 1
175 175 :/ (stack base)
176 o b66bb base
176 o b66b base
177 177
178 178 If rebase is available, we show a hint how to rebase to that head
179 179
180 180 $ hg --config extensions.rebase= show stack
181 o baa4b new 2
182 / (2 commits ahead; hg rebase --source 2b218 --dest baa4b)
181 o baa4 new 2
182 / (2 commits ahead; hg rebase --source 2b21 --dest baa4)
183 183 :
184 184 : (stack head)
185 : @ eaffc draft 2
186 : o 2b218 draft 1
185 : @ eaff draft 2
186 : o 2b21 draft 1
187 187 :/ (stack base)
188 o b66bb base
188 o b66b base
189 189
190 190 Similar tests but for multiple heads
191 191
192 192 $ hg -q up 0
193 193 $ echo h2 > foo
194 194 $ hg -q commit -m 'new head 2'
195 195 $ hg phase --public -r .
196 196 $ hg -q up 2
197 197
198 198 $ hg show stack
199 o baa4b new 2
199 o baa4 new 2
200 200 / (2 commits ahead)
201 : o 9a848 new head 2
201 : o 9a84 new head 2
202 202 :/ (1 commits ahead)
203 203 :
204 204 : (stack head)
205 : @ eaffc draft 2
206 : o 2b218 draft 1
205 : @ eaff draft 2
206 : o 2b21 draft 1
207 207 :/ (stack base)
208 o b66bb base
208 o b66b base
209 209
210 210 $ hg --config extensions.rebase= show stack
211 o baa4b new 2
212 / (2 commits ahead; hg rebase --source 2b218 --dest baa4b)
213 : o 9a848 new head 2
214 :/ (1 commits ahead; hg rebase --source 2b218 --dest 9a848)
211 o baa4 new 2
212 / (2 commits ahead; hg rebase --source 2b21 --dest baa4)
213 : o 9a84 new head 2
214 :/ (1 commits ahead; hg rebase --source 2b21 --dest 9a84)
215 215 :
216 216 : (stack head)
217 : @ eaffc draft 2
218 : o 2b218 draft 1
217 : @ eaff draft 2
218 : o 2b21 draft 1
219 219 :/ (stack base)
220 o b66bb base
220 o b66b base
@@ -1,237 +1,267 b''
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [extensions]
3 3 > show =
4 4 > EOF
5 5
6 6 $ hg init repo0
7 7 $ cd repo0
8 8
9 9 Command works on an empty repo
10 10
11 11 $ hg show work
12 12
13 13 Single draft changeset shown
14 14
15 15 $ echo 0 > foo
16 16 $ hg -q commit -A -m 'commit 0'
17 17
18 18 $ hg show work
19 @ 9f171 commit 0
19 @ 9f17 commit 0
20 20
21 21 Even when it isn't the wdir
22 22
23 23 $ hg -q up null
24 24
25 25 $ hg show work
26 o 9f171 commit 0
26 o 9f17 commit 0
27 27
28 28 Single changeset is still there when public because it is a head
29 29
30 30 $ hg phase --public -r 0
31 31 $ hg show work
32 o 9f171 commit 0
32 o 9f17 commit 0
33 33
34 34 A draft child will show both it and public parent
35 35
36 36 $ hg -q up 0
37 37 $ echo 1 > foo
38 38 $ hg commit -m 'commit 1'
39 39
40 40 $ hg show work
41 @ 181cc commit 1
42 o 9f171 commit 0
41 @ 181c commit 1
42 o 9f17 commit 0
43 43
44 44 Multiple draft children will be shown
45 45
46 46 $ echo 2 > foo
47 47 $ hg commit -m 'commit 2'
48 48
49 49 $ hg show work
50 @ 128c8 commit 2
51 o 181cc commit 1
52 o 9f171 commit 0
50 @ 128c commit 2
51 o 181c commit 1
52 o 9f17 commit 0
53 53
54 54 Bumping first draft changeset to public will hide its parent
55 55
56 56 $ hg phase --public -r 1
57 57 $ hg show work
58 @ 128c8 commit 2
59 o 181cc commit 1
58 @ 128c commit 2
59 o 181c commit 1
60 60 |
61 61 ~
62 62
63 63 Multiple DAG heads will be shown
64 64
65 65 $ hg -q up -r 1
66 66 $ echo 3 > foo
67 67 $ hg commit -m 'commit 3'
68 68 created new head
69 69
70 70 $ hg show work
71 @ f0abc commit 3
72 | o 128c8 commit 2
71 @ f0ab commit 3
72 | o 128c commit 2
73 73 |/
74 o 181cc commit 1
74 o 181c commit 1
75 75 |
76 76 ~
77 77
78 78 Even when wdir is something else
79 79
80 80 $ hg -q up null
81 81
82 82 $ hg show work
83 o f0abc commit 3
84 | o 128c8 commit 2
83 o f0ab commit 3
84 | o 128c commit 2
85 85 |/
86 o 181cc commit 1
86 o 181c commit 1
87 87 |
88 88 ~
89 89
90 90 Draft child shows public head (multiple heads)
91 91
92 92 $ hg -q up 0
93 93 $ echo 4 > foo
94 94 $ hg commit -m 'commit 4'
95 95 created new head
96 96
97 97 $ hg show work
98 @ 668ca commit 4
99 | o f0abc commit 3
100 | | o 128c8 commit 2
98 @ 668c commit 4
99 | o f0ab commit 3
100 | | o 128c commit 2
101 101 | |/
102 | o 181cc commit 1
102 | o 181c commit 1
103 103 |/
104 o 9f171 commit 0
104 o 9f17 commit 0
105 105
106 106 $ cd ..
107 107
108 108 Branch name appears in output
109 109
110 110 $ hg init branches
111 111 $ cd branches
112 112 $ echo 0 > foo
113 113 $ hg -q commit -A -m 'commit 0'
114 114 $ echo 1 > foo
115 115 $ hg commit -m 'commit 1'
116 116 $ echo 2 > foo
117 117 $ hg commit -m 'commit 2'
118 118 $ hg phase --public -r .
119 119 $ hg -q up -r 1
120 120 $ hg branch mybranch
121 121 marked working directory as branch mybranch
122 122 (branches are permanent and global, did you want a bookmark?)
123 123 $ echo 3 > foo
124 124 $ hg commit -m 'commit 3'
125 125 $ echo 4 > foo
126 126 $ hg commit -m 'commit 4'
127 127
128 128 $ hg show work
129 @ f8dd3 (mybranch) commit 4
130 o 90cfc (mybranch) commit 3
131 | o 128c8 commit 2
129 @ f8dd (mybranch) commit 4
130 o 90cf (mybranch) commit 3
131 | o 128c commit 2
132 132 |/
133 o 181cc commit 1
133 o 181c commit 1
134 134 |
135 135 ~
136 136
137 137 $ cd ..
138 138
139 139 Bookmark name appears in output
140 140
141 141 $ hg init bookmarks
142 142 $ cd bookmarks
143 143 $ echo 0 > foo
144 144 $ hg -q commit -A -m 'commit 0'
145 145 $ echo 1 > foo
146 146 $ hg commit -m 'commit 1'
147 147 $ echo 2 > foo
148 148 $ hg commit -m 'commit 2'
149 149 $ hg phase --public -r .
150 150 $ hg bookmark @
151 151 $ hg -q up -r 1
152 152 $ echo 3 > foo
153 153 $ hg commit -m 'commit 3'
154 154 created new head
155 155 $ echo 4 > foo
156 156 $ hg commit -m 'commit 4'
157 157 $ hg bookmark mybook
158 158
159 159 $ hg show work
160 @ cac82 (mybook) commit 4
161 o f0abc commit 3
162 | o 128c8 (@) commit 2
160 @ cac8 (mybook) commit 4
161 o f0ab commit 3
162 | o 128c (@) commit 2
163 163 |/
164 o 181cc commit 1
164 o 181c commit 1
165 165 |
166 166 ~
167 167
168 168 $ cd ..
169 169
170 170 Tags are rendered
171 171
172 172 $ hg init tags
173 173 $ cd tags
174 174 $ echo 0 > foo
175 175 $ hg -q commit -A -m 'commit 1'
176 176 $ echo 1 > foo
177 177 $ hg commit -m 'commit 2'
178 178 $ hg tag 0.1
179 179 $ hg phase --public -r .
180 180 $ echo 2 > foo
181 181 $ hg commit -m 'commit 3'
182 182 $ hg tag 0.2
183 183
184 184 $ hg show work
185 @ 37582 Added tag 0.2 for changeset 6379c25b76f1
186 o 6379c (0.2) commit 3
187 o a2ad9 Added tag 0.1 for changeset 6a75536ea0b1
185 @ 3758 Added tag 0.2 for changeset 6379c25b76f1
186 o 6379 (0.2) commit 3
187 o a2ad Added tag 0.1 for changeset 6a75536ea0b1
188 188 |
189 189 ~
190 190
191 191 $ cd ..
192 192
193 193 Multiple names on same changeset render properly
194 194
195 195 $ hg init multiplenames
196 196 $ cd multiplenames
197 197 $ echo 0 > foo
198 198 $ hg -q commit -A -m 'commit 1'
199 199 $ hg phase --public -r .
200 200 $ hg branch mybranch
201 201 marked working directory as branch mybranch
202 202 (branches are permanent and global, did you want a bookmark?)
203 203 $ hg bookmark mybook
204 204 $ echo 1 > foo
205 205 $ hg commit -m 'commit 2'
206 206
207 207 $ hg show work
208 @ 34834 (mybook) (mybranch) commit 2
209 o 97fcc commit 1
208 @ 3483 (mybook) (mybranch) commit 2
209 o 97fc commit 1
210 210
211 211 Multiple bookmarks on same changeset render properly
212 212
213 213 $ hg book mybook2
214 214 $ hg show work
215 @ 34834 (mybook mybook2) (mybranch) commit 2
216 o 97fcc commit 1
215 @ 3483 (mybook mybook2) (mybranch) commit 2
216 o 97fc commit 1
217 217
218 218 $ cd ..
219 219
220 220 Extra namespaces are rendered
221 221
222 222 $ hg init extranamespaces
223 223 $ cd extranamespaces
224 224 $ echo 0 > foo
225 225 $ hg -q commit -A -m 'commit 1'
226 226 $ hg phase --public -r .
227 227 $ echo 1 > foo
228 228 $ hg commit -m 'commit 2'
229 229 $ echo 2 > foo
230 230 $ hg commit -m 'commit 3'
231 231
232 232 $ hg --config extensions.revnames=$TESTDIR/revnamesext.py show work
233 @ 32f3e (r2) commit 3
234 o 6a755 (r1) commit 2
235 o 97fcc (r0) commit 1
233 @ 32f3 (r2) commit 3
234 o 6a75 (r1) commit 2
235 o 97fc (r0) commit 1
236 236
237 237 $ cd ..
238
239 Prefix collision on hashes increases shortest node length
240
241 $ hg init hashcollision
242 $ cd hashcollision
243 $ echo 0 > a
244 $ hg -q commit -Am 0
245 $ for i in 17 1057 2857 4025; do
246 > hg -q up 0
247 > echo $i > a
248 > hg -q commit -m $i
249 > echo 0 > a
250 > hg commit -m "$i commit 2"
251 > done
252
253 $ hg show work
254 @ cfd04 4025 commit 2
255 o c562d 4025
256 | o 08048 2857 commit 2
257 | o c5623 2857
258 |/
259 | o 6a6b6 1057 commit 2
260 | o c5625 1057
261 |/
262 | o 96b4e 17 commit 2
263 | o 11424 17
264 |/
265 o b4e73 0
266
267 $ cd ..
@@ -1,173 +1,173 b''
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [extensions]
3 3 > show =
4 4 > EOF
5 5
6 6 No arguments shows available views
7 7
8 8 $ hg init empty
9 9 $ cd empty
10 10 $ hg show
11 11 available views:
12 12
13 13 bookmarks -- bookmarks and their associated changeset
14 14 stack -- current line of work
15 15 work -- changesets that aren't finished
16 16
17 17 abort: no view requested
18 18 (use "hg show VIEW" to choose a view)
19 19 [255]
20 20
21 21 `hg help show` prints available views
22 22
23 23 $ hg help show
24 24 hg show VIEW
25 25
26 26 show various repository information
27 27
28 28 A requested view of repository data is displayed.
29 29
30 30 If no view is requested, the list of available views is shown and the
31 31 command aborts.
32 32
33 33 Note:
34 34 There are no backwards compatibility guarantees for the output of this
35 35 command. Output may change in any future Mercurial release.
36 36
37 37 Consumers wanting stable command output should specify a template via
38 38 "-T/--template".
39 39
40 40 List of available views:
41 41
42 42 bookmarks bookmarks and their associated changeset
43 43
44 44 stack current line of work
45 45
46 46 work changesets that aren't finished
47 47
48 48 (use 'hg help -e show' to show help for the show extension)
49 49
50 50 options:
51 51
52 52 -T --template TEMPLATE display with template
53 53
54 54 (some details hidden, use --verbose to show complete help)
55 55
56 56 Unknown view prints error
57 57
58 58 $ hg show badview
59 59 abort: unknown view: badview
60 60 (run "hg show" to see available views)
61 61 [255]
62 62
63 63 HGPLAIN results in abort
64 64
65 65 $ HGPLAIN=1 hg show bookmarks
66 66 abort: must specify a template in plain mode
67 67 (invoke with -T/--template to control output format)
68 68 [255]
69 69
70 70 But not if a template is specified
71 71
72 72 $ HGPLAIN=1 hg show bookmarks -T '{bookmark}\n'
73 73 (no bookmarks set)
74 74
75 75 $ cd ..
76 76
77 77 bookmarks view with no bookmarks prints empty message
78 78
79 79 $ hg init books
80 80 $ cd books
81 81 $ touch f0
82 82 $ hg -q commit -A -m initial
83 83
84 84 $ hg show bookmarks
85 85 (no bookmarks set)
86 86
87 87 bookmarks view shows bookmarks in an aligned table
88 88
89 89 $ echo book1 > f0
90 90 $ hg commit -m 'commit for book1'
91 91 $ echo book2 > f0
92 92 $ hg commit -m 'commit for book2'
93 93
94 94 $ hg bookmark -r 1 book1
95 95 $ hg bookmark a-longer-bookmark
96 96
97 97 $ hg show bookmarks
98 * a-longer-bookmark 7b570
99 book1 b757f
98 * a-longer-bookmark 7b57
99 book1 b757
100 100
101 101 A custom bookmarks template works
102 102
103 103 $ hg show bookmarks -T '{node} {bookmark} {active}\n'
104 104 7b5709ab64cbc34da9b4367b64afff47f2c4ee83 a-longer-bookmark True
105 105 b757f780b8ffd71267c6ccb32e0882d9d32a8cc0 book1 False
106 106
107 107 bookmarks JSON works
108 108
109 109 $ hg show bookmarks -T json
110 110 [
111 111 {
112 112 "active": true,
113 113 "bookmark": "a-longer-bookmark",
114 114 "longestbookmarklen": 17,
115 115 "node": "7b5709ab64cbc34da9b4367b64afff47f2c4ee83",
116 "nodelen": 5
116 "nodelen": 4
117 117 },
118 118 {
119 119 "active": false,
120 120 "bookmark": "book1",
121 121 "longestbookmarklen": 17,
122 122 "node": "b757f780b8ffd71267c6ccb32e0882d9d32a8cc0",
123 "nodelen": 5
123 "nodelen": 4
124 124 }
125 125 ]
126 126
127 127 JSON works with no bookmarks
128 128
129 129 $ hg book -d a-longer-bookmark
130 130 $ hg book -d book1
131 131 $ hg show bookmarks -T json
132 132 [
133 133 ]
134 134
135 135 commands.show.aliasprefix aliases values to `show <view>`
136 136
137 137 $ hg --config commands.show.aliasprefix=s sbookmarks
138 138 (no bookmarks set)
139 139
140 140 $ hg --config commands.show.aliasprefix=sh shwork
141 @ 7b570 commit for book2
142 o b757f commit for book1
143 o ba592 initial
141 @ 7b57 commit for book2
142 o b757 commit for book1
143 o ba59 initial
144 144
145 145 $ hg --config commands.show.aliasprefix='s sh' swork
146 @ 7b570 commit for book2
147 o b757f commit for book1
148 o ba592 initial
146 @ 7b57 commit for book2
147 o b757 commit for book1
148 o ba59 initial
149 149
150 150 $ hg --config commands.show.aliasprefix='s sh' shwork
151 @ 7b570 commit for book2
152 o b757f commit for book1
153 o ba592 initial
151 @ 7b57 commit for book2
152 o b757 commit for book1
153 o ba59 initial
154 154
155 155 The aliases don't appear in `hg config`
156 156
157 157 $ hg --config commands.show.aliasprefix=s config alias
158 158 [1]
159 159
160 160 Doesn't overwrite existing alias
161 161
162 162 $ hg --config alias.swork='log -r .' --config commands.show.aliasprefix=s swork
163 163 changeset: 2:7b5709ab64cb
164 164 tag: tip
165 165 user: test
166 166 date: Thu Jan 01 00:00:00 1970 +0000
167 167 summary: commit for book2
168 168
169 169
170 170 $ hg --config alias.swork='log -r .' --config commands.show.aliasprefix=s config alias
171 171 alias.swork=log -r .
172 172
173 173 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now