diff --git a/Gemfile b/Gemfile
index 49fbcad04fcdbb0d9a46c79e9185e10013c00f33..375929a7444ef14e467a29a09863b40ffaf6ae29 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,7 +8,7 @@ def linux_only(require_as)
   RUBY_PLATFORM.include?('linux') && require_as
 end
 
-gem "rails", "3.2.9"
+gem "rails", "3.2.11"
 
 # Supported DBs
 gem "mysql2", group: :mysql
diff --git a/Gemfile.lock b/Gemfile.lock
index d8be14ba80ab191d6001e601026d27cdfa8fbb54..bf14bd93d7cc4e03e0592e84bdf257f4ad79daac 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -81,12 +81,12 @@ GIT
 GEM
   remote: http://rubygems.org/
   specs:
-    actionmailer (3.2.9)
-      actionpack (= 3.2.9)
+    actionmailer (3.2.11)
+      actionpack (= 3.2.11)
       mail (~> 2.4.4)
-    actionpack (3.2.9)
-      activemodel (= 3.2.9)
-      activesupport (= 3.2.9)
+    actionpack (3.2.11)
+      activemodel (= 3.2.11)
+      activesupport (= 3.2.11)
       builder (~> 3.0.0)
       erubis (~> 2.7.0)
       journey (~> 1.0.4)
@@ -94,18 +94,18 @@ GEM
       rack-cache (~> 1.2)
       rack-test (~> 0.6.1)
       sprockets (~> 2.2.1)
-    activemodel (3.2.9)
-      activesupport (= 3.2.9)
+    activemodel (3.2.11)
+      activesupport (= 3.2.11)
       builder (~> 3.0.0)
-    activerecord (3.2.9)
-      activemodel (= 3.2.9)
-      activesupport (= 3.2.9)
+    activerecord (3.2.11)
+      activemodel (= 3.2.11)
+      activesupport (= 3.2.11)
       arel (~> 3.0.2)
       tzinfo (~> 0.3.29)
-    activeresource (3.2.9)
-      activemodel (= 3.2.9)
-      activesupport (= 3.2.9)
-    activesupport (3.2.9)
+    activeresource (3.2.11)
+      activemodel (= 3.2.11)
+      activesupport (= 3.2.11)
+    activesupport (3.2.11)
       i18n (~> 0.6)
       multi_json (~> 1.0)
     acts-as-taggable-on (2.3.3)
@@ -240,7 +240,7 @@ GEM
     jquery-ui-rails (2.0.2)
       jquery-rails
       railties (>= 3.1.0)
-    json (1.7.5)
+    json (1.7.6)
     jwt (0.1.5)
       multi_json (>= 1.0)
     kaminari (0.14.1)
@@ -264,7 +264,7 @@ GEM
     mime-types (1.19)
     modernizr (2.6.2)
       sprockets (~> 2.0)
-    multi_json (1.3.7)
+    multi_json (1.5.0)
     multi_xml (0.5.1)
     multipart-post (1.1.5)
     mysql2 (0.3.11)
@@ -306,7 +306,7 @@ GEM
     pyu-ruby-sasl (0.0.3.3)
     quiet_assets (1.0.1)
       railties (~> 3.1)
-    rack (1.4.1)
+    rack (1.4.3)
     rack-accept (0.4.5)
       rack (>= 0.4)
     rack-cache (1.2)
@@ -321,26 +321,26 @@ GEM
       rack
     rack-test (0.6.2)
       rack (>= 1.0)
-    rails (3.2.9)
-      actionmailer (= 3.2.9)
-      actionpack (= 3.2.9)
-      activerecord (= 3.2.9)
-      activeresource (= 3.2.9)
-      activesupport (= 3.2.9)
+    rails (3.2.11)
+      actionmailer (= 3.2.11)
+      actionpack (= 3.2.11)
+      activerecord (= 3.2.11)
+      activeresource (= 3.2.11)
+      activesupport (= 3.2.11)
       bundler (~> 1.0)
-      railties (= 3.2.9)
+      railties (= 3.2.11)
     rails-dev-tweaks (0.6.1)
       actionpack (~> 3.1)
       railties (~> 3.1)
-    railties (3.2.9)
-      actionpack (= 3.2.9)
-      activesupport (= 3.2.9)
+    railties (3.2.11)
+      actionpack (= 3.2.11)
+      activesupport (= 3.2.11)
       rack-ssl (~> 1.3.2)
       rake (>= 0.8.7)
       rdoc (~> 3.4)
       thor (>= 0.14.6, < 2.0)
     raindrops (0.10.0)
-    rake (10.0.1)
+    rake (10.0.3)
     raphael-rails (1.5.2)
     rb-fsevent (0.9.2)
     rb-inotify (0.8.8)
@@ -411,7 +411,7 @@ GEM
       capybara (~> 1)
       railties (>= 3)
       spinach (>= 0.4)
-    sprockets (2.2.1)
+    sprockets (2.2.2)
       hike (~> 1.2)
       multi_json (~> 1.0)
       rack (~> 1.0)
@@ -506,7 +506,7 @@ DEPENDENCIES
   pygments.rb!
   quiet_assets (~> 1.0.1)
   rack-mini-profiler
-  rails (= 3.2.9)
+  rails (= 3.2.11)
   rails-dev-tweaks
   raphael-rails (= 1.5.2)
   rb-fsevent
