diff --git a/mercurial/commands.py b/mercurial/commands.py
index cb4ff8ef466b2bb5fa820e32501fcc0fc9195087_bWVyY3VyaWFsL2NvbW1hbmRzLnB5..bf93e78f26380032ace7720534f79d6126d8503f_bWVyY3VyaWFsL2NvbW1hbmRzLnB5 100644
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -238,11 +238,12 @@
     if not pats:
         raise util.Abort(_('at least one filename or pattern is required'))
 
-    opmap = [('user', lambda x: ui.shortuser(x[0].user())),
-             ('number', lambda x: str(x[0].rev())),
-             ('changeset', lambda x: short(x[0].node())),
-             ('date', getdate),
-             ('file', lambda x: x[0].path()),
+    opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
+             ('number', ' ', lambda x: str(x[0].rev())),
+             ('changeset', ' ', lambda x: short(x[0].node())),
+             ('date', ' ', getdate),
+             ('file', ' ', lambda x: x[0].path()),
+             ('line_number', ':', lambda x: str(x[1])),
             ]
 
     if (not opts.get('user') and not opts.get('changeset')
@@ -253,10 +254,8 @@
     if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
         raise util.Abort(_('at least one of -n/-c is required for -l'))
 
-    funcmap = [func for op, func in opmap if opts.get(op)]
-    if linenumber:
-        lastfunc = funcmap[-1]
-        funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
+    funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
+    funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
 
     def bad(x, y):
         raise util.Abort("%s: %s" % (x, y))
@@ -274,8 +273,8 @@
         lines = fctx.annotate(follow=follow, linenumber=linenumber)
         pieces = []
 
-        for f in funcmap:
+        for f, sep in funcmap:
             l = [f(n) for n, dummy in lines]
             if l:
                 sized = [(x, encoding.colwidth(x)) for x in l]
                 ml = max([w for x, w in sized])
@@ -278,8 +277,9 @@
             l = [f(n) for n, dummy in lines]
             if l:
                 sized = [(x, encoding.colwidth(x)) for x in l]
                 ml = max([w for x, w in sized])
-                pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
+                pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
+                               for x, w in sized])
 
         if pieces:
             for p, l in zip(zip(*pieces), lines):
@@ -283,7 +283,7 @@
 
         if pieces:
             for p, l in zip(zip(*pieces), lines):
-                ui.write("%s: %s" % (" ".join(p), l[1]))
+                ui.write("%s: %s" % ("".join(p), l[1]))
 
 @command('archive',
     [('', 'no-decode', None, _('do not pass files through decoders')),
diff --git a/tests/test-annotate.t b/tests/test-annotate.t
index cb4ff8ef466b2bb5fa820e32501fcc0fc9195087_dGVzdHMvdGVzdC1hbm5vdGF0ZS50..bf93e78f26380032ace7720534f79d6126d8503f_dGVzdHMvdGVzdC1hbm5vdGF0ZS50 100644
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -193,6 +193,26 @@
   3 b:5: b5
   7 b:7: d
 
+Issue2807: alignment of line numbers with -l
+
+  $ echo more >> b
+  $ hg ci -mmore -d '5 0'
+  $ echo more >> b
+  $ hg ci -mmore -d '6 0'
+  $ echo more >> b
+  $ hg ci -mmore -d '7 0'
+  $ hg annotate -nlf b
+   0 a: 1: a
+   6 b: 2: z
+   1 a: 3: a
+   3 b: 4: b4
+   4 b: 5: c
+   3 b: 5: b5
+   7 b: 7: d
+   8 b: 8: more
+   9 b: 9: more
+  10 b:10: more
+
 linkrev vs rev
 
   $ hg annotate -r tip -n a
@@ -231,5 +251,5 @@
 missing file
 
   $ hg ann nosuchfile
-  abort: nosuchfile: no such file in rev c8abddb41a00
+  abort: nosuchfile: no such file in rev e9e6b4fa872f
   [255]