diff --git a/CHANGELOG b/CHANGELOG
index 19999491153b5051b831ea1ccb422c6fd311f7d2..b2c783ef9dbedc47be3ef9dc1912eff2e7a637b7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,21 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
+v 7.11.0 (unreleased)
+  - Fix clone URL field and X11 Primary selection (Dmitry Medvinsky)
+  - Ignore invalid lines in .gitmodules
+  -
+  -
+  -
+  -
+  -
+  -
+  -
+  - Improve new project command options (Ben Bodenmiller)
+
 v 7.10.0 (unreleased)
+  - Ignore submodules that are defined in .gitmodules but are checked in as directories.
+  - Allow projects to be imported from Google Code.
+  - Remove access control for uploaded images to fix broken images in emails (Hannes Rosenögger)
   - Allow users to be invited by email to join a group or project.
   - Don't crash when project repository doesn't exist.
   - Add config var to block auto-created LDAP users.
@@ -15,6 +30,7 @@ v 7.10.0 (unreleased)
   - Don't leak existence of group or project via search.
   - Fix bug where Wiki pages that included a '/' were no longer accessible (Stan Hu)
   - Fix bug where error messages from Dropzone would not be displayed on the issues page (Stan Hu)
+  - Add a rake task to check repository integrity with `git fsck`
   - Add ability to configure Reply-To address in gitlab.yml (Stan Hu)
   - Move current user to the top of the list in assignee/author filters (Stan Hu)
   - Fix broken side-by-side diff view on merge request page (Stan Hu)
@@ -75,7 +91,6 @@ v 7.9.0 (unreleased)
   - Fix admin user projects lists.
   - Don't leak private group existence by redirecting from namespace controller to group controller.
   - Ability to skip some items from backup (database, respositories or uploads)
-  - Fix "Hello @username." references not working by no longer allowing usernames to end in period.
   - Archive repositories in background worker.
   - Import GitHub, Bitbucket or GitLab.com projects owned by authenticated user into current namespace.
   - Project labels are now available over the API under the "tag_list" field (Cristian Medina) 
@@ -92,6 +107,12 @@ v 7.9.0 (unreleased)
   - Remove truncation from issue titles on milestone page (Jason Blanchard)
   - Fix stuck Merge Request merging events from old installations (Ben Bodenmiller)
   - Fix merge request comments on files with multiple commits
+  - Fix Resource Owner Password Authentication Flow
+  
+v 7.9.4
+  - Security: Fix project import URL regex to prevent arbitary local repos from being imported
+  - Fixed issue where only 25 commits would load in file listings
+  - Fix LDAP identities  after config update
 
 v 7.9.3
   - Contains no changes
diff --git a/Gemfile b/Gemfile
index 5261b0e175f4d4dae7f6052418f569f843f67a32..e26127a4ad039ba56220c89aaf19f383adabed8a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -39,7 +39,7 @@ gem "browser"
 
 # Extracting information from a git repository
 # Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.1.6'
+gem "gitlab_git", '~> 7.1.10'
 
 # Ruby/Rack Git Smart-HTTP Server Handler
 gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack'
diff --git a/Gemfile.lock b/Gemfile.lock
index cd1887fd465491467f0f4b5ee66a76d22100c3ed..3129c53515fa3dfa526c6450c93d426f30f0286d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -212,7 +212,7 @@ GEM
       mime-types (~> 1.19)
     gitlab_emoji (0.1.0)
       gemojione (~> 2.0)
-    gitlab_git (7.1.6)
+    gitlab_git (7.1.10)
       activesupport (~> 4.0)
       charlock_holmes (~> 0.6)
       gitlab-linguist (~> 3.0)
@@ -703,7 +703,7 @@ DEPENDENCIES
   gitlab-grack (~> 2.0.0.rc2)
   gitlab-linguist (~> 3.0.1)
   gitlab_emoji (~> 0.1)
-  gitlab_git (~> 7.1.6)
+  gitlab_git (~> 7.1.10)
   gitlab_meta (= 7.0)
   gitlab_omniauth-ldap (= 1.2.1)
   gollum-lib (~> 4.0.2)
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index fda142293bc9b42daab5866d9c52f38339a8409e..bd52d3d4d70c07b54916dcb5bcfe1f2544e1bdbd 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -115,8 +115,8 @@ if location.hash
 window.addEventListener "hashchange", shiftWindow
 
 $ ->
-  # Click a .one_click_select field, select the contents
-  $(".one_click_select").on 'click', -> $(@).select()
+  # Click a .js-select-on-focus field, select the contents
+  $(".js-select-on-focus").on "focusin", -> $(this).select()
 
   $('.remove-row').bind 'ajax:success', ->
     $(this).closest('li').fadeOut()
diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee
index 010a2b0e42b88588a704acaf488daee667f34e53..917228bd27658837d7c9ad3e6e83b632f7e9a8f9 100644
--- a/app/assets/javascripts/branch-graph.js.coffee
+++ b/app/assets/javascripts/branch-graph.js.coffee
@@ -214,7 +214,7 @@ class @BranchGraph
       stroke: @colors[commit.space]
       "stroke-width": 2
     )