diff --git a/VERSION b/VERSION
index fcdb2e109f68cff5600955a73908885fe8599bb4..1454f6ed4b751b190ba93ad2c721979cc0977fbc 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.0.0
+4.0.1
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 8c90f5aee26cb84f8c7053009eddc1fe8623e33b..d34e5a99c796ac8024baca26bbe92bb723b15706 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -27,10 +27,13 @@ class Namespace < ActiveRecord::Base
 
   after_create :ensure_dir_exist
   after_update :move_dir
+  after_commit :update_gitolite, on: :update, if: :require_update_gitolite
   after_destroy :rm_dir
 
   scope :root, where('type IS NULL')
 
+  attr_accessor :require_update_gitolite
+
   def self.search query
     where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
   end
@@ -48,8 +51,17 @@ class Namespace < ActiveRecord::Base
   end
 
   def ensure_dir_exist
-    namespace_dir_path = File.join(Gitlab.config.gitolite.repos_path, path)
-    system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path)
+    unless dir_exists?
+      system("mkdir -m 770 #{namespace_full_path}")
+    end
+  end
+
+  def dir_exists?
+    File.exists?(namespace_full_path)
+  end
+
+  def namespace_full_path
+    @namespace_full_path ||= File.join(Gitlab.config.gitolite.repos_path, path)
   end
 
   def move_dir
@@ -62,10 +74,18 @@ class Namespace < ActiveRecord::Base
 
       if system("mv #{old_path} #{new_path}")
         send_update_instructions
+        @require_update_gitolite = true
+      else
+        raise "Namespace move error #{old_path} #{new_path}"
       end
     end
   end
 
+  def update_gitolite
+    @require_update_gitolite = false
+    projects.each(&:update_repository)
+  end
+
   def rm_dir
     dir_path = File.join(Gitlab.config.gitolite.repos_path, path)
     system("rm -rf #{dir_path}")
diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb
index 09b3c1d622fe9033991bb244b00f292677daf795..73a1d00ca3bf6f647b3c8ddaa9e26477c1cd6936 100644
--- a/app/observers/user_observer.rb
+++ b/app/observers/user_observer.rb
@@ -14,7 +14,7 @@ class UserObserver < ActiveRecord::Observer
       if user.namespace
         user.namespace.update_attributes(path: user.username)
       else
-        user.create_namespace!(path: user.username, name: user.name)
+        user.create_namespace!(path: user.username, name: user.username)
       end
     end
   end
diff --git a/app/roles/namespaced_project.rb b/app/roles/namespaced_project.rb
index 8656890a45690557413b9b6e440ef2bc2bc3e357..dbd533f84947c308d0dcc546eeb46156bb8c637a 100644
--- a/app/roles/namespaced_project.rb
+++ b/app/roles/namespaced_project.rb
@@ -24,7 +24,7 @@ module NamespacedProject
       save!
     end
   rescue Gitlab::ProjectMover::ProjectMoveError => ex
-    raise TransferError.new(ex.message)
+    raise Project::TransferError.new(ex.message)
   end
 
   def name_with_namespace
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index 1d4d6a13c2bb33efa7c780e02d307623e95b81e2..7996c317548a5a597a5bb3fc910c6c92c13027e2 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -6,6 +6,10 @@
     = @issue.created_at.stamp("Aug 21, 2011")
 
   %span.right
+    - if can? current_user, :write_issue, @project
+      = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn grouped" do
+        %i.icon-plus
+        New Issue
     - if can?(current_user, :admin_project, @project) || @issue.author == current_user
       - if @issue.closed
         = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put,  class: "btn grouped reopen_issue"
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index d40d9525bb89d42edac9cb70cff303e6822382c0..f47e8b3e9ff882c0fb32392608a1f1c9dad12034 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -15,7 +15,7 @@
         = nav_link(path: 'groups#merge_requests') do
           = link_to merge_requests_group_path(@group) do
             Merge Requests
-            %span.count= current_user.cared_merge_requests.of_group(@group).count
+            %span.count= current_user.cared_merge_requests.opened.of_group(@group).count
         = nav_link(path: 'groups#search') do
           = link_to "Search", search_group_path(@group)
         = nav_link(path: 'groups#people') do
diff --git a/app/views/notes/_common_form.html.haml b/app/views/notes/_common_form.html.haml
index d76be75bc273a43ef7b90d104b3213845c3c62e6..ae5d72504218c57f24c1be0a8ff7fa5295d2cd3a 100644
--- a/app/views/notes/_common_form.html.haml
+++ b/app/views/notes/_common_form.html.haml
@@ -22,12 +22,12 @@
       .span4.notify_opts
         %h6.left Notify via email:
         = label_tag :notify do
-          = check_box_tag :notify, 1, @note.noteable_type != "Commit"
+          = check_box_tag :notify, 1, false
           %span Project team
 
         - if @note.notify_only_author?(current_user)
           = label_tag :notify_author do
-            = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
+            = check_box_tag :notify_author, 1 , false
             %span Commit author
       .span5.attachments
         %h6.left Attachment:
