diff --git a/.rubocop.yml b/.rubocop.yml
index 71273ce6098f7e2f2aa88b470b91b4edd32882be..2fda0b03119adccf18fe46b3186db1d978e930af 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -691,7 +691,7 @@ Style/ZeroLengthPredicate:
 # branches, and conditions.
 Metrics/AbcSize:
   Enabled: true
-  Max: 70
+  Max: 60
 
 # Avoid excessive block nesting.
 Metrics/BlockNesting:
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 7486fdbc50b3f93d9d04db440483984df5d1dcce..39e898a4f952d339c155a7939d571a5fdd6c8cfc 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-0.7.2
+0.7.1
diff --git a/app/assets/javascripts/compare.js.coffee b/app/assets/javascripts/compare.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..f20992ead3ec6851819c5564499bcb08f87a95bf
--- /dev/null
+++ b/app/assets/javascripts/compare.js.coffee
@@ -0,0 +1,67 @@
+class @Compare
+  constructor: (@opts) ->
+    @source_loading = $ ".js-source-loading"
+    @target_loading = $ ".js-target-loading"
+
+    $('.js-compare-dropdown').each (i, dropdown) =>
+      $dropdown = $(dropdown)
+
+      $dropdown.glDropdown(
+        selectable: true
+        fieldName: $dropdown.data 'field-name'
+        filterable: true
+        id: (obj, $el) ->
+          $el.data 'id'
+        toggleLabel: (obj, $el) ->
+          $el.text().trim()
+        clicked: (e, el) =>
+          if $dropdown.is '.js-target-branch'
+            @getTargetHtml()
+          else if $dropdown.is '.js-source-branch'
+            @getSourceHtml()
+          else if $dropdown.is '.js-target-project'
+            @getTargetProject()
+      )
+
+    @initialState()
+
+  initialState: ->
+    @getSourceHtml()
+    @getTargetHtml()
+
+  getTargetProject: ->
+    $.ajax(
+      url: @opts.targetProjectUrl
+      data:
+        target_project_id:  $("input[name='merge_request[target_project_id]']").val()
+      beforeSend: ->
+        $('.mr_target_commit').empty()
+      success: (html) ->
+        $('.js-target-branch-dropdown .dropdown-content').html html
+    )
+
+  getSourceHtml: ->
+    @sendAjax(@opts.sourceBranchUrl, @source_loading, '.mr_source_commit',
+      ref: $("input[name='merge_request[source_branch]']").val()
+    )
+
+  getTargetHtml: ->
+    @sendAjax(@opts.targetBranchUrl, @target_loading, '.mr_target_commit',
+      target_project_id: $("input[name='merge_request[target_project_id]']").val()
+      ref: $("input[name='merge_request[target_branch]']").val()
+    )
+
+  sendAjax: (url, loading, target, data) ->
+    $target = $(target)
+
+    $.ajax(
+      url: url
+      data: data
+      beforeSend: ->
+        loading.show()
+        $target.empty()
+      success: (html) ->
+        loading.hide()
+        $target.html html
+        $('.js-timeago', $target).timeago()
+    )
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index e8d25591f63a70191d9de9ee122f977e6a38e5db..ee1d0fad28910531be2e57b1f5e27b528bb842af 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -57,14 +57,30 @@ class GitLabDropdownFilter
 
   filter: (search_text) ->
     data = @options.data()
-    results = data
 
-    if search_text isnt ""
-      results = fuzzaldrinPlus.filter(data, search_text,
-        key: @options.keys
-      )
+    if data?
+      results = data
 
-    @options.callback results
+      if search_text isnt ''
+        results = fuzzaldrinPlus.filter(data, search_text,
+          key: @options.keys
+        )
+
+      @options.callback results
+    else
+      elements = @options.elements()
+
+      if search_text
+        elements.each ->
+          $el = $(@)
+          matches = fuzzaldrinPlus.match($el.text().trim(), search_text)
+
+          if matches.length
+            $el.show()
+          else
+            $el.hide()
+      else
+        elements.show()
 
 class GitLabDropdownRemote
   constructor: (@dataEndpoint, @options) ->
@@ -123,7 +139,7 @@ class GitLabDropdown
     if _.isString(@filterInput)
       @filterInput = @getElement(@filterInput)
 
-    search_fields = if @options.search then @options.search.fields else [];
+    searchFields = if @options.search then @options.search.fields else [];
 
     if @options.data
       # If data is an array
@@ -147,7 +163,14 @@ class GitLabDropdown
         filterInputBlur: @filterInputBlur
         remote: @options.filterRemote
         query: @options.data
-        keys: @options.search.fields
+        keys: searchFields
+        elements: =>
+          selector = '.dropdown-content li:not(.divider)'
+
+          if @dropdown.find('.dropdown-toggle-page').length
+            selector = ".dropdown-page-one #{selector}"
+
+          return $(selector)
         data: =>
           return @fullData
         callback: (data) =>
@@ -376,7 +399,7 @@ class GitLabDropdown
 
       # Toggle the dropdown label
       if @options.toggleLabel
-        $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject)
+        $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject, el)
       if value?
         if !field.length and fieldName
           # Create hidden input for form
diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee
index f73127f49f0fa0119cc65e97b8252ec64a6bfd1c..6bd4e885a036cf5bdbb1a19a86e813baa187f2cb 100644
--- a/app/assets/javascripts/milestone_select.js.coffee
+++ b/app/assets/javascripts/milestone_select.js.coffee
@@ -85,15 +85,21 @@ class @MilestoneSelect
           # display:block overrides the hide-collapse rule
           $value.removeAttr('style')
         clicked: (selected) ->
+          page = $('body').data 'page'
+          isIssueIndex = page is 'projects:issues:index'
+          isMRIndex = page is page is 'projects:merge_requests:index'
+
           if $dropdown.hasClass 'js-filter-bulk-update'
             return
 
-          if $dropdown.hasClass('js-filter-submit')
+          if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
             if selected.name?
               selectedMilestone = selected.name
             else
               selectedMilestone = ''
             Issues.filterResults $dropdown.closest('form')
