[PATCH] templatekw: add 'dirty' keyword to indicate a dirty working directory

Matt Harbison mharbison at attotech.com
Tue Jun 23 15:22:21 CDT 2015

# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1435088760 14400
#      Tue Jun 23 15:46:00 2015 -0400
# Node ID 64ee46ed27022fc1033265f7d08dc48a9c71e91d
# Parent  7fdd1782fc4ee9da87d8af13e806dc9055db2c38
templatekw: add 'dirty' keyword to indicate a dirty working directory

This displays a '+' if the context is a dirty working directory, the same as how
the identify command prints a '+'.  It also works within an if clause, in case
output other than '+' is desired:

    $ hg log -r "wdir()" -T '{if(dirty, "dirty!", "not dirty!")}\n'
    $ hg log -r tip -T '{if(dirty, "dirty!", "not dirty!")}\n'
    not dirty!

It might be nice to have a different keyword, one that encompasses both this
ability to do a dirty check, as well as one that identifies wdir() like the
identify command.  The tests added to test-status.t demonstrate that it is a bit
verbose to do with this, now that workingctx.hex() returns all 'f's.  But I have
no idea what to call it, and it should probably be capable of piping through
'short', which currently loses the '+'.

Something to note here- the identify command uses repo.status() to check the
state, and ctx.dirty() for each subrepo.  This appears to make it insensitive to
changes in the branch name, and to some merge cases (see the merge argument to
context.dirty())... unless these changes occur in a subrepo.  This seems wrong,
and since templates can be applied to csets other than wdir(), repo.status() is
avoided here.  Deleted files are covered by repo.status() though, so they are
also considered with dirty() here.

diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py
--- a/mercurial/templatekw.py
+++ b/mercurial/templatekw.py
@@ -251,6 +251,14 @@ def showdiffstat(repo, ctx, templ, **arg
     maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
     return '%s: +%s/-%s' % (len(stats), adds, removes)
+def showdirty(repo, ctx, templ, **args):
+    """:dirty: '+' or ''.  Indicates if the changeset is a dirty working
+    directory.
+    """
+    if ctx.dirty(missing=True):
+        return '+'
+    return ''
 def showextras(**args):
     """:extras: List of dicts with key, value entries of the 'extras'
     field of this changeset."""
@@ -433,6 +441,7 @@ keywords = {
     'date': showdate,
     'desc': showdescription,
     'diffstat': showdiffstat,
+    'dirty': showdirty,
     'extras': showextras,
     'file_adds': showfileadds,
     'file_copies': showfilecopies,
diff --git a/tests/test-newbranch.t b/tests/test-newbranch.t
--- a/tests/test-newbranch.t
+++ b/tests/test-newbranch.t
@@ -22,10 +22,14 @@
   (branches are permanent and global, did you want a bookmark?)
   $ hg branch
+  $ hg log -r 'wdir()' -T '{if(dirty, "dirty!", "not dirty!")}\n'
+  dirty!
   $ hg ci -m "add branch name"
   $ hg branch bar
   marked working directory as branch bar
   $ hg ci -m "change branch name"
+  $ hg log -r 'wdir()' -T '{if(dirty, "dirty!", "not dirty!")}\n'
+  not dirty!
 Branch shadowing:
diff --git a/tests/test-status.t b/tests/test-status.t
--- a/tests/test-status.t
+++ b/tests/test-status.t
@@ -239,6 +239,11 @@ Test templater support:
   abort: "status" not in template map
+  $ hg log -r 'wdir()' -T "{if(dirty, '{p1node|short}', '{node|short}')}{dirty}\n"
+  389aef86a55e+
+  $ hg log -r tip -T "{if(dirty, '{p1node|short}', '{node|short}')}{dirty}\n"
+  389aef86a55e
 hg status ignoreddir/file:
   $ hg status ignoreddir/file
@@ -325,6 +330,12 @@ Assert flag1 flag2 [0-same | 1-different
   $ echo x > modified
   $ hg copy modified copied
   $ hg ci -m 'test checkin' -d "1000001 0"
+Still dirty, because 'deleted' is missing
+  $ hg log -r 'wdir()' -T "{if(dirty, '{p1node|short}', '{node|short}')}{dirty}\n"
+  2c7cbe8d2e93+
+  $ hg id
+  2c7cbe8d2e93+ tip
   $ rm *
   $ touch unrelated
   $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0"

More information about the Mercurial-devel mailing list