diff --git a/app/views/notes/_per_line_form.html.haml b/app/views/notes/_per_line_form.html.haml
index ff80ad4e0d52d9fd279b70154f6afb29fc9a2413..ce391dccae7d2764bb9d4ad9ab3417c610c7e9d7 100644
--- a/app/views/notes/_per_line_form.html.haml
+++ b/app/views/notes/_per_line_form.html.haml
@@ -23,12 +23,12 @@
                 %h6.left Notify via email:
                 .labels
                   = label_tag :notify do
-                    = check_box_tag :notify, 1, @note.noteable_type != "Commit"
+                    = check_box_tag :notify, 1, false
                     %span Project team
 
                   - if @note.notify_only_author?(current_user)
                     = label_tag :notify_author do
-                      = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
+                      = check_box_tag :notify_author, 1 , false
                       %span Commit author
 
 :javascript
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index f47625eb132ab304a71e35bf2ccf998fbe413c1f..3aac21d3771062183cb467a9316f32311a6d981e 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -89,6 +89,7 @@ backup:
 ## Gitolite settings
 gitolite:
   admin_uri: git@localhost:gitolite-admin
+  # repos_path must not be a symlink
   repos_path: /home/git/repositories/
   hooks_path: /home/git/.gitolite/hooks/
   admin_key: gitlab
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 4fe3ced4d8d1f7021a4e8cc8064a1ceaf74d65bc..08ea63f7f8d891c4f462f777ad125d7391c3b1e3 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -324,7 +324,7 @@ Settings.gitlab['email_from'] ||= Settings.pre_40_config ? Settings.email_from :
 Settings.gitlab['url']        ||= Settings.pre_40_config ? Settings.url : Settings.send(:build_gitlab_url)
 
 Settings['gravatar'] ||= Settingslogic.new({})
-Settings.gravatar['enabled']    ||= Settings.pre_40_config ? !Settings.disable_gravatar? : true
+Settings.gravatar['enabled']      = Settings.pre_40_config ? !Settings.disable_gravatar? : true if Settings.gravatar['enabled'].nil?
 Settings.gravatar['plain_url']  ||= Settings.pre_40_config ? Settings.gravatar_url      : 'http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm'
 Settings.gravatar['ssl_url']    ||= Settings.pre_40_config ? Settings.gravatar_ssl_url  : 'https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm'
 
diff --git a/config/initializers/4_resque.rb b/config/initializers/4_resque.rb
index 419dbe0606107554236ba85e1abd556bb03c1dfa..03c2b785fae43020336982a7645ee31f15021fcd 100644
--- a/config/initializers/4_resque.rb
+++ b/config/initializers/4_resque.rb
@@ -27,3 +27,5 @@ Resque::Server.use Authentication
 
 # Mailer
 Resque::Mailer.excluded_environments = []
+
+Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection }
diff --git a/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb b/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb
index 6f2da4136a3cad9623e68ce7c6021abbe3358ad2..f6b97390b938cee842fd26d6b95b57dbfe031df3 100644
--- a/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb
+++ b/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb
@@ -5,7 +5,7 @@ class MoveNoteableCommitToOwnField < ActiveRecord::Migration
     Note.where(noteable_type: 'Commit').update_all('commit_id = noteable_id')
 
     if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
-      Note.where("noteable_type != 'Commit'").update_all('new_noteable_id = CAST (noteable_id AS INTEGER)')
+      Note.where("noteable_type != 'Commit'").update_all('new_noteable_id = CAST (CASE noteable_id WHEN \'\' THEN NULL ELSE noteable_id END AS INTEGER)')
     else
       Note.where("noteable_type != 'Commit'").update_all('new_noteable_id = noteable_id')
     end
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 718e4cf6419ad367b1d96b8fcdbc1b12115865ea..26cfc4a112494cafa25384978fa37149490e5f28 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -270,33 +270,33 @@ used for the `email.from` setting in `config/gitlab.yml`)
     sudo -u gitlab -H bundle exec rake gitlab:app:setup RAILS_ENV=production
 
 
-## Check Application Status
+## Install Init Script
 
-Check if GitLab and its environment is configured correctly:
+Download the init script (will be /etc/init.d/gitlab):
 
-    sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production
+    sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/4-0-stable/init.d/gitlab -P /etc/init.d/
+    sudo chmod +x /etc/init.d/gitlab
 
-To make sure you didn't miss anything run a more thorough check with:
+Make GitLab start on boot:
 
-    sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production
+    sudo update-rc.d gitlab defaults 21
 
-If you are all green: congratulations, you successfully installed GitLab!
-Although this is the case, there are still a few steps to go.
 
+## Check Application Status
 
-## Install Init Script
+Check if GitLab and its environment is configured correctly:
 
-Download the init script (will be /etc/init.d/gitlab):
+    sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production
 
-    sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab -P /etc/init.d/
-    sudo chmod +x /etc/init.d/gitlab
+To make sure you didn't miss anything run a more thorough check with:
 
-Make GitLab start on boot:
+    sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production
 
-    sudo update-rc.d gitlab defaults 21
+If all items are green, then congratulations on successfully installing GitLab!
+However there are still a few steps left.
 
 
-Start your GitLab instance:
+## Start Your GitLab Instance
 
     sudo service gitlab start
     # or
@@ -316,7 +316,7 @@ If you can't or don't want to use Nginx as your web server, have a look at the
 
 Download an example site config:
 
