diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 82119022cf9b249feefb39c04045bd3fa8c30865..c3efdffe5634cd290f1ace003a4f011aacac6a75 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -171,6 +171,14 @@ class ProjectsController < ApplicationController
     end
   end
 
+  def housekeeping
+    ::Projects::HousekeepingService.new(@project).execute
+
+    respond_to do |format|
+      format.html { redirect_to project_path(@project) }
+    end
+  end
+
   def toggle_star
     current_user.toggle_star(@project)
     @project.reload
diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..48875ac34497c6a0cc0ce5f3347f4155ec77446e
--- /dev/null
+++ b/app/services/projects/housekeeping_service.rb
@@ -0,0 +1,22 @@
+# Projects::HousekeepingService class
+#
+# Used for git housekeeping
+#
+# Ex.
+#   Projects::HousekeepingService.new(project, user).execute
+#
+module Projects
+  class HousekeepingService < BaseService
+    include Gitlab::ShellAdapter
+
+    def initialize(project)
+      @project = project
+    end
+
+    def execute
+      if gitlab_shell.exists?(@project.path_with_namespace + '.git')
+        gitlab_shell.gc(@project.path_with_namespace)
+      end
+    end
+  end
+end
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index afbf88b55073ed9bdcb37b348c3d345e5b18aa80..8e49299223c35dfe11ba64296351411a3efe1c63 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -141,6 +141,17 @@
       - else
         .nothing-here-block Only the project owner can archive a project
 
+      .panel.panel-default.panel.panel-warning
+        .panel-heading Housekeeping
+        .errors-holder
+        .panel-body
+          %p
+            Runs a number of housekeeping tasks within the current repository,
+            such as compressing file revisions and removing unreachable objects.
+            %br
+          = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project),
+              method: :post, class: "btn btn-warning"
+
       .panel.panel-default.panel.panel-warning
         .panel-heading Rename repository
         .errors-holder
diff --git a/config/routes.rb b/config/routes.rb
index f6812c9280a8819ed7e022904626ab1d7a4c75cc..f6e17a21479e2599deb5f1914bceffe9f91eb7cc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -381,6 +381,7 @@ Gitlab::Application.routes.draw do
         delete :remove_fork
         post :archive
         post :unarchive
+        post :housekeeping
         post :toggle_star
         post :markdown_preview
         get :autocomplete_sources
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 01b8bda05c6741cf7b914735722447388cec42f7..59f7a45b791b09ca04c7f615938acbe183bf23c2 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -149,6 +149,18 @@ module Gitlab
                                    "#{path}.git", tag_name])
     end
 
+    # Gc repository
+    #
+    # path - project path with namespace
+    #
+    # Ex.
+    #   gc("gitlab/gitlab-ci")
+    #
+    def gc(path)
+      Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'gc',
+                                   "#{path}.git"])
+    end
+
     # Add new key to gitlab-shell
     #
     # Ex.