-    r.image(gon.relative_url_root + commit.author.icon, avatar_box_x, avatar_box_y, 20, 20)
+    r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20)
     r.text(@offsetX + @unitSpace * @mspace + 35, y, commit.message.split("\n")[0]).attr(
       "text-anchor": "start"
       font: "14px Monaco, monospace"
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index fc75f1438368c198c2610768af32c0965d4a905f..ae5d088d593d4823676c75e87da1b0f0100e639f 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -58,14 +58,6 @@ class @MergeRequest
       , 'json'
 
   bindEvents: ->
-    this.$('.merge-request-tabs').on 'click', 'a', (event) =>
-      a = $(event.currentTarget)
-
-      href = a.attr('href')
-      History.replaceState {path: href}, document.title, href
-
-      event.preventDefault()
-
     this.$('.merge-request-tabs').on 'click', 'li', (event) =>
       this.activateTab($(event.currentTarget).data('action'))
 
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index 0e5567c77341fe2b0924e713b5f4ab5585f1eff1..35ece5b270b95c119292704452884f888e1ad650 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -3,40 +3,54 @@ def index
   end
 
   def show
-    @filepath = clean_path_info(params[:filepath])
-    @format = params[:format]
+    category = clean_path_info(path_params[:category])
+    file = path_params[:file]
 
     respond_to do |format|
-      format.md { render_doc }
-      format.all { send_file_data }
-    end
-  end
+      format.any(:markdown, :md, :html) do
+        path = Rails.root.join('doc', category, "#{file}.md")
 
-  def shortcuts
-  end
+        if File.exist?(path)
+          @markdown = File.read(path)
 
-  private
+          render 'show.html.haml'
+        else
+          # Force template to Haml
+          render 'errors/not_found.html.haml', layout: 'errors', status: 404
+        end
+      end
+
+      # Allow access to images in the doc folder
+      format.any(:png, :gif, :jpeg) do
+        path = Rails.root.join('doc', category, "#{file}.#{params[:format]}")
+
+        if File.exist?(path)
+          send_file(path, disposition: 'inline')
+        else
+          head :not_found
+        end
+      end
 
-  def render_doc
-    if File.exists?(Rails.root.join('doc', @filepath + '.md'))
-      render 'show.html.haml'
-    else
-      not_found!
+      # Any other format we don't recognize, just respond 404
+      format.any { head :not_found }
     end
   end
 
-  def send_file_data
-    path = Rails.root.join('doc', "#{@filepath}.#{@format}")
-    if File.exists?(path)
-      send_file(path, disposition: 'inline')
-    else
-      head :not_found
-    end
+  def shortcuts
   end
 
   def ui
   end
 
+  private
+
+  def path_params
+    params.require(:category)
+    params.require(:file)
+
+    params
+  end
+
   PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
 
   # Taken from ActionDispatch::FileHandler
diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb
index fb4ef987367289575d945cac8d8cec144f6a7f3b..73c912e285bf86193e982c9cb23a9351322d7daf 100644
--- a/app/controllers/import/google_code_controller.rb
+++ b/app/controllers/import/google_code_controller.rb
@@ -54,6 +54,11 @@ def create_user_map
       render "new_user_map" and return
     end
 
+    # This is the default, so let's not save it into the database.
+    user_map.reject! do |key, value|
+      value == Gitlab::GoogleCodeImport::Client.mask_email(key)
+    end
+
     session[:google_code_user_map] = user_map
 
     flash[:notice] = "The user map has been saved. Continue by selecting the projects you want to import."
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 87e39f1363a6acce991bf6101ca7c6fe998284a7..894cf93b9ae7c624aa5cb2c6ca05f81bc80ddee2 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -10,11 +10,11 @@ class Projects::CommitController < Projects::ApplicationController
   def show
     return git_not_found! unless @commit
 
-    @line_notes = @project.notes.for_commit_id(commit.id).inline
+    @line_notes = commit.notes(@project).inline
     @diffs = @commit.diffs
     @note = @project.build_commit_note(commit)
-    @notes_count = @project.notes.for_commit_id(commit.id).count
-    @notes = @project.notes.for_commit_id(@commit.id).not_inline.fresh
+    @notes_count = commit.notes(@project).count
+    @notes = commit.notes(@project).not_inline.fresh
     @noteable = @commit
     @comments_allowed = @reply_allowed = true
     @comments_target  = {
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 9020e86c44e95903bd43214fa72951c5f9e2d9b2..276dced865678e1f85bf72f2307bc39a2cb3e16a 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -1,7 +1,11 @@
 class Projects::UploadsController < Projects::ApplicationController
   layout 'project'
 
-  before_filter :project
+  # We want to skip these filters for only the `show` action if `image?` is true, 
+  # but `skip_before_filter` doesn't work with both `only` and `if`, so we accomplish the same like this.
+  skipped_filters = [:authenticate_user!, :reject_blocked!, :project, :repository]
+  skip_before_filter  *skipped_filters, only: [:show]
+  before_filter       *skipped_filters, only: [:show], unless: :image?
 
   def create
     link_to_file = ::Projects::UploadService.new(project, params[:file]).
@@ -21,15 +25,32 @@ def create
   end
 
   def show
-    uploader = FileUploader.new(project, params[:secret])
+    return not_found! if uploader.nil? || !uploader.file.exists?
 
-    return redirect_to uploader.url unless uploader.file_storage?
+    disposition = uploader.image? ? 'inline' : 'attachment'
+    send_file uploader.file.path, disposition: disposition
+  end
 
-    uploader.retrieve_from_store!(params[:filename])
+  def uploader
+    return @uploader if defined?(@uploader)
 
-    return not_found! unless uploader.file.exists?
+    namespace = params[:namespace_id]
+    id = params[:project_id]
 
-    disposition = uploader.image? ? 'inline' : 'attachment'
-    send_file uploader.file.path, disposition: disposition
+    file_project = Project.find_with_namespace("#{namespace}/#{id}")
+
+    if file_project.nil?
+      @uploader = nil 
+      return
+    end
+
+    @uploader = FileUploader.new(file_project, params[:secret])
+    @uploader.retrieve_from_store!(params[:filename])
+
+    @uploader
+  end
+
+  def image?
+    uploader && uploader.file.exists? && uploader.image?
   end
 end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 006fa62c8f96bd86e16c02390e7282cdef352240..1cabc060c2affd7afd6ca56864a7aa74b5d76183 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -134,6 +134,25 @@ def committer
     User.find_for_commit(committer_email, committer_name)
   end
 
+  def participants(project, current_user = nil)
+    users = []
+    users << author
+    users << committer
+    
+    users.push *self.mentioned_users(current_user, project)
+
+    notes(project).each do |note|
+      users << note.author
+      users.push *note.mentioned_users(current_user, project)
+    end
+
+    users.uniq
+  end
+
+  def notes(project)
+    project.notes.for_commit_id(self.id)
+  end
+
   def method_missing(m, *args, &block)
     @raw.send(m, *args, &block)
   end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 478134dff68f8fa11f42c8b52ffd7750fdc60314..a21d9bdfe8aae4a74fdaf82e88a3d81fc8a5f141 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -122,15 +122,15 @@ def participants(current_user = self.author)
     users = []
     users << author
     users << assignee if is_assigned?
-    mentions = []
-    mentions << self.mentioned_users(current_user)
+
+    users.push *self.mentioned_users(current_user)
 
     notes.each do |note|
       users << note.author
-      mentions << note.mentioned_users(current_user)
+      users.push *note.mentioned_users(current_user)
     end
 
-    users.concat(mentions.reduce([], :|)).uniq
+    users.uniq
   end
 
   def subscribed?(user)
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index b7882a2bb160253b1ef2492e445a71c874232385..acd9a1edc4886b78a1091210de99d097560a53a4 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -42,10 +42,10 @@ def has_mentioned?(target)
     Note.cross_reference_exists?(target, local_reference)
   end
 
-  def mentioned_users(current_user = nil)
+  def mentioned_users(current_user = nil, p = project)
     return [] if mentionable_text.blank?
 
-    ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
+    ext = Gitlab::ReferenceExtractor.new(p, current_user)
     ext.analyze(mentionable_text)
     ext.users.uniq
   end
diff --git a/app/models/label.rb b/app/models/label.rb
index 9d7099c5652db38d914eae00a3e5823a37813f28..1f22ed23d42d88792c265f1fec20dae4676f7ade 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -13,6 +13,8 @@
 class Label < ActiveRecord::Base
   DEFAULT_COLOR = '#428BCA'
 
+  default_value_for :color, DEFAULT_COLOR
+
   belongs_to :project
   has_many :label_links, dependent: :destroy
   has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index a0d79d7e5c061d76c98e507630cb8ec6b43660df..e1de114375e63ce012d3d5eb93d57bf99a30322a 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -59,6 +59,7 @@ def search(query)
     end
 
     def clean_path(path)
+      path = path.dup
       path.gsub!(/@.*\z/,             "")
       path.gsub!(/\.git\z/,           "")
       path.gsub!(/\A-+/,              "")
diff --git a/app/models/note.rb b/app/models/note.rb
index 4bb911777502d711a36a170a883a61f4359c48d1..7a692c069fda4947261adb4b52a2a5b6a93e0d3b 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -332,14 +332,6 @@ def max_attachment_size
     current_application_settings.max_attachment_size.megabytes.to_i
   end
 
-  def commit_author
-    @commit_author ||=
-      project.team.users.find_by(email: noteable.author_email) ||
-      project.team.users.find_by(name: noteable.author_name)
-  rescue
-    nil
-  end
-
   def cross_reference?
     note.start_with?(self.class.cross_reference_note_prefix)
   end
diff --git a/app/models/project.rb b/app/models/project.rb
index c71a4ba5ae7d1e7faf45259ef75ee9c1dc8ff3f6..46713511e53285c16ea50760998b648cdff9f28e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -27,7 +27,6 @@
 #  import_type            :string(255)
 #  import_source          :string(255)
 #  avatar                 :string(255)
-#  import_data            :text
 #
 
 require 'carrierwave/orm/activerecord'
@@ -51,8 +50,6 @@ class Project < ActiveRecord::Base
   default_value_for :wall_enabled, false
   default_value_for :snippets_enabled, gitlab_config_features.snippets
 
-  serialize :import_data, JSON
-
   # set last_activity_at to the same as created_at
   after_create :set_last_activity_at
   def set_last_activity_at
@@ -122,6 +119,7 @@ def set_last_activity_at
 
   has_many :project_group_links, dependent: :destroy
   has_many :invited_groups, through: :project_group_links, source: :group
+  has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
 
   delegate :name, to: :owner, allow_nil: true, prefix: true
   delegate :members, to: :team, prefix: true
@@ -273,8 +271,7 @@ def add_import_job
   end
 
   def clear_import_data
-    self.import_data = nil
-    self.save
+    self.import_data.destroy if self.import_data
   end
 
   def import?
diff --git a/app/models/project_import_data.rb b/app/models/project_import_data.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6a8a8a56eb5874653265aa820300de5847524cb8
--- /dev/null
+++ b/app/models/project_import_data.rb
@@ -0,0 +1,19 @@
+# == Schema Information
+#
+# Table name: project_import_datas
+#
+#  id           :integer          not null, primary key
+#  project_id   :integer
+#  data         :text
+#
+
+require 'carrierwave/orm/activerecord'
+require 'file_size_validator'
+
+class ProjectImportData < ActiveRecord::Base
+  belongs_to :project
+  
+  serialize :data, JSON
+
+  validates :project, presence: true
+end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index b35e72c4bdb00f5c05293bd191acb57547bbdf87..c11c28805ebdd4a4c4cf5298451e95c02613daa0 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -87,6 +87,18 @@ def visibility_level_field
     visibility_level
   end
 
+  def participants(current_user = self.author)
+    users = []
+    users << author
+    
+    notes.each do |note|
+      users << note.author
+      users.push *note.mentioned_users(current_user)
+    end
+
+    users.uniq
+  end
+
   class << self
     def search(query)
       where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%")
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index cfed7964c37e8626810125fae29350dd9f58a14d..c7e45a2c2c705ab1addf21ef552c16f4d3f9405f 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -127,17 +127,12 @@ def new_note(note)
 
     recipients = []
 
-    if note.commit_id.present?
-      recipients << note.commit_author
-    end
-    
     # Add all users participating in the thread (author, assignee, comment authors)
     participants = 
-      if target.respond_to?(:participants)
-        target.participants
-      elsif target.is_a?(Commit)
-        author_ids = Note.for_commit_id(target.id).pluck(:author_id).uniq
-        User.where(id: author_ids)
+      if target.is_a?(Commit)
+        target.participants(note.project, note.author)
+      elsif target.respond_to?(:participants)
+        target.participants(note.author)
       else
         note.mentioned_users
       end
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
index ae6260bcdab714411401a2b1ea9b876d1490532e..c2d8f48f6e420ee0b55e3f8671d036a24052e4d2 100644
--- a/app/services/projects/participants_service.rb
+++ b/app/services/projects/participants_service.rb
@@ -13,19 +13,21 @@ def execute(note_type, note_id)
     end
 
     def participants_in(type, id)
-      users = case type
-              when "Issue"
-                issue = project.issues.find_by_iid(id)
-                issue ? issue.participants(current_user) : []
-              when "MergeRequest"
-                merge_request = project.merge_requests.find_by_iid(id)
-                merge_request ? merge_request.participants(current_user) : []
-              when "Commit"
-                author_ids = Note.for_commit_id(id).pluck(:author_id).uniq
-                User.where(id: author_ids)
-              else
-                []
-              end
+      users = 
+        case type
+        when "Issue"
+          issue = project.issues.find_by_iid(id)
+          issue.participants(current_user) if issue
+        when "MergeRequest"
+          merge_request = project.merge_requests.find_by_iid(id)
+          merge_request.participants(current_user) if merge_request
+        when "Commit"
+          commit = project.repository.commit(id)
+          commit.participants(project, current_user) if commit
+        end
+
+      return [] unless users
+      
       sorted(users)
     end
 
diff --git a/app/views/help/show.html.haml b/app/views/help/show.html.haml
index f22aa92caf7435ee9fc81faf763df144bbc08ac2..cc1be6a717aeaf68026f078c2d81629702a9678d 100644
--- a/app/views/help/show.html.haml
+++ b/app/views/help/show.html.haml
@@ -1,2 +1,2 @@
 .documentation.wiki
-  = markdown File.read(Rails.root.join('doc', @filepath + '.md')).gsub("$your_email", current_user.email)
+  = markdown @markdown.gsub('$your_email', current_user.email)
diff --git a/app/views/layouts/_bootlint.haml b/app/views/layouts/_bootlint.haml
new file mode 100644
index 0000000000000000000000000000000000000000..69280687a9d87c5c439186c600a6a5b897309081
--- /dev/null
+++ b/app/views/layouts/_bootlint.haml
@@ -0,0 +1,4 @@
+:javascript
+  jQuery(document).ready(function() {
+    javascript:(function(){var s=document.createElement("script");s.onload=function(){bootlint.showLintReportForCurrentDocument([], {hasProblems: false, problemFree: false});};s.src="https://maxcdn.bootstrapcdn.com/bootlint/latest/bootlint.min.js";document.body.appendChild(s)})();
+  });
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index f03664178bfd9314d22729f59085fd1b4d05cc04..0a962bd4b10229d7de62ec9a981b1f0a23ed1e19 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -16,6 +16,7 @@
 
   = render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
   = render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id')
+  = render 'layouts/bootlint' if Rails.env == 'development'
 
   -# Atom feed
   - if current_user
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index c6026f968045358927506784a4cb8bf0812f5ee4..8e1aaa4d051c0da760105c4f819825ac0f4b6a0b 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -12,7 +12,7 @@
       - if @note_counts
         - note_count = @note_counts.fetch(commit.id, 0)
       - else
-        - notes = project.notes.for_commit_id(commit.id)
+        - notes = commit.notes(project)
         - note_count = notes.user.count
 
       - if note_count > 0
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 49806ceaa9671182f21785534680362dac537c28..4f8104e0792370a7c4ae407b8ab247494a570620 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -27,20 +27,19 @@
     %legend Create a new repository
     %pre.dark
       :preserve
-        mkdir #{@project.path}
+        git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')}
         cd #{@project.path}
-        git init
         touch README.md
         git add README.md
-        git commit -m "first commit"
-        git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
+        git commit -m "add README"
         git push -u origin master
 
   %fieldset
-    %legend Push an existing Git repository
+    %legend Existing folder or Git repository
     %pre.dark
       :preserve
-        cd existing_git_repo
+        cd existing_folder
+        git init
         git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
         git push -u origin master
 
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index ad993db6c0b584646277dfd2b5f5610a2fbc31ff..261d52dedc1db5193590f0506e0a5b7d956589aa 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -16,7 +16,7 @@
     .col-sm-10
       .input-group
         .input-group-addon.label-color-preview &nbsp;
-        = f.color_field :color, value: "#AA33EE", class: "form-control"
+        = f.color_field :color, class: "form-control"
       .help-block
         Choose any color.
         %br
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index a74aede4e6bacba98678caafce79a91a7ddf2009..cec02de84cad38a234aae430ac48d83d2bd2100a 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -36,17 +36,17 @@
 
   - if @commits.present?
     %ul.nav.nav-tabs.merge-request-tabs
-      %li.notes-tab{data: {action: 'notes'}}
+      %li.notes-tab{data: {action: 'notes', toggle: 'tab'}}
         = link_to merge_request_path(@merge_request) do
           %i.fa.fa-comments
           Discussion
           %span.badge= @merge_request.mr_and_commit_notes.user.count
-      %li.commits-tab{data: {action: 'commits'}}
+      %li.commits-tab{data: {action: 'commits', toggle: 'tab'}}
         = link_to merge_request_path(@merge_request), title: 'Commits' do
           %i.fa.fa-history
           Commits
           %span.badge= @commits.size
-      %li.diffs-tab{data: {action: 'diffs'}}
+      %li.diffs-tab{data: {action: 'diffs', toggle: 'tab'}}
         = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) do
           %i.fa.fa-list-alt
           Changes
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index a1121750ca349e0b25ba94fdf77a228385660789..8b1e3a6dd5e229f8992984a7f2fa60a2ea4ca085 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -15,7 +15,7 @@
       :"data-html" => "true",
       :"data-container" => "body"}
       = gitlab_config.protocol.upcase
