diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index b082bfc434bca43f89185a53e5e72db89015f1a6..886a09f52af7d0b1fb36751a0377f044bc3a02af 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -178,7 +178,6 @@ module Gitlab
         Gitlab::Markdown::SanitizationFilter,
 
         Gitlab::Markdown::UploadLinkFilter,
-        Gitlab::Markdown::RelativeLinkFilter,
         Gitlab::Markdown::EmojiFilter,
         Gitlab::Markdown::TableOfContentsFilter,
         Gitlab::Markdown::AutolinkFilter,
@@ -193,6 +192,8 @@ module Gitlab
         Gitlab::Markdown::CommitReferenceFilter,
         Gitlab::Markdown::LabelReferenceFilter,
 
+        Gitlab::Markdown::RelativeLinkFilter,
+
         Gitlab::Markdown::TaskListFilter
       ]
     end
diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb
index 37ed423eeda684e46ed8b380e01efe71fcc2d03c..b044a73ed179e3971873971313a611543ab8e311 100644
--- a/lib/gitlab/markdown/abstract_reference_filter.rb
+++ b/lib/gitlab/markdown/abstract_reference_filter.rb
@@ -2,7 +2,7 @@ require 'gitlab/markdown'
 
 module Gitlab
   module Markdown
-    # Issues, Snippets, Merge Requests, Commits and Commit Ranges share
+    # Issues, Merge Requests, Snippets, Commits and Commit Ranges share
     # similar functionality in refernce filtering.
     class AbstractReferenceFilter < ReferenceFilter
       include CrossProjectReference
@@ -64,8 +64,13 @@ module Gitlab
           object_link_filter(content, object_class.reference_pattern)
         end
 
-        replace_link_nodes_matching(object_class.link_reference_pattern) do |content|
-          object_link_filter(content, object_class.link_reference_pattern)
+        replace_link_nodes_with_href(object_class.reference_pattern) do |link, text|
+          object_link_filter(link, object_class.reference_pattern, link_text: text)
+        end
+
+        replace_link_nodes_with_text(object_class.link_reference_pattern) do |text|
+          object_link_filter(text, object_class.link_reference_pattern)
+        end
         end
       end
 
@@ -76,7 +81,7 @@ module Gitlab
       #
       # Returns a String with references replaced with links. All links
       # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
-      def object_link_filter(text, pattern)
+      def object_link_filter(text, pattern, link_text: nil)
         references_in(text, pattern) do |match, id, project_ref, matches|
           project = project_from_ref(project_ref)
 
@@ -88,10 +93,13 @@ module Gitlab
             url = matches[:url] if matches.names.include?("url")
             url ||= url_for_object(object, project)
 
-            text = object.reference_link_text(context[:project])
+            text = link_text
+            unless text
+              text = object.reference_link_text(context[:project])
 
