diff --git a/app/models/repository.rb b/app/models/repository.rb
index b1a789492d37d230f8191d9235607e63ccf90fa7..e834936aa9354cf194d60ede27c5616d6e2f79c1 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -196,16 +196,14 @@ class Repository
     true
   end
 
-  # TODO: why we don't pass user here?
-  def rm_tag(tag_name)
+  def rm_tag(user, tag_name)
     before_remove_tag
+    tag = find_tag(tag_name)
 
-    begin
-      rugged.tags.delete(tag_name)
-      true
-    rescue Rugged::ReferenceError
-      false
-    end
+    GitOperationService.new(user, self).rm_tag(tag)
+
+    after_remove_tag
+    true
   end
 
   def ref_names
@@ -401,6 +399,11 @@ class Repository
     repository_event(:remove_tag)
   end
 
+  # Runs code after removing a tag.
+  def after_remove_tag
+    expire_tags_cache
+  end
+
   def before_import
     expire_content_cache
   end
diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb
index a44dee14a0f7da03051a6e86a6ff9592a2d5418e..9d4bffb93e9e182d69e2e1c1cf423ce9f1563835 100644
--- a/app/services/delete_tag_service.rb
+++ b/app/services/delete_tag_service.rb
@@ -7,7 +7,7 @@ class DeleteTagService < BaseService
       return error('No such tag', 404)
     end
 
-    if repository.rm_tag(tag_name)
+    if repository.rm_tag(current_user, tag_name)
       release = project.releases.find_by(tag: tag_name)
       release.destroy if release
 
diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb
index ed9822cfee6c387b850bc429dae127ed428fcb10..3b7f702e3abb7e88ef509b82615f2d9ecdd79434 100644
--- a/app/services/git_operation_service.rb
+++ b/app/services/git_operation_service.rb
@@ -15,7 +15,7 @@ class GitOperationService
 
   def rm_branch(branch)
     ref = Gitlab::Git::BRANCH_REF_PREFIX + branch.name
-    oldrev = branch.dereferenced_target.id
+    oldrev = branch.target
     newrev = Gitlab::Git::BLANK_SHA
 
     update_ref_in_hooks(ref, newrev, oldrev)
@@ -36,6 +36,16 @@ class GitOperationService
     end
   end
 
+  def rm_tag(tag)
+    ref = Gitlab::Git::TAG_REF_PREFIX + tag.name
+    oldrev = tag.target
+    newrev = Gitlab::Git::BLANK_SHA
+
+    update_ref_in_hooks(ref, newrev, oldrev) do
+      repository.rugged.tags.delete(tag_name)
+    end
+  end
+
   # Whenever `source_branch_name` is passed, if `branch_name` doesn't exist,
   # it would be created from `source_branch_name`.
   # If `source_project` is passed, and the branch doesn't exist,
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b1fee342b57a10b24bb33186630419f5172f29d9..0f43c5c019af7ea00562d09fcc6076baa7ed7e6c 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1419,9 +1419,10 @@ describe Repository, models: true do
   describe '#rm_tag' do
     it 'removes a tag' do
       expect(repository).to receive(:before_remove_tag)
-      expect(repository.rugged.tags).to receive(:delete).with('v1.1.0')
 
-      repository.rm_tag('v1.1.0')
+      repository.rm_tag(create(:user), 'v1.1.0')
+
+      expect(repository.find_tag('v1.1.0')).to be_nil
     end
   end