-  = text_field_tag :project_clone, default_url_to_repo(project), class: "one_click_select form-control", readonly: true
+  = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true
   - if project.kind_of?(Project)
     .input-group-addon
       .visibility-level-label.has_tooltip{'data-title' => "#{visibility_level_label(project.visibility_level)} project" }
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 9da7ebf4290df3f7a04f44c96480018332ba536c..d422acb31d6bc842434580517934374282b50edb 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -11,7 +11,7 @@
   end
 
   resource_owner_from_credentials do |routes|
-    u = User.find_by(email: params[:username])
+    u = User.find_by(email: params[:username]) || User.find_by(username: params[:username])
     u if u && u.valid_password?(params[:password])
   end
 
@@ -83,7 +83,7 @@
   #
   # If not specified, Doorkeeper enables all the four grant flows.
   #
-  # grant_flows %w(authorization_code implicit password client_credentials)
+  grant_flows %w(authorization_code password client_credentials)
 
   # Under some circumstances you might want to have applications auto-approved,
   # so that the user skips the authorization step.
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
index 6978ad9302402ed85db235d392997f1f5fc969ba..ca58ae92d1b35d1d3f34dc51c37ec63680bd64e5 100644
--- a/config/initializers/mime_types.rb
+++ b/config/initializers/mime_types.rb
@@ -6,4 +6,5 @@
 
 Mime::Type.register_alias "text/plain", :diff
 Mime::Type.register_alias "text/plain", :patch