+          else if $dropdown.hasClass('js-filter-submit')
+            $dropdown.closest('form').submit()
           else
             selected = $selectbox
               .find('input[type="hidden"]')
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 82dc1acbd017c96ff2144d681a79605ab5705cdb..ba6c7930cdcd9e47d4be70977f2ad82f2985073b 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -248,7 +248,7 @@
 
 .dropdown-title {
   position: relative;
-  padding: 0 0 15px;
+  padding: 0 25px 15px;
   margin: 0 10px 10px;
   font-weight: 600;
   line-height: 1;
@@ -275,7 +275,7 @@
 }
 
 .dropdown-menu-close {
-  right: 7px;
+  right: 5px;
   width: 20px;
   height: 20px;
   top: -1px;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 8272615768d90a3d3d09af7a9c84a8cc807829f6..6453c91d955069866bea7c0873c9f3fbc26e8306 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -47,6 +47,7 @@ li.commit {
 
     .commit_short_id {
       min-width: 65px;
+      color: $gl-dark-link-color;
       font-family: $monospace_font;
     }
 
@@ -88,6 +89,10 @@ li.commit {
       padding: 0;
       margin: 0;
     }
+
+    a {
+      color: $gl-dark-link-color;
+    }
   }
 
   .commit-row-info {
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index bd224705f04aa29366c410542713eccabdfdc39b..604f1700cf840543786e51c956b68d272be2966e 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -59,6 +59,9 @@
   position: relative;
   overflow-y: auto;
   padding: 15px;
+  .form-actions {
+    margin: -$gl-padding+1;
+  }
 }
 
 body.modal-open {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 1c6a420897433d7f5d5f1e6b421ee1339365cff4..b79335eab9155bb336eca8d3e2b2c7fa64b27fac 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -123,6 +123,8 @@
 
 .mr_source_commit,
 .mr_target_commit {
+  margin-bottom: 0;
+
   .commit {
     margin: 0;
     padding: 2px 0;
@@ -174,10 +176,6 @@
   display: none;
 }
 
-.merge-request-form .select2-container {
-  width: 250px !important;
-}
-
 #modal_merge_info .modal-dialog {
   width: 600px;
 
@@ -200,3 +198,76 @@
     overflow-x: scroll;
   }
 }
+
+.panel-new-merge-request {
+  .panel-heading {
+    padding: 5px 10px;
+    font-weight: 600;
+    line-height: 25px;
+  }
+
+  .panel-body {
+    padding: 10px 5px;
+  }
+
+  .panel-footer {
+    padding: 5px 10px;
+  }
+
+  .commit {
+    .commit-row-title {
+      margin-bottom: 4px;
+    }
+
+    .avatar {
+      width: 20px;
+      height: 20px;
+      margin-right: 5px;
+    }
+
+    .commit-row-info {
+      line-height: 20px;
+    }
+  }
+
+  .btn-clipboard {
+    margin-right: 5px;
+    padding: 0;
+    background: transparent;
+  }
+
+  .ci-status-link {
+    margin-right: 5px;
+  }
+}
+
+.merge-request-select {
+  padding-left: 5px;
+  padding-right: 5px;
+  margin-bottom: 10px;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+
+  @media (min-width: $screen-sm-min) {
+    float: left;
+    width: 50%;
+    margin-bottom: 0;
+  }
+
+  .dropdown-menu-toggle {
+    width: 100%;
+  }
+
+  .dropdown-menu {
+    left: 5px;
+    right: 5px;
+    width: auto;
+  }
+}
+
+.issuable-form-select-holder {
+  display: inline-block;
+  width: 250px;
+}
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index ed5a1901056decd020146d3fbb0b5abb5cc5f6cb..da3a32a9f8e5cb49a4fe45bcd43a181050c125b1 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -208,20 +208,20 @@ class Projects::MergeRequestsController < Projects::ApplicationController
     #This is always source
     @source_project = @merge_request.nil? ? @project : @merge_request.source_project
     @commit = @repository.commit(params[:ref]) if params[:ref].present?
+    render layout: false
   end
 
   def branch_to
     @target_project = selected_target_project
     @commit = @target_project.commit(params[:ref]) if params[:ref].present?
+    render layout: false
   end
 
   def update_branches
     @target_project = selected_target_project
     @target_branches = @target_project.repository.branch_names
 
-    respond_to do |format|
-      format.js
-    end
+    render layout: false
   end
 
   def ci_status
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index de508036888ca9d8e31dac372401aa59d26c3ef5..35ba543cef12f42d10d781e1eb91c27017d9f60c 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -28,7 +28,7 @@ module CommitsHelper
 
   def commit_to_html(commit, project, inline = true)
     template = inline ? "inline_commit" : "commit"
-    escape_javascript(render "projects/commits/#{template}", commit: commit, project: project) unless commit.nil?
+    render "projects/commits/#{template}", commit: commit, project: project unless commit.nil?
   end
 
   # Breadcrumb links for a Project and, if applicable, a tree path
@@ -117,7 +117,7 @@ module CommitsHelper
       end
     end
     link_to(
-      "Browse Files »",
+      "Browse Files",
       namespace_project_tree_path(project.namespace, project, commit),
       class: "pull-right"
     )
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6a43be2cf3ef14049e07f6b38ed9a4ab05e0fe13
--- /dev/null
+++ b/app/helpers/form_helper.rb
@@ -0,0 +1,18 @@
+module FormHelper
+  def form_errors(model)
+    return unless model.errors.any?
+
+    pluralized = 'error'.pluralize(model.errors.count)
+    headline   = "The form contains the following #{pluralized}:"
+
+    content_tag(:div, class: 'alert alert-danger', id: 'error_explanation') do
+      content_tag(:h4, headline) <<
+      content_tag(:ul) do
+        model.errors.full_messages.
+          map { |msg| content_tag(:li, msg) }.
+          join.
+          html_safe
+      end
+    end
+  end
+end
diff --git a/app/views/abuse_reports/new.html.haml b/app/views/abuse_reports/new.html.haml
index 3bc1b24b5e2067bebdeb20392d91a0e46c255ba9..06be1a53318a068f98e17ec6f39f48af82c109f1 100644
--- a/app/views/abuse_reports/new.html.haml
+++ b/app/views/abuse_reports/new.html.haml
@@ -3,11 +3,9 @@
 %p Please use this form to report users who create spam issues, comments or behave inappropriately.
 %hr
 = form_for @abuse_report, html: { class: 'form-horizontal js-quick-submit js-requires-input'} do |f|
+  = form_errors(@abuse_report)
+
   = f.hidden_field :user_id
-  - if @abuse_report.errors.any?
-    .alert.alert-danger
-      - @abuse_report.errors.full_messages.each do |msg|
-        %p= msg
   .form-group
     = f.label :user_id, class: 'control-label'
     .col-sm-10
diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml
index 6f325914d14f048a0574546cc41a95d5b0f0bf97..d88f3ad314d01c51bca8e6ac56a20b4296e5cff9 100644
--- a/app/views/admin/appearances/_form.html.haml
+++ b/app/views/admin/appearances/_form.html.haml
@@ -1,8 +1,5 @@
 = form_for @appearance, url: admin_appearances_path, html: { class: 'form-horizontal'} do |f|
-  - if @appearance.errors.any?
-    .alert.alert-danger
-      - @appearance.errors.full_messages.each do |msg|
-        %p= msg
+  = form_errors(@appearance)
 
   %fieldset.sign-in
     %legend
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index de86dacbb1242e3f9188750da30cf628f8baafca..a8cca1a81cb3537728aa505f8320cc2a5878e738 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -1,9 +1,5 @@
 = form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
-  - if @application_setting.errors.any?
-    #error_explanation
-      .alert.alert-danger
-        - @application_setting.errors.full_messages.each do |msg|
-          %p= msg
+  = form_errors(@application_setting)
 
   %fieldset
     %legend Visibility and Access Controls
diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml
index e18f7b499dd3fc9543fb25a5362b0164c44c2259..4aacbb8cd7791c01485068310af6aa145e8c8e28 100644
--- a/app/views/admin/applications/_form.html.haml
+++ b/app/views/admin/applications/_form.html.haml
@@ -1,9 +1,6 @@
 = form_for [:admin, @application], url: @url, html: {class: 'form-horizontal', role: 'form'} do |f|
-  - if application.errors.any?
-    .alert.alert-danger
-      %button{ type: "button", class: "close", "data-dismiss" => "alert"} &times;
-      - application.errors.full_messages.each do |msg|
-        %p= msg
+  = form_errors(application)
+
   = content_tag :div, class: 'form-group' do
     = f.label :name, class: 'col-sm-2 control-label'
     .col-sm-10
diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml
index b748460a9f7a46f49978c163bec58b9e784fe371..6b157abf8422db584d0fdcc12dd79ccb6411c677 100644
--- a/app/views/admin/broadcast_messages/_form.html.haml
+++ b/app/views/admin/broadcast_messages/_form.html.haml
@@ -4,10 +4,8 @@
     = render_broadcast_message(@broadcast_message.message.presence || "Your message here")
 
 = form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-quick-submit js-requires-input'} do |f|
-  -if @broadcast_message.errors.any?
-    .alert.alert-danger
-      - @broadcast_message.errors.full_messages.each do |msg|
-        %p= msg
+  = form_errors(@broadcast_message)
+
   .form-group
     = f.label :message, class: 'control-label'
     .col-sm-10
diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml
index 5b46b3222a9cc5a5ffcdf21c72451a0f739f39be..15aa059c93d0b5f82a329537e92a02d7189fd452 100644
--- a/app/views/admin/deploy_keys/new.html.haml
+++ b/app/views/admin/deploy_keys/new.html.haml
@@ -4,11 +4,7 @@
 
 %div
   = form_for [:admin, @deploy_key], html: { class: 'deploy-key-form form-horizontal' } do |f|
-    -if @deploy_key.errors.any?
-      .alert.alert-danger
-        %ul
-          - @deploy_key.errors.full_messages.each do |msg|
-            %li= msg
+    = form_errors(@deploy_key)
 
     .form-group
       = f.label :title, class: "control-label"
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 7f2b1cd235d990ce976cbea59d6dbef2fe0932a3..0cc405401cf5450f712941b31eed7a21af9420a3 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -1,8 +1,5 @@
 = form_for [:admin, @group], html: { class: "form-horizontal" } do |f|
-  - if @group.errors.any?
-    .alert.alert-danger
-      %span= @group.errors.full_messages.first
-
+  = form_errors(@group)
   = render 'shared/group_form', f: f
 
   .form-group.group-description-holder
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index 53b3cd04c682964175ec96071a94b82a4d998f2a..ad952052f253efc3ef1ab423502621d7cb677e37 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -10,10 +10,8 @@
 
 
 = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-horizontal' } do |f|
-  -if @hook.errors.any?
-    .alert.alert-danger
-      - @hook.errors.full_messages.each do |msg|
-        %p= msg
+  = form_errors(@hook)
+
   .form-group
     = f.label :url, "URL:", class: 'control-label'
     .col-sm-10
diff --git a/app/views/admin/identities/_form.html.haml b/app/views/admin/identities/_form.html.haml
index 3a7885582262b02dd5bb9414952dbb0c1af2aae1..112a201fafa7bc975b5335e244b00a01e887e206 100644
--- a/app/views/admin/identities/_form.html.haml
+++ b/app/views/admin/identities/_form.html.haml
@@ -1,9 +1,5 @@
 = form_for [:admin, @user, @identity], html: { class: 'form-horizontal fieldset-form' } do |f|
-  - if @identity.errors.any?
-    #error_explanation
-      .alert.alert-danger
-        - @identity.errors.full_messages.each do |msg|
-          %p= msg
+  = form_errors(@identity)
 
   .form-group
     = f.label :provider, class: 'control-label'
diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml
index 8c6b389bf157ac2c103861ae794ffe631bd71f55..448aa95354818b0ac87f39ac546984585a2ff99e 100644
--- a/app/views/admin/labels/_form.html.haml
+++ b/app/views/admin/labels/_form.html.haml
@@ -1,11 +1,5 @@
 = form_for [:admin, @label], html: { class: 'form-horizontal label-form js-requires-input' } do |f|
-  -if @label.errors.any?
-    .row
-      .col-sm-offset-2.col-sm-10
-        .alert.alert-danger
-          - @label.errors.full_messages.each do |msg|
-            %span= msg
-            %br
+  = form_errors(@label)
 
   .form-group
     = f.label :title, class: 'control-label'
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index d2527ede99559ea4980af70ea43239fb9f460889..b05fdbd5552c50d1ad8705b12c740eb56c332c79 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -1,10 +1,6 @@
 .user_new
   = form_for [:admin, @user], html: { class: 'form-horizontal fieldset-form' } do |f|
-    -if @user.errors.any?
-      #error_explanation
-        .alert.alert-danger
-          - @user.errors.full_messages.each do |msg|
-            %p= msg
+    = form_errors(@user)
 
     %fieldset
       %legend Account
diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml
index 906b0676150cfa50173099b6dd7058b74f306728..5c98265727a13e899f315e14d7705efd33e86b7e 100644
--- a/app/views/doorkeeper/applications/_form.html.haml
+++ b/app/views/doorkeeper/applications/_form.html.haml
@@ -1,9 +1,5 @@
 = form_for application, url: doorkeeper_submit_path(application), html: {role: 'form'} do |f|
-  - if application.errors.any?
-    .alert.alert-danger
-      %ul
-        - application.errors.full_messages.each do |msg|
-          %li= msg
+  = form_errors(application)
 
   .form-group
     = f.label :name, class: 'label-light'
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index ea5a0358392911d17750a6b19987c0e4222a4dfb..a698cbbe9dbd4a5b67ca118cf2fa16b8e1ec8867 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -5,9 +5,7 @@
     Group settings
   .panel-body
     = form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f|
-      - if @group.errors.any?
-        .alert.alert-danger
-          %span= @group.errors.full_messages.first
+      = form_errors(@group)
       = render 'shared/group_form', f: f
 
       .form-group
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index 30ab8aeba13e9d1706bf189bdf98190ae0e7395d..2b8bc269e645c117c15955469075b156f3406c77 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -6,10 +6,7 @@
 %hr
 
 = form_for @group, html: { class: 'group-form form-horizontal' } do |f|
-  - if @group.errors.any?
-    .alert.alert-danger
-      %span= @group.errors.full_messages.first
-
+  = form_errors(@group)
   = render 'shared/group_form', f: f, autofocus: true
 
   .form-group.group-description-holder
diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml
index 4d78215ed3c3bbd19b91da0ecea081437c4e0f1d..b3ed59a1a4aa0a0cc923258a5b7a8e100eff5879 100644
--- a/app/views/profiles/keys/_form.html.haml
+++ b/app/views/profiles/keys/_form.html.haml
@@ -1,10 +1,6 @@
 %div
   = form_for [:profile, @key], html: { class: 'js-requires-input' } do |f|
-    - if @key.errors.any?
-      .alert.alert-danger
-        %ul
-          - @key.errors.full_messages.each do |msg|
-            %li= msg
+    = form_errors(@key)
 
     .form-group
       = f.label :key, class: 'label-light'
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 3d15c0d932bc22cda43e17d3fdac39a8bb03ede4..6609295a2a5517fcd4317cfe3b0e7554ccaa63f4 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -2,11 +2,7 @@
 - header_title page_title, profile_notifications_path
 
 = form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f|
-  -if @user.errors.any?
-    %div.alert.alert-danger
-      %ul
-        - @user.errors.full_messages.each do |msg|
-          %li= msg
+  = form_errors(@user)
 
   = hidden_field_tag :notification_type, 'global'
   .row
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index 44d758dceb3190e5382b19383abd3d6a97e82eb5..5ac8a8b9d093e9f3340d621384911e4274ca4a38 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -13,11 +13,8 @@
       - unless @user.password_automatically_set?
         or recover your current one
     = form_for @user, url: profile_password_path, method: :put, html: {class: "update-password"} do |f|
-      -if @user.errors.any?
-        .alert.alert-danger
-          %ul
-            - @user.errors.full_messages.each do |msg|
-              %li= msg
+      = form_errors(@user)
+
       - unless @user.password_automatically_set?
         .form-group
           = f.label :current_password, class: 'label-light'
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index d165f758c81f5bc16a09cd81f4d6a05765a80ab4..2eb9fac57c31ae2934f35d3caf178ea3cb078d72 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -7,11 +7,8 @@
     Please set a new password before proceeding.
     %br
     After a successful password update you will be redirected to login screen.
-  -if @user.errors.any?
-    .alert.alert-danger
-      %ul
-        - @user.errors.full_messages.each do |msg|
-          %li= msg
+
+  = form_errors(@user)
 
   - unless @user.password_automatically_set?
     .form-group
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index dcb3be9585db98cc3cc4d2e055636140843aa6a8..f59d27f7ed013307a7a1c0ff4f786529e4255cc9 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -1,9 +1,6 @@
 = form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit-user prepend-top-default" }, authenticity_token: true do |f|
-  -if @user.errors.any?
-    %div.alert.alert-danger
-      %ul
-        - @user.errors.full_messages.each do |msg|
-          %li= msg
+  = form_errors(@user)
+
   .row
     .col-lg-3.profile-settings-sidebar
       %h4.prepend-top-0
diff --git a/app/views/projects/_errors.html.haml b/app/views/projects/_errors.html.haml
index 7c8bb33ed7edc4f3d868742ec68f1a16005d3aab..2dba22d3be665f0b975f054135b3417aca300ede 100644
--- a/app/views/projects/_errors.html.haml
+++ b/app/views/projects/_errors.html.haml
@@ -1,4 +1 @@
-- if @project.errors.any?
-  .alert.alert-danger
-    %button{ type: "button", class: "close", "data-dismiss" => "alert"} &times;
-    = @project.errors.full_messages.first
+= form_errors(@project)
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index fa34f7b7d6112b8f43da0c05b4fdf03c28456483..f7c8647ac0e4994089551e7fe87c9d2e969e3bea 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -18,24 +18,17 @@
       .pull-right
         - if commit.status
           = render_ci_status(commit)
-          &nbsp;
         = clipboard_button(clipboard_text: commit.id)
         = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
 
-      .notes_count
-        - if note_count > 0
-          %span.light
-            %i.fa.fa-comments
-            = note_count
-
     - if commit.description?
       .commit-row-description.js-toggle-content
         %pre
           = preserve(markdown(escape_once(commit.description), pipeline: :single_line))
 
     .commit-row-info
+      by
       = commit_author_link(commit, avatar: true, size: 24)
-      authored
       .committed_ago
         #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} &nbsp;
       = link_to_browse_code(project, commit)
diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml
index 5e182af26693f87f24cbefc167a8e3d464b7ba03..f6565f858366b793ace7f3bf50fa14685d9cc7cf 100644
--- a/app/views/projects/deploy_keys/_form.html.haml
+++ b/app/views/projects/deploy_keys/_form.html.haml
@@ -1,10 +1,6 @@
 %div
   = form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: 'deploy-key-form form-horizontal js-requires-input' } do |f|
