diff --git a/hgitaly/revision.py b/hgitaly/revision.py
index 364d32a1513ca505531d845f7ea88ee14af7b145_aGdpdGFseS9yZXZpc2lvbi5weQ==..88981e79d7de9dd2e43a148e4850266ffd765ffb_aGdpdGFseS9yZXZpc2lvbi5weQ== 100644
--- a/hgitaly/revision.py
+++ b/hgitaly/revision.py
@@ -22,9 +22,12 @@
 from heptapod.gitlab.branch import (
     gitlab_branch_from_ref,
 )
+from heptapod.gitlab.tag import (
+    gitlab_tag_from_ref,
+)
 from .branch import (
     gitlab_branch_head
 )
 from .gitlab_ref import (
     gitlab_special_ref_target
 )
@@ -25,9 +28,10 @@
 from .branch import (
     gitlab_branch_head
 )
 from .gitlab_ref import (
     gitlab_special_ref_target
 )
+from .tag import tagged_changeset
 
 logger = logging.getLogger(__name__)
 
@@ -75,7 +79,10 @@
             return None
 
     # non ambigous ref forms: they should obviously take precedence
-    # TODO direct reference to tag here as well
+    gl_tag = gitlab_tag_from_ref(revision)
+    if gl_tag is not None:
+        return tagged_changeset(repo, gl_tag)
+
     gl_branch = gitlab_branch_from_ref(revision)
     if gl_branch is not None:
         # can return None
diff --git a/hgitaly/service/tests/test_commit.py b/hgitaly/service/tests/test_commit.py
index 364d32a1513ca505531d845f7ea88ee14af7b145_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfY29tbWl0LnB5..88981e79d7de9dd2e43a148e4850266ffd765ffb_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfY29tbWl0LnB5 100644
--- a/hgitaly/service/tests/test_commit.py
+++ b/hgitaly/service/tests/test_commit.py
@@ -198,6 +198,7 @@
                               utc_timestamp=now,
                               message="A single line",
                               user="HGitaly Test <hgitaly@heptapod.test>")
+    wrapper.command('tag', b'testtag', rev=ctx.hex())
     ctx2 = wrapper.commit_file('foo',
                                tz_timestamp=(123456, -7200),  # UTC+2
                                parent=ctx,
@@ -238,6 +239,9 @@
     assert commit_top is not None
     assert commit_top.subject == b"in topic"
 
+    # a tag
+    assert find_commit(b'testtag').commit == commit
+
     # with revision given in full "ref" form
     assert find_commit(
         b'refs/heads/topic/default/antelope').commit == commit_top
@@ -241,6 +245,7 @@
     # with revision given in full "ref" form
     assert find_commit(
         b'refs/heads/topic/default/antelope').commit == commit_top
+    assert find_commit(b'refs/tags/testtag').commit == commit
 
     # with explicitely set default GitLab branch:
     set_default_gitlab_branch(wrapper.repo, b'topic/default/antelope')
@@ -253,6 +258,13 @@
     # with unknown changeset
     assert not find_commit(b'unknown').HasField('commit')
 
+    # 'tip' is not a valid tag
+    # TODO avoid resolving it when given in implicit form (just 'tip')
+    # but that requires not fallbacking to scmutil.revsingle and is not
+    # suited for the current work on stable branch.
+    assert not find_commit(b'refs/tags/tip').HasField('commit')
+    assert not find_commit(b'refs/tags/unknown').HasField('commit')
+
     # special cases of invalid commit ids (prefix or not)
     assert not find_commit(b'f' * 39).HasField('commit')
     assert not find_commit(b'f' * 40).HasField('commit')
diff --git a/hgitaly/tag.py b/hgitaly/tag.py
index 364d32a1513ca505531d845f7ea88ee14af7b145_aGdpdGFseS90YWcucHk=..88981e79d7de9dd2e43a148e4850266ffd765ffb_aGdpdGFseS90YWcucHk= 100644
--- a/hgitaly/tag.py
+++ b/hgitaly/tag.py
@@ -36,3 +36,16 @@
     """
     for name, target in iter_gitlab_tags(repo, **kwargs):
         yield gitlab_tag_ref(name), target
+
+
+def tagged_changeset(repo, tag_name):
+    """Return the changeset that the given tags points to, or None.
+
+    :return: a changectx.
+    """
+    tags = repo.tags()
+    node = tags.get(tag_name)
+    if node is None or repo.tagtype(tag_name) in EXCLUDED_TAG_TYPES:
+        return None  # voluntarily explit
+
+    return repo[node]
diff --git a/tests_with_gitaly/test_commit.py b/tests_with_gitaly/test_commit.py
index 364d32a1513ca505531d845f7ea88ee14af7b145_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9jb21taXQucHk=..88981e79d7de9dd2e43a148e4850266ffd765ffb_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9jb21taXQucHk= 100644
--- a/tests_with_gitaly/test_commit.py
+++ b/tests_with_gitaly/test_commit.py
@@ -229,7 +229,8 @@
     assert_compare(revision=b'topic/default/sampletop')
     assert_compare(revision=b'refs/heads/topic/default/sampletop')
     assert_compare(revision=b'start-tag')
-    # TODO refs/tags not implemented!
+    assert_compare(revision=b'refs/tags/start-tag')
+    assert_compare(revision=b'refs/tags/unknown')
     # TODO special refs and keep-arounds
     # TODO cases of collision/shadowing