-Mime::Type.register_alias 'text/html', :md
+Mime::Type.register_alias 'text/html',  :markdown
+Mime::Type.register_alias 'text/html',  :md
diff --git a/config/routes.rb b/config/routes.rb
index cf1b3684d9266806b7e8624490f294b9251456d8..9ec68b5d6638043bc29a5ccfd3ea0273bcf73385 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -39,9 +39,9 @@
 
   # Help
   get 'help'                  => 'help#index'
+  get 'help/:category/:file'  => 'help#show', as: :help_page, constraints: { category: /.*/, file: /[^\/\.]+/ }
   get 'help/shortcuts'
   get 'help/ui'               => 'help#ui'
-  get 'help/:filepath'        => 'help#show', as: :help_page, constraints: { filepath: /[^\.]+/ }
 
   #
   # Global snippets
diff --git a/db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb b/db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb
deleted file mode 100644
index 7ce53c2a0d6d68ea600ced498523ee9db1d18aa7..0000000000000000000000000000000000000000
--- a/db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-class RemovePeriodsAtEndsOfUsernames < ActiveRecord::Migration
-  include Gitlab::ShellAdapter
-
-  class Namespace < ActiveRecord::Base
-    class << self
-      def by_path(path)
-        where('lower(path) = :value', value: path.downcase).first
-      end
-
-      def clean_path(path)
-        path = path.dup
-        path.gsub!(/@.*\z/,             "")
-        path.gsub!(/\.git\z/,           "")
-        path.gsub!(/\A-/,               "")
-        path.gsub!(/.\z/,               "")
-        path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
-
-        counter = 0
-        base = path
-        while Namespace.by_path(path).present?
-          counter += 1
-          path = "#{base}#{counter}"
-        end
-
-        path
-      end
-    end
-  end
-
-  def up
-    changed_paths = {}
-
-    select_all("SELECT id, username FROM users WHERE username LIKE '%.'").each do |user|
-      username_was = user["username"]
-      username = Namespace.clean_path(username_was)
-      changed_paths[username_was] = username
-
-      username = quote_string(username)
-      execute "UPDATE users SET username = '#{username}' WHERE id = #{user["id"]}"
-      execute "UPDATE namespaces SET path = '#{username}', name = '#{username}' WHERE type IS NULL AND owner_id = #{user["id"]}"
-    end
-
-    select_all("SELECT id, path FROM namespaces WHERE type = 'Group' AND path LIKE '%.'").each do |group|
-      path_was = group["path"]
-      path = Namespace.clean_path(path_was)
-      changed_paths[path_was] = path
-
-      path = quote_string(path)
-      execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{group["id"]}"
-    end
-
-    changed_paths.each do |path_was, path|
-      if gitlab_shell.mv_namespace(path_was, path)
-        # If repositories moved successfully we need to remove old satellites
-        # and send update instructions to users.
-        # However we cannot allow rollback since we moved namespace dir
-        # So we basically we mute exceptions in next actions
-        begin
-          gitlab_shell.rm_satellites(path_was)
-          # We cannot send update instructions since models and mailers
-          # can't safely be used from migrations as they may be written for 
-          # later versions of the database.
-          # send_update_instructions
-        rescue
-          # Returning false does not rollback after_* transaction but gives
-          # us information about failing some of tasks
-          false
-        end
-      else
-        # if we cannot move namespace directory we should rollback
-        # db changes in order to prevent out of sync between db and fs
-        raise Exception.new('namespace directory cannot be moved')
-      end
-    end
-  end
-end
diff --git a/db/migrate/20150417121913_create_project_import_data.rb b/db/migrate/20150417121913_create_project_import_data.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c78f5fde85e0598ff39cc508f2c0d4af5020501b
--- /dev/null
+++ b/db/migrate/20150417121913_create_project_import_data.rb
@@ -0,0 +1,8 @@
+class CreateProjectImportData < ActiveRecord::Migration
+  def change
+    create_table :project_import_data do |t|
+      t.references :project
+      t.text :data
+    end
+  end
+end
diff --git a/db/migrate/20150417122318_remove_import_data_from_project.rb b/db/migrate/20150417122318_remove_import_data_from_project.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c275b49d2288a5c57c8354d4d8052e9399b1f8d5
--- /dev/null
+++ b/db/migrate/20150417122318_remove_import_data_from_project.rb
@@ -0,0 +1,5 @@
+class RemoveImportDataFromProject < ActiveRecord::Migration
+  def change
+    remove_column :projects, :import_data
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e2a5be5733d4c96f9d431d58426609e5b7680922..7e101ca142291a0a48301c4d992abb41aa4d2174 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20150413192223) do
+ActiveRecord::Schema.define(version: 20150417122318) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -381,6 +381,11 @@
     t.integer  "group_access", default: 30, null: false
   end
 