-    -if @key.errors.any?
-      .alert.alert-danger
-        %ul
-          - @key.errors.full_messages.each do |msg|
-            %li= msg
+    = form_errors(@key)
 
     .form-group
       = f.label :title, class: "control-label"
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 67d016bd871015f2c414e03eea5ea413c19a92f6..e39224d86c6a1c88f60c31961ca6492bd40fb7db 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -9,10 +9,8 @@
 %hr.clearfix
 
 = form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
-  -if @hook.errors.any?
-    .alert.alert-danger
-      - @hook.errors.full_messages.each do |msg|
-        %p= msg
+  = form_errors(@hook)
+
   .form-group
     = f.label :url, "URL", class: 'control-label'
     .col-sm-10
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index be7a0bb5628060f090fe097c4f3a3561e4e94176..aa143e54ffe4a8902be01b18c4579c42f2e059a2 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -1,11 +1,5 @@
 = form_for [@project.namespace.becomes(Namespace), @project, @label], html: { class: 'form-horizontal label-form js-quick-submit js-requires-input' } do |f|
-  -if @label.errors.any?
-    .row
-      .col-sm-offset-2.col-sm-10
-        .alert.alert-danger
-          - @label.errors.full_messages.each do |msg|
-            %span= msg
-            %br
+  = form_errors(@label)
 
   .form-group
     = f.label :title, class: 'control-label'
diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml
index 01dc7519beea37651610217fbf4d194d02329373..7d7c487e9709daebd056021597f754486e212485 100644
--- a/app/views/projects/merge_requests/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/_new_compare.html.haml
@@ -5,33 +5,74 @@
   .hide.alert.alert-danger.mr-compare-errors
   .merge-request-branches.row
     .col-md-6
-      .panel.panel-default
+      .panel.panel-default.panel-new-merge-request
         .panel-heading
-          %strong Source branch
-        .panel-body
-          = f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted?, required: true })
-          &nbsp;
-          = f.select(:source_branch, @merge_request.source_branches, { include_blank: true }, { class: 'source_branch select2 span2', required: true, data: { placeholder: "Select source branch" } })
+          Source branch
+        .panel-body.clearfix
+          .merge-request-select.dropdown
+            = f.hidden_field :source_project_id
+            = dropdown_toggle @merge_request.source_project_path, { toggle: "dropdown", field_name: "#{f.object_name}[source_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-source-project" }
+            .dropdown-menu.dropdown-menu-selectable.dropdown-source-project
+              = dropdown_title("Select source project")
+              = dropdown_filter("Search projects")
+              = dropdown_content do
+                - is_active = f.object.source_project_id == @merge_request.source_project.id
+                %ul
+                  %li
+                    %a{ href: "#", class: "#{("is-active" if is_active)}", data: { id: @merge_request.source_project.id } }
+                      = @merge_request.source_project_path
+          .merge-request-select.dropdown
+            = f.hidden_field :source_branch
+            = dropdown_toggle "Select source branch", { toggle: "dropdown", field_name: "#{f.object_name}[source_branch]" }, { toggle_class: "js-compare-dropdown js-source-branch" }
+            .dropdown-menu.dropdown-menu-selectable.dropdown-source-branch
+              = dropdown_title("Select source branch")
+              = dropdown_filter("Search branches")
+              = dropdown_content do
+                %ul
+                  - @merge_request.source_branches.each do |branch|
+                    %li
+                      %a{ href: "#", class: "#{("is-active" if f.object.source_branch == branch)}", data: { id: branch } }
+                        = branch
         .panel-footer
-          .mr_source_commit
+          = icon('spinner spin', class: 'js-source-loading')
+          %ul.list-unstyled.mr_source_commit
 
     .col-md-6
-      .panel.panel-default
+      .panel.panel-default.panel-new-merge-request
         .panel-heading
-          %strong Target branch
-        .panel-body
+          Target branch
+        .panel-body.clearfix
           - projects =  @project.forked_from_project.nil? ? [@project] : [@project, @project.forked_from_project]
-          = f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace', f.object.target_project_id), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted?, required: true })
-          &nbsp;
-          = f.select(:target_branch, @merge_request.target_branches, { include_blank: true }, { class: 'target_branch select2 span2', required: true, data: { placeholder: "Select target branch" } })
+          .merge-request-select.dropdown
+            = f.hidden_field :target_project_id
+            = dropdown_toggle f.object.target_project.path_with_namespace, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
+            .dropdown-menu.dropdown-menu-selectable.dropdown-target-project
+              = dropdown_title("Select target project")
+              = dropdown_filter("Search projects")
+              = dropdown_content do
+                %ul
+                  - projects.each do |project|
+                    %li
+                      %a{ href: "#", class: "#{("is-active" if f.object.target_project_id == project.id)}", data: { id: project.id } }
+                        = project.path_with_namespace
+          .merge-request-select.dropdown
+            = f.hidden_field :target_branch
+            = dropdown_toggle f.object.target_branch, { toggle: "dropdown", field_name: "#{f.object_name}[target_branch]" }, { toggle_class: "js-compare-dropdown js-target-branch" }
+            .dropdown-menu.dropdown-menu-selectable.dropdown-target-branch.js-target-branch-dropdown
+              = dropdown_title("Select target branch")
+              = dropdown_filter("Search branches")
+              = dropdown_content do
+                %ul
+                  - @merge_request.target_branches.each do |branch|
+                    %li
+                      %a{ href: "#", class: "#{("is-active" if f.object.target_branch == branch)}", data: { id: branch } }
+                        = branch
         .panel-footer
-          .mr_target_commit
+          = icon('spinner spin', class: "js-target-loading")
+          %ul.list-unstyled.mr_target_commit
 
   - if @merge_request.errors.any?
-    .alert.alert-danger
-      - @merge_request.errors.full_messages.each do |msg|
-        %div= msg
-
+    = form_errors(@merge_request)
   - elsif @merge_request.source_branch.present? && @merge_request.target_branch.present?
     .light-well.append-bottom-default
       .center
@@ -45,40 +86,11 @@
             and
             %span.label-branch #{@merge_request.target_branch}
             are the same.