-    sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab -P /etc/nginx/sites-available/
+    sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/4-0-stable/nginx/gitlab -P /etc/nginx/sites-available/
     sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab
 
 Make sure to edit the config file to match your setup:
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 5f1ed080fa582d95ed9e7bdc5afef2504660ba3a..9cf021717c69a80f1a8cda91fcf0dca4abf58391 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -48,7 +48,7 @@ namespace :gitlab do
           see_database_guide,
           "http://guides.rubyonrails.org/getting_started.html#configuring-a-database"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -65,7 +65,7 @@ namespace :gitlab do
           "https://github.com/gitlabhq/gitlabhq/wiki/Migrate-from-SQLite-to-MySQL",
           see_database_guide
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -85,7 +85,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "GitLab"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -98,7 +98,7 @@ namespace :gitlab do
       end
 
       # omniauth or ldap could have been deleted from the file
-      unless Gitlab.config.pre_40_config
+      unless Gitlab.config['git_host']
         puts "no".green
       else
         puts "yes".red
@@ -110,7 +110,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "GitLab"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -129,7 +129,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Install Init Script"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -142,7 +142,7 @@ namespace :gitlab do
         return
       end
 
-      recipe_content = `curl https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab 2>/dev/null`
+      recipe_content = `curl https://raw.github.com/gitlabhq/gitlab-recipes/4-0-stable/init.d/gitlab 2>/dev/null`
       script_content = File.read(script_path)
 
       if recipe_content == script_content
@@ -155,7 +155,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Install Init Script"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -169,9 +169,9 @@ namespace :gitlab do
       else
         puts "no".red
         try_fixing_it(
-          "sudo -u gitlab -H bundle exec rake db:migrate"
+          "sudo -u gitlab -H bundle exec rake db:migrate RAILS_ENV=production"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -194,14 +194,14 @@ namespace :gitlab do
         else
           puts "no".red
           try_fixing_it(
-            "sudo -u gitlab -H bundle exec rake gitlab:satellites:create",
+            "sudo -u gitlab -H bundle exec rake gitlab:satellites:create RAILS_ENV=production",
             "If necessary, remove the tmp/repo_satellites directory ...",
             "... and rerun the above command"
           )
           for_more_information(
             "doc/raketasks/maintenance.md "
           )
-          check_failed
+          fix_and_rerun
         end
       end
     end
@@ -222,7 +222,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "GitLab"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -242,7 +242,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "GitLab"
         )
-        check_failed
+        fix_and_rerun
       end
     end
   end
@@ -256,7 +256,7 @@ namespace :gitlab do
       start_checking "Environment"
 
       check_gitlab_in_git_group
-      check_issue_1056_shell_profile_error
+      check_issue_1059_shell_profile_error
       check_gitlab_git_config
       check_python2_exists
       check_python2_version
@@ -290,7 +290,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "GitLab"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -308,16 +308,16 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "System Users"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
     # see https://github.com/gitlabhq/gitlabhq/issues/1059
-    def check_issue_1056_shell_profile_error
+    def check_issue_1059_shell_profile_error
       gitolite_ssh_user = Gitlab.config.gitolite.ssh_user
       print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... "
 
-      profile_file = File.join(gitolite_home, ".profile")
+      profile_file = File.join(gitolite_user_home, ".profile")
 
       unless File.read(profile_file) =~ /^-e PATH/
         puts "yes".green
@@ -332,7 +332,7 @@ namespace :gitlab do
           see_installation_guide_section("Gitolite"),
           "https://github.com/gitlabhq/gitlabhq/issues/1059"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -352,7 +352,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Packages / Dependencies"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -378,7 +378,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Packages / Dependencies"
         )
-        check_failed
+        fix_and_rerun
       end
     end
   end
@@ -398,6 +398,7 @@ namespace :gitlab do
       check_dot_gitolite_user_and_group
       check_dot_gitolite_permissions
       check_repo_base_exists
+      check_repo_base_is_not_symlink
       check_repo_base_user_and_group
       check_repo_base_permissions
       check_can_clone_gitolite_admin
@@ -434,7 +435,7 @@ namespace :gitlab do
       for_more_information(
         see_installation_guide_section "Gitolite"
       )
-      check_failed
+      fix_and_rerun
     end
 
     # assumes #check_can_clone_gitolite_admin has been run before
@@ -466,7 +467,7 @@ namespace :gitlab do
       for_more_information(
         see_installation_guide_section "Gitolite"
       )
-      check_failed
+      fix_and_rerun
     ensure
       FileUtils.rm_rf("/tmp/gitolite_gitlab_test")
     end
@@ -474,7 +475,7 @@ namespace :gitlab do
     def check_dot_gitolite_exists
       print "Config directory exists? ... "
 
-      gitolite_config_path = File.join(gitolite_home, ".gitolite")
+      gitolite_config_path = File.join(gitolite_user_home, ".gitolite")
 
       if File.directory?(gitolite_config_path)
         puts "yes".green
@@ -488,20 +489,20 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
     def check_dot_gitolite_permissions
       print "Config directory access is drwxr-x---? ... "
 
-      gitolite_config_path = File.join(gitolite_home, ".gitolite")
+      gitolite_config_path = File.join(gitolite_user_home, ".gitolite")
       unless File.exists?(gitolite_config_path)
         puts "can't check because of previous errors".magenta
         return
       end
 