+  create_table "project_import_data", force: true do |t|
+    t.integer "project_id"
+    t.text    "data"
+  end
+
   create_table "projects", force: true do |t|
     t.string   "name"
     t.string   "path"
@@ -409,7 +414,6 @@
     t.string   "import_type"
     t.string   "import_source"
     t.boolean  "merge_requests_rebase_default", default: true
-    t.text     "import_data"
   end
 
   add_index "projects", ["created_at", "id"], name: "index_projects_on_created_at_and_id", using: :btree
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 0acb15896d379d0ac80a7b555d178dd9507984dd..0acf92fbf54262072c2d9d1a0c1c48570b1aff2b 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -71,3 +71,9 @@ keys of all the projects you have access to are available. This project
 access can happen through being a direct member of the project, or through
 a group. See `def accessible_deploy_keys` in `app/models/user.rb` for more
 information.
+
+## Applications
+
+### Eclipse
+
+How to add your ssh key to Eclipse: http://wiki.eclipse.org/EGit/User_Guide#Eclipse_SSH_Configuration
diff --git a/features/steps/dashboard/help.rb b/features/steps/dashboard/help.rb
index fa52e391f05bbe7273d8300ff66410bdf427cb18..ef433c57c6eebfc4dfafd134e8053484eba03e9c 100644
--- a/features/steps/dashboard/help.rb
+++ b/features/steps/dashboard/help.rb
@@ -8,7 +8,7 @@ class Spinach::Features::DashboardHelp < Spinach::FeatureSteps
   end
 
   step 'I visit the "Rake Tasks" help page' do
-    visit help_page_path('raketasks/maintenance', format: 'md')
+    visit help_page_path("raketasks", "maintenance")
   end
 
   step 'I should see "Rake Tasks" page markdown rendered' do
diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb
index 777472cf3c5beb5f56c50432c5fb1bde1961343c..b5e82563ff1f6d4bae0e50128b9d24c75805254f 100644
--- a/lib/gitlab/google_code_import/importer.rb
+++ b/lib/gitlab/google_code_import/importer.rb
@@ -5,7 +5,10 @@ class Importer
 
       def initialize(project)
         @project = project
-        @repo = GoogleCodeImport::Repository.new(project.import_data["repo"])
+
+        import_data = project.import_data.try(:data)
+        repo_data = import_data["repo"] if import_data
+        @repo = GoogleCodeImport::Repository.new(repo_data)
 
         @closed_statuses = []
         @known_labels = Set.new
@@ -27,9 +30,10 @@ def execute
 
       def user_map
         @user_map ||= begin
-          user_map = Hash.new { |hash, user| hash[user] = Client.mask_email(user) }
+          user_map = Hash.new { |hash, user| Client.mask_email(user) }
 
-          stored_user_map = project.import_data["user_map"]
+          import_data = project.import_data.try(:data)
+          stored_user_map = import_data["user_map"] if import_data
           user_map.update(stored_user_map) if stored_user_map
 
           user_map