-            extras = object_link_text_extras(object, matches)
-            text += " (#{extras.join(", ")})" if extras.any?
+              extras = object_link_text_extras(object, matches)
+              text += " (#{extras.join(", ")})" if extras.any?
+            end
 
             %(<a href="#{url}" #{data}
                  title="#{title}"
diff --git a/lib/gitlab/markdown/external_issue_reference_filter.rb b/lib/gitlab/markdown/external_issue_reference_filter.rb
index 8f86f13976abc847adb81542675fb4177a970c1d..14bdf5521fc5fd1ddae486ba496d323cb75a1c18 100644
--- a/lib/gitlab/markdown/external_issue_reference_filter.rb
+++ b/lib/gitlab/markdown/external_issue_reference_filter.rb
@@ -30,6 +30,10 @@ module Gitlab
         replace_text_nodes_matching(ExternalIssue.reference_pattern) do |content|
           issue_link_filter(content)
         end
+
+        replace_link_nodes_with_href(ExternalIssue.reference_pattern) do |link, text|
+          issue_link_filter(link, link_text: text)
+        end
       end
 
       # Replace `JIRA-123` issue references in text with links to the referenced
@@ -39,7 +43,7 @@ module Gitlab
       #
       # Returns a String with `JIRA-123` references replaced with links. All
       # links have `gfm` and `gfm-issue` class names attached for styling.
-      def issue_link_filter(text)
+      def issue_link_filter(text, link_text: nil)
         project = context[:project]
 
         self.class.references_in(text) do |match, issue|
@@ -49,9 +53,11 @@ module Gitlab
           klass = reference_class(:issue)
           data  = data_attribute(project: project.id)
 
+          text = link_text || match
+
           %(<a href="#{url}" #{data}
                title="#{title}"
-               class="#{klass}">#{match}</a>)
+               class="#{klass}">#{text}</a>)
         end
       end
 
diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb
index 618acb7a57814c32c1bc31f131a2d6cde8fdb40d..4d0507b607d2ff54f63eca9ec312bd4581689785 100644
--- a/lib/gitlab/markdown/label_reference_filter.rb
+++ b/lib/gitlab/markdown/label_reference_filter.rb
@@ -30,6 +30,10 @@ module Gitlab
         replace_text_nodes_matching(Label.reference_pattern) do |content|
           label_link_filter(content)
         end
+
+        replace_link_nodes_with_href(Label.reference_pattern) do |link, text|
+          label_link_filter(link, link_text: text)
+        end
       end
 
       # Replace label references in text with links to the label specified.
@@ -38,7 +42,7 @@ module Gitlab
       #
       # Returns a String with label references replaced with links. All links
       # have `gfm` and `gfm-label` class names attached for styling.
-      def label_link_filter(text)
+      def label_link_filter(text, link_text: nil)
         project = context[:project]
 
         self.class.references_in(text) do |match, id, name|
@@ -49,8 +53,10 @@ module Gitlab
             klass = reference_class(:label)
             data = data_attribute(project: project.id, label: label.id)
 
+            text = link_text || render_colored_label(label)
+
             %(<a href="#{url}" #{data}
-                 class="#{klass}">#{render_colored_label(label)}</a>)
+                 class="#{klass}">#{text}</a>)
           else
             match
           end
diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb
index e52633ee74c901f182d16eac40bdaf6eb495306c..2597784c7aec39f19969ad165a562889f90d7d5c 100644
--- a/lib/gitlab/markdown/reference_filter.rb
+++ b/lib/gitlab/markdown/reference_filter.rb
@@ -122,7 +122,7 @@ module Gitlab
         doc
       end
 
-      def replace_link_nodes_matching(pattern)
+      def replace_link_nodes_with_text(pattern)
         return doc if project.nil?
 
         doc.search('a').each do |node|
@@ -132,6 +132,9 @@ module Gitlab
           link = node.attr('href')
           text = node.text
 
+          next unless link && text
+
+          link = URI.decode(link)
           # Ignore ending punctionation like periods or commas
           next unless link == text && text =~ /\A#{pattern}/
 
@@ -145,6 +148,30 @@ module Gitlab
         doc
       end
 
+      def replace_link_nodes_with_href(pattern)
+        return doc if project.nil?
+
+        doc.search('a').each do |node|
+          klass = node.attr('class')
+          next if klass && klass.include?('gfm')
+
+          link = node.attr('href')
+          text = node.text
+
+          next unless link && text
+          link = URI.decode(link)
+          next unless link && link =~ /\A#{pattern}\z/
+
+          html = yield link, text
+
+          next if html == link
+
+          node.replace(html)
+        end
+
+        doc
+      end
+
       # Ensure that a :project key exists in context
       #
       # Note that while the key might exist, its value could be nil!
diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb
index 632be4d754255bbf4803dbe3c6f2e12ace6a4b9a..692c51fd324ad8783ed9204159c3e259aa278023 100644
--- a/lib/gitlab/markdown/relative_link_filter.rb
+++ b/lib/gitlab/markdown/relative_link_filter.rb
@@ -17,6 +17,9 @@ module Gitlab
         return doc unless linkable_files?
 
         doc.search('a').each do |el|
+          klass = el.attr('class')
+          next if klass && klass.include?('gfm')
+          
           process_link_attr el.attribute('href')
         end
 
diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb
index ab5e1f6fe9eda11e4794b8fb6db570546b1eca26..0a20d9c034729e660e51f1f211307f1b98bd2f76 100644
--- a/lib/gitlab/markdown/user_reference_filter.rb
+++ b/lib/gitlab/markdown/user_reference_filter.rb
@@ -52,6 +52,10 @@ module Gitlab
         replace_text_nodes_matching(User.reference_pattern) do |content|
           user_link_filter(content)
         end
+
+        replace_link_nodes_with_href(User.reference_pattern) do |link, text|
+          user_link_filter(link, link_text: text)
+        end
       end
 
       # Replace `@user` user references in text with links to the referenced
@@ -61,12 +65,12 @@ module Gitlab
       #
       # Returns a String with `@user` references replaced with links. All links
       # have `gfm` and `gfm-project_member` class names attached for styling.
-      def user_link_filter(text)
+      def user_link_filter(text, link_text: nil)
         self.class.references_in(text) do |match, username|
           if username == 'all'
-            link_to_all
+            link_to_all(link_text: link_text)
           elsif namespace = Namespace.find_by(path: username)
-            link_to_namespace(namespace) || match
+            link_to_namespace(namespace, link_text: link_text) || match
           else
             match
           end
@@ -83,36 +87,36 @@ module Gitlab
         reference_class(:project_member)
       end
 
-      def link_to_all
+      def link_to_all(link_text: nil)
         project = context[:project]
         url = urls.namespace_project_url(project.namespace, project,
                                          only_path: context[:only_path])
         data = data_attribute(project: project.id)
-        text = User.reference_prefix + 'all'
+        text = link_text || User.reference_prefix + 'all'
 
         link_tag(url, data, text)
       end
 
-      def link_to_namespace(namespace)
+      def link_to_namespace(namespace, link_text: nil)
         if namespace.is_a?(Group)
-          link_to_group(namespace.path, namespace)
+          link_to_group(namespace.path, namespace, link_text: link_text)
         else
-          link_to_user(namespace.path, namespace)
+          link_to_user(namespace.path, namespace, link_text: link_text)
         end
       end
 
-      def link_to_group(group, namespace)
+      def link_to_group(group, namespace, link_text: nil)
         url = urls.group_url(group, only_path: context[:only_path])
         data = data_attribute(group: namespace.id)
-        text = Group.reference_prefix + group
+        text = link_text || Group.reference_prefix + group
 
         link_tag(url, data, text)
       end
 
-      def link_to_user(user, namespace)
+      def link_to_user(user, namespace, link_text: nil)
         url = urls.user_url(user, only_path: context[:only_path])
         data = data_attribute(user: namespace.owner_id)
-        text = User.reference_prefix + user
+        text = link_text || User.reference_prefix + user
 
         link_tag(url, data, text)
       end