-      if `stat --printf %a #{gitolite_config_path}` == "750"
+      if File.stat(gitolite_config_path).mode.to_s(8).ends_with?("750")
         puts "yes".green
       else
         puts "no".red
@@ -511,7 +512,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -519,31 +520,30 @@ namespace :gitlab do
       gitolite_ssh_user = Gitlab.config.gitolite.ssh_user
       print "Config directory owned by #{gitolite_ssh_user}:#{gitolite_ssh_user} ... "
 
-      gitolite_config_path = File.join(gitolite_home, ".gitolite")
+      gitolite_config_path = File.join(gitolite_user_home, ".gitolite")
       unless File.exists?(gitolite_config_path)
         puts "can't check because of previous errors".magenta
         return
       end
 
-      if `stat --printf %U #{gitolite_config_path}` == gitolite_ssh_user && # user
-         `stat --printf %G #{gitolite_config_path}` == gitolite_ssh_user #group
+      if File.stat(gitolite_config_path).uid == uid_for(gitolite_ssh_user) &&
+         File.stat(gitolite_config_path).gid == gid_for(gitolite_ssh_user)
         puts "yes".green
       else
         puts "no".red
-        puts "#{gitolite_config_path} is not owned by #{gitolite_ssh_user}".red
         try_fixing_it(
           "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{gitolite_config_path}"
         )
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
     def check_gitolite_is_up_to_date
       print "Using recommended version ... "
-      if gitolite_version.try(:start_with?, "v3.04")
+      if gitolite_version.try(:start_with?, "v3.2")
         puts "yes".green
       else
         puts "no".red
@@ -558,7 +558,7 @@ namespace :gitlab do
     end
 
     def check_gitoliterc_git_config_keys
-      gitoliterc_path = File.join(gitolite_home, ".gitolite.rc")
+      gitoliterc_path = File.join(gitolite_user_home, ".gitolite.rc")
 
       print "Allow all Git config keys in .gitolite.rc ... "
       option_name = if has_gitolite3?
@@ -567,7 +567,7 @@ namespace :gitlab do
                     else
                       # assume older version
                       # see https://github.com/sitaramc/gitolite/blob/v2.3/conf/example.gitolite.rc#L49