-
-
-  .form-actions
-    = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn"
-
-:javascript
-  var source_branch = $("#merge_request_source_branch")
-    , target_branch = $("#merge_request_target_branch")
-    , target_project = $("#merge_request_target_project_id");
-
-  $.get("#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {ref: source_branch.val() });
-  $.get("#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: target_project.val(),ref: target_branch.val() });
-
-  target_project.on("change", function() {
-    $.get("#{update_branches_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id:  $(this).val() });
-  });
-  source_branch.on("change", function() {
-    $.get("#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {ref: $(this).val() });
-    $(".mr-compare-errors").fadeOut();
-    $(".mr-compare-btn").enable();
-  });
-  target_branch.on("change", function() {
-    $.get("#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
-    $(".mr-compare-errors").fadeOut();
-    $(".mr-compare-btn").enable();
-  });
-
+  = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn"
 
 :javascript
-  $(".merge-request-form").on('submit', function () {
-    if ($("#merge_request_source_branch").val() === "" || $('#merge_request_target_branch').val() === "") {
-      $(".mr-compare-errors").html("You must select source and target branch to proceed");
-      $(".mr-compare-errors").fadeIn();
-      event.preventDefault();
-      return;
-    }
+  new Compare({
+    targetProjectUrl: "#{update_branches_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}",
+    sourceBranchUrl: "#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}",
+    targetBranchUrl: "#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}"
   });
diff --git a/app/views/projects/merge_requests/branch_from.html.haml b/app/views/projects/merge_requests/branch_from.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..4f90dde6fa801e2f065ac6959f7705e6b4818a2a
--- /dev/null
+++ b/app/views/projects/merge_requests/branch_from.html.haml
@@ -0,0 +1 @@
+= commit_to_html(@commit, @source_project, false)
diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml
deleted file mode 100644
index 9210798f39c051f4fff1f98910bf68f3147e817d..0000000000000000000000000000000000000000
--- a/app/views/projects/merge_requests/branch_from.js.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-:plain
-  $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
-  $('.js-timeago').timeago()
diff --git a/app/views/projects/merge_requests/branch_to.html.haml b/app/views/projects/merge_requests/branch_to.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..67a7a6bcec9d993f28f9f2c578797cd95100aaeb
--- /dev/null
+++ b/app/views/projects/merge_requests/branch_to.html.haml
@@ -0,0 +1 @@
+= commit_to_html(@commit, @target_project, false)
diff --git a/app/views/projects/merge_requests/branch_to.js.haml b/app/views/projects/merge_requests/branch_to.js.haml
deleted file mode 100644
index 32fe2d535f319ff7bac1077fcf7fbd22c85bace4..0000000000000000000000000000000000000000
--- a/app/views/projects/merge_requests/branch_to.js.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-:plain
-  $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}");
-  $('.js-timeago').timeago()
diff --git a/app/views/projects/merge_requests/update_branches.html.haml b/app/views/projects/merge_requests/update_branches.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..1b93188a10c70a2683224bac1e0e4dcd8d14cec6
--- /dev/null
+++ b/app/views/projects/merge_requests/update_branches.html.haml
@@ -0,0 +1,5 @@
+%ul
+  - @target_branches.each do |branch|
+    %li
+      %a{ href: "#", class: "#{("is-active" if "a" == branch)}", data: { id: branch } }
+        = branch
diff --git a/app/views/projects/merge_requests/update_branches.js.haml b/app/views/projects/merge_requests/update_branches.js.haml
deleted file mode 100644
index ca21b3bc0deb365c4db2f3ecc72576c80cd5e4e4..0000000000000000000000000000000000000000
--- a/app/views/projects/merge_requests/update_branches.js.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-:plain
-  $(".target_branch").html("#{escape_javascript(options_for_select(@target_branches))}");
-
-  $('select.target_branch').select2({
-    width: 'resolve',
-    dropdownAutoWidth: true
-  });
-
-  $(".mr_target_commit").html("");
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index 23f2bca7baf470f0f34926bd117342e10036983b..b2dae1c70ee0acb614d9dca54b3808a7df5a8f17 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -1,9 +1,6 @@
 = form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'form-horizontal milestone-form gfm-form js-quick-submit js-requires-input'}  do |f|
-  -if @milestone.errors.any?
-    .alert.alert-danger
-      %ul
-        - @milestone.errors.full_messages.each do |msg|
-          %li= msg
+  = form_errors(@milestone)
+
   .row
     .col-md-6
       .form-group
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index cfd7e1534ca81c1d24778fa72787f9a3b7353e99..653b02da4dbbb10d1bf10c952dd3ac479326f555 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -13,11 +13,7 @@
 
 - if can? current_user, :admin_project, @project
   = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'form-horizontal' } do |f|
-    -if @protected_branch.errors.any?
-      .alert.alert-danger
-        %ul
-          - @protected_branch.errors.full_messages.each do |msg|
-            %li= msg
+    = form_errors(@protected_branch)
 
     .form-group
       = f.label :name, "Branch", class: 'control-label'
diff --git a/app/views/projects/variables/show.html.haml b/app/views/projects/variables/show.html.haml
index efe1e6f24c22e144d7b32de64321dfbd9d1fe1c3..ca284b84d39150deb4f6933655129154649bb73b 100644
--- a/app/views/projects/variables/show.html.haml
+++ b/app/views/projects/variables/show.html.haml
@@ -13,13 +13,7 @@
 
 
 = nested_form_for @project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' }  do |f|
-  - if @project.errors.any?
-    #error_explanation
-      %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:"
-      .alert.alert-error
-        %ul
-          - @project.errors.full_messages.each do |msg|
-            %li= msg
+  = form_errors(@project)
 
   = f.fields_for :variables do |variable_form|
     .form-group
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index f0d1932e23cfb1514ce9aeff32905a5f9998a81b..812876e283562f30afff796211508b2a78871362 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -1,9 +1,5 @@
 = form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form gfm-form prepend-top-default js-quick-submit' } do |f|
-  -if @page.errors.any?
-    #error_explanation
-      .alert.alert-danger
-        - @page.errors.full_messages.each do |msg|
-          %p= msg
+  = form_errors(@page)
 
   = f.hidden_field :title, value: @page.title
   .form-group
diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml
index 5a60ff5a5da8c9fa8e598436610d1fc21208fde9..fc935166bf67379cb59f8de94df0ed00776e753f 100644
--- a/app/views/shared/_service_settings.html.haml
+++ b/app/views/shared/_service_settings.html.haml
@@ -1,9 +1,4 @@
-- if @service.errors.any?
-  #error_explanation
-    .alert.alert-danger
-      %ul
-        - @service.errors.full_messages.each do |msg|
-          %li= msg
+= form_errors(@service)
 
 - if @service.help.present?
   .well
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index e2a9e5bfb9234574d197a76468a181f992be1a2a..757a3812deb94588a1aef40237486d8c5f2cef02 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -1,10 +1,5 @@
-- if issuable.errors.any?
-  .row
-    .col-sm-offset-2.col-sm-10
-      .alert.alert-danger
-        - issuable.errors.full_messages.each do |msg|
-          %span= msg
-          %br
+= form_errors(issuable)
+
 .form-group
   = f.label :title, class: 'control-label'
   .col-sm-10
@@ -53,10 +48,11 @@
     .issue-assignee
       = f.label :assignee_id, "Assignee", class: 'control-label'
       .col-sm-10
-        = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
-            placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
-            selected: issuable.assignee_id, project: @target_project || @project,
-            first_user: true, current_user: true, include_blank: true)
+        .issuable-form-select-holder
+          = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
+              placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
+              selected: issuable.assignee_id, project: @target_project || @project,
+              first_user: true, current_user: true, include_blank: true)
         &nbsp;
         = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
   .form-group
@@ -64,8 +60,9 @@
       = f.label :milestone_id, "Milestone", class: 'control-label'
       .col-sm-10
         - if milestone_options(issuable).present?
-          = f.select(:milestone_id, milestone_options(issuable),
-            { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
+          .issuable-form-select-holder
+            = f.select(:milestone_id, milestone_options(issuable),
+              { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
         - else
           .prepend-top-10
           %span.light No open milestones available.
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index 1041eccd1dfb0a08b160b2560535d0d348a20a85..47ec09f62c604262456d2267470f7f916f8861a8 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -1,10 +1,6 @@
 .snippet-form-holder
   = form_for @snippet, url: url, html: { class: "form-horizontal snippet-form js-requires-input" } do |f|
-    - if @snippet.errors.any?
-      .alert.alert-danger
-        %ul
-          - @snippet.errors.full_messages.each do |msg|
-            %li= msg
+    = form_errors(@snippet)
 
     .form-group
       = f.label :title, class: 'control-label'
diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb
index a9fc38fb04a1e242123fb93cbe17108d173e3ed9..1b445bbbd10200baee8b5b0485206bd480c8a8fd 100644
--- a/config/initializers/metrics.rb
+++ b/config/initializers/metrics.rb
@@ -75,6 +75,29 @@ if Gitlab::Metrics.enabled?
       config.instrument_methods(const)
       config.instrument_instance_methods(const)
     end
+
+    # Instruments all Banzai filters
+    Dir[Rails.root.join('lib', 'banzai', 'filter', '*.rb')].each do |file|
+      klass = File.basename(file, File.extname(file)).camelize
+      const = Banzai::Filter.const_get(klass)
+
+      config.instrument_methods(const)
+      config.instrument_instance_methods(const)
+    end
+
+    config.instrument_methods(Banzai::ReferenceExtractor)
+    config.instrument_instance_methods(Banzai::ReferenceExtractor)
+
+    config.instrument_methods(Banzai::Renderer)
+    config.instrument_methods(Banzai::Querying)
+
+    [Issuable, Mentionable, Participable].each do |klass|
+      config.instrument_instance_methods(klass)
+      config.instrument_instance_methods(klass::ClassMethods)
+    end
+
+    config.instrument_methods(Gitlab::ReferenceExtractor)
+    config.instrument_instance_methods(Gitlab::ReferenceExtractor)
   end
 
   GC::Profiler.enable
diff --git a/doc/development/README.md b/doc/development/README.md
index 2f4e7845ccc525798cfcbb311980ad5bc86d7f86..3f3ef068f960d543ebb6b65093a32685a67a8a1a 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -2,6 +2,8 @@
 
 - [Architecture](architecture.md) of GitLab
 - [CI setup](ci_setup.md) for testing GitLab
+- [Code review guidelines](code_review.md) for reviewing code and having code
+  reviewed.
 - [Gotchas](gotchas.md) to avoid
 - [How to dump production data to staging](db_dump.md)
 - [Instrumentation](instrumentation.md)
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
new file mode 100644
index 0000000000000000000000000000000000000000..40ae55ab905527733b6c962d3db4b8a9f2b3d269
--- /dev/null
+++ b/doc/development/code_review.md
@@ -0,0 +1,78 @@
+# Code Review Guidelines
+
+This guide contains advice and best practices for performing code review, and
+having your code reviewed.
+
+All merge requests for GitLab CE and EE, whether written by a GitLab team member
+or a volunteer contributor, must go through a code review process to ensure the
+code is effective, understandable, and maintainable.
+
+Any developer can, and is encouraged to, perform code review on merge requests
+of colleagues and contributors. However, the final decision to accept a merge
+request is up to one of our merge request "endbosses", denoted on the
+[team page](https://about.gitlab.com/team).
+
+## Everyone
+
+- Accept that many programming decisions are opinions. Discuss tradeoffs, which
+  you prefer, and reach a resolution quickly.
+- Ask questions; don't make demands. ("What do you think about naming this
+  `:user_id`?")
+- Ask for clarification. ("I didn't understand. Can you clarify?")
+- Avoid selective ownership of code. ("mine", "not mine", "yours")
+- Avoid using terms that could be seen as referring to personal traits. ("dumb",
+  "stupid"). Assume everyone is attractive, intelligent, and well-meaning.
+- Be explicit. Remember people don't always understand your intentions online.
+- Be humble. ("I'm not sure - let's look it up.")
+- Don't use hyperbole. ("always", "never", "endlessly", "nothing")
+- Be careful about the use of sarcasm. Everything we do is public; what seems
+  like good-natured ribbing to you and a long-time colleague might come off as
+  mean and unwelcoming to a person new to the project.
+- Consider one-on-one chats or video calls if there are too many "I didn't
+  understand" or "Alternative solution:" comments. Post a follow-up comment
+  summarizing one-on-one discussion.
+
+## Having your code reviewed
+
+- The first reviewer of your code is _you_. Before you perform that first push
+  of your shiny new branch, read through the entire diff. Does it make sense?
+  Did you include something unrelated to the overall purpose of the changes? Did
+  you forget to remove any debugging code?
+- Be grateful for the reviewer's suggestions. ("Good call. I'll make that
+  change.")
+- Don't take it personally. The review is of the code, not of you.
+- Explain why the code exists. ("It's like that because of these reasons. Would
+  it be more clear if I rename this class/file/method/variable?")
+- Extract unrelated changes and refactorings into future merge requests/issues.
+- Seek to understand the reviewer's perspective.
+- Try to respond to every comment.
+- Push commits based on earlier rounds of feedback as isolated commits to the
+  branch. Do not squash until the branch is ready to merge. Reviewers should be
+  able to read individual updates based on their earlier feedback.
+
+## Reviewing code
+
+Understand why the change is necessary (fixes a bug, improves the user
+experience, refactors the existing code). Then:
+
+- Communicate which ideas you feel strongly about and those you don't.
+- Identify ways to simplify the code while still solving the problem.
+- Offer alternative implementations, but assume the author already considered
+  them. ("What do you think about using a custom validator here?")
+- Seek to understand the author's perspective.
+- If you don't understand a piece of code, _say so_. There's a good chance
+  someone else would be confused by it as well.
+- After a round of line notes, it can be helpful to post a summary note such as
+  "LGTM :thumbsup:", or "Just a couple things to address."
+- Avoid accepting a merge request before the build succeeds ("Merge when build
+  succeeds" is fine).
+
+## Credits
+
+Largely based on the [thoughtbot code review guide].
+
+[thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review
+
+---
+
+[Return to Development documentation](README.md)
diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md
index c0192bd67094b587234be81d2c80fb3a82242db4..c1cf2e77c2689ec05187499af6a2750d56eae848 100644
--- a/doc/development/instrumentation.md
+++ b/doc/development/instrumentation.md
@@ -2,36 +2,35 @@
 
 GitLab Performance Monitoring allows instrumenting of custom blocks of Ruby
 code. This can be used to measure the time spent in a specific part of a larger
-chunk of code. The resulting data is written to a separate series.
+chunk of code. The resulting data is stored as a field in the transaction that
+executed the block.
 
-To start measuring a block of Ruby code you should use
-`Gitlab::Metrics.measure` and give it a name for the series to store the data
-in:
+To start measuring a block of Ruby code you should use `Gitlab::Metrics.measure`
+and give it a name:
 
 ```ruby
-Gitlab::Metrics.measure(:user_logins) do
+Gitlab::Metrics.measure(:foo) do
   ...
 end
 ```
 
-The first argument of this method is the series name and should be plural. This
-name will be prefixed with `rails_` or `sidekiq_` depending on whether the code
-was run in the Rails application or one of the Sidekiq workers. In the
-above example the final series names would be as follows:
+3 values are measured for a block:
 
-- rails_user_logins
-- sidekiq_user_logins
+1. The real time elapsed, stored in NAME_real_time.
+2. The CPU time elapsed, stored in NAME_cpu_time.
+3. The call count, stored in NAME_call_count.
 
-Series names should be plural as this keeps the naming style in line with the
-other series names.
+Both the real and CPU timings are measured in milliseconds.
 
-By default metrics measured using a block contain a single value, "duration",
-which contains the number of milliseconds it took to execute the block. Custom
-values can be added by passing a Hash as the 2nd argument. Custom tags can be
-added by passing a Hash as the 3rd argument. A simple example is as follows:
+Multiple calls to the same block will result in the final values being the sum
+of all individual values. Take this code for example:
 
 ```ruby
-Gitlab::Metrics.measure(:example_series, { number: 10 }, { class: self.class.to_s }) do
-  ...
+3.times do
+  Gitlab::Metrics.measure(:sleep) do
+    sleep 1
+  end
 end
 ```
+
+Here the final value of `sleep_real_time` will be `3`, _not_ `1`.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index d97dc7d13115f4894baeb848b6ee14e4909d1db0..f8f7d6a9ebedfb54fcc0669164eb63310d403a7a 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -352,7 +352,7 @@ GitLab Shell is an SSH access and repository management software developed speci
     cd /home/git
     sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
     cd gitlab-workhorse
-    sudo -u git -H git checkout v0.7.2
+    sudo -u git -H git checkout v0.7.1
     sudo -u git -H make
 
 ### Initialize Database and Activate Advanced Features
diff --git a/doc/update/8.6-to-8.7.md b/doc/update/8.6-to-8.7.md
index 57847d2d9fd45af6a851feceb54e594f213374b1..8599133a726c292de860f8cf8353b9718cc646d9 100644
--- a/doc/update/8.6-to-8.7.md
+++ b/doc/update/8.6-to-8.7.md
@@ -58,7 +58,7 @@ GitLab 8.1.
 ```bash
 cd /home/git/gitlab-workhorse
 sudo -u git -H git fetch --all
-sudo -u git -H git checkout v0.7.2
+sudo -u git -H git checkout v0.7.1
 sudo -u git -H make
 ```
 
diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature
index 10bd6fec80373d7682281760535ac5d66f8e8581..67f1e117f7fa9671dc71cd0e2588f958074d6c86 100644
--- a/features/project/forked_merge_requests.feature
+++ b/features/project/forked_merge_requests.feature
@@ -4,6 +4,7 @@ Feature: Project Forked Merge Requests
     And I am a member of project "Shop"
     And I have a project forked off of "Shop" called "Forked Shop"
 
+  @javascript
   Scenario: I submit new unassigned merge request to a forked project
     Given I visit project "Forked Shop" merge requests page
     And I click link "New Merge Request"
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 823658b4f240657b768e5d8f59a48ffed4bba3bf..ecda4ea824035665c6ba4b8718dd2119eb8c3b40 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -70,6 +70,7 @@ Feature: Project Merge Requests
     When I click link "Reopen"
     Then I should see reopened merge request "Bug NS-04"
 
+  @javascript
   Scenario: I submit new unassigned merge request
     Given I click link "New Merge Request"
     And I submit new merge request "Wiki Feature"
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index 7e4425ff6625a988449464b49b1cba4f35dc0506..612bb8fd8b1e5d4f554cbaaedbda44505cb1c50e 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -34,10 +34,14 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
   end
 
   step 'I fill out a "Merge Request On Forked Project" merge request' do
-    select @forked_project.path_with_namespace, from: "merge_request_source_project_id"
-    select @project.path_with_namespace, from: "merge_request_target_project_id"
-    select "fix", from: "merge_request_source_branch"
-    select "master", from: "merge_request_target_branch"
+    first('.js-source-project').click
+    first('.dropdown-source-project a', text: @forked_project.path_with_namespace)
+
+    first('.js-target-project').click
+    first('.dropdown-target-project a', text: @project.path_with_namespace)
+
+    first('.js-source-branch').click
+    first('.dropdown-source-branch .dropdown-content a', text: 'fix').click
 
     click_button "Compare branches and continue"
 
@@ -115,10 +119,10 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
   end
 
   step 'I fill out an invalid "Merge Request On Forked Project" merge request' do
-    expect(find(:select, "merge_request_source_project_id", {}).value).to eq @forked_project.id.to_s
-    expect(find(:select, "merge_request_target_project_id", {}).value).to eq @project.id.to_s
-    expect(find(:select, "merge_request_source_branch", {}).value).to eq ""
-    expect(find(:select, "merge_request_target_branch", {}).value).to eq "master"
+    expect(find_by_id("merge_request_source_project_id", visible: false).value).to eq @forked_project.id.to_s
+    expect(find_by_id("merge_request_target_project_id", visible: false).value).to eq @project.id.to_s
+    expect(find_by_id("merge_request_source_branch", visible: false).value).to eq nil
+    expect(find_by_id("merge_request_target_branch", visible: false).value).to eq "master"
     click_button "Compare branches"
   end
 
@@ -127,7 +131,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
   end
 
   step 'the target repository should be the original repository' do
-    expect(page).to have_select("merge_request_target_project_id", selected: @project.path_with_namespace)
+    expect(find_by_id("merge_request_target_project_id").value).to eq "#{@project.id}"
   end
 
   step 'I click "Assign to" dropdown"' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 9887bf80a894ef7fc0ac04bcbe69e75f0d620399..2a7f2cca005947cc50ce4e2e2c2abc1fa427604d 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -93,8 +93,12 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
   end
 
   step 'I submit new merge request "Wiki Feature"' do
-    select "fix", from: "merge_request_source_branch"
-    select "feature", from: "merge_request_target_branch"
+    find('.js-source-branch').click
+    find('.dropdown-source-branch .dropdown-content a', text: 'fix').click
+
+    find('.js-target-branch').click
+    first('.dropdown-target-branch .dropdown-content a', text: 'feature').click
+
     click_button "Compare branches"
     fill_in "merge_request_title", with: "Wiki Feature"
     click_button "Submit merge request"
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 243469b8e7d55f0eb237a70e0581604ed85e65aa..e072505e5d7bec13e6807fa9921575e5b6741c8e 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -213,13 +213,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
   end
 
   step 'I see Browse file link' do
-    expect(page).to have_link 'Browse File »'
-    expect(page).not_to have_link 'Browse Files »'
+    expect(page).to have_link 'Browse File'
+    expect(page).not_to have_link 'Browse Files'
   end
 
   step 'I see Browse code link' do
-    expect(page).to have_link 'Browse Files »'
-    expect(page).not_to have_link 'Browse File »'
+    expect(page).to have_link 'Browse Files'
     expect(page).not_to have_link 'Browse Directory »'
   end
 
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index ae714c87dc54bef7bb9032af713e897b699f7081..c14a9c4c72218fea9baef0482a0dbc88f20c784c 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -19,8 +19,10 @@ module Banzai
       cache_key = full_cache_key(cache_key, context[:pipeline])
 
       if cache_key
-        Rails.cache.fetch(cache_key) do
-          cacheless_render(text, context)
+        Gitlab::Metrics.measure(:banzai_cached_render) do
+          Rails.cache.fetch(cache_key) do
+            cacheless_render(text, context)
+          end
         end
       else
         cacheless_render(text, context)
@@ -64,13 +66,15 @@ module Banzai
     private
 
     def self.cacheless_render(text, context = {})
-      result = render_result(text, context)
+      Gitlab::Metrics.measure(:banzai_cacheless_render) do
+        result = render_result(text, context)
 
-      output = result[:output]
-      if output.respond_to?(:to_html)
-        output.to_html
-      else
-        output.to_s
+        output = result[:output]
+        if output.respond_to?(:to_html)
+          output.to_html
+        else
+          output.to_s
+        end
       end
     end
 
diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb
index 4a3f47b5a95632b481b1e3e0ce16b0770c23ef96..2a0a5629be55093c7ed13756e6115e7e072a18c7 100644
--- a/lib/gitlab/metrics.rb
+++ b/lib/gitlab/metrics.rb
@@ -74,24 +74,32 @@ module Gitlab
     #
     # Example:
     #
-    #     Gitlab::Metrics.measure(:find_by_username_timings) do
+    #     Gitlab::Metrics.measure(:find_by_username_duration) do
     #       User.find_by_username(some_username)
     #     end
     #
-    # series - The name of the series to store the data in.
-    # values - A Hash containing extra values to add to the metric.
-    # tags - A Hash containing extra tags to add to the metric.
+    # name - The name of the field to store the execution time in.
     #
     # Returns the value yielded by the supplied block.
-    def self.measure(series, values = {}, tags = {})
-      return yield unless Transaction.current
+    def self.measure(name)
+      trans = current_transaction
+
+      return yield unless trans
+
+      real_start = Time.now.to_f
+      cpu_start = System.cpu_time
 
-      start = Time.now.to_f
       retval = yield
-      duration = (Time.now.to_f - start) * 1000.0
-      values = values.merge(duration: duration)
 
-      Transaction.current.add_metric(series, values, tags)
+      cpu_stop = System.cpu_time
+      real_stop = Time.now.to_f
+
+      real_time = (real_stop - real_start) * 1000.0
+      cpu_time = cpu_stop - cpu_start
+
+      trans.increment("#{name}_real_time", real_time)
+      trans.increment("#{name}_cpu_time", cpu_time)
+      trans.increment("#{name}_call_count", 1)
 
       retval
     end
@@ -107,5 +115,11 @@ module Gitlab
           new(udp: { host: host, port: port })
       end
     end
+
+    private
+
+    def self.current_transaction
+      Transaction.current
+    end
   end
 end
diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb
index 83371265278f6da3b93d1bb34bd0186771e6cc7f..a7d183b2f94a801f9c8f44d72034e35cf3edd312 100644
--- a/lib/gitlab/metrics/system.rb
+++ b/lib/gitlab/metrics/system.rb
@@ -30,6 +30,17 @@ module Gitlab
           0
         end
       end
+
+      # THREAD_CPUTIME is not supported on OS X
+      if Process.const_defined?(:CLOCK_THREAD_CPUTIME_ID)
+        def self.cpu_time
+          Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond)
+        end
+      else
+        def self.cpu_time
+          Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond)
+        end
+      end
     end
   end
 end
diff --git a/spec/features/dashboard_issues_spec.rb b/spec/features/dashboard_issues_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..39805da9d0bb3f8a35a6584d50cc34be7a4c0729
--- /dev/null
+++ b/spec/features/dashboard_issues_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+describe "Dashboard Issues filtering", feature: true, js: true do
+  let(:user)      { create(:user) }
+  let(:project)   { create(:project) }
+  let(:milestone) { create(:milestone, project: project) }
+
+  context 'filtering by milestone' do
+    before do
+      project.team << [user, :master]
+      login_as(user)
+
+      create(:issue, project: project, author: user, assignee: user)
+      create(:issue, project: project, author: user, assignee: user, milestone: milestone)
+
+      visit_issues
+    end
+
+    it 'should show all issues with no milestone' do
+      show_milestone_dropdown
+
+      click_link 'No Milestone'
+
+      expect(page).to have_selector('.issue', count: 1)
+    end
+
+    it 'should show all issues with any milestone' do
+      show_milestone_dropdown
+
+      click_link 'Any Milestone'
+
+      expect(page).to have_selector('.issue', count: 2)
+    end
+
+    it 'should show all issues with the selected milestone' do
+      show_milestone_dropdown
+
+      page.within '.dropdown-content' do
+        click_link milestone.title
+      end
+
+      expect(page).to have_selector('.issue', count: 1)
+    end
+  end
+
+  def show_milestone_dropdown
+    click_button 'Milestone'
+    expect(page).to have_selector('.dropdown-content', visible: true)
+  end
+
+  def visit_issues
+    visit issues_dashboard_path
+  end
+end
diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb
index fd02d584848ad96e94ee1fa525bcd1c13defa13b..00b60bd0e7564551a175c7bc64f908de34ecef67 100644
--- a/spec/features/merge_requests/create_new_mr_spec.rb
+++ b/spec/features/merge_requests/create_new_mr_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-feature 'Create New Merge Request', feature: true, js: false do
+feature 'Create New Merge Request', feature: true, js: true do
   let(:user) { create(:user) }
   let(:project) { create(:project, :public) }
 
@@ -13,9 +13,12 @@ feature 'Create New Merge Request', feature: true, js: false do
 
   it 'generates a diff for an orphaned branch' do
     click_link 'New Merge Request'
-    select "orphaned-branch", from: "merge_request_source_branch"
-    select "master", from: "merge_request_target_branch"
+
+    first('.js-source-branch').click
+    first('.dropdown-source-branch .dropdown-content a', text: 'orphaned-branch').click
+
     click_button "Compare branches"
+    click_link "Changes"
 
     expect(page).to have_content "README.md"
     expect(page).to have_content "wm.png"
@@ -23,6 +26,8 @@ feature 'Create New Merge Request', feature: true, js: false do
     fill_in "merge_request_title", with: "Orphaned MR test"
     click_button "Submit merge request"
 
+    click_link "Check out branch"
+
     expect(page).to have_content 'git checkout -b orphaned-branch origin/orphaned-branch'
   end
 end
diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b20373a96fb4bef8a218882d4b84ab0d6916a2e3
--- /dev/null
+++ b/spec/helpers/form_helper_spec.rb
@@ -0,0 +1,46 @@
+require 'rails_helper'
+
+describe FormHelper do
+  describe 'form_errors' do
+    it 'returns nil when model has no errors' do
+      model = double(errors: [])
+
+      expect(helper.form_errors(model)).to be_nil
+    end
+
+    it 'renders an alert div' do
+      model = double(errors: errors_stub('Error 1'))
+
+      expect(helper.form_errors(model)).
+        to include('<div class="alert alert-danger" id="error_explanation">')
+    end
+
+    it 'contains a summary message' do
+      single_error = double(errors: errors_stub('A'))
+      multi_errors = double(errors: errors_stub('A', 'B', 'C'))
+
+      expect(helper.form_errors(single_error)).
+        to include('<h4>The form contains the following error:')
+      expect(helper.form_errors(multi_errors)).
+        to include('<h4>The form contains the following errors:')
+    end
+
+    it 'renders each message' do
+      model = double(errors: errors_stub('Error 1', 'Error 2', 'Error 3'))
+
+      errors = helper.form_errors(model)
+
+      aggregate_failures do
+        expect(errors).to include('<li>Error 1</li>')
+        expect(errors).to include('<li>Error 2</li>')
+        expect(errors).to include('<li>Error 3</li>')
+      end
+    end
+
+    def errors_stub(*messages)
+      ActiveModel::Errors.new(double).tap do |errors|
+        messages.each { |msg| errors.add(:base, msg) }
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb
index f8c1d956ca1fb9e0c5cb41d2e7e2b6b7e217dfbd..d6ae54e25e859830a534a11ed47eea2dc8f23f32 100644
--- a/spec/lib/gitlab/metrics/system_spec.rb
+++ b/spec/lib/gitlab/metrics/system_spec.rb
@@ -26,4 +26,10 @@ describe Gitlab::Metrics::System do
       end
     end
   end
+
+  describe '.cpu_time' do
+    it 'returns a Fixnum' do
+      expect(described_class.cpu_time).to be_an_instance_of(Fixnum)
+    end
+  end
 end
diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb
index 8f63a5f2043d6da59c675b1d43b12daf434b90a7..3dee13e27f442d2b7c5cba896f175c0f36b3062a 100644
--- a/spec/lib/gitlab/metrics_spec.rb
+++ b/spec/lib/gitlab/metrics_spec.rb
@@ -74,24 +74,21 @@ describe Gitlab::Metrics do
       let(:transaction) { Gitlab::Metrics::Transaction.new }
 
       before do
-        allow(Gitlab::Metrics::Transaction).to receive(:current).
+        allow(Gitlab::Metrics).to receive(:current_transaction).
           and_return(transaction)
       end
 
       it 'adds a metric to the current transaction' do
-        expect(transaction).to receive(:add_metric).
-          with(:foo, { duration: a_kind_of(Numeric) }, { tag: 'value' })
+        expect(transaction).to receive(:increment).
+          with('foo_real_time', a_kind_of(Numeric))
 
-        Gitlab::Metrics.measure(:foo, {}, tag: 'value') { 10 }
-      end
-
-      it 'supports adding of custom values' do
-        values = { duration: a_kind_of(Numeric), number: 10 }
+        expect(transaction).to receive(:increment).
+          with('foo_cpu_time', a_kind_of(Numeric))
 
-        expect(transaction).to receive(:add_metric).
-          with(:foo, values, { tag: 'value' })
+        expect(transaction).to receive(:increment).
+          with('foo_call_count', 1)
 
-        Gitlab::Metrics.measure(:foo, { number: 10 }, tag: 'value') { 10 }
+        Gitlab::Metrics.measure(:foo) { 10 }
       end
 
       it 'returns the return value of the block' do