diff --git a/mercurial/help/templates.txt b/mercurial/help/templates.txt
index 04f5b5e3792e6bbdaf9b70aaf86db2649b2354aa_bWVyY3VyaWFsL2hlbHAvdGVtcGxhdGVzLnR4dA==..8f23f80966062bf29e07f8b6c3dc86d7a618286a_bWVyY3VyaWFsL2hlbHAvdGVtcGxhdGVzLnR4dA== 100644
--- a/mercurial/help/templates.txt
+++ b/mercurial/help/templates.txt
@@ -72,6 +72,8 @@
 
 - sub(pat, repl, expr)
 
+- word(number, text[, separator])
+
 Also, for any expression that returns a list, there is a list operator:
 
 - expr % "{template}"
@@ -130,3 +132,7 @@
 - Show only commit descriptions that start with "template"::
 
    $ hg log --template "{startswith(\"template\", firstline(desc))}\n"
+
+- Print the first word of each line of a commit message::
+
+   $ hg log --template "{word(\"0\", desc)}\n"
diff --git a/mercurial/templater.py b/mercurial/templater.py
index 04f5b5e3792e6bbdaf9b70aaf86db2649b2354aa_bWVyY3VyaWFsL3RlbXBsYXRlci5weQ==..8f23f80966062bf29e07f8b6c3dc86d7a618286a_bWVyY3VyaWFsL3RlbXBsYXRlci5weQ== 100644
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -477,6 +477,25 @@
     return ''
 
 
+def word(context, mapping, args):
+    """return nth word from a string"""
+    if not (2 <= len(args) <= 3):
+        raise error.ParseError(_("word expects two or three arguments, got %d")
+                               % len(args))
+
+    num = int(stringify(args[0][0](context, mapping, args[0][1])))
+    text = stringify(args[1][0](context, mapping, args[1][1]))
+    if len(args) == 3:
+        splitter = stringify(args[2][0](context, mapping, args[2][1]))
+    else:
+        splitter = None
+
+    tokens = text.split(splitter)
+    if num >= len(tokens):
+        return ''
+    else:
+        return tokens[num]
+
 methods = {
     "string": lambda e, c: (runstring, e[1]),
     "rawstring": lambda e, c: (runrawstring, e[1]),
@@ -504,6 +523,7 @@
     "startswith": startswith,
     "strip": strip,
     "sub": sub,
+    "word": word,
 }
 
 # template engine
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
index 04f5b5e3792e6bbdaf9b70aaf86db2649b2354aa_dGVzdHMvdGVzdC1jb21tYW5kLXRlbXBsYXRlLnQ=..8f23f80966062bf29e07f8b6c3dc86d7a618286a_dGVzdHMvdGVzdC1jb21tYW5kLXRlbXBsYXRlLnQ= 100644
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -1917,3 +1917,61 @@
   $ hg log -Gv -R a --template '{desc|user()}'
   hg: parse error: expected a symbol, got 'func'
   [255]
+
+Test word function (including index out of bounds graceful failure)
+
+  $ hg log -Gv -R a --template "{word('1', desc)}"
+  @
+  |
+  o
+  |
+  o
+  
+  o
+  |\
+  | o  head
+  | |
+  o |  branch
+  |/
+  o  user,
+  |
+  o  person
+  |
+  o  1
+  |
+  o  1
+  
+
+Test word third parameter used as splitter
+
+  $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
+  @  future
+  |
+  o  third
+  |
+  o  sec
+  
+  o    merge
+  |\
+  | o  new head
+  | |
+  o |  new branch
+  |/
+  o  n
+  |
+  o  n
+  |
+  o
+  |
+  o  line 1
+     line 2
+
+Test word error messages for not enough and too many arguments
+
+  $ hg log -Gv -R a --template "{word('0')}"
+  hg: parse error: word expects two or three arguments, got 1
+  [255]
+
+  $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
+  hg: parse error: word expects two or three arguments, got 7
+  [255]