Show More
@@ -0,0 +1,185 b'' | |||
|
1 | $ mkdir folder | |
|
2 | $ cd folder | |
|
3 | $ hg init | |
|
4 | $ mkdir x x/l x/m x/n x/l/u x/l/u/a | |
|
5 | $ touch a b x/aa.o x/bb.o | |
|
6 | $ hg status | |
|
7 | ? a | |
|
8 | ? b | |
|
9 | ? x/aa.o | |
|
10 | ? x/bb.o | |
|
11 | ||
|
12 | $ hg status --terse u | |
|
13 | ? a | |
|
14 | ? b | |
|
15 | ? x/ | |
|
16 | $ hg status --terse maudric | |
|
17 | ? a | |
|
18 | ? b | |
|
19 | ? x/ | |
|
20 | $ hg status --terse madric | |
|
21 | ? a | |
|
22 | ? b | |
|
23 | ? x/aa.o | |
|
24 | ? x/bb.o | |
|
25 | $ hg status --terse f | |
|
26 | abort: 'f' not recognized | |
|
27 | [255] | |
|
28 | ||
|
29 | Add a .hgignore so that we can also have ignored files | |
|
30 | ||
|
31 | $ echo ".*\.o" > .hgignore | |
|
32 | $ hg status | |
|
33 | ? .hgignore | |
|
34 | ? a | |
|
35 | ? b | |
|
36 | $ hg status -i | |
|
37 | I x/aa.o | |
|
38 | I x/bb.o | |
|
39 | ||
|
40 | Tersing ignored files | |
|
41 | $ hg status -t i --ignored | |
|
42 | I x/ | |
|
43 | ||
|
44 | Adding more files | |
|
45 | $ mkdir y | |
|
46 | $ touch x/aa x/bb y/l y/m y/l.o y/m.o | |
|
47 | $ touch x/l/aa x/m/aa x/n/aa x/l/u/bb x/l/u/a/bb | |
|
48 | ||
|
49 | $ hg status | |
|
50 | ? .hgignore | |
|
51 | ? a | |
|
52 | ? b | |
|
53 | ? x/aa | |
|
54 | ? x/bb | |
|
55 | ? x/l/aa | |
|
56 | ? x/l/u/a/bb | |
|
57 | ? x/l/u/bb | |
|
58 | ? x/m/aa | |
|
59 | ? x/n/aa | |
|
60 | ? y/l | |
|
61 | ? y/m | |
|
62 | ||
|
63 | $ hg status --terse u | |
|
64 | ? .hgignore | |
|
65 | ? a | |
|
66 | ? b | |
|
67 | ? x/ | |
|
68 | ? y/ | |
|
69 | ||
|
70 | $ hg add x/aa x/bb .hgignore | |
|
71 | $ hg status --terse au | |
|
72 | A .hgignore | |
|
73 | A x/aa | |
|
74 | A x/bb | |
|
75 | ? a | |
|
76 | ? b | |
|
77 | ? x/l/ | |
|
78 | ? x/m/ | |
|
79 | ? x/n/ | |
|
80 | ? y/ | |
|
81 | ||
|
82 | Including ignored files | |
|
83 | ||
|
84 | $ hg status --terse aui | |
|
85 | A .hgignore | |
|
86 | A x/aa | |
|
87 | A x/bb | |
|
88 | ? a | |
|
89 | ? b | |
|
90 | ? x/l/ | |
|
91 | ? x/m/ | |
|
92 | ? x/n/ | |
|
93 | ? y/l | |
|
94 | ? y/m | |
|
95 | $ hg status --terse au -i | |
|
96 | I x/aa.o | |
|
97 | I x/bb.o | |
|
98 | I y/l.o | |
|
99 | I y/m.o | |
|
100 | ||
|
101 | Committing some of the files | |
|
102 | ||
|
103 | $ hg commit x/aa x/bb .hgignore -m "First commit" | |
|
104 | $ hg status | |
|
105 | ? a | |
|
106 | ? b | |
|
107 | ? x/l/aa | |
|
108 | ? x/l/u/a/bb | |
|
109 | ? x/l/u/bb | |
|
110 | ? x/m/aa | |
|
111 | ? x/n/aa | |
|
112 | ? y/l | |
|
113 | ? y/m | |
|
114 | $ hg status --terse mardu | |
|
115 | ? a | |
|
116 | ? b | |
|
117 | ? x/l/ | |
|
118 | ? x/m/ | |
|
119 | ? x/n/ | |
|
120 | ? y/ | |
|
121 | ||
|
122 | Modifying already committed files | |
|
123 | ||
|
124 | $ echo "Hello" >> x/aa | |
|
125 | $ echo "World" >> x/bb | |
|
126 | $ hg status --terse maurdc | |
|
127 | M x/aa | |
|
128 | M x/bb | |
|
129 | ? a | |
|
130 | ? b | |
|
131 | ? x/l/ | |
|
132 | ? x/m/ | |
|
133 | ? x/n/ | |
|
134 | ? y/ | |
|
135 | ||
|
136 | Respecting other flags | |
|
137 | ||
|
138 | $ hg status --terse marduic --all | |
|
139 | M x/aa | |
|
140 | M x/bb | |
|
141 | ? a | |
|
142 | ? b | |
|
143 | ? x/l/ | |
|
144 | ? x/m/ | |
|
145 | ? x/n/ | |
|
146 | ? y/l | |
|
147 | ? y/m | |
|
148 | I x/aa.o | |
|
149 | I x/bb.o | |
|
150 | I y/l.o | |
|
151 | I y/m.o | |
|
152 | C .hgignore | |
|
153 | $ hg status --terse marduic -a | |
|
154 | $ hg status --terse marduic -c | |
|
155 | C .hgignore | |
|
156 | $ hg status --terse marduic -m | |
|
157 | M x/aa | |
|
158 | M x/bb | |
|
159 | ||
|
160 | Passing 'i' in terse value will consider the ignored files while tersing | |
|
161 | ||
|
162 | $ hg status --terse marduic -u | |
|
163 | ? a | |
|
164 | ? b | |
|
165 | ? x/l/ | |
|
166 | ? x/m/ | |
|
167 | ? x/n/ | |
|
168 | ? y/l | |
|
169 | ? y/m | |
|
170 | ||
|
171 | Omitting 'i' in terse value does not consider ignored files while tersing | |
|
172 | ||
|
173 | $ hg status --terse marduc -u | |
|
174 | ? a | |
|
175 | ? b | |
|
176 | ? x/l/ | |
|
177 | ? x/m/ | |
|
178 | ? x/n/ | |
|
179 | ? y/ | |
|
180 | ||
|
181 | Trying with --rev | |
|
182 | ||
|
183 | $ hg status --terse marduic --rev 0 --rev 1 | |
|
184 | abort: cannot use --terse with --rev | |
|
185 | [255] |
@@ -400,6 +400,178 b' def dorecord(ui, repo, commitfunc, cmdsu' | |||
|
400 | 400 | |
|
401 | 401 | return commit(ui, repo, recordinwlock, pats, opts) |
|
402 | 402 | |
|
403 | def tersestatus(root, statlist, status, ignorefn, ignore): | |
|
404 | """ | |
|
405 | Returns a list of statuses with directory collapsed if all the files in the | |
|
406 | directory has the same status. | |
|
407 | """ | |
|
408 | ||
|
409 | def numfiles(dirname): | |
|
410 | """ | |
|
411 | Calculates the number of tracked files in a given directory which also | |
|
412 | includes files which were removed or deleted. Considers ignored files | |
|
413 | if ignore argument is True or 'i' is present in status argument. | |
|
414 | """ | |
|
415 | if lencache.get(dirname): | |
|
416 | return lencache[dirname] | |
|
417 | if 'i' in status or ignore: | |
|
418 | def match(localpath): | |
|
419 | absolutepath = os.path.join(root, localpath) | |
|
420 | if os.path.isdir(absolutepath) and isemptydir(absolutepath): | |
|
421 | return True | |
|
422 | return False | |
|
423 | else: | |
|
424 | def match(localpath): | |
|
425 | # there can be directory whose all the files are ignored and | |
|
426 | # hence the drectory should also be ignored while counting | |
|
427 | # number of files or subdirs in it's parent directory. This | |
|
428 | # checks the same. | |
|
429 | # XXX: We need a better logic here. | |
|
430 | if os.path.isdir(os.path.join(root, localpath)): | |
|
431 | return isignoreddir(localpath) | |
|
432 | else: | |
|
433 | # XXX: there can be files which have the ignored pattern but | |
|
434 | # are not ignored. That leads to bug in counting number of | |
|
435 | # tracked files in the directory. | |
|
436 | return ignorefn(localpath) | |
|
437 | lendir = 0 | |
|
438 | abspath = os.path.join(root, dirname) | |
|
439 | # There might be cases when a directory does not exists as the whole | |
|
440 | # directory can be removed and/or deleted. | |
|
441 | try: | |
|
442 | for f in os.listdir(abspath): | |
|
443 | localpath = os.path.join(dirname, f) | |
|
444 | if not match(localpath): | |
|
445 | lendir += 1 | |
|
446 | except OSError: | |
|
447 | pass | |
|
448 | lendir += len(absentdir.get(dirname, [])) | |
|
449 | lencache[dirname] = lendir | |
|
450 | return lendir | |
|
451 | ||
|
452 | def isemptydir(abspath): | |
|
453 | """ | |
|
454 | Check whether a directory is empty or not, i.e. there is no files in the | |
|
455 | directory and all its subdirectories. | |
|
456 | """ | |
|
457 | for f in os.listdir(abspath): | |
|
458 | fullpath = os.path.join(abspath, f) | |
|
459 | if os.path.isdir(fullpath): | |
|
460 | # recursion here | |
|
461 | ret = isemptydir(fullpath) | |
|
462 | if not ret: | |
|
463 | return False | |
|
464 | else: | |
|
465 | return False | |
|
466 | return True | |
|
467 | ||
|
468 | def isignoreddir(localpath): | |
|
469 | """ | |
|
470 | This function checks whether the directory contains only ignored files | |
|
471 | and hence should the directory be considered ignored. Returns True, if | |
|
472 | that should be ignored otherwise False. | |
|
473 | """ | |
|
474 | dirpath = os.path.join(root, localpath) | |
|
475 | for f in os.listdir(dirpath): | |
|
476 | filepath = os.path.join(dirpath, f) | |
|
477 | if os.path.isdir(filepath): | |
|
478 | # recursion here | |
|
479 | ret = isignoreddir(os.path.join(localpath, f)) | |
|
480 | if not ret: | |
|
481 | return False | |
|
482 | else: | |
|
483 | if not ignorefn(os.path.join(localpath, f)): | |
|
484 | return False | |
|
485 | return True | |
|
486 | ||
|
487 | def absentones(removedfiles, missingfiles): | |
|
488 | """ | |
|
489 | Returns a dictionary of directories with files in it which are either | |
|
490 | removed or missing (deleted) in them. | |
|
491 | """ | |
|
492 | absentdir = {} | |
|
493 | absentfiles = removedfiles + missingfiles | |
|
494 | while absentfiles: | |
|
495 | f = absentfiles.pop() | |
|
496 | par = os.path.dirname(f) | |
|
497 | if par == '': | |
|
498 | continue | |
|
499 | # we need to store files rather than number of files as some files | |
|
500 | # or subdirectories in a directory can be counted twice. This is | |
|
501 | # also we have used sets here. | |
|
502 | try: | |
|
503 | absentdir[par].add(f) | |
|
504 | except KeyError: | |
|
505 | absentdir[par] = set([f]) | |
|
506 | absentfiles.append(par) | |
|
507 | return absentdir | |
|
508 | ||
|
509 | indexes = {'m': 0, 'a': 1, 'r': 2, 'd': 3, 'u': 4, 'i': 5, 'c': 6} | |
|
510 | # get a dictonary of directories and files which are missing as os.listdir() | |
|
511 | # won't be able to list them. | |
|
512 | absentdir = absentones(statlist[2], statlist[3]) | |
|
513 | finalrs = [[]] * len(indexes) | |
|
514 | didsomethingchanged = False | |
|
515 | # dictionary to store number of files and subdir in a directory so that we | |
|
516 | # don't compute that again. | |
|
517 | lencache = {} | |
|
518 | ||
|
519 | for st in pycompat.bytestr(status): | |
|
520 | ||
|
521 | try: | |
|
522 | ind = indexes[st] | |
|
523 | except KeyError: | |
|
524 | # TODO: Need a better error message here | |
|
525 | raise error.Abort("'%s' not recognized" % st) | |
|
526 | ||
|
527 | sfiles = statlist[ind] | |
|
528 | if not sfiles: | |
|
529 | continue | |
|
530 | pardict = {} | |
|
531 | for a in sfiles: | |
|
532 | par = os.path.dirname(a) | |
|
533 | pardict.setdefault(par, []).append(a) | |
|
534 | ||
|
535 | rs = [] | |
|
536 | newls = [] | |
|
537 | for par, files in pardict.iteritems(): | |
|
538 | lenpar = numfiles(par) | |
|
539 | if lenpar == len(files): | |
|
540 | newls.append(par) | |
|
541 | ||
|
542 | if not newls: | |
|
543 | continue | |
|
544 | ||
|
545 | while newls: | |
|
546 | newel = newls.pop() | |
|
547 | if newel == '': | |
|
548 | continue | |
|
549 | parn = os.path.dirname(newel) | |
|
550 | pardict[newel] = [] | |
|
551 | # Adding pycompat.ossep as newel is a directory. | |
|
552 | pardict.setdefault(parn, []).append(newel + pycompat.ossep) | |
|
553 | lenpar = numfiles(parn) | |
|
554 | if lenpar == len(pardict[parn]): | |
|
555 | newls.append(parn) | |
|
556 | ||
|
557 | # dict.values() for Py3 compatibility | |
|
558 | for files in pardict.values(): | |
|
559 | rs.extend(files) | |
|
560 | ||
|
561 | rs.sort() | |
|
562 | finalrs[ind] = rs | |
|
563 | didsomethingchanged = True | |
|
564 | ||
|
565 | # If nothing is changed, make sure the order of files is preserved. | |
|
566 | if not didsomethingchanged: | |
|
567 | return statlist | |
|
568 | ||
|
569 | for x in xrange(len(indexes)): | |
|
570 | if not finalrs[x]: | |
|
571 | finalrs[x] = statlist[x] | |
|
572 | ||
|
573 | return finalrs | |
|
574 | ||
|
403 | 575 | def findpossible(cmd, table, strict=False): |
|
404 | 576 | """ |
|
405 | 577 | Return cmd -> (aliases, command table entry) |
@@ -4617,6 +4617,7 b' def serve(ui, repo, **opts):' | |||
|
4617 | 4617 | ('u', 'unknown', None, _('show only unknown (not tracked) files')), |
|
4618 | 4618 | ('i', 'ignored', None, _('show only ignored files')), |
|
4619 | 4619 | ('n', 'no-status', None, _('hide status prefix')), |
|
4620 | ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')), | |
|
4620 | 4621 | ('C', 'copies', None, _('show source of copied files')), |
|
4621 | 4622 | ('0', 'print0', None, _('end filenames with NUL, for use with xargs')), |
|
4622 | 4623 | ('', 'rev', [], _('show difference from revision'), _('REV')), |
@@ -4662,6 +4663,16 b' def status(ui, repo, *pats, **opts):' | |||
|
4662 | 4663 | |
|
4663 | 4664 | .. container:: verbose |
|
4664 | 4665 | |
|
4666 | The -t/--terse option abbreviates the output by showing directory name | |
|
4667 | if all the files in it share the same status. The option expects a value | |
|
4668 | which can be a string formed by using 'm', 'a', 'r', 'd', 'u', 'i', 'c' | |
|
4669 | where, 'm' stands for 'modified', 'a' for 'added', 'r' for 'removed', | |
|
4670 | 'd' for 'deleted', 'u' for 'unknown', 'i' for 'ignored' and 'c' for clean. | |
|
4671 | ||
|
4672 | It terses the output of only those status which are passed. The ignored | |
|
4673 | files are not considered while tersing until 'i' is there in --terse value | |
|
4674 | or the --ignored option is used. | |
|
4675 | ||
|
4665 | 4676 | Examples: |
|
4666 | 4677 | |
|
4667 | 4678 | - show changes in the working directory relative to a |
@@ -4688,10 +4699,14 b' def status(ui, repo, *pats, **opts):' | |||
|
4688 | 4699 | opts = pycompat.byteskwargs(opts) |
|
4689 | 4700 | revs = opts.get('rev') |
|
4690 | 4701 | change = opts.get('change') |
|
4702 | terse = opts.get('terse') | |
|
4691 | 4703 | |
|
4692 | 4704 | if revs and change: |
|
4693 | 4705 | msg = _('cannot specify --rev and --change at the same time') |
|
4694 | 4706 | raise error.Abort(msg) |
|
4707 | elif revs and terse: | |
|
4708 | msg = _('cannot use --terse with --rev') | |
|
4709 | raise error.Abort(msg) | |
|
4695 | 4710 | elif change: |
|
4696 | 4711 | node2 = scmutil.revsingle(repo, change, None).node() |
|
4697 | 4712 | node1 = repo[node2].p1().node() |
@@ -4712,6 +4727,7 b' def status(ui, repo, *pats, **opts):' | |||
|
4712 | 4727 | show = [k for k in states if opts.get(k)] |
|
4713 | 4728 | if opts.get('all'): |
|
4714 | 4729 | show += ui.quiet and (states[:4] + ['clean']) or states |
|
4730 | ||
|
4715 | 4731 | if not show: |
|
4716 | 4732 | if ui.quiet: |
|
4717 | 4733 | show = states[:4] |
@@ -4722,6 +4738,9 b' def status(ui, repo, *pats, **opts):' | |||
|
4722 | 4738 | stat = repo.status(node1, node2, m, |
|
4723 | 4739 | 'ignored' in show, 'clean' in show, 'unknown' in show, |
|
4724 | 4740 | opts.get('subrepos')) |
|
4741 | if terse: | |
|
4742 | stat = cmdutil.tersestatus(repo.root, stat, terse, | |
|
4743 | repo.dirstate._ignore, opts.get('ignored')) | |
|
4725 | 4744 | changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat) |
|
4726 | 4745 | |
|
4727 | 4746 | if (opts.get('all') or opts.get('copies') |
@@ -231,7 +231,7 b' Show all commands + options' | |||
|
231 | 231 | push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure |
|
232 | 232 | remove: after, force, subrepos, include, exclude |
|
233 | 233 | serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, subrepos |
|
234 | status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template | |
|
234 | status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template | |
|
235 | 235 | summary: remote |
|
236 | 236 | update: clean, check, merge, date, rev, tool |
|
237 | 237 | addremove: similarity, subrepos, include, exclude, dry-run |
General Comments 0
You need to be logged in to leave comments.
Login now