@@ -58,24 +62,7 @@ def import_labels
       def import_issues
         return unless repo.issues
 
-        last_id = 0
-
-        deleted_issues = []
-
-        repo.issues.each do |raw_issue|
-          while raw_issue["id"] > last_id + 1
-            last_id += 1
-
-            issue = project.issues.create!(
-              title:        "Deleted issue",
-              description:  "*This issue has been deleted*",
-              author_id:    project.creator_id,
-              state:        "closed"
-            )
-            deleted_issues << issue
-          end
-          last_id = raw_issue["id"]
-
+        while raw_issue = repo.issues.shift
           author  = user_map[raw_issue["author"]["name"]]
           date    = DateTime.parse(raw_issue["published"]).to_formatted_s(:long)
 
@@ -112,7 +99,8 @@ def import_issues
             end
           end
 
-          issue = project.issues.create!(
+          issue = Issue.create!(
+            project_id:   project.id,
             title:        raw_issue["title"],
             description:  body,
             author_id:    project.creator_id,
@@ -121,39 +109,46 @@ def import_issues
           )
           issue.add_labels_by_names(labels)
 
+          if issue.iid != raw_issue["id"]
+            issue.update_attribute(:iid, raw_issue["id"])
+          end
+
           import_issue_comments(issue, comments)
         end
-
-        deleted_issues.each(&:destroy!)
       end
 
       def import_issue_comments(issue, comments)
-        comments.each do |raw_comment|
-          next if raw_comment.has_key?("deletedBy")
-
-          content     = format_content(raw_comment["content"])
-          updates     = format_updates(raw_comment["updates"])
-          attachments = format_attachments(issue.iid, raw_comment["id"], raw_comment["attachments"])
-
-          next if content.blank? && updates.blank? && attachments.blank?
-
-          author  = user_map[raw_comment["author"]["name"]]
-          date    = DateTime.parse(raw_comment["published"]).to_formatted_s(:long)
-
-          body = format_issue_comment_body(
-            raw_comment["id"],
-            author,
-            date,
-            content,
-            updates,
-            attachments
-          )
+        Note.transaction do
+          while raw_comment = comments.shift
+            next if raw_comment.has_key?("deletedBy")
+
+            content     = format_content(raw_comment["content"])
+            updates     = format_updates(raw_comment["updates"])
+            attachments = format_attachments(issue.iid, raw_comment["id"], raw_comment["attachments"])
+
+            next if content.blank? && updates.blank? && attachments.blank?
+
+            author  = user_map[raw_comment["author"]["name"]]
+            date    = DateTime.parse(raw_comment["published"]).to_formatted_s(:long)
+
+            body = format_issue_comment_body(
+              raw_comment["id"],
+              author,
+              date,
+              content,
+              updates,
+              attachments
+            )
 
-          issue.notes.create!(
-            project_id: project.id,
-            author_id:  project.creator_id,
-            note:       body
-          )
+            # Needs to match order of `comment_columns` below.
+            Note.create!(
+              project_id:     project.id,
+              noteable_type:  "Issue",
+              noteable_id:    issue.id,
+              author_id:      project.creator_id,
+              note:           body
+            )
+          end
         end
       end
 
@@ -232,7 +227,7 @@ def escape_for_markdown(s)
 
       def create_label(name)
         color = nice_label_color(name)
-        project.labels.create!(name: name, color: color)
+        Label.create!(project_id: project.id, name: name, color: color)
       end
 
       def format_content(raw_content)
diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb
index 7ac4387d79d218da2531408733443ded93de6f74..0cfeaf9d61c4aaec5da765c9b6c4de0fbc358d77 100644
--- a/lib/gitlab/google_code_import/project_creator.rb
+++ b/lib/gitlab/google_code_import/project_creator.rb
@@ -11,12 +11,7 @@ def initialize(repo, namespace, current_user, user_map = nil)
       end
 
       def execute
-        import_data = {
-          "repo"      => repo.raw_data,
-          "user_map"  => user_map
-        }
-
-        @project = Project.new(
+        project = ::Projects::CreateService.new(current_user,
           name: repo.name,
           path: repo.name,
           description: repo.summary,
@@ -25,21 +20,17 @@ def execute
           visibility_level: Gitlab::VisibilityLevel::PUBLIC,
           import_type: "google_code",
           import_source: repo.name,
-          import_url: repo.import_url,
-          import_data: import_data
-        )
+          import_url: repo.import_url
+        ).execute
 
-        if @project.save!
-          @project.reload
-
-          if @project.import_failed?
-            @project.import_retry
-          else
-            @project.import_start
-          end
-        end
+        import_data = project.create_import_data(
+          data: {
+            "repo"      => repo.raw_data,
+            "user_map"  => user_map
+          }
+        )
 
-        @project
+        project
       end
     end
   end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 8073417a16a470ff80066477e182e8ae6aae4786..47c456d8dc747224a81aa8831c8514c2ffda9b91 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -68,23 +68,8 @@ def gfm_with_options(text, options = {}, project = @project, html_options = {})
       @options      = options
       @html_options = html_options
 
-      # Extract pre blocks so they are not altered
-      # from http://github.github.com/github-flavored-markdown/
-      text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| extract_piece(match) }
-      # Extract links with probably parsable hrefs
-      text.gsub!(%r{<a.*?>.*?</a>}m) { |match| extract_piece(match) }
-      # Extract images with probably parsable src
-      text.gsub!(%r{<img.*?>}m) { |match| extract_piece(match) }
-
       # TODO: add popups with additional information
 
-      text = parse(text, project)
-
-      # Insert pre block extractions
-      text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
-        insert_piece($1)
-      end
-
       # Used markdown pipelines in GitLab:
       # GitlabEmojiFilter - performs emoji replacement.
       # SanitizationFilter - remove unsafe HTML tags and attributes
@@ -129,6 +114,21 @@ def gfm_with_options(text, options = {}, project = @project, html_options = {})
 
       text = result[:output].to_html(save_with: save_options)
 
+      # Extract pre blocks so they are not altered
+      # from http://github.github.com/github-flavored-markdown/
+      text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| extract_piece(match) }
+      # Extract links with probably parsable hrefs
+      text.gsub!(%r{<a.*?>.*?</a>}m) { |match| extract_piece(match) }
+      # Extract images with probably parsable src
+      text.gsub!(%r{<img.*?>}m) { |match| extract_piece(match) }
+
+      text = parse(text, project)
+
+      # Insert pre block extractions
+      text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
+        insert_piece($1)
+      end
+
       if options[:parse_tasks]
         text = parse_tasks(text)
       end
