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 | return commit(ui, repo, recordinwlock, pats, opts) |
|
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 | def findpossible(cmd, table, strict=False): |
|
575 | def findpossible(cmd, table, strict=False): | |
404 | """ |
|
576 | """ | |
405 | Return cmd -> (aliases, command table entry) |
|
577 | Return cmd -> (aliases, command table entry) |
@@ -4617,6 +4617,7 b' def serve(ui, repo, **opts):' | |||||
4617 | ('u', 'unknown', None, _('show only unknown (not tracked) files')), |
|
4617 | ('u', 'unknown', None, _('show only unknown (not tracked) files')), | |
4618 | ('i', 'ignored', None, _('show only ignored files')), |
|
4618 | ('i', 'ignored', None, _('show only ignored files')), | |
4619 | ('n', 'no-status', None, _('hide status prefix')), |
|
4619 | ('n', 'no-status', None, _('hide status prefix')), | |
|
4620 | ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')), | |||
4620 | ('C', 'copies', None, _('show source of copied files')), |
|
4621 | ('C', 'copies', None, _('show source of copied files')), | |
4621 | ('0', 'print0', None, _('end filenames with NUL, for use with xargs')), |
|
4622 | ('0', 'print0', None, _('end filenames with NUL, for use with xargs')), | |
4622 | ('', 'rev', [], _('show difference from revision'), _('REV')), |
|
4623 | ('', 'rev', [], _('show difference from revision'), _('REV')), | |
@@ -4662,6 +4663,16 b' def status(ui, repo, *pats, **opts):' | |||||
4662 |
|
4663 | |||
4663 | .. container:: verbose |
|
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 | Examples: |
|
4676 | Examples: | |
4666 |
|
4677 | |||
4667 | - show changes in the working directory relative to a |
|
4678 | - show changes in the working directory relative to a | |
@@ -4688,10 +4699,14 b' def status(ui, repo, *pats, **opts):' | |||||
4688 | opts = pycompat.byteskwargs(opts) |
|
4699 | opts = pycompat.byteskwargs(opts) | |
4689 | revs = opts.get('rev') |
|
4700 | revs = opts.get('rev') | |
4690 | change = opts.get('change') |
|
4701 | change = opts.get('change') | |
|
4702 | terse = opts.get('terse') | |||
4691 |
|
4703 | |||
4692 | if revs and change: |
|
4704 | if revs and change: | |
4693 | msg = _('cannot specify --rev and --change at the same time') |
|
4705 | msg = _('cannot specify --rev and --change at the same time') | |
4694 | raise error.Abort(msg) |
|
4706 | raise error.Abort(msg) | |
|
4707 | elif revs and terse: | |||
|
4708 | msg = _('cannot use --terse with --rev') | |||
|
4709 | raise error.Abort(msg) | |||
4695 | elif change: |
|
4710 | elif change: | |
4696 | node2 = scmutil.revsingle(repo, change, None).node() |
|
4711 | node2 = scmutil.revsingle(repo, change, None).node() | |
4697 | node1 = repo[node2].p1().node() |
|
4712 | node1 = repo[node2].p1().node() | |
@@ -4712,6 +4727,7 b' def status(ui, repo, *pats, **opts):' | |||||
4712 | show = [k for k in states if opts.get(k)] |
|
4727 | show = [k for k in states if opts.get(k)] | |
4713 | if opts.get('all'): |
|
4728 | if opts.get('all'): | |
4714 | show += ui.quiet and (states[:4] + ['clean']) or states |
|
4729 | show += ui.quiet and (states[:4] + ['clean']) or states | |
|
4730 | ||||
4715 | if not show: |
|
4731 | if not show: | |
4716 | if ui.quiet: |
|
4732 | if ui.quiet: | |
4717 | show = states[:4] |
|
4733 | show = states[:4] | |
@@ -4722,6 +4738,9 b' def status(ui, repo, *pats, **opts):' | |||||
4722 | stat = repo.status(node1, node2, m, |
|
4738 | stat = repo.status(node1, node2, m, | |
4723 | 'ignored' in show, 'clean' in show, 'unknown' in show, |
|
4739 | 'ignored' in show, 'clean' in show, 'unknown' in show, | |
4724 | opts.get('subrepos')) |
|
4740 | opts.get('subrepos')) | |
|
4741 | if terse: | |||
|
4742 | stat = cmdutil.tersestatus(repo.root, stat, terse, | |||
|
4743 | repo.dirstate._ignore, opts.get('ignored')) | |||
4725 | changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat) |
|
4744 | changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat) | |
4726 |
|
4745 | |||
4727 | if (opts.get('all') or opts.get('copies') |
|
4746 | if (opts.get('all') or opts.get('copies') |
@@ -231,7 +231,7 b' Show all commands + options' | |||||
231 | push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure |
|
231 | push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure | |
232 | remove: after, force, subrepos, include, exclude |
|
232 | remove: after, force, subrepos, include, exclude | |
233 | serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, subrepos |
|
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 | summary: remote |
|
235 | summary: remote | |
236 | update: clean, check, merge, date, rev, tool |
|
236 | update: clean, check, merge, date, rev, tool | |
237 | addremove: similarity, subrepos, include, exclude, dry-run |
|
237 | addremove: similarity, subrepos, include, exclude, dry-run |
General Comments 0
You need to be logged in to leave comments.
Login now