-                      "$GL_GITCONFIG_KEYS"
+                      "\\$GL_GITCONFIG_KEYS"
                     end
       option_value = ".*"
       if open(gitoliterc_path).grep(/#{option_name}\s*=[>]?\s*["']#{option_value}["']/).any?
@@ -582,12 +582,12 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
     def check_gitoliterc_repo_umask
-      gitoliterc_path = File.join(gitolite_home, ".gitolite.rc")
+      gitoliterc_path = File.join(gitolite_user_home, ".gitolite.rc")
 
       print "Repo umask is 0007 in .gitolite.rc? ... "
       option_name = if has_gitolite3?
@@ -596,7 +596,7 @@ namespace :gitlab do
                     else
                       # assume older version
                       # see https://github.com/sitaramc/gitolite/blob/v2.3/conf/example.gitolite.rc#L32
-                      "$REPO_UMASK"
+                      "\\$REPO_UMASK"
                     end
       option_value = "0007"
       if open(gitoliterc_path).grep(/#{option_name}\s*=[>]?\s*#{option_value}/).any?
@@ -611,7 +611,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -635,7 +635,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Setup GitLab Hooks"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -666,7 +666,7 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Setup GitLab Hooks"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -688,7 +688,27 @@ namespace :gitlab do
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
+      end
+    end
+
+    def check_repo_base_is_not_symlink
+      print "Repo base directory is a symlink? ... "
+
+      repo_base_path = Gitlab.config.gitolite.repos_path
+      unless File.exists?(repo_base_path)
+        puts "can't check because of previous errors".magenta
+        return
+      end
+
+      unless File.symlink?(repo_base_path)
+        puts "no".green
+      else
+        puts "yes".red
+        try_fixing_it(
+          "Make sure it's set to the real directory in config/gitlab.yml"
+        )
+        fix_and_rerun
       end
     end
 
@@ -701,18 +721,17 @@ namespace :gitlab do
         return
       end
 
-      if `stat --printf %a #{repo_base_path}` == "6770"
+      if File.stat(repo_base_path).mode.to_s(8).ends_with?("6770")
         puts "yes".green
       else
         puts "no".red
-        puts "#{repo_base_path} is not writable".red
         try_fixing_it(
           "sudo chmod -R ug+rwXs,o-rwx #{repo_base_path}"
         )
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -726,19 +745,18 @@ namespace :gitlab do
         return
       end
 
-      if `stat --printf %U #{repo_base_path}` == gitolite_ssh_user && # user
-         `stat --printf %G #{repo_base_path}` == gitolite_ssh_user #group
+      if File.stat(repo_base_path).uid == uid_for(gitolite_ssh_user) &&
+         File.stat(repo_base_path).gid == gid_for(gitolite_ssh_user)
         puts "yes".green
       else
         puts "no".red
-        puts "#{repo_base_path} is not owned by #{gitolite_ssh_user}".red
         try_fixing_it(
           "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{repo_base_path}"
         )
         for_more_information(
           see_installation_guide_section "Gitolite"
         )
-        check_failed
+        fix_and_rerun
       end
     end
 
@@ -767,12 +785,12 @@ namespace :gitlab do
         else
           puts "wrong or missing".red
           try_fixing_it(
-            "sudo -u gitlab -H bundle exec rake gitlab:gitolite:update_repos"
+            "sudo -u gitlab -H bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production"
           )
           for_more_information(
             "doc/raketasks/maintenance.md"
           )
-          check_failed
+          fix_and_rerun
         end
       end
     end
@@ -808,11 +826,12 @@ namespace :gitlab do
           for_more_information(
             "lib/support/rewrite-hooks.sh"
           )
-          check_failed
+          fix_and_rerun
           next
         end
 
-        if run_and_match("stat --format %N #{project_hook_file}", /#{hook_file}.+->.+#{gitolite_hook_file}/)
+        if File.lstat(project_hook_file).symlink? &&
+            File.realpath(project_hook_file) == File.realpath(gitolite_hook_file)
           puts "ok".green
         else
           puts "not a link to Gitolite's hook".red
@@ -822,7 +841,7 @@ namespace :gitlab do
           for_more_information(
             "lib/support/rewrite-hooks.sh"
           )
-          check_failed
+          fix_and_rerun
         end
       end
     end
@@ -831,12 +850,12 @@ namespace :gitlab do
     # Helper methods
     ########################
 
-    def gitolite_home
+    def gitolite_user_home
       File.expand_path("~#{Gitlab.config.gitolite.ssh_user}")
     end
 
     def gitolite_version
-      gitolite_version_file = "#{gitolite_home}/gitolite/src/VERSION"
+      gitolite_version_file = "#{gitolite_user_home}/gitolite/src/VERSION"
       if File.readable?(gitolite_version_file)
         File.read(gitolite_version_file)
       end
@@ -880,7 +899,7 @@ namespace :gitlab do
           see_installation_guide_section("Install Init Script"),
           "see log/resque.log for possible errors"
         )
-        check_failed
+        fix_and_rerun
       end
     end
   end
@@ -889,7 +908,7 @@ namespace :gitlab do
   # Helper methods
   ##########################
 
-  def check_failed
+  def fix_and_rerun
     puts "  Please #{"fix the error above"} and rerun the checks.".red
   end
 
@@ -908,29 +927,6 @@ namespace :gitlab do
     puts ""
   end
 
-  # Runs the given command
-  #
-  # Returns nil if the command was not found
-  # Returns the output of the command otherwise
-  #
-  # see also #run_and_match
-  def run(command)
-    unless `#{command} 2>/dev/null`.blank?
-      `#{command}`
-    end
-  end
-
-  # Runs the given command and matches the output agains the given pattern
-  #
-  # Returns nil if nothing matched
-  # Retunrs the MatchData if the pattern matched
-  #
-  # see also #run
-  # see also String#match
-  def run_and_match(command, pattern)
-    run(command).try(:match, pattern)
-  end
-
   def see_database_guide
     "doc/install/databases.md"
   end
@@ -952,18 +948,4 @@ namespace :gitlab do
       puts "  #{step}"
     end
   end
-
-  def warn_user_is_not_gitlab
-    unless @warned_user_not_gitlab
-      current_user = run("whoami").chomp
-      unless current_user == "gitlab"
-        puts "#{Colored.color(:black)+Colored.color(:on_yellow)} Warning #{Colored.extra(:clear)}"
-        puts "  You are running as user #{current_user.magenta}, we hope you know what you are doing."
-        puts "  Some tests may pass\/fail for the wrong reason."
-        puts "  For meaningful results you should run this as user #{"gitlab".magenta}."
-        puts ""
-      end
-      @warned_user_not_gitlab = true
-    end
-  end
 end
diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake
new file mode 100644
index 0000000000000000000000000000000000000000..2a0ffe0f4bdf918e9d8bbeb06acf39b729c0a359
--- /dev/null
+++ b/lib/tasks/gitlab/cleanup.rake
@@ -0,0 +1,128 @@
+namespace :gitlab do
+  namespace :cleanup do
+    desc "GITLAB | Cleanup | Clean gitolite config"
+    task :config => :environment  do
+      warn_user_is_not_gitlab
+
+      real_repos = Project.all.map(&:path_with_namespace)
+      real_repos << "gitolite-admin"
+      real_repos << "@all"
+
+      remove_flag = ENV['REMOVE']
+
+      puts "Looking for repositories to remove... "
+      Gitlab::GitoliteConfig.new.apply do |config|
+        all_repos = []
+        garbage_repos = []
+
+        all_repos = config.conf.repos.keys
+        garbage_repos = all_repos - real_repos
+
+        garbage_repos.each do |repo_name|
+          if remove_flag
+            config.conf.rm_repo(repo_name)
+            print "to remove...".red
+          end
+
+          puts repo_name.red
+        end
+      end
+
+      unless remove_flag
+        puts "To cleanup repositories run this command with REMOVE=true".yellow
+      end
+    end
+
+    desc "GITLAB | Cleanup | Clean namespaces"
+    task :dirs => :environment  do
+      warn_user_is_not_gitlab
+      remove_flag = ENV['REMOVE']
+
+
+      namespaces = Namespace.pluck(:path)
+      git_base_path = Gitlab.config.gitolite.repos_path
+      all_dirs = Dir.glob(git_base_path + '/*')
+
+      puts git_base_path.yellow
+      puts "Looking for directories to remove... "
+
+      all_dirs.reject! do |dir|
+        # skip if git repo
+        dir =~ /.git$/
+      end
+
+      all_dirs.reject! do |dir|
+        dir_name = File.basename dir
+
+        # skip if namespace present
+        namespaces.include?(dir_name)
+      end
+
+      all_dirs.each do |dir_path|
+
+        if remove_flag
+          if FileUtils.rm_rf dir_path
+            puts "Removed...#{dir_path}".red
+          else
+            puts "Cannot remove #{dir_path}".red
+          end
+        else
+          puts "Can be removed: #{dir_path}".red
+        end
+      end
+
+      unless remove_flag
+        puts "To cleanup this directories run this command with REMOVE=true".yellow
+      end
+    end
+
+    desc "GITLAB | Cleanup | Clean respositories"
+    task :repos => :environment  do
+      warn_user_is_not_gitlab
+      remove_flag = ENV['REMOVE']
+
+      git_base_path = Gitlab.config.gitolite.repos_path
+      all_dirs = Dir.glob(git_base_path + '/*')
+
+      global_projects = Project.where(namespace_id: nil).pluck(:path)
+
+      puts git_base_path.yellow
+      puts "Looking for global repos to remove... "
+
+      # skip non git repo
+      all_dirs.select! do |dir|
+        dir =~ /.git$/
+      end
+
+      # skip existing repos
+      all_dirs.reject! do |dir|
+        repo_name = File.basename dir
+        path = repo_name.gsub(/\.git$/, "")
+        global_projects.include?(path)
+      end
+
+      # skip gitolite admin
+      all_dirs.reject! do |dir|
+        repo_name = File.basename dir
+        repo_name == 'gitolite-admin.git'
+      end
+
+
+      all_dirs.each do |dir_path|
+        if remove_flag
+          if FileUtils.rm_rf dir_path
+            puts "Removed...#{dir_path}".red
+          else
+            puts "Cannot remove #{dir_path}".red
+          end
+        else
+          puts "Can be removed: #{dir_path}".red
+        end
+      end
+
+      unless remove_flag
+        puts "To cleanup this directories run this command with REMOVE=true".yellow
+      end
+    end
+  end
+end
diff --git a/lib/tasks/gitlab/enable_namespaces.rake b/lib/tasks/gitlab/enable_namespaces.rake
index 1be9ba6469d29860c9a3f62df7002d25136fa0e1..ee80c0905cb4f41a88a677b94636032e0c16c141 100644
--- a/lib/tasks/gitlab/enable_namespaces.rake
+++ b/lib/tasks/gitlab/enable_namespaces.rake
@@ -1,34 +1,87 @@
 namespace :gitlab do
   desc "GITLAB | Enable usernames and namespaces for user projects"
   task enable_namespaces: :environment do
-    print "\nUsernames for users:".yellow
+    warn_user_is_not_gitlab
 
+    migrate_user_namespaces
+    migrate_groups
+    migrate_projects
+
+    puts "Rebuild Gitolite ... "
+    gitolite = Gitlab::Gitolite.new
+    gitolite.update_repositories(Project.where('namespace_id IS NOT NULL'))
+    puts "... #{"done".green}"
+  end
+
+  def migrate_user_namespaces
+    puts "\nGenerate usernames for users without one: ".blue
     User.find_each(batch_size: 500) do |user|
-      next if user.namespace
+      if user.namespace
+        print '-'.cyan
+        next
+      end
 
-      User.transaction do
-        username = user.email.match(/^[^@]*/)[0]
-        if user.update_attributes!(username: username)
+      username = if user.username.present?
+                   # if user already has username filled
+                   user.username
+                 else
+                   build_username(user)
+                 end
+
+      begin
+        User.transaction do
+          user.update_attributes!(username: username)
           print '.'.green
-        else
-          print 'F'.red
         end
+      rescue
+        print 'F'.red
       end
     end
+    puts "\nDone"
+  end
+
+  def build_username(user)
+    username = nil
+
+    # generate username
+    username = user.email.match(/^[^@]*/)[0]
+    username.gsub!("+", ".")
+
+    # return username if no mathes
+    return username unless User.find_by_username(username)
+
+    # look for same username
+    (1..10).each do |i|
+      suffixed_username = "#{username}#{i}"
+
+      return suffixed_username unless User.find_by_username(suffixed_username)
+    end
+  end
 
-    print "\n\nDirs for groups:".yellow
+  def migrate_groups
+    puts "\nCreate directories for groups: ".blue
 
     Group.find_each(batch_size: 500) do |group|
-      if group.ensure_dir_exist
-        print '.'.green
-      else
+      begin
+        if group.dir_exists?
+          print '-'.cyan
+        else
+          if group.ensure_dir_exist
+            print '.'.green
+          else
+            print 'F'.red
+          end
+        end
+      rescue
         print 'F'.red
       end
     end
+    puts "\nDone"
+  end
 
-    print "\n\nMove projects from groups under groups dirs:".yellow
+  def migrate_projects
     git_path = Gitlab.config.gitolite.repos_path
-
+    puts "\nMove projects in groups into respective directories ... ".blue
     Project.where('namespace_id IS NOT NULL').find_each(batch_size: 500) do |project|
       next unless project.group
 
@@ -59,9 +112,6 @@ namespace :gitlab do
       end
     end
 
-    print "\n\nRebuild gitolite:".yellow
-    gitolite = Gitlab::Gitolite.new
-    gitolite.update_repositories(Project.where('namespace_id IS NOT NULL'))
-    puts "\n"
+    puts "\nDone"
   end
 end
diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake
index 85458fe2c43fdd53888671878d2a7afdb64c15f5..4b906684dcd206891f0a4a47c6e2b3ca3235b544 100644
--- a/lib/tasks/gitlab/info.rake
+++ b/lib/tasks/gitlab/info.rake
@@ -3,17 +3,6 @@ namespace :gitlab do
     desc "GITLAB | Show information about GitLab and its environment"
     task info: :environment  do
 
-      # check which OS is running
-      os_name = run("lsb_release -irs")
-      os_name ||= if File.readable?('/etc/system-release')
-                    File.read('/etc/system-release')
-                  end
-      os_name ||= if File.readable?('/etc/debian_version')
-                    debian_version = File.read('/etc/debian_version')
-                    "Debian #{debian_version}"
-                  end
-      os_name.squish!
-
       # check if there is an RVM environment
       rvm_version = run_and_match("rvm --version", /[\d\.]+/).try(:to_s)
       # check Ruby version
@@ -80,31 +69,5 @@ namespace :gitlab do
       puts "Git:\t\t#{Gitlab.config.git.bin_path}"
 
     end
-
-
-    # Helper methods
-
-    # Runs the given command and matches the output agains the given pattern
-    #
-    # Returns nil if nothing matched
-    # Retunrs the MatchData if the pattern matched
-    #
-    # see also #run
-    # see also String#match
-    def run_and_match(command, regexp)
-      run(command).try(:match, regexp)
-    end
-
-    # Runs the given command
-    #
-    # Returns nil if the command was not found
-    # Returns the output of the command otherwise
-    #
-    # see also #run_and_match
-    def run(command)
-      unless `#{command} 2>/dev/null`.blank?
-        `#{command}`
-      end
-    end
   end
 end
diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake
new file mode 100644
index 0000000000000000000000000000000000000000..5dd97fa2f920ddc3288c9837858413c75d86ca55
--- /dev/null
+++ b/lib/tasks/gitlab/task_helpers.rake
@@ -0,0 +1,70 @@
+namespace :gitlab do
+
+  # Check which OS is running
+  #
+  # It will primarily use lsb_relase to determine the OS.
+  # It has fallbacks to Debian, SuSE and OS X.
+  def os_name
+    os_name = run("lsb_release -irs")
+    os_name ||= if File.readable?('/etc/system-release')
+                  File.read('/etc/system-release')
+                end
+    os_name ||= if File.readable?('/etc/debian_version')
+                  debian_version = File.read('/etc/debian_version')
+                  "Debian #{debian_version}"
+                end
+    os_name ||= if File.readable?('/etc/SuSE-release')
+                  File.read('/etc/SuSE-release')
+                end
+    os_name ||= if os_x_version = run("sw_vers -productVersion")
+                  "Mac OS X #{os_x_version}"
+                end
+    os_name.try(:squish!)
+  end
+
+  # Runs the given command and matches the output agains the given pattern
+  #
+  # Returns nil if nothing matched
+  # Retunrs the MatchData if the pattern matched
+  #
+  # see also #run
+  # see also String#match
+  def run_and_match(command, regexp)
+    run(command).try(:match, regexp)
+  end
+
+  # Runs the given command
+  #
+  # Returns nil if the command was not found
+  # Returns the output of the command otherwise
+  #
+  # see also #run_and_match
+  def run(command)
+    unless `#{command} 2>/dev/null`.blank?
+      `#{command}`
+    end
+  end
+
+  def uid_for(user_name)
+    run("id -u #{user_name}").chomp.to_i
+  end
+
+  def gid_for(group_name)
+    group_line = File.read("/etc/group").lines.select{|l| l.start_with?("#{group_name}:")}.first
+    group_line.split(":")[2].to_i
+  end
+
+  def warn_user_is_not_gitlab
+    unless @warned_user_not_gitlab
+      current_user = run("whoami").chomp
+      unless current_user == "gitlab"
+        puts "#{Colored.color(:black)+Colored.color(:on_yellow)} Warning #{Colored.extra(:clear)}"
+        puts "  You are running as user #{current_user.magenta}, we hope you know what you are doing."
+        puts "  Things may work\/fail for the wrong reasons."
+        puts "  For correct results you should run this as user #{"gitlab".magenta}."
+        puts ""
+      end
+      @warned_user_not_gitlab = true
+    end
+  end
+end
diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake
index 0825324a424812fcc902cbf9a4326856ed85332c..bf031403db8ef9209e9911eedfb4ae8a7cf9c4e3 100644
--- a/lib/tasks/resque.rake
+++ b/lib/tasks/resque.rake
@@ -4,6 +4,7 @@ task "resque:setup" => :environment do
   Resque.after_fork do
     Resque.redis.client.reconnect
   end
+  Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection }
 end
 
 desc "Alias for resque:work (To run workers on Heroku)"