@@ -150,7 +150,7 @@ def insert_piece(id)
       @extractions[id]
     end
 
-    # Private: Parses text for references and emoji
+    # Private: Parses text for references
     #
     # text - Text to parse
     #
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 0571574aa4fdc5e538835b398046e4723c5cfe34..9aeed5e69399c27cd0e88362d194029042090bae 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -2,7 +2,7 @@ module Gitlab
   module Regex
     extend self
 
-    NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*[a-zA-Z0-9_\-]|[a-zA-Z0-9_])'.freeze
+    NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*)'.freeze
 
     def namespace_regex
       @namespace_regex ||= /\A#{NAMESPACE_REGEX_STR}\z/.freeze
@@ -10,7 +10,7 @@ def namespace_regex
 
     def namespace_regex_message
       "can contain only letters, digits, '_', '-' and '.'. " \
-      "Cannot start with '-' or end in '.'." \
+      "Cannot start with '-'." \
     end
 
 
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index d791b7155f9a4fc72bb884977969c68c03f69ec3..04a2eb12db0f5a8a6c3e1060814f414e20e57c7d 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -687,6 +687,23 @@ namespace :gitlab do
     end
   end
 
+  namespace :repo do
+    desc "GITLAB | Check the integrity of the repositories managed by GitLab"
+    task check: :environment do
+      namespace_dirs = Dir.glob(
+        File.join(Gitlab.config.gitlab_shell.repos_path, '*')
+      )
+
+      namespace_dirs.each do |namespace_dir|
+        repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
+        repo_dirs.each do |dir|
+          puts "\nChecking repo at #{dir}"
+          system(*%w(git fsck), chdir: dir)
+        end
+      end
+    end
+  end
+
   # Helper methods
   ##########################
 
diff --git a/public/deploy.html b/public/deploy.html
index d9c4bb5c5833038732b13f7f69641978b09c512d..e41ed76573d2d3c6200df6d5a5281b350d43bdc8 100644
--- a/public/deploy.html
+++ b/public/deploy.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
   <head>
-    <title>Deploy in progress. Please try again in few minutes</title>
+    <title>Deploy in progress. Please try again in a few minutes</title>
     <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
   </head>
   <body>
     <h1><center><img src="/gitlab_logo.png"/></center>Deploy in progress</h1>
-    <h3>Please try again in few minutes or contact your administrator.</h3>
+    <h3>Please try again in a few minutes or contact your administrator.</h3>
   </body>
 </html>
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..93535ced7ae5ea9a71a4d6d43ba149a35d5fe7ed
--- /dev/null
+++ b/spec/controllers/help_controller_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe HelpController do
+  let(:user) { create(:user) }
+
+  before do
+    sign_in(user)
+  end
+
+  describe 'GET #show' do
+    context 'for Markdown formats' do
+      context 'when requested file exists' do
+        before do
+          get :show, category: 'ssh', file: 'README', format: :md
+        end
+
+        it 'assigns to @markdown' do
+          expect(assigns[:markdown]).not_to be_empty
+        end
+
+        it 'renders HTML' do
+          expect(response).to render_template('show.html.haml')
+          expect(response.content_type).to eq 'text/html'
+        end
+      end
+
+      context 'when requested file is missing' do
+        it 'renders not found' do
+          get :show, category: 'foo', file: 'bar', format: :md
+          expect(response).to be_not_found
+        end
+      end
+    end
+
+    context 'for image formats' do
+      context 'when requested file exists' do
+        it 'renders the raw file' do
+          get :show, category: 'workflow/protected_branches',
+            file: 'protected_branches1', format: :png
+          expect(response).to be_success
+          expect(response.content_type).to eq 'image/png'
+          expect(response.headers['Content-Disposition']).to match(/^inline;/)
+        end
+      end
+
+      context 'when requested file is missing' do
+        it 'renders not found' do
+          get :show, category: 'foo', file: 'bar', format: :png
+          expect(response).to be_not_found
+        end
+      end
+    end
+
+    context 'for other formats' do
+      it 'always renders not found' do
+        get :show, category: 'ssh', file: 'README', format: :foo
+        expect(response).to be_not_found
+      end
+    end
+  end
+end
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index 029f48b2d7a666ab62e317bbd12578e8693b9cb8..f51abfedae529db22d8ec3705233e27e1d0dc61f 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -54,4 +54,227 @@
       end
     end
   end
+
+  describe "GET #show" do
+    let(:go) do
+      get :show,
+        namespace_id: project.namespace.to_param,
+        project_id:   project.to_param,
+        secret:       "123456",
+        filename:     "image.jpg"
+    end
+
+    context "when the project is public" do
+      before do
+        project.update_attribute(:visibility_level, Project::PUBLIC)
+      end
+
+      context "when not signed in" do
+        context "when the file exists" do
+          before do
+            allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+            allow(jpg).to receive(:exists?).and_return(true)
+          end
+
+          it "responds with status 200" do
+            go
+
+            expect(response.status).to eq(200)
+          end
+        end
+
+        context "when the file doesn't exist" do
+          it "responds with status 404" do
+            go
+
+            expect(response.status).to eq(404)
+          end
+        end
+      end
+
+      context "when signed in" do
+        before do
+          sign_in(user)
+        end
+
+        context "when the file exists" do
+          before do
+            allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+            allow(jpg).to receive(:exists?).and_return(true)
+          end
+
+          it "responds with status 200" do
+            go
+
+            expect(response.status).to eq(200)
+          end
+        end
+
+        context "when the file doesn't exist" do
+          it "responds with status 404" do
+            go
+
+            expect(response.status).to eq(404)
+          end
+        end
+      end
+    end
+
+    context "when the project is private" do
+      before do
+        project.update_attribute(:visibility_level, Project::PRIVATE)
+      end
+
+      context "when not signed in" do
+        context "when the file exists" do
+          before do
+            allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+            allow(jpg).to receive(:exists?).and_return(true)
+          end
+
+          context "when the file is an image" do
+            before do
+              allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
+            end
+
+            it "responds with status 200" do
+              go
+
+              expect(response.status).to eq(200)
+            end
+          end
+
+          context "when the file is not an image" do
+            it "redirects to the sign in page" do
+              go
+
+              expect(response).to redirect_to(new_user_session_path)
+            end
+          end
+        end
+
+        context "when the file doesn't exist" do
+          it "redirects to the sign in page" do
+            go
+
+            expect(response).to redirect_to(new_user_session_path)
+          end
+        end
+      end
+
+      context "when signed in" do
+        before do
+          sign_in(user)
+        end
+
+        context "when the user has access to the project" do
+          before do
+            project.team << [user, :master]
+          end
+
+          context "when the user is blocked" do
+            before do
+              user.block
+              project.team << [user, :master]
+            end
+
+            context "when the file exists" do
+              before do
+                allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+                allow(jpg).to receive(:exists?).and_return(true)
+              end
+
+              context "when the file is an image" do
+                before do
+                  allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
+                end
+
+                it "responds with status 200" do
+                  go
+
+                  expect(response.status).to eq(200)
+                end
+              end
+
+              context "when the file is not an image" do
+                it "redirects to the sign in page" do
+                  go
+
+                  expect(response).to redirect_to(new_user_session_path)
+                end
+              end
+            end
+
+            context "when the file doesn't exist" do
+              it "redirects to the sign in page" do
+                go
+
+                expect(response).to redirect_to(new_user_session_path)
+              end
+            end
+          end
+
+          context "when the user isn't blocked" do
+            context "when the file exists" do
+              before do
+                allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+                allow(jpg).to receive(:exists?).and_return(true)
+              end
+
+              it "responds with status 200" do
+                go
+
+                expect(response.status).to eq(200)
+              end
+            end
+
+            context "when the file doesn't exist" do
+              it "responds with status 404" do
+                go
+
+                expect(response.status).to eq(404)
+              end
+            end
+          end
+        end
+
+        context "when the user doesn't have access to the project" do
+          context "when the file exists" do
+            before do
+              allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+              allow(jpg).to receive(:exists?).and_return(true)
+            end
+
+            context "when the file is an image" do
+              before do
+                allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
+              end
+
+              it "responds with status 200" do
+                go
+
+                expect(response.status).to eq(200)
+              end
+            end
+
+            context "when the file is not an image" do
+              it "responds with status 404" do
+                go
+
+                expect(response.status).to eq(404)
+              end
+            end
+          end
+
+          context "when the file doesn't exist" do
+            it "responds with status 404" do
+              go
+
+              expect(response.status).to eq(404)
+            end
+          end
+        end
+      end
+    end
+  end
 end
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 28423eb8caa5568c3a75e5fe39f5783f28dee6ad..8c6b669ce78283393c053393d32e2ad83a7cab23 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -6,7 +6,7 @@
       login_as :user
     end
     it 'replace the variable $your_email with the email of the user' do
