@@ -402,6 +402,116 @@
return commit(ui, repo, recordinwlock, pats, opts)
+def tersestatus(root, statlist, status, ignorefn, ignore):
+ """
+ Returns a list of statuses with directory collapsed if all the files in the
+ directory has the same status.
+ """
+
+ def numfiles(dirname):
+ """
+ Calculates the number of tracked files in a given directory which also
+ includes files which were removed or deleted. Considers ignored files
+ if ignore argument is True or 'i' is present in status argument.
+ """
+ if 'i' in status or ignore:
+ def match(fname):
+ return False
+ else:
+ match = ignorefn
+ lendir = 0
+ abspath = os.path.join(root, dirname)
+ # There might be cases when a directory does not exists as the whole
+ # directory can be removed and/or deleted.
+ try:
+ for f in os.listdir(abspath):
+ if not match(f):
+ lendir += 1
+ except OSError:
+ pass
+ lendir += absentdir.get(dirname, 0)
+ return lendir
+
+ def absentones(removedfiles, missingfiles):
+ """
+ Returns a dictionary of directories and number of files which are either
+ removed or missing (deleted) in them.
+ """
+ absentdir = {}
+ absentfiles = removedfiles + missingfiles
+ while absentfiles:
+ f = absentfiles.pop()
+ par = os.path.dirname(f)
+ if par == '':
+ continue
+ try:
+ absentdir[par] += 1
+ except KeyError:
+ absentdir[par] = 1
+ if par not in removedfiles:
+ absentfiles.append(par)
+ return absentdir
+
+ indexes = {'m': 0, 'a': 1, 'r': 2, 'd': 3, 'u': 4, 'i': 5, 'c': 6}
+ absentdir = absentones(statlist[2], statlist[3])
+ finalrs = [[]] * len(indexes)
+ didsomethingchanged = False
+
+ for st in pycompat.bytestr(status):
+
+ try:
+ ind = indexes[st]
+ except KeyError:
+ # TODO: Need a better error message here
+ raise error.Abort("'%s' not recognized" % st)
+
+ sfiles = statlist[ind]
+ if not sfiles:
+ continue
+ pardict = {}
+ for a in sfiles:
+ par = os.path.dirname(a)
+ pardict.setdefault(par, []).append(a)
+
+ rs = []
+ newls = []
+ for par, files in pardict.iteritems():
+ lenpar = numfiles(par)
+ if lenpar == len(files):
+ newls.append(par)
+
+ if not newls:
+ continue
+
+ while newls:
+ newel = newls.pop()
+ if newel == '':
+ continue
+ parn = os.path.dirname(newel)
+ pardict[newel] = []
+ # Adding pycompat.ossep as newel is a directory.
+ pardict.setdefault(parn, []).append(newel + pycompat.ossep)
+ lenpar = numfiles(parn)
+ if lenpar == len(pardict[parn]):
+ newls.append(parn)
+
+ # dict.values() for Py3 compatibility
+ for files in pardict.values():
+ rs.extend(files)
+
+ finalrs[ind] = rs
+ didsomethingchanged = True
+
+ # If nothing is changed, make sure the order of files is preserved.
+ if not didsomethingchanged:
+ return statlist
+
+ for x in xrange(len(indexes)):
+ if not finalrs[x]:
+ finalrs[x] = statlist[x]
+
+ return finalrs
+
def findpossible(cmd, table, strict=False):
"""
Return cmd -> (aliases, command table entry)
@@ -4709,6 +4709,7 @@
('u', 'unknown', None, _('show only unknown (not tracked) files')),
('i', 'ignored', None, _('show only ignored files')),
('n', 'no-status', None, _('hide status prefix')),
+ ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
('C', 'copies', None, _('show source of copied files')),
('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
('', 'rev', [], _('show difference from revision'), _('REV')),
@@ -4780,6 +4781,7 @@
opts = pycompat.byteskwargs(opts)
revs = opts.get('rev')
change = opts.get('change')
+ terse = opts.get('terse')
if revs and change:
msg = _('cannot specify --rev and --change at the same time')
@@ -4804,16 +4806,28 @@
show = [k for k in states if opts.get(k)]
if opts.get('all'):
show += ui.quiet and (states[:4] + ['clean']) or states
+ if ui.quiet and terse:
+ for st in ('ignored', 'unknown'):
+ if st[0:1] in terse:
+ show.append(st)
+
if not show:
if ui.quiet:
show = states[:4]
else:
show = states[:5]
+ if terse:
+ for st in ('ignored', 'unknown', 'clean'):
+ if st[0:1] in terse:
+ show.append(st)
m = scmutil.match(repo[node2], pats, opts)
stat = repo.status(node1, node2, m,
'ignored' in show, 'clean' in show, 'unknown' in show,
opts.get('subrepos'))
+ if terse:
+ stat = cmdutil.tersestatus(repo.root, stat, terse,
+ repo.dirstate._ignore, opts.get('ignore'))
changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
if (opts.get('all') or opts.get('copies')
@@ -230,7 +230,7 @@
push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
remove: after, force, subrepos, include, exclude
serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, subrepos
- status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
+ status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
summary: remote
update: clean, check, merge, date, rev, tool
addremove: similarity, subrepos, include, exclude, dry-run
new file mode 100644
@@ -0,0 +1,106 @@
+ $ mkdir folder
+ $ cd folder
+ $ hg init
+ $ mkdir x
+ $ touch a b x/aa.o x/bb.o
+ $ hg status
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+
+Show that only passed status are tersed
+ $ hg status --terse m
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+ $ hg status --terse a
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+ $ hg status --terse u
+ ? a
+ ? b
+ ? x/
+ $ hg status --terse i
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+ $ hg status --terse r
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+ $ hg status --terse d
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+ $ hg status --terse c
+ ? a
+ ? b
+ ? x/aa.o
+ ? x/bb.o
+ $ hg status --terse maudric
+ ? a
+ ? b
+ ? x/
+ $ hg status --terse f
+ abort: 'f' not recognized
+ [255]
+
+Have a .hgignore so that we can also have ignored files
+
+ $ echo ".*\.o" > .hgignore
+ $ hg status
+ ? .hgignore
+ ? a
+ ? b
+ $ hg status -i
+ I x/aa.o
+ I x/bb.o
+
+ $ hg status -t i
+ ? .hgignore
+ ? a
+ ? b
+ I x/
+
+Test interaction of ignore with other statuses while tersing
+
+ $ hg status -t maudric
+ ? .hgignore
+ ? a
+ ? b
+ I x/
+
+ $ touch x/aa x/bb
+ $ hg status -t marduc
+ ? .hgignore
+ ? a
+ ? b
+ ? x/
+ $ hg status -t mardiuc
+ ? .hgignore
+ ? a
+ ? b
+ ? x/aa
+ ? x/bb
+ I x/aa.o
+ I x/bb.o
+ $ hg add x/
+ adding x/aa
+ adding x/bb
+ $ hg status -t marduc
+ A x/
+ ? .hgignore
+ ? a
+ ? b
+ $ hg status -t marduc -a
+ A x/
+ $ hg status -t marduic -a
+ A x/aa
+ A x/bb