-      visit help_page_path(filepath: 'ssh/README', format: 'md')
+      visit help_page_path('ssh', 'README')
       expect(page).to have_content("ssh-keygen -t rsa -C \"#{@user.email}\"")
     end
   end
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 107ba49962a8b749a2b1043b7a555f1da3abc1d4..1c4503ae0ef31c50f9496e342a1971e274f494b1 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -12,9 +12,13 @@
       }
     } 
   }
-  let(:project) { create(:project, import_data: import_data) }
+  let(:project) { create(:project) }
   subject       { described_class.new(project) }
 
+  before do
+    project.create_import_data(data: import_data)
+  end
+
   describe "#execute" do
 
     it "imports status labels" do
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index f5db548f97c8f8f1dc5cd79e4e74da71180bd320..e219a57c29e63fa4d72c2958df8303b2ef31765b 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -64,50 +64,35 @@
   end
 end
 
-#              help GET    /help(.:format)              help#index
-#  help_permissions GET    /help/permissions(.:format)  help#permissions
-#     help_workflow GET    /help/workflow(.:format)     help#workflow
-#          help_api GET    /help/api(.:format)          help#api
-#    help_web_hooks GET    /help/web_hooks(.:format)    help#web_hooks
-# help_system_hooks GET    /help/system_hooks(.:format) help#system_hooks
-#     help_markdown GET    /help/markdown(.:format)     help#markdown
-#          help_ssh GET    /help/ssh(.:format)          help#ssh
-#    help_raketasks GET    /help/raketasks(.:format)    help#raketasks
-describe HelpController, 'routing' do
-  it 'to #index' do
-    expect(get('/help')).to route_to('help#index')
-  end
-
-  it 'to #permissions' do
-    expect(get('/help/permissions/permissions')).to route_to('help#show', filepath: 'permissions/permissions')
-  end
-
-  it 'to #workflow' do
-    expect(get('/help/workflow/README')).to route_to('help#show', filepath: 'workflow/README')
-  end
-
-  it 'to #api' do
-    expect(get('/help/api/README')).to route_to('help#show', filepath: 'api/README')
-  end
-
-  it 'to #web_hooks' do
-    expect(get('/help/web_hooks/web_hooks')).to route_to('help#show', filepath: 'web_hooks/web_hooks')
+#            help GET /help(.:format)                 help#index
+#       help_page GET /help/:category/:file(.:format) help#show {:category=>/.*/, :file=>/[^\/\.]+/}
+#  help_shortcuts GET /help/shortcuts(.:format)       help#shortcuts
+#         help_ui GET /help/ui(.:format)              help#ui
+describe HelpController, "routing" do
+  it "to #index" do
+    expect(get("/help")).to route_to('help#index')
   end
 
-  it 'to #system_hooks' do
-    expect(get('/help/system_hooks/system_hooks')).to route_to('help#show', filepath: 'system_hooks/system_hooks')
-  end
+  it 'to #show' do
+    path = '/help/markdown/markdown.md'
+    expect(get(path)).to route_to('help#show',
+                                  category: 'markdown',
+                                  file: 'markdown',
+                                  format: 'md')
 
-  it 'to #markdown' do
-    expect(get('/help/markdown/markdown')).to route_to('help#show',filepath: 'markdown/markdown')
+    path = '/help/workflow/protected_branches/protected_branches1.png'
+    expect(get(path)).to route_to('help#show',
+                                  category: 'workflow/protected_branches',
+                                  file: 'protected_branches1',
+                                  format: 'png')
   end
 
-  it 'to #ssh' do
-    expect(get('/help/ssh/README')).to route_to('help#show', filepath: 'ssh/README')
+  it 'to #shortcuts' do
+    expect(get('/help/shortcuts')).to route_to('help#shortcuts')
   end
 
-  it 'to #raketasks' do
-    expect(get('/help/raketasks/README')).to route_to('help#show', filepath: 'raketasks/README')
+  it 'to #ui' do
+    expect(get('/help/ui')).to route_to('help#ui')
   end
 end
 
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index bfca2c88264354f7aca3f3abd5c06579ec18ccc0..6d2bc41c2b90342aaab01c096d626e6b67f1ca2f 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -149,7 +149,7 @@ def should_not_email(user_id)
 
       before do
         build_team(note.project)
-        note.stub(:commit_author => @u_committer)
+        allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer)
       end
 
       describe :new_note do