diff --git a/CHANGELOG b/CHANGELOG
index 7f076f70c7c7da504949c3f5354d6ce2b6719137..28c1c30e2082a98a6b3c37832d61671815ae3846 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,19 +1,25 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
 v 8.6.0 (unreleased)
+  - Add confidential issues
   - Bump gitlab_git to 9.0.3 (Stan Hu)
   - Support Golang subpackage fetching (Stan Hu)
   - Bump Capybara gem to 2.6.2 (Stan Hu)
+  - New branch button appears on issues where applicable
   - Contributions to forked projects are included in calendar
   - Improve the formatting for the user page bio (Connor Shea)
   - Removed the default password from the initial admin account created during
     setup. A password can be provided during setup (see installation docs), or
     GitLab will ask the user to create a new one upon first visit.
   - Fix issue when pushing to projects ending in .wiki
+  - Add support for wiki with UTF-8 page names (Hiroyuki Sato)
+  - Fix wiki search results point to raw source (Hiroyuki Sato)
   - Don't load all of GitLab in mail_room
+  - HTTP error pages work independently from location and config (Artem Sidorenko)
   - Update `omniauth-saml` to 1.5.0 to allow for custom response attributes to be set
   - Memoize @group in Admin::GroupsController (Yatish Mehta)
   - Indicate how much an MR diverged from the target branch (Pierre de La Morinerie)
+  - Added omniauth-auth0 Gem (Daniel Carraro)
   - Strip leading and trailing spaces in URL validator (evuez)
   - Add "last_sign_in_at" and "confirmed_at" to GET /users/* API endpoints for admins (evuez)
   - Return empty array instead of 404 when commit has no statuses in commit status API
@@ -21,6 +27,7 @@ v 8.6.0 (unreleased)
   - Rewrite logo to simplify SVG code (Sean Lang)
   - Allow to use YAML anchors when parsing the `.gitlab-ci.yml` (Pascal Bach)
   - Ignore jobs that start with `.` (hidden jobs)
+  - Hide builds from project's settings when the feature is disabled
   - Allow to pass name of created artifacts archive in `.gitlab-ci.yml`
   - Refactor and greatly improve search performance
   - Add support for cross-project label references
@@ -32,13 +39,25 @@ v 8.6.0 (unreleased)
   - Fix bug where Bitbucket `closed` issues were imported as `opened` (Iuri de Silvio)
   - Don't show Issues/MRs from archived projects in Groups view
   - Fix wrong "iid of max iid" in Issuable sidebar for some merged MRs
+  - Fix empty source_sha on Merge Request when there is no diff (Pierre de La Morinerie)
   - Increase the notes polling timeout over time (Roberto Dip)
   - Add shortcut to toggle markdown preview (Florent Baldino)
   - Show labels in dashboard and group milestone views
   - Add main language of a project in the list of projects (Tiago Botelho)
+  - Add #upcoming filter to Milestone filter (Tiago Botelho)
   - Add ability to show archived projects on dashboard, explore and group pages
   - Move group activity to separate page
+  - Create external users which are excluded of internal and private projects unless access was explicitly granted
   - Continue parameters are checked to ensure redirection goes to the same instance
+  - User deletion is now done in the background so the request can not time out
+  - Canceled builds are now ignored in compound build status if marked as `allowed to fail`
+  - Trigger a todo for mentions on commits page
+
+v 8.5.8
+  - Bump Git version requirement to 2.7.4
+
+v 8.5.7
+  - Bump Git version requirement to 2.7.3
 
 v 8.5.6
   - Obtain a lease before querying LDAP
@@ -48,7 +67,6 @@ v 8.5.5
   - Prevent a 500 error in Todos when author was removed
   - Fix pagination for filtered dashboard and explore pages
   - Fix "Show all" link behavior
-  - Add #upcoming filter to Milestone filter (Tiago Botelho)
 
 v 8.5.4
   - Do not cache requests for badges (including builds badge)
diff --git a/Gemfile b/Gemfile
index a0e8e7966273eb0556c494943f9dca4be23792a3..e500bfb78859bf2564db1fd1c7610cd05d0ccb65 100644
--- a/Gemfile
+++ b/Gemfile
@@ -22,6 +22,7 @@ gem 'devise',                 '~> 3.5.4'
 gem 'devise-async',           '~> 0.9.0'
 gem 'doorkeeper',             '~> 2.2.0'
 gem 'omniauth',               '~> 1.3.1'
+gem 'omniauth-auth0',         '~> 1.4.1'
 gem 'omniauth-azure-oauth2',  '~> 0.0.6'
 gem 'omniauth-bitbucket',     '~> 0.0.2'
 gem 'omniauth-cas3',          '~> 1.1.2'
@@ -50,7 +51,7 @@ gem "browser", '~> 1.0.0'
 
 # Extracting information from a git repository
 # Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 9.0'
+gem "gitlab_git", '~> 10.0'
 
 # LDAP Auth
 # GitLab fork with several improvements to original library. For full list of changes
@@ -58,7 +59,9 @@ gem "gitlab_git", '~> 9.0'
 gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
 
 # Git Wiki
-gem 'gollum-lib', '~> 4.1.0'
+# Required manually in config/initializers/gollum.rb to control load order
+gem 'gollum-lib', '~> 4.1.0', require: false
+gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
 
 # Language detection
 gem "github-linguist", "~> 4.7.0", require: "linguist"
diff --git a/Gemfile.lock b/Gemfile.lock
index f4f5649eb752ed60ceb97dc37a5073047cc2ac43..63ed9441c62daa26893f189a45d96c264ee13059 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -359,11 +359,11 @@ GEM
       posix-spawn (~> 0.3)
     gitlab_emoji (0.3.1)
       gemojione (~> 2.2, >= 2.2.1)
-    gitlab_git (9.0.3)
+    gitlab_git (10.0.0)
       activesupport (~> 4.0)
       charlock_holmes (~> 0.7.3)
       github-linguist (~> 4.7.0)
-      rugged (~> 0.24.0b13)
+      rugged (~> 0.24.0)
     gitlab_meta (7.0)
     gitlab_omniauth-ldap (1.2.1)
       net-ldap (~> 0.9)
@@ -381,6 +381,9 @@ GEM
       rouge (~> 1.9)
       sanitize (~> 2.1.0)
       stringex (~> 2.5.1)
+    gollum-rugged_adapter (0.4.2)
+      mime-types (>= 1.15)
+      rugged (~> 0.24.0, >= 0.21.3)
     gon (6.0.1)
       actionpack (>= 3.0)
       json
@@ -495,6 +498,8 @@ GEM
     omniauth (1.3.1)
       hashie (>= 1.2, < 4)
       rack (>= 1.0, < 3)
+    omniauth-auth0 (1.4.1)
+      omniauth-oauth2 (~> 1.1)
     omniauth-azure-oauth2 (0.0.6)
       jwt (~> 1.0)
       omniauth (~> 1.0)
@@ -703,7 +708,7 @@ GEM
     rubyntlm (0.5.2)
     rubypants (0.2.0)
     rufus-scheduler (3.1.10)
-    rugged (0.24.0b13)
+    rugged (0.24.0)
     safe_yaml (1.0.4)
     sanitize (2.1.0)
       nokogiri (>= 1.4.4)
@@ -937,10 +942,11 @@ DEPENDENCIES
   github-markup (~> 1.3.1)
   gitlab-flowdock-git-hook (~> 1.0.1)
   gitlab_emoji (~> 0.3.0)
-  gitlab_git (~> 9.0)
+  gitlab_git (~> 10.0)
   gitlab_meta (= 7.0)
   gitlab_omniauth-ldap (~> 1.2.1)
   gollum-lib (~> 4.1.0)
+  gollum-rugged_adapter (~> 0.4.2)
   gon (~> 6.0.1)
   grape (~> 0.13.0)
   grape-entity (~> 0.4.2)
@@ -969,6 +975,7 @@ DEPENDENCIES
   oauth2 (~> 1.0.0)
   octokit (~> 3.8.0)
   omniauth (~> 1.3.1)
+  omniauth-auth0 (~> 1.4.1)
   omniauth-azure-oauth2 (~> 0.0.6)
   omniauth-bitbucket (~> 0.0.2)
   omniauth-cas3 (~> 1.1.2)
diff --git a/README.md b/README.md
index 3ec1d4a776cb68afff4a253fcd1d0f5b08c7964b..afa60116ebba5b1c38e2e4b9174d90d41f6c74e3 100644
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
 
 - Ubuntu/Debian/CentOS/RHEL
 - Ruby (MRI) 2.1
-- Git 1.7.10+
+- Git 2.7.4+
 - Redis 2.8+
 - MySQL or PostgreSQL
 
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 0aefea7d8d9d250e95a7ec109f6cf5378be15d9d..a022c207d08fca9fb8600daaac1917932146c697 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -14,7 +14,6 @@ class Dispatcher
 
     path = page.split(':')
     shortcut_handler = null
-
     switch page
       when 'projects:issues:index'
         Issues.init()
@@ -25,6 +24,8 @@ class Dispatcher
         new ZenMode()
       when 'projects:milestones:show', 'groups:milestones:show', 'dashboard:milestones:show'
         new Milestone()
+      when 'dashboard:todos:index'
+        new Todos()
       when 'projects:milestones:new', 'projects:milestones:edit'
         new ZenMode()
         new DropzoneInput($('.milestone-form'))
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index c579657d4d216145af034cb9cd9f0ea0b62e47c8..ca7b22bd816bba123e4554f57706dbf6daaef951 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -303,11 +303,15 @@ class GitLabDropdown
         if oldValue
           value = "#{oldValue},#{value}"
       else
-        @dropdown.find(ACTIVE_CLASS).removeClass ACTIVE_CLASS
+        @dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS
 
       # Toggle active class for the tick mark
       el.toggleClass "is-active"
 
+      # Toggle the dropdown label
+      if @options.toggleLabel
+        $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject)
+
       if value?
         if !field.length
           # Create hidden input for form
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index d663e34871c244bccefb4b01bfdab00b12a206d6..f50df1f5ea3f1da8f8d07baa5bf43a702d8e612e 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -7,6 +7,7 @@ class @Issue
     # Prevent duplicate event bindings
     @disableTaskList()
     @fixAffixScroll()
+    @initParticipants()
     if $('a.btn-close').length
       @initTaskList()
       @initIssueBtnEventListeners()
@@ -84,3 +85,27 @@ class @Issue
       type: 'PATCH'
       url: $('form.js-issuable-update').attr('action')
       data: patchData
+
+  initParticipants: ->
+    _this = @
+    $(document).on "click", ".js-participants-more", @toggleHiddenParticipants
+
+    $(".js-participants-author").each (i) ->
+      if i >= _this.PARTICIPANTS_ROW_COUNT
+        $(@)
+          .addClass "js-participants-hidden"
+          .hide()
+
+  toggleHiddenParticipants: (e) ->
+    e.preventDefault()
+
+    currentText = $(this).text().trim()
+    lessText = $(this).data("less-text")
+    originalText = $(this).data("original-text")
+
+    if currentText is originalText
+      $(this).text(lessText)
+    else
+      $(this).text(originalText)
+
+    $(".js-participants-hidden").toggle()
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
index a0acf3028bfbd933902a28db0c4b3ba958bc3d27..1127b289264979acfea06dde32e51bf65575fb53 100644
--- a/app/assets/javascripts/issues.js.coffee
+++ b/app/assets/javascripts/issues.js.coffee
@@ -41,24 +41,28 @@
     @timer = null
     $("#issue_search").keyup ->
       clearTimeout(@timer)
-      @timer = setTimeout(Issues.filterResults, 500)
+      @timer = setTimeout( ->
+        Issues.filterResults $("#issue_search_form")
+      , 500)
 
-  filterResults: =>
-    form = $("#issue_search_form")
-    search = $("#issue_search").val()
-    $('.issues-holder').css("opacity", '0.5')
-    issues_url = form.attr('action') + '?' + form.serialize()
+  filterResults: (form) =>
+    $('.issues-holder, .merge-requests-holder').css("opacity", '0.5')
+    formAction = form.attr('action')
+    formData = form.serialize()
+    issuesUrl = formAction
+    issuesUrl += ("#{if formAction.indexOf("?") < 0 then '?' else '&'}")
+    issuesUrl += formData
 
     $.ajax
       type: "GET"
-      url: form.attr('action')
-      data: form.serialize()
+      url: formAction
+      data: formData
       complete: ->
-        $('.issues-holder').css("opacity", '1.0')
+        $('.issues-holder, .merge-requests-holder').css("opacity", '1.0')
       success: (data) ->
-        $('.issues-holder').html(data.html)
+        $('.issues-holder, .merge-requests-holder').html(data.html)
         # Change url so if user reload a page - search results are saved
-        history.replaceState {page: issues_url}, document.title, issues_url
+        history.replaceState {page: issuesUrl}, document.title, issuesUrl
         Issues.reload()
       dataType: "json"
 
diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee
index 5ade2cb66cb5cb17cb69488afe60e61c1f6c613c..4a0c18a99a6bce7a24791f8fd451abe85f9fe510 100644
--- a/app/assets/javascripts/labels_select.js.coffee
+++ b/app/assets/javascripts/labels_select.js.coffee
@@ -1,30 +1,32 @@
 class @LabelsSelect
   constructor: ->
     $('.js-label-select').each (i, dropdown) ->
-      projectId = $(dropdown).data('project-id')
-      labelUrl = $(dropdown).data("labels")
-      selectedLabel = $(dropdown).data('selected')
+      $dropdown = $(dropdown)
+      projectId = $dropdown.data('project-id')
+      labelUrl = $dropdown.data('labels')
+      selectedLabel = $dropdown.data('selected')
       if selectedLabel
-        selectedLabel = selectedLabel.split(",")
+        selectedLabel = selectedLabel.split(',')
       newLabelField = $('#new_label_name')
       newColorField = $('#new_label_color')
-      showNo = $(dropdown).data('show-no')
-      showAny = $(dropdown).data('show-any')
+      showNo = $dropdown.data('show-no')
+      showAny = $dropdown.data('show-any')
+      defaultLabel = $dropdown.data('default-label')
 
       if newLabelField.length
-        $('.suggest-colors-dropdown a').on "click", (e) ->
+        $('.suggest-colors-dropdown a').on 'click', (e) ->
           e.preventDefault()
           e.stopPropagation()
-          newColorField.val $(this).data("color")
+          newColorField.val $(this).data('color')
           $('.js-dropdown-label-color-preview')
-            .css 'background-color', $(this).data("color")
+            .css 'background-color', $(this).data('color')
             .addClass 'is-active'
 
-        $('.js-new-label-btn').on "click", (e) ->
+        $('.js-new-label-btn').on 'click', (e) ->
           e.preventDefault()
           e.stopPropagation()
 
-          if newLabelField.val() isnt "" && newColorField.val() isnt ""
+          if newLabelField.val() isnt '' and newColorField.val() isnt ''
             $('.js-new-label-btn').disable()
 
             # Create new label with API
@@ -33,46 +35,38 @@ class @LabelsSelect
               color: newColorField.val()
             }, (label) ->
               $('.js-new-label-btn').enable()
-              $('.dropdown-menu-back', $(dropdown).parent()).trigger "click"
+              $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
 
-      $(dropdown).glDropdown(
+      $dropdown.glDropdown(
         data: (term, callback) ->
-          # We have to fetch the JS version of the labels list because there is no
-          # public facing JSON url for labels
           $.ajax(
             url: labelUrl
           ).done (data) ->
-            html = $(data)
-            data = []
-            html.find('.label-row a').each ->
-              data.push(
-                title: $(@).text().trim()
-              )
-
             if showNo
               data.unshift(
-                id: "0"
-                title: 'No label'
+                id: 0
+                title: 'No Label'
               )
 
             if showAny
               data.unshift(
-                title: 'Any label'
+                isAny: true
+                title: 'Any Label'
               )
 
             if data.length > 2
-              data.splice 2, 0, "divider"
+              data.splice 2, 0, 'divider'
 
             callback data
         renderRow: (label) ->
           if $.isArray(selectedLabel)
-            selected = ""
+            selected = ''
             $.each selectedLabel, (i, selectedLbl) ->
               selectedLbl = selectedLbl.trim()
-              if selected is "" && label.title is selectedLbl
-                selected = "is-active"
+              if selected is '' and label.title is selectedLbl
+                selected = 'is-active'
           else
-            selected = if label.title is selectedLabel then "is-active" else ""
+            selected = if label.title is selectedLabel then 'is-active' else ''
 
           "<li>
             <a href='#' class='#{selected}'>
@@ -83,10 +77,24 @@ class @LabelsSelect
         search:
           fields: ['title']
         selectable: true
-        fieldName: $(dropdown).data('field-name')
+        toggleLabel: (selected) ->
+          if selected and selected.title isnt 'Any Label'
+            selected.title
+          else
+            defaultLabel
+        fieldName: $dropdown.data('field-name')
         id: (label) ->
-          label.title
+          if label.isAny?
+            ''
+          else
+            label.title
         clicked: ->
-          if $(dropdown).hasClass "js-filter-submit"
-            $(dropdown).parents('form').submit()
+          page = $('body').data 'page'
+          isIssueIndex = page is 'projects:issues:index'
+          isMRIndex = page is page is 'projects:merge_requests:index'
+
+          if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
+            Issues.filterResults $dropdown.closest('form')
+          else if $dropdown.hasClass 'js-filter-submit'
+            $dropdown.closest('form').submit()
       )
diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee
index 5e884454a6585e9963263dcda575f83ef7fccc34..e17a1adb6484b4d957e7c5a3e088abc3c2a7a69a 100644
--- a/app/assets/javascripts/milestone_select.js.coffee
+++ b/app/assets/javascripts/milestone_select.js.coffee
@@ -1,60 +1,65 @@
 class @MilestoneSelect
   constructor: ->
     $('.js-milestone-select').each (i, dropdown) ->
-      projectId = $(dropdown).data('project-id')
-      milestonesUrl = $(dropdown).data('milestones')
-      selectedMilestone = $(dropdown).data('selected')
-      showNo = $(dropdown).data('show-no')
-      showAny = $(dropdown).data('show-any')
-      useId = $(dropdown).data('use-id')
+      $dropdown = $(dropdown)
+      projectId = $dropdown.data('project-id')
+      milestonesUrl = $dropdown.data('milestones')
+      selectedMilestone = $dropdown.data('selected')
+      showNo = $dropdown.data('show-no')
+      showAny = $dropdown.data('show-any')
+      useId = $dropdown.data('use-id')
+      defaultLabel = $dropdown.data('default-label')
 
-      $(dropdown).glDropdown(
+      $dropdown.glDropdown(
         data: (term, callback) ->
           $.ajax(
             url: milestonesUrl
           ).done (data) ->
-            html = $(data)
-            data = []
-            html.find('.milestone strong a').each ->
-              link = $(@).attr("href").split("/")
-              data.push(
-                id: link[link.length - 1]
-                title: $(@).text().trim()
-              )
-
             if showNo
               data.unshift(
-                id: "0"
+                id: '0'
                 title: 'No Milestone'
               )
 
             if showAny
               data.unshift(
+                isAny: true
                 title: 'Any Milestone'
               )
 
             if data.length > 2
-              data.splice 2, 0, "divider"
+              data.splice 2, 0, 'divider'
 
             callback(data)
         filterable: true
         search:
           fields: ['title']
         selectable: true
-        fieldName: $(dropdown).data('field-name')
+        toggleLabel: (selected) ->
+          if selected && 'id' of selected
+            selected.title
+          else
+            defaultLabel
+        fieldName: $dropdown.data('field-name')
         text: (milestone) ->
           milestone.title
         id: (milestone) ->
           if !useId
-            if milestone.title isnt "Any milestone"
+            if !milestone.isAny?
               milestone.title
             else
-              ""
+              ''
           else
             milestone.id
         isSelected: (milestone) ->
           milestone.title is selectedMilestone
         clicked: ->
-          if $(dropdown).hasClass "js-filter-submit"
-            $(dropdown).parents('form').submit()
+          page = $('body').data 'page'
+          isIssueIndex = page is 'projects:issues:index'
+          isMRIndex = page is page is 'projects:merge_requests:index'
+
+          if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
+            Issues.filterResults $dropdown.closest('form')
+          else if $dropdown.hasClass 'js-filter-submit'
+            $dropdown.closest('form').submit()
       )
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 75d7f52bbb6e7e7e29ba6129a7ac7238be218ddc..82532216589d94a513b231f24a0e4fe92d148912 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -343,6 +343,7 @@ class @Notes
   updateNote: (_xhr, note, _status) =>
     # Convert returned HTML to a jQuery object so we can modify it further
     $html = $(note.html)
+    $('.js-timeago', $html).timeago()
     $html.syntaxHighlight()
     $html.find('.js-task-list-container').taskList('enable')
 
@@ -626,10 +627,10 @@ class @Notes
       if closebtn.text() isnt closetext
         closebtn.text(closetext)
 
-      if reopenbtn.is(':not(.btn-comment-and-reopen)')
+      if reopenbtn.is('.btn-comment-and-reopen')
         reopenbtn.removeClass('btn-comment-and-reopen')
 
-      if closebtn.is(':not(.btn-comment-and-close)')
+      if closebtn.is('.btn-comment-and-close')
         closebtn.removeClass('btn-comment-and-close')
 
       if discardbtn.is(':visible')
diff --git a/app/assets/javascripts/project_new.js.coffee b/app/assets/javascripts/project_new.js.coffee
index fecdb9fc2e773436fe8ac193903d8d97ed2cf533..63dee4ed5d79ea823e036070c58b1a9af680bf16 100644
--- a/app/assets/javascripts/project_new.js.coffee
+++ b/app/assets/javascripts/project_new.js.coffee
@@ -3,3 +3,16 @@ class @ProjectNew
     $('.project-edit-container').on 'ajax:before', =>
       $('.project-edit-container').hide()
       $('.save-project-loader').show()
+    @toggleSettings()
+    @toggleSettingsOnclick()
+
+
+  toggleSettings: ->
+    checked = $("#project_builds_enabled").prop("checked")
+    if checked
+      $('.builds-feature').show()
+    else
+      $('.builds-feature').hide()
+
+  toggleSettingsOnclick: ->
+    $("#project_builds_enabled").on 'click', @toggleSettings
diff --git a/app/assets/javascripts/todos.js.coffee b/app/assets/javascripts/todos.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..b6b4bd90e6afa2f394e6d0b2123e36d36167341d
--- /dev/null
+++ b/app/assets/javascripts/todos.js.coffee
@@ -0,0 +1,56 @@
+class @Todos
+  constructor: (@name) ->
+    @clearListeners()
+    @initBtnListeners()
+
+  clearListeners: ->
+    $('.done-todo').off('click')
+    $('.js-todos-mark-all').off('click')
+
+  initBtnListeners: ->
+    $('.done-todo').on('click', @doneClicked)
+    $('.js-todos-mark-all').on('click', @allDoneClicked)
+
+  doneClicked: (e) =>
+    e.preventDefault()
+    e.stopImmediatePropagation()
+
+    $this = $(e.currentTarget)
+    $this.disable()
+
+    $.ajax
+      type: 'POST'
+      url: $this.attr('href')
+      dataType: 'json'
+      data: '_method': 'delete'
+      success: (data) =>
+        @clearDone $this.closest('li')
+        @updateBadges data
+
+  allDoneClicked: (e) =>
+    e.preventDefault()
+    e.stopImmediatePropagation()
+
+    $this = $(e.currentTarget)
+    $this.disable()
+
+    $.ajax
+      type: 'POST'
+      url: $this.attr('href')
+      dataType: 'json'
+      data: '_method': 'delete'
+      success: (data) =>
+        $this.remove()
+        $('.js-todos-list').remove()
+        @updateBadges data
+
+  clearDone: ($row) ->
+    $ul = $row.closest('ul')
+    $row.remove()
+
+    if not $ul.find('li').length
+      $ul.parents('.panel').remove()
+
+  updateBadges: (data) ->
+    $('.todos-pending .badge, .todos-pending-count').text data.count
+    $('.todos-done .badge').text data.done_count
diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee
index 987c6f4b8d2123bafb1d156a11350b5632648d4d..3d6452d2f4693d36691df7ff987bc257de83d761 100644
--- a/app/assets/javascripts/users_select.js.coffee
+++ b/app/assets/javascripts/users_select.js.coffee
@@ -4,14 +4,16 @@ class @UsersSelect
     @userPath = "/autocomplete/users/:id.json"
 
     $('.js-user-search').each (i, dropdown) =>
-      @projectId = $(dropdown).data('project-id')
-      @showCurrentUser = $(dropdown).data('current-user')
-      showNullUser = $(dropdown).data('null-user')
-      showAnyUser = $(dropdown).data('any-user')
-      firstUser = $(dropdown).data('first-user')
-      selectedId = $(dropdown).data('selected')
-
-      $(dropdown).glDropdown(
+      $dropdown = $(dropdown)
+      @projectId = $dropdown.data('project-id')
+      @showCurrentUser = $dropdown.data('current-user')
+      showNullUser = $dropdown.data('null-user')
+      showAnyUser = $dropdown.data('any-user')
+      firstUser = $dropdown.data('first-user')
+      selectedId = $dropdown.data('selected')
+      defaultLabel = $dropdown.data('default-label')
+
+      $dropdown.glDropdown(
         data: (term, callback) =>
           @users term, (users) =>
             if term.length is 0
@@ -52,10 +54,21 @@ class @UsersSelect
         search:
           fields: ['name', 'username']
         selectable: true
-        fieldName: $(dropdown).data('field-name')
+        fieldName: $dropdown.data('field-name')
+        toggleLabel: (selected) ->
+          if selected && 'id' of selected
+            selected.name
+          else
+            defaultLabel
         clicked: ->
-          if $(dropdown).hasClass "js-filter-submit"
-            $(dropdown).parents('form').submit()
+          page = $('body').data 'page'
+          isIssueIndex = page is 'projects:issues:index'
+          isMRIndex = page is page is 'projects:merge_requests:index'
+
+          if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
+            Issues.filterResults $dropdown.closest('form')
+          else if $dropdown.hasClass 'js-filter-submit'
+            $dropdown.closest('form').submit()
         renderRow: (user) ->
           username = if user.username then "@#{user.username}" else ""
           avatar = if user.avatar_url then user.avatar_url else false
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index d20b77ffae9e048ad3b0c4550a17b57be0c91f44..c36f29dda0eb15b0533a291418e836b112028df3 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -23,15 +23,11 @@
   margin-bottom: -$gl-padding;
   background-color: $background-color;
   padding: $gl-padding;
-  margin-bottom: 0px;
+  margin-bottom: 0;
   border-top: 1px solid $border-color;
   border-bottom: 1px solid $border-color;
   color: $gl-gray;
 
-  a {
-    color: $md-link-color;
-  }
-
   &.oneline-block {
     line-height: 42px;
   }
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 8d475137b039573be87a521dd179a53b96fb6620..657c5f033c700335f74dd186f247c3f04f78645c 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -37,23 +37,23 @@
 }
 
 @mixin btn-green {
-  @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #FFFFFF);
+  @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #fff);
 }
 
 @mixin btn-blue {
-  @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
+  @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #fff);
 }
 
 @mixin btn-blue-medium {
-  @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #FFFFFF);
+  @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #fff);
 }
 
 @mixin btn-orange {
-  @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
+  @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #fff);
 }
 
 @mixin btn-red {
-  @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #FFFFFF);
+  @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #fff);
 }
 
 @mixin btn-gray {
@@ -127,7 +127,7 @@
     margin-right: 7px;
     float: left;
     &:last-child {
-      margin-right: 0px;
+      margin-right: 0;
     }
     &.btn-xs {
       margin-right: 3px;
@@ -139,7 +139,6 @@
 
   .caret {
     margin-left: 5px;
-    color: $gray-darkest;
   }
 }
 
@@ -170,7 +169,7 @@
     margin-right: 7px;
     float: left;
     &:last-child {
-      margin-right: 0px;
+      margin-right: 0;
     }
   }
 }
@@ -209,3 +208,13 @@
     background-color: #e4e7ed !important;
   }
 }
+
+.btn-loading {
+  &:not(.disabled) .fa {
+    display: none;
+  }
+
+  .fa {
+    margin-right: 5px;
+  }
+}
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index 580012abd777ccf4e268460fcdd6a629d9e30858..e3192823a1a20ed665708da4cabf7cb278297f1a 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -33,19 +33,19 @@
   }
 
   .q2 {
-    fill: #ACD5F2 !important;
+    fill: #acd5f2 !important;
   }
 
   .q3 {
-    fill: #7FA8D1 !important;
+    fill: #7fa8d1 !important;
   }
 
   .q4 {
-    fill: #49729B !important;
+    fill: #49729b !important;
   }
 
   .q5 {
-    fill: #254E77 !important;
+    fill: #254e77 !important;
   }
 
   .domain-background {
diff --git a/app/assets/stylesheets/framework/callout.scss b/app/assets/stylesheets/framework/callout.scss
index 20a9bfb9816b3222d64c5d21aaeb99c008698ec7..da7bab74a32dc1e55f042f8ae51bec05e08232b2 100644
--- a/app/assets/stylesheets/framework/callout.scss
+++ b/app/assets/stylesheets/framework/callout.scss
@@ -39,6 +39,6 @@
 }
 .bs-callout-success {
   background-color: #dff0d8;
-  border-color: #5cA64d;
+  border-color: #5ca64d;
   color: #3c763d;
 }
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index ff551f151f1eb7eb1c3e507ef35da3afe3d921a3..bc03c2180becdd93fd2aa80311f88ef2d009107f 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -1,6 +1,6 @@
 /** COLORS **/
 .cgray { color: $gl-gray; }
-.clgray { color: #BBB }
+.clgray { color: #bbb }
 .cred { color: $gl-text-red; }
 .cgreen { color: $gl-text-green; }
 .cdark { color: #444 }
@@ -8,20 +8,20 @@
 /** COMMON CLASSES **/
 .prepend-top-0 { margin-top: 0; }
 .prepend-top-5 { margin-top: 5px; }
-.prepend-top-10 { margin-top:10px }
+.prepend-top-10 { margin-top: 10px }
 .prepend-top-default { margin-top: $gl-padding !important; }
-.prepend-top-20 { margin-top:20px }
-.prepend-left-10 { margin-left:10px }
+.prepend-top-20 { margin-top: 20px }
+.prepend-left-10 { margin-left: 10px }
 .prepend-left-default { margin-left: $gl-padding; }
-.prepend-left-20 { margin-left:20px }
+.prepend-left-20 { margin-left: 20px }
 .append-right-5 { margin-right: 5px }
-.append-right-10 { margin-right:10px }
+.append-right-10 { margin-right: 10px }
 .append-right-default { margin-right: $gl-padding; }
-.append-right-20 { margin-right:20px }
-.append-bottom-0 { margin-bottom:0 }
-.append-bottom-10 { margin-bottom:10px }
-.append-bottom-15 { margin-bottom:15px }
-.append-bottom-20 { margin-bottom:20px }
+.append-right-20 { margin-right: 20px }
+.append-bottom-0 { margin-bottom: 0 }
+.append-bottom-10 { margin-bottom: 10px }
+.append-bottom-15 { margin-bottom: 15px }
+.append-bottom-20 { margin-bottom: 20px }
 .append-bottom-default { margin-bottom: $gl-padding; }
 .inline { display: inline-block }
 .center { text-align: center }
@@ -51,7 +51,7 @@ pre {
   }
 
   &.well-pre {
-    border: 1px solid #EEE;
+    border: 1px solid #eee;
     background: #f9f9f9;
     border-radius: 0;
     color: #555;
@@ -103,7 +103,7 @@ span.update-author {
 }
 
 .user-mention {
-  color: #2FA0BB;
+  color: #2fa0bb;
   font-weight: bold;
 }
 
@@ -134,10 +134,10 @@ p.time {
 
 // Fix issue with notes & lists creating a bunch of bottom borders.
 li.note {
-  img { max-width:100% }
+  img { max-width: 100% }
   .note-title {
     li {
-      border-bottom:none !important;
+      border-bottom: none !important;
     }
   }
 }
@@ -187,9 +187,9 @@ li.note {
 
 .error-message {
   padding: 10px;
-  background: #C67;
+  background: #c67;
   margin: 0;
-  color: #FFF;
+  color: #fff;
 
   a {
     color: #fff;
@@ -200,7 +200,7 @@ li.note {
 .browser-alert {
   padding: 10px;
   text-align: center;
-  background: #C67;
+  background: #c67;
   color: #fff;
   font-weight: bold;
   a {
@@ -271,7 +271,7 @@ img.emoji {
 
 table {
   td.permission-x {
-    background: #D9EDF7 !important;
+    background: #d9edf7 !important;
     text-align: center;
   }
 }
@@ -280,7 +280,7 @@ table {
   float: left;
   text-align: center;
   font-size: 32px;
-  color: #AAA;
+  color: #aaa;
   width: 60px;
 }
 
@@ -347,7 +347,7 @@ table {
 
   .profiler-button,
   .profiler-controls {
-    border-color: #EEE !important;
+    border-color: #eee !important;
   }
 }
 
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 5b647fc6176b5e179f4a8d8d72c767350a745367..a48b6c17fa013398d4f1257cfbe6a5c7980cb9d8 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -4,11 +4,17 @@
   height: 0;
   margin-left: 2px;
   vertical-align: middle;
-  border-top: $caret-width-base dashed $dropdown-caret-color;
+  border-top: $caret-width-base dashed;
   border-right: $caret-width-base solid transparent;
   border-left: $caret-width-base solid transparent;
 }
 
+.btn-group {
+  .caret {
+    margin-left: 0;
+  }
+}
+
 .dropdown {
   position: relative;
 }
@@ -161,9 +167,8 @@
 
 .dropdown-menu-user-full-name {
   display: block;
-  margin-bottom: 2px;
   font-weight: 600;
-  line-height: 1;
+  line-height: 16px;
   text-overflow: ellipsis;
   overflow: hidden;
   white-space: nowrap;
@@ -171,7 +176,7 @@
 
 .dropdown-menu-user-username {
   display: block;
-  line-height: 1;
+  line-height: 16px;
   text-overflow: ellipsis;
   overflow: hidden;
   white-space: nowrap;
@@ -261,7 +266,7 @@
     position: absolute;
     top: 10px;
     right: 10px;
-    color: #C7C7C7;
+    color: #c7c7c7;
     font-size: 12px;
     pointer-events: none;
   }
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index b034a4882c1a819b1c9a22028929de8324e38cc6..646e261083121b342c4ba934fa05a34632a7c3a6 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -30,7 +30,7 @@
       right: 15px;
 
       .btn {
-        padding: 0px 10px;
+        padding: 0 10px;
         font-size: 13px;
         line-height: 28px;
       }
@@ -84,7 +84,7 @@
 
     &.blob-no-preview {
       background: #eee;
-      text-shadow: 0 1px 2px #FFF;
+      text-shadow: 0 1px 2px #fff;
       padding: 100px 0;
     }
 
@@ -124,7 +124,7 @@
       }
       td.line-numbers {
         float: none;
-        border-left: 1px solid #DDD;
+        border-left: 1px solid #ddd;
       }
       td.lines {
         padding: 0;
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index c431e2b0df3de88990a14bbef455ab6972b8a3e1..40a508c1ebc73fa96137f1e510e8f6026fc97740 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -3,22 +3,11 @@
   vertical-align: top;
 }
 
-@media (min-width: 800px)  {
+@media (min-width: $screen-sm-min)  {
   .issues-filters,
   .issues_bulk_update {
-    select, .select2-container {
-      width: 120px !important;
-      display: inline-block;
-    }
-  }
-}
-
-@media (min-width: 1200px) {
-  .issues-filters,
-  .issues_bulk_update {
-    select, .select2-container {
-      width: 150px !important;
-      display: inline-block;
+    .dropdown-menu-toggle {
+      width: 132px;
     }
   }
 }
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 18136509da58b34f4ca91fa60802903dfdb2b4ab..91b6451e68adc5bf7bdbe3e8b24a2203ffc21868 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -7,8 +7,8 @@ input {
 }
 
 input[type='text'].danger {
-  background: #F2DEDE!important;
-  border-color: #D66;
+  background: #f2dede!important;
+  border-color: #d66;
   text-shadow: 0 1px 1px #fff
 }
 
diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss
index 12cef6f8ea1c7a6bcbba402b110d655cb66e5d2d..2a4cf4fc335ee49ee3adadfe584ec160f1633ae7 100644
--- a/app/assets/stylesheets/framework/gitlab-theme.scss
+++ b/app/assets/stylesheets/framework/gitlab-theme.scss
@@ -23,13 +23,13 @@
       &:hover {
         background-color: $color-darker;
         a {
-          color: #FFF;
+          color: #fff;
         }
       }
     }
 
     .collapse-nav a {
-      color: #FFF;
+      color: #fff;
       background: $color;
     }
 
@@ -42,7 +42,7 @@
 
         &:hover {
           background-color: $color-dark;
-          color: #FFF;
+          color: #fff;
           text-decoration: none;
         }
       }
@@ -71,7 +71,7 @@
       }
 
       &.active a {
-        color: #FFF;
+        color: #fff;
         background: $color-dark;
 
         &.no-highlight {
@@ -79,42 +79,42 @@
         }
 
         i {
-          color: #FFF
+          color: #fff
         }
       }
     }
   }
 }
 
-$theme-blue: #2980B9;
+$theme-blue: #2980b9;
 $theme-charcoal: #333c47;
-$theme-graphite: #888888;
+$theme-graphite: #888;
 $theme-gray: #373737;
 $theme-green: #019875;
-$theme-violet: #554488;
+$theme-violet: #548;
 
 body {
   &.ui_blue {
-    @include gitlab-theme(#BECDE9, $theme-blue, #1970A9, #096099);
+    @include gitlab-theme(#becde9, $theme-blue, #1970a9, #096099);
   }
 
   &.ui_charcoal {
-    @include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272D);
+    @include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d);
   }
 
   &.ui_graphite {
-    @include gitlab-theme(#CCCCCC, $theme-graphite, #777777, #666666);
+    @include gitlab-theme(#ccc, $theme-graphite, #777, #666);
   }
 
   &.ui_gray {
-    @include gitlab-theme(#979797, $theme-gray, #272727, #222222);
+    @include gitlab-theme(#979797, $theme-gray, #272727, #222);
   }
 
   &.ui_green {
-    @include gitlab-theme(#AADDCC, $theme-green, #018865, #017855);
+    @include gitlab-theme(#adc, $theme-green, #018865, #017855);
   }
 
   &.ui_violet {
-    @include gitlab-theme(#9988CC, $theme-violet, #443366, #332255);
+    @include gitlab-theme(#98c, $theme-violet, #436, #325);
   }
 }
\ No newline at end of file
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index f72bd2234863baab5d3073a7d97bf5cdd66320c0..a6c9fce5b891e4c5dd371b05c9f4584d1ed12e21 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -7,8 +7,8 @@ header {
 
   &.navbar-empty {
     height: 58px;
-    background: #FFF;
-    border-bottom: 1px solid #EEE;
+    background: #fff;
+    border-bottom: 1px solid #eee;
 
     .center-logo {
       margin: 11px 0;
@@ -28,7 +28,7 @@ header {
     min-height: $header-height;
     background-color: #fff;
     border: none;
-    border-bottom: 1px solid #EEE;
+    border-bottom: 1px solid #eee;
 
     .container-fluid {
       width: 100% !important;
@@ -47,7 +47,7 @@ header {
         text-align: center;
 
         &:hover, &:focus, &:active {
-          background-color: #FFF;
+          background-color: #fff;
         }
       }
 
@@ -59,7 +59,7 @@ header {
         right: 2px;
 
         &:hover {
-          background-color: #EEE;
+          background-color: #eee;
         }
         &.active {
           color: #7f8fa4;
@@ -142,7 +142,7 @@ header {
     font-size: 18px;
 
     .navbar-nav {
-      margin: 0px;
+      margin: 0;
       float: none !important;
 
       .visible-xs, .visable-sm {
diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss
index 12e2f00fe89cced5c91ac7147d2fe23c3292dda7..7cf4d4fba421fc51c087c69f09e9a1771e14b861 100644
--- a/app/assets/stylesheets/framework/highlight.scss
+++ b/app/assets/stylesheets/framework/highlight.scss
@@ -1,8 +1,8 @@
 .file-content.code {
   border: none;
   box-shadow: none;
-  margin: 0px;
-  padding: 0px;
+  margin: 0;
+  padding: 0;
   table-layout: fixed;
 
   pre {
diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
index 77a00586b268b890a1830db5fa2dc9e26312ee18..7f7b7c806e71ada444f63d658933777cbb4361f7 100644
--- a/app/assets/stylesheets/framework/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -20,7 +20,7 @@
   display: block;
   float: left;
   margin-right: 10px;
-  color: #FFF;
+  color: #fff;
   font-size: $gl-font-size;
   line-height: 25px;
 
diff --git a/app/assets/stylesheets/framework/jquery.scss b/app/assets/stylesheets/framework/jquery.scss
index 85a6f4b8b5524ff046ddb437e327532706e69673..eb3fbd9155b4041700059b6011ab060216db0da2 100644
--- a/app/assets/stylesheets/framework/jquery.scss
+++ b/app/assets/stylesheets/framework/jquery.scss
@@ -3,13 +3,13 @@
   font-size: $font-size-base;
 
   &.ui-datepicker-inline {
-    border: 1px solid #DDD;
+    border: 1px solid #ddd;
     padding: 10px;
     width: 270px;
 
     .ui-datepicker-header {
-      background: #FFF;
-      border-color: #DDD;
+      background: #fff;
+      border-color: #ddd;
     }
 
     .ui-datepicker-calendar td a {
@@ -52,20 +52,20 @@
   }
 
   .ui-state-default {
-    border: 1px solid #FFF;
-    background: #FFF;
+    border: 1px solid #fff;
+    background: #fff;
     color: #777;
   }
 
   .ui-state-highlight {
-    border: 1px solid #EEE;
-    background: #EEE;
+    border: 1px solid #eee;
+    background: #eee;
   }
 
   .ui-state-active {
     border: 1px solid $gl-primary;
     background: $gl-primary;
-    color: #FFF;
+    color: #fff;
   }
 
   .ui-state-hover,
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index bfec0911b3ca925ba8ba9c13a3271fc029ffdae4..2b4bb1eebf965f60af68b15860bad5660c5f81a3 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -141,6 +141,10 @@ ul.content-list {
   }
 }
 
+.panel > .content-list > li {
+  padding: $gl-padding-top $gl-padding;
+}
+
 ul.controls {
   padding-top: 1px;
   float: right;
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 1d8611b04dcdc4d5b59d6d44784b5942e32a60cf..8328aac4e7adef360155418725894a08bf3b985d 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -71,7 +71,7 @@
 }
 
 .md-preview-holder {
-  background: #FFF;
+  background: #fff;
   border: 1px solid #ddd;
   min-height: 169px;
   padding: 5px;
@@ -80,7 +80,7 @@
 
 .markdown-area {
   @include border-radius(0);
-  background: #FFF;
+  background: #fff;
   border: 1px solid #ddd;
   min-height: 140px;
   max-height: 500px;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 1d5000fe38881cdf5b388ab0ebf35caea083e2f8..377bfa174bd44bddbce7b8619d97184ff3528e59 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -67,17 +67,17 @@
  * Base mixin for lists in GitLab
  */
 @mixin basic-list {
-  margin: 5px 0px;
-  padding: 0px;
+  margin: 5px 0;
+  padding: 0;
   list-style: none;
 
   > li {
     @include clearfix;
 
     padding: 10px 0;
-    border-bottom: 1px solid #EEE;
+    border-bottom: 1px solid #eee;
     display: block;
-    margin: 0px;
+    margin: 0;
 
     &:last-child {
       border-bottom: none;
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 3bfac2ad9b558871a7fef2ea89e75716899b27ca..5ea4f9a49dbf497fb7e8a0c2ea60e3f7c6162954 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -128,12 +128,12 @@
 .show-aside {
   display: none;
   position: fixed;
-  right: 0px;
+  right: 0;
   top: 30%;
   padding: 5px 15px;
-  background: #EEE;
+  background: #eee;
   font-size: 20px;
   color: #777;
   z-index: 100;
-  @include box-shadow(0 1px 2px #DDD);
+  @include box-shadow(0 1px 2px #ddd);
 }
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index b2fbc95e04364662ba462b568d5bd8a9d8f027ef..5f4ce87b085e9fd0d51aa5364f93458d681c9616 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -26,7 +26,7 @@
     }
 
     &.active a {
-      color: #000000;
+      color: #000;
       border-bottom: 2px solid #4688f1;
     }
 
@@ -41,7 +41,7 @@
 .top-area {
   @include clearfix;
 
-  border-bottom: 1px solid #EEE;
+  border-bottom: 1px solid #eee;
 
   .nav-text {
     padding-top: 16px;
@@ -59,7 +59,7 @@
   .nav-links {
     display: inline-block;
     width: 50%;
-    margin-bottom: 0px;
+    margin-bottom: 0;
     border-bottom: none;
 
     /* Small devices (phones, tablets, 768px and lower) */
@@ -74,7 +74,7 @@
     float: right;
     text-align: right;
     padding: 11px 0;
-    margin-bottom: 0px;
+    margin-bottom: 0;
 
     > .dropdown {
       margin-right: $gl-padding-top;
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 7bf04e4ad74b8e9dfe77f35ff6f139ccdb16f224..b3371229d5a55cd0d3c24484526b67b99376e1e0 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -151,7 +151,7 @@
   padding: 2px 25px 2px 5px;
   background: #fff image-url('select2.png');
   background-repeat: no-repeat;
-  background-position: right 0px bottom 6px;
+  background-position: right 0 bottom 6px;
   border: 1px solid $input-border;
   @include border-radius($border-radius-default);
   @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
@@ -229,7 +229,7 @@
 
 .namespace-result {
   .namespace-kind {
-    color: #AAA;
+    color: #aaa;
     font-weight: normal;
   }
   .namespace-path {
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 26df9acd2aeed3fdcf703cd8fff0f27ad45a2a10..be05db58c40d030d202bac790866c5477291f584 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -16,7 +16,7 @@
   .gitlab-text-container-link {
     z-index: 1;
     position: absolute;
-    left: 0px;
+    left: 0;
   }
 
   #logo {
@@ -47,7 +47,7 @@
   width: 100%;
 
   .container-fluid {
-    background: #FFF;
+    background: #fff;
     padding: 0 $gl-padding;
 
     &.container-blank {
@@ -103,7 +103,7 @@
     }
 
     &:hover {
-      background-color: #EEE;
+      background-color: #eee;
     }
   }
 
@@ -143,7 +143,7 @@
   overflow: hidden;
 
   &.navbar-collapse {
-    padding: 0px !important;
+    padding: 0 !important;
   }
 
   li {
@@ -182,7 +182,7 @@
       .count {
         float: right;
         background: #eee;
-        padding: 0px 8px;
+        padding: 0 8px;
         @include border-radius(6px);
       }
 
@@ -194,8 +194,8 @@
 }
 
 .sidebar-subnav {
-  margin-left: 0px;
-  padding-left: 0px;
+  margin-left: 0;
+  padding-left: 0;
 
   li {
     list-style: none;
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index ddf76704a53c3dfb97dad924455d0f07fbd31d56..dd42db1840f35497578ad092008a0e827b182548 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -95,7 +95,7 @@
   }
 
   &.label-inverse {
-    background-color: #333333;
+    background-color: #333;
   }
 }
 
@@ -138,7 +138,7 @@
     }
 
     .btn-clipboard {
-      min-width: 0px;
+      min-width: 0;
     }
   }
 
diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
index b1b8295411b196811de8fcd21aabfeda04c59957..f63ac033234c7a67df31cc4f24032bed9e77864f 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
@@ -57,7 +57,7 @@ $component-active-bg:       $brand-info;
 
 $input-color:                    $text-color;
 $input-border:                   #e7e9ed;
-$input-border-focus:             #7F8FA4;
+$input-border-focus:             #7f8fa4;
 $legend-color:                   $text-color;
 
 
@@ -125,8 +125,8 @@ $panel-inner-border:       $border-color;
 //
 //##
 
-$well-bg:                     #F9F9F9;
-$well-border:                 #EEE;
+$well-bg:                     #f9f9f9;
+$well-border:                 #eee;
 
 //== Code
 //
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 9381cb3281cae9e7da4c643a4c19d7b021410478..949295a1d0cf0984dfb6016a78da5cda47220a34 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -27,13 +27,13 @@
     line-height: 10px;
     color: #555;
     vertical-align: middle;
-    background-color: #FCFCFC;
+    background-color: #fcfcfc;
     border-width: 1px;
     border-style: solid;
-    border-color: #CCC #CCC #BBB;
+    border-color: #ccc #ccc #bbb;
     border-image: none;
     border-radius: 3px;
-    box-shadow: 0px -1px 0px #BBB inset;
+    box-shadow: 0 -1px 0 #bbb inset;
   }
 
   h1 {
@@ -187,7 +187,7 @@ body {
 }
 
 .page-title-empty {
-  margin-top: 0px;
+  margin-top: 0;
   line-height: 1.3;
   font-size: 1.25em;
   font-weight: 600;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index d491d01a3cf4ef9a074af0bcf1fa32a3795a3a47..d455a3d8e29f5f5692ca2eb170b2675feffe6fa8 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -1,53 +1,82 @@
-$row-hover: #f4f8fe;
-$gl-text-color: #54565B;
-$gl-text-green: #4A2;
-$gl-text-red: #D12F19;
-$gl-text-orange: #D90;
-$gl-header-color: #323232;
-$gl-link-color: #333c48;
-$md-text-color: #444;
-$md-link-color: #3084bb;
-$progress-color: #c0392b;
-$gl-font-size: 15px;
-$list-font-size: 15px;
+/*
+ * Layout
+ */
 $sidebar_collapsed_width: 62px;
 $sidebar_width: 230px;
 $gutter_collapsed_width: 62px;
 $gutter_width: 290px;
 $gutter_inner_width: 258px;
-$avatar_radius: 50%;
-$code_font_size: 13px;
-$code_line_height: 1.5;
+
+/*
+ * UI elements
+ */
 $border-color: #efeff1;
 $table-border-color: #eef0f2;
 $background-color: #faf9f9;
-$header-height: 58px;
-$fixed-layout-width: 1280px;
-$gl-gray: #5a5a5a;
+
+/*
+ * Text
+ */
+$gl-font-size: 15px;
+$gl-title-color: #333;
+$gl-text-color: #555;
+$gl-placeholder-color: #8f8f8f;
+$gl-text-green: #4a2;
+$gl-text-red: #d12f19;
+$gl-text-orange: #d90;
+$gl-header-color: $gl-title-color;
+$gl-link-color: #333c48;
+$gl-gray: $gl-text-color;
+
+/*
+ * Lists
+ */
+$list-font-size: $gl-font-size;
+$list-title-color: $gl-title-color;
+$list-text-color: $gl-text-color;
+
+/*
+ * Markdown
+ */
+$md-text-color: #444;
+$md-link-color: #3084bb;
+
+/*
+ * Code
+ */
+$code_font_size: 13px;
+$code_line_height: 1.5;
+
+/*
+ * Padding
+ */
 $gl-padding: 16px;
 $gl-btn-padding: 10px;
 $gl-vert-padding: 6px;
-$gl-padding-top:10px;
+$gl-padding-top: 10px;
+
+/*
+ * Misc
+ */
+$row-hover: #f4f8fe;
+$progress-color: #c0392b;
+$avatar_radius: 50%;
+$header-height: 58px;
+$fixed-layout-width: 1280px;
 $gl-avatar-size: 40px;
-$secondary-text: #7f8fa4;
-$error-exclamation-point: #E62958;
+$error-exclamation-point: #e62958;
 $border-radius-default: 3px;
-$list-title-color: #333333;
-$list-text-color: #555555;
-
-$btn-transparent-color: #8F8F8F;
-
-$ssh-key-icon-color: #8F8F8F;
+$btn-transparent-color: #8f8f8f;
+$ssh-key-icon-color: #8f8f8f;
 $ssh-key-icon-size: 18px;
-
-$provider-btn-group-border: #E5E5E5;
-$provider-btn-not-active-color: #4688F1;
+$provider-btn-group-border: #e5e5e5;
+$provider-btn-not-active-color: #4688f1;
 
 /*
  * Color schema
  */
 
-$white-light: #FFFFFF;
+$white-light: #fff;
 $white-normal: #ededed;
 $white-dark: #ededed;
 
@@ -57,55 +86,55 @@ $gray-dark: #ededed;
 $gray-darkest: #c9c9c9;
 
 $green-light: #38ae67;
-$green-normal: #2FAA60;
-$green-dark: #2CA05B;
+$green-normal: #2faa60;
+$green-dark: #2ca05b;
 
-$blue-light: #2EA8E5;
-$blue-normal: #2D9FD8;
-$blue-dark: #2897CE;
+$blue-light: #2ea8e5;
+$blue-normal: #2d9fd8;
+$blue-dark: #2897ce;
 
-$blue-medium-light: #3498CB;
-$blue-medium: #2F8EBF;
-$blue-medium-dark: #2D86B4;
+$blue-medium-light: #3498cb;
+$blue-medium: #2f8ebf;
+$blue-medium-dark: #2d86b4;
 
 $orange-light: rgba(252, 109, 38, 0.80);
-$orange-normal: #E75E40;
-$orange-dark: #CE5237;
+$orange-normal: #e75e40;
+$orange-dark: #ce5237;
 
-$red-light: #F06559;
-$red-normal: #E52C5A;
-$red-dark: #D22852;
+$red-light: #f06559;
+$red-normal: #e52c5a;
+$red-dark: #d22852;
 
-$border-white-light: #F1F2F4;
-$border-white-normal: #D6DAE2;
-$border-white-dark: #C6CACF;
+$border-white-light: #f1f2f4;
+$border-white-normal: #d6dae2;
+$border-white-dark: #c6cacf;
 
 $border-gray-light: rgba(0, 0, 0, 0.06);
 $border-gray-normal: rgba(0, 0, 0, 0.10);;
-$border-gray-dark: #C6CACF;
+$border-gray-dark: #c6cacf;
 
-$border-green-light: #2FAA60;
-$border-green-normal: #2CA05B;
+$border-green-light: #2faa60;
+$border-green-normal: #2ca05b;
 $border-green-dark: #279654;
 
-$border-blue-light: #2D9FD8;
-$border-blue-normal: #2897CE;
-$border-blue-dark: #258DC1;
+$border-blue-light: #2d9fd8;
+$border-blue-normal: #2897ce;
+$border-blue-dark: #258dc1;
 
 $border-orange-light: #fc6d26;
-$border-orange-normal: #CE5237;
-$border-orange-dark: #C14E35;
+$border-orange-normal: #ce5237;
+$border-orange-dark: #c14e35;
 
-$border-red-light: #F24F41;
-$border-red-normal: #D22852;
-$border-red-dark: #CA264F;
+$border-red-light: #f24f41;
+$border-red-normal: #d22852;
+$border-red-dark: #ca264f;
 
-$help-well-bg: #FAFAFA;
-$help-well-border: #E5E5E5;
+$help-well-bg: #fafafa;
+$help-well-border: #e5e5e5;
 
-$warning-message-bg: #FBF2D9;
-$warning-message-color: #9E8E60;
-$warning-message-border: #F0E2BB;
+$warning-message-bg: #fbf2d9;
+$warning-message-color: #9e8e60;
+$warning-message-border: #f0e2bb;
 
 /* header */
 $light-grey-header: #faf9f9;
@@ -143,23 +172,22 @@ $dropdown-border-color: rgba(#000, .1);
 $dropdown-shadow-color: rgba(#000, .1);
 $dropdown-divider-color: rgba(#000, .1);
 $dropdown-header-color: #959494;
-$dropdown-caret-color: #54565B;
-$dropdown-title-btn-color: #BFBFBF;
-$dropdown-input-color: #C7C7C7;
+$dropdown-title-btn-color: #bfbfbf;
+$dropdown-input-color: #c7c7c7;
 $dropdown-input-focus-border: rgb(58, 171, 240);
 $dropdown-input-focus-shadow: rgba(#000, .2);
 $dropdown-loading-bg: rgba(#fff, .6);
 
 $dropdown-toggle-bg: #fff;
 $dropdown-toggle-color: #626262;
-$dropdown-toggle-border-color: #EAEAEA;
+$dropdown-toggle-border-color: #eaeaea;
 $dropdown-toggle-hover-border-color: darken($dropdown-toggle-border-color, 15%);
-$dropdown-toggle-icon-color: #C4C4C4;
+$dropdown-toggle-icon-color: #c4c4c4;
 $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color;
 
 /*
  *  Award emoji
  */
-$award-emoji-menu-bg: #FFF;
-$award-emoji-menu-border: #F1F2F4;
-$award-emoji-new-btn-icon-color: #DCDCDC;
+$award-emoji-menu-bg: #fff;
+$award-emoji-menu-border: #f1f2f4;
+$award-emoji-new-btn-icon-color: #dcdcdc;
diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss
index c3f27333fadab1570a73a4379e9fe801b0b02f26..02e24ec7c4d59bb78387ace8c61e5d1d433060c4 100644
--- a/app/assets/stylesheets/framework/zen.scss
+++ b/app/assets/stylesheets/framework/zen.scss
@@ -2,7 +2,7 @@
   a.js-zen-enter {
     color: $gl-gray;
     position: absolute;
-    top: 0px;
+    top: 0;
     right: 4px;
     line-height: 56px;
   }
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index b794da2ce9805cd477eb62c9e95174754aca6014..47673944896f2e9d49877781ba88a8645915c677 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -43,12 +43,12 @@
   // Search result highlight
   span.highlight_word {
     background-color: #ffe792 !important;
-    color: #000000 !important;
+    color: #000 !important;
   }
 
   .hll { background-color: #373b41 }
   .c { color: #969896 } /* Comment */
-  .err { color: #cc6666 } /* Error */
+  .err { color: #c66 } /* Error */
   .k { color: #b294bb } /* Keyword */
   .l { color: #de935f } /* Literal */
   .n { color: #c5c8c6 } /* Name */
@@ -58,7 +58,7 @@
   .cp { color: #969896 } /* Comment.Preproc */
   .c1 { color: #969896 } /* Comment.Single */
   .cs { color: #969896 } /* Comment.Special */
-  .gd { color: #cc6666 } /* Generic.Deleted */
+  .gd { color: #c66 } /* Generic.Deleted */
   .ge { font-style: italic } /* Generic.Emph */
   .gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */
   .gi { color: #b5bd68 } /* Generic.Inserted */
@@ -77,17 +77,17 @@
   .na { color: #81a2be } /* Name.Attribute */
   .nb { color: #c5c8c6 } /* Name.Builtin */
   .nc { color: #f0c674 } /* Name.Class */
-  .no { color: #cc6666 } /* Name.Constant */
+  .no { color: #c66 } /* Name.Constant */
   .nd { color: #8abeb7 } /* Name.Decorator */
   .ni { color: #c5c8c6 } /* Name.Entity */
-  .ne { color: #cc6666 } /* Name.Exception */
+  .ne { color: #c66 } /* Name.Exception */
   .nf { color: #81a2be } /* Name.Function */
   .nl { color: #c5c8c6 } /* Name.Label */
   .nn { color: #f0c674 } /* Name.Namespace */
   .nx { color: #81a2be } /* Name.Other */
   .py { color: #c5c8c6 } /* Name.Property */
   .nt { color: #8abeb7 } /* Name.Tag */
-  .nv { color: #cc6666 } /* Name.Variable */
+  .nv { color: #c66 } /* Name.Variable */
   .ow { color: #8abeb7 } /* Operator.Word */
   .w { color: #c5c8c6 } /* Text.Whitespace */
   .mf { color: #de935f } /* Literal.Number.Float */
@@ -106,8 +106,8 @@
   .s1 { color: #b5bd68 } /* Literal.String.Single */
   .ss { color: #b5bd68 } /* Literal.String.Symbol */
   .bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */
-  .vc { color: #cc6666 } /* Name.Variable.Class */
-  .vg { color: #cc6666 } /* Name.Variable.Global */
-  .vi { color: #cc6666 } /* Name.Variable.Instance */
+  .vc { color: #c66 } /* Name.Variable.Class */
+  .vg { color: #c66 } /* Name.Variable.Global */
+  .vi { color: #c66 } /* Name.Variable.Instance */
   .il { color: #de935f } /* Literal.Number.Integer.Long */
 }
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 9098e07adcd793aad582ea01bf9b2e6c42837a29..806401c21ae603b7c11273dd4e96263c5933e5a0 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -43,7 +43,7 @@
   // Search result highlight
   span.highlight_word {
     background-color: #ffe792 !important;
-    color: #000000 !important;
+    color: #000 !important;
   }
 
   .hll { background-color: #49483e }
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 8b1a2824f76c78bffd35f8ddef42caa37f17241f..6a809d4dfd26658060e0acb83f6e60e8658bd33f 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -96,7 +96,7 @@
   .m { color: #2aa198 } /* Literal.Number */
   .s { color: #2aa198 } /* Literal.String */
   .na { color: #93a1a1 } /* Name.Attribute */
-  .nb { color: #B58900 } /* Name.Builtin */
+  .nb { color: #b58900 } /* Name.Builtin */
   .nc { color: #268bd2 } /* Name.Class */
   .no { color: #cb4b16 } /* Name.Constant */
   .nd { color: #268bd2 } /* Name.Decorator */
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 7ad89dd2c7c3ae0acb7cf141ccdf93b831652658..b90c95c62d1378d1e9d3db0ce684b6c23321b452 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -96,7 +96,7 @@
   .m { color: #2aa198 } /* Literal.Number */
   .s { color: #2aa198 } /* Literal.String */
   .na { color: #586e75 } /* Name.Attribute */
-  .nb { color: #B58900 } /* Name.Builtin */
+  .nb { color: #b58900 } /* Name.Builtin */
   .nc { color: #268bd2 } /* Name.Class */
   .no { color: #cb4b16 } /* Name.Constant */
   .nd { color: #268bd2 } /* Name.Decorator */
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 8a091028a6c6df8ea29739e3115c0a457d8b57a8..8c1b0cd84ecc84beb82d6f71c312dde55f8414c3 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -23,7 +23,7 @@
   .line_holder {
     .diff-line-num {
       &.old {
-        background: #ffdddd;
+        background: #fdd;
         border-color: #f1c0c0;
       }
 
@@ -68,66 +68,66 @@
   }
 
   .hll { background-color: #f8f8f8 }
-  .c { color: #999988; font-style: italic; }
+  .c { color: #998; font-style: italic; }
   .err { color: #a61717; background-color: #e3d2d2; }
   .k { font-weight: bold; }
   .o { font-weight: bold; }
-  .cm { color: #999988; font-style: italic; }
-  .cp { color: #999999; font-weight: bold; }
-  .c1 { color: #999988; font-style: italic; }
-  .cs { color: #999999; font-weight: bold; font-style: italic; }
-  .gd { color: #000000; background-color: #ffdddd; }
-  .gd .x { color: #000000; background-color: #ffaaaa; }
+  .cm { color: #998; font-style: italic; }
+  .cp { color: #999; font-weight: bold; }
+  .c1 { color: #998; font-style: italic; }
+  .cs { color: #999; font-weight: bold; font-style: italic; }
+  .gd { color: #000; background-color: #fdd; }
+  .gd .x { color: #000; background-color: #faa; }
   .ge { font-style: italic; }
-  .gr { color: #aa0000; }
-  .gh { color: #999999; }
-  .gi { color: #000000; background-color: #ddffdd; }
-  .gi .x { color: #000000; background-color: #aaffaa; }
-  .go { color: #888888; }
-  .gp { color: #555555; }
+  .gr { color: #a00; }
+  .gh { color: #999; }
+  .gi { color: #000; background-color: #dfd; }
+  .gi .x { color: #000; background-color: #afa; }
+  .go { color: #888; }
+  .gp { color: #555; }
   .gs { font-weight: bold; }
   .gu { color: #800080; font-weight: bold; }
-  .gt { color: #aa0000; }
+  .gt { color: #a00; }
   .kc { font-weight: bold; }
   .kd { font-weight: bold; }
   .kn { font-weight: bold; }
   .kp { font-weight: bold; }
   .kr { font-weight: bold; }
-  .kt { color: #445588; font-weight: bold; }
-  .m { color: #009999; }
-  .s { color: #dd1144; }
-  .n { color: #333333; }
+  .kt { color: #458; font-weight: bold; }
+  .m { color: #099; }
+  .s { color: #d14; }
+  .n { color: #333; }
   .na { color: teal; }
   .nb { color: #0086b3; }
-  .nc { color: #445588; font-weight: bold; }
+  .nc { color: #458; font-weight: bold; }
   .no { color: teal; }
   .ni { color: purple; }
-  .ne { color: #990000; font-weight: bold; }
-  .nf { color: #990000; font-weight: bold; }
-  .nn { color: #555555; }
+  .ne { color: #900; font-weight: bold; }
+  .nf { color: #900; font-weight: bold; }
+  .nn { color: #555; }
   .nt { color: navy; }
   .nv { color: teal; }
   .ow { font-weight: bold; }
-  .w { color: #bbbbbb; }
-  .mf { color: #009999; }
-  .mh { color: #009999; }
-  .mi { color: #009999; }
-  .mo { color: #009999; }
-  .sb { color: #dd1144; }
-  .sc { color: #dd1144; }
-  .sd { color: #dd1144; }
-  .s2 { color: #dd1144; }
-  .se { color: #dd1144; }
-  .sh { color: #dd1144; }
-  .si { color: #dd1144; }
-  .sx { color: #dd1144; }
+  .w { color: #bbb; }
+  .mf { color: #099; }
+  .mh { color: #099; }
+  .mi { color: #099; }
+  .mo { color: #099; }
+  .sb { color: #d14; }
+  .sc { color: #d14; }
+  .sd { color: #d14; }
+  .s2 { color: #d14; }
+  .se { color: #d14; }
+  .sh { color: #d14; }
+  .si { color: #d14; }
+  .sx { color: #d14; }
   .sr { color: #009926; }
-  .s1 { color: #dd1144; }
+  .s1 { color: #d14; }
   .ss { color: #990073; }
-  .bp { color: #999999; }
+  .bp { color: #999; }
   .vc { color: teal; }
   .vg { color: teal; }
   .vi { color: teal; }
-  .il { color: #009999; }
-  .gc { color: #999; background-color: #EAF2F5; }
+  .il { color: #099; }
+  .gc { color: #999; background-color: #eaf2f5; }
 }
diff --git a/app/assets/stylesheets/pages/appearances.scss b/app/assets/stylesheets/pages/appearances.scss
index e2070f17c3b1abbaa72230043eeef61327612236..878f44116ba11ab6653740144ba853efd6f37b62 100644
--- a/app/assets/stylesheets/pages/appearances.scss
+++ b/app/assets/stylesheets/pages/appearances.scss
@@ -4,7 +4,7 @@
 }
 
 .appearance-light-logo-preview {
-  background-color:  $background-color;
+  background-color: $background-color;
   max-width: 72px;
   padding: 10px;
   margin-bottom: 10px;
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 75f298019e32af333ebfd5525044093a1a05b28b..201f3e5ca46124f5cd4e4913fe5f89febb98e560 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -1,6 +1,6 @@
 .build-page {
   pre.trace {
-    background: #111111;
+    background: #111;
     color: #fff;
     font-family: $monospace_font;
     white-space: pre;
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index c0cc30d33a64a44a63070b25e03c7dbb44114cbe..971656feb42782d0082158da1e250eaa7385cd00 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -55,7 +55,7 @@
     padding: 10px 0;
 
     li {
-      padding: 3px 0px;
+      padding: 3px 0;
       line-height: 20px;
     }
   }
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 818fd03e2ae21164dcd37dc66136a14f0c19222e..d57be1b2daa97fdbef1f4c8b75f194c8d1867dce 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -9,7 +9,7 @@
 
 .lists-separator {
   margin: 10px 0;
-  border-color: #DDD;
+  border-color: #ddd;
 }
 
 .commits-row {
@@ -76,7 +76,7 @@ li.commit {
 
   .commit-row-description {
     font-size: 14px;
-    border-left: 1px solid #EEE;
+    border-left: 1px solid #eee;
     padding: 10px 15px;
     margin: 5px 0 10px 5px;
     background: #f9f9f9;
@@ -152,7 +152,7 @@ li.commit {
 
     .count {
       padding-top: 6px;
-      padding-bottom: 0px;
+      padding-bottom: 0;
       font-size: 12px;
       color: #333;
       display: block;
diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss
index 886393991485e70f31c724f0c0ad2511098c5309..cf7567513ec6945aedfcc6f883a007af3b871e8a 100644
--- a/app/assets/stylesheets/pages/dashboard.scss
+++ b/app/assets/stylesheets/pages/dashboard.scss
@@ -11,15 +11,15 @@
 }
 
 .dashboard-search-filter {
-  padding:5px;
+  padding: 5px;
 
   .search-text-input {
-    float:left;
+    float: left;
     @extend .col-md-2;
   }
   .btn {
     margin-left: 5px;
-    float:left;
+    float: left;
   }
 }
 
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index a7925e795499e76698d33f4a628f911384f1c39c..d5862a11aca52948e2c52781fcfe738a1acf2a94 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -1,7 +1,7 @@
 // Common
 .diff-file {
   border: 1px solid $border-color;
-  border-top: none;
+  margin-bottom: $gl-padding;
 
   .diff-header {
     position: relative;
@@ -29,7 +29,7 @@
   .diff-content {
     overflow: auto;
     overflow-y: hidden;
-    background: #FFF;
+    background: #fff;
     color: #333;
 
     .unfold {
@@ -57,8 +57,8 @@
       font-family: $monospace_font;
       border: none;
       border-collapse: separate;
-      margin: 0px;
-      padding: 0px;
+      margin: 0;
+      padding: 0;
       .line_holder td {
         line-height: $code_line_height;
         font-size: $code_font_size;
@@ -76,10 +76,10 @@
     }
 
     .old_line, .new_line {
-      margin: 0px;
-      padding: 0px;
+      margin: 0;
+      padding: 0;
       border: none;
-      padding: 0px 5px;
+      padding: 0 5px;
       border-right: 1px solid;
       text-align: right;
       min-width: 35px;
@@ -97,8 +97,8 @@
     }
     .line_content {
       display: block;
-      margin: 0px;
-      padding: 0px 0.5em;
+      margin: 0;
+      padding: 0 0.5em;
       border: none;
       &.parallel {
         display: table-cell;
@@ -118,7 +118,7 @@
       background-color: #fff;
       line-height: 0;
       img {
-        border: 1px solid #FFF;
+        border: 1px solid #fff;
         background: image-url('trans_bg.gif');
         max-width: 100%;
       }
@@ -183,7 +183,7 @@
           height: 14px;
           width: 15px;
           position: absolute;
-          top: 0px;
+          top: 0;
           background: image-url('swipemode_sprites.gif') 0 3px no-repeat;
         }
         .bottom-handle {
@@ -191,7 +191,7 @@
           height: 14px;
           width: 15px;
           position: absolute;
-          bottom: 0px;
+          bottom: 0;
           background: image-url('swipemode_sprites.gif') 0 -11px no-repeat;
         }
       }
@@ -206,8 +206,8 @@
       .frame.added, .frame.deleted {
         position: absolute;
         display: block;
-        top: 0px;
-        left: 0px;
+        top: 0;
+        left: 0;
       }
       .controls {
         display: block;
@@ -215,7 +215,7 @@
         width: 300px;
         z-index: 100;
         position: absolute;
-        bottom: 0px;
+        bottom: 0;
         left: 50%;
         margin-left: -150px;
 
@@ -231,11 +231,11 @@
         .dragger {
           display: block;
           position: absolute;
-          left: 0px;
-          top: 0px;
+          left: 0;
+          top: 0;
           height: 14px;
           width: 14px;
-          background: image-url('onion_skin_sprites.gif') 0px -34px repeat-x;
+          background: image-url('onion_skin_sprites.gif') 0 -34px repeat-x;
           cursor: pointer;
         }
 
@@ -243,17 +243,17 @@
           display: block;
           position: absolute;
           top: 2px;
-          right: 0px;
+          right: 0;
           height: 10px;
           width: 10px;
-          background: image-url('onion_skin_sprites.gif') -2px 0px no-repeat;
+          background: image-url('onion_skin_sprites.gif') -2px 0 no-repeat;
         }
 
         .opaque {
           display: block;
           position: absolute;
           top: 2px;
-          left: 0px;
+          left: 0;
           height: 10px;
           width: 10px;
           background: image-url('onion_skin_sprites.gif') -2px -10px no-repeat;
@@ -265,7 +265,7 @@
   .view-modes {
     padding: 10px;
     text-align: center;
-    background: #EEE;
+    background: #eee;
 
     ul, li {
       list-style: none;
@@ -361,3 +361,11 @@
     border-color: $border;
   }
 }
+
+.files {
+  margin-top: -1px;
+
+  .diff-file:last-child {
+    margin-bottom: 0;
+  }
+}
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 39d916cd336002e58b8a7896935a2281553dc317..43be5e38ba810b000ba9c46b12921c34da40eeb2 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -14,9 +14,9 @@
   }
 
   .cancel-btn {
-    color: #B94A48;
+    color: #b94a48;
     &:hover {
-      color: #B94A48;
+      color: #b94a48;
     }
   }
 
diff --git a/app/assets/stylesheets/pages/emojis.scss b/app/assets/stylesheets/pages/emojis.scss
index 6c721b514f826eee338b169875a88ebeb31cf3be..b731abc7450aa4cec8efe9bb2eacbd805a9f10f1 100644
--- a/app/assets/stylesheets/pages/emojis.scss
+++ b/app/assets/stylesheets/pages/emojis.scss
@@ -1,60 +1,60 @@
-.emoji-0023-20E3 { background-position: 0px 0px; }
-.emoji-002A-20E3 { background-position: -20px 0px; }
-.emoji-0030-20E3 { background-position: 0px -20px; }
+.emoji-0023-20E3 { background-position: 0 0; }
+.emoji-002A-20E3 { background-position: -20px 0; }
+.emoji-0030-20E3 { background-position: 0 -20px; }
 .emoji-0031-20E3 { background-position: -20px -20px; }
-.emoji-0032-20E3 { background-position: -40px 0px; }
+.emoji-0032-20E3 { background-position: -40px 0; }
 .emoji-0033-20E3 { background-position: -40px -20px; }
-.emoji-0034-20E3 { background-position: 0px -40px; }
+.emoji-0034-20E3 { background-position: 0 -40px; }
 .emoji-0035-20E3 { background-position: -20px -40px; }
 .emoji-0036-20E3 { background-position: -40px -40px; }
-.emoji-0037-20E3 { background-position: -60px 0px; }
+.emoji-0037-20E3 { background-position: -60px 0; }
 .emoji-0038-20E3 { background-position: -60px -20px; }
 .emoji-0039-20E3 { background-position: -60px -40px; }
-.emoji-00A9 { background-position: 0px -60px; }
+.emoji-00A9 { background-position: 0 -60px; }
 .emoji-00AE { background-position: -20px -60px; }
 .emoji-1F004 { background-position: -40px -60px; }
 .emoji-1F0CF { background-position: -60px -60px; }
-.emoji-1F170 { background-position: -80px 0px; }
+.emoji-1F170 { background-position: -80px 0; }
 .emoji-1F171 { background-position: -80px -20px; }
 .emoji-1F17E { background-position: -80px -40px; }
 .emoji-1F17F { background-position: -80px -60px; }
-.emoji-1F18E { background-position: 0px -80px; }
+.emoji-1F18E { background-position: 0 -80px; }
 .emoji-1F191 { background-position: -20px -80px; }
 .emoji-1F192 { background-position: -40px -80px; }
 .emoji-1F193 { background-position: -60px -80px; }
 .emoji-1F194 { background-position: -80px -80px; }
-.emoji-1F195 { background-position: -100px 0px; }
+.emoji-1F195 { background-position: -100px 0; }
 .emoji-1F196 { background-position: -100px -20px; }
 .emoji-1F197 { background-position: -100px -40px; }
 .emoji-1F198 { background-position: -100px -60px; }
 .emoji-1F199 { background-position: -100px -80px; }
-.emoji-1F19A { background-position: 0px -100px; }
+.emoji-1F19A { background-position: 0 -100px; }
 .emoji-1F1E6-1F1E8 { background-position: -20px -100px; }
 .emoji-1F1E6-1F1E9 { background-position: -40px -100px; }
 .emoji-1F1E6-1F1EA { background-position: -60px -100px; }
 .emoji-1F1E6-1F1EB { background-position: -80px -100px; }
 .emoji-1F1E6-1F1EC { background-position: -100px -100px; }
-.emoji-1F1E6-1F1EE { background-position: -120px 0px; }
+.emoji-1F1E6-1F1EE { background-position: -120px 0; }
 .emoji-1F1E6-1F1F1 { background-position: -120px -20px; }
 .emoji-1F1E6-1F1F2 { background-position: -120px -40px; }
 .emoji-1F1E6-1F1F4 { background-position: -120px -60px; }
 .emoji-1F1E6-1F1F6 { background-position: -120px -80px; }
 .emoji-1F1E6-1F1F7 { background-position: -120px -100px; }
-.emoji-1F1E6-1F1F8 { background-position: 0px -120px; }
+.emoji-1F1E6-1F1F8 { background-position: 0 -120px; }
 .emoji-1F1E6-1F1F9 { background-position: -20px -120px; }
 .emoji-1F1E6-1F1FA { background-position: -40px -120px; }
 .emoji-1F1E6-1F1FC { background-position: -60px -120px; }
 .emoji-1F1E6-1F1FD { background-position: -80px -120px; }
 .emoji-1F1E6-1F1FF { background-position: -100px -120px; }
 .emoji-1F1E7-1F1E6 { background-position: -120px -120px; }
-.emoji-1F1E7-1F1E7 { background-position: -140px 0px; }
+.emoji-1F1E7-1F1E7 { background-position: -140px 0; }
 .emoji-1F1E7-1F1E9 { background-position: -140px -20px; }
 .emoji-1F1E7-1F1EA { background-position: -140px -40px; }
 .emoji-1F1E7-1F1EB { background-position: -140px -60px; }
 .emoji-1F1E7-1F1EC { background-position: -140px -80px; }
 .emoji-1F1E7-1F1ED { background-position: -140px -100px; }
 .emoji-1F1E7-1F1EE { background-position: -140px -120px; }
-.emoji-1F1E7-1F1EF { background-position: 0px -140px; }
+.emoji-1F1E7-1F1EF { background-position: 0 -140px; }
 .emoji-1F1E7-1F1F1 { background-position: -20px -140px; }
 .emoji-1F1E7-1F1F2 { background-position: -40px -140px; }
 .emoji-1F1E7-1F1F3 { background-position: -60px -140px; }
@@ -62,7 +62,7 @@
 .emoji-1F1E7-1F1F6 { background-position: -100px -140px; }
 .emoji-1F1E7-1F1F7 { background-position: -120px -140px; }
 .emoji-1F1E7-1F1F8 { background-position: -140px -140px; }
-.emoji-1F1E7-1F1F9 { background-position: -160px 0px; }
+.emoji-1F1E7-1F1F9 { background-position: -160px 0; }
 .emoji-1F1E7-1F1FB { background-position: -160px -20px; }
 .emoji-1F1E7-1F1FC { background-position: -160px -40px; }
 .emoji-1F1E7-1F1FE { background-position: -160px -60px; }
@@ -70,7 +70,7 @@
 .emoji-1F1E8-1F1E6 { background-position: -160px -100px; }
 .emoji-1F1E8-1F1E8 { background-position: -160px -120px; }
 .emoji-1F1E8-1F1E9 { background-position: -160px -140px; }
-.emoji-1F1E8-1F1EB { background-position: 0px -160px; }
+.emoji-1F1E8-1F1EB { background-position: 0 -160px; }
 .emoji-1F1E8-1F1EC { background-position: -20px -160px; }
 .emoji-1F1E8-1F1ED { background-position: -40px -160px; }
 .emoji-1F1E8-1F1EE { background-position: -60px -160px; }
@@ -79,7 +79,7 @@
 .emoji-1F1E8-1F1F2 { background-position: -120px -160px; }
 .emoji-1F1E8-1F1F3 { background-position: -140px -160px; }
 .emoji-1F1E8-1F1F4 { background-position: -160px -160px; }
-.emoji-1F1E8-1F1F5 { background-position: -180px 0px; }
+.emoji-1F1E8-1F1F5 { background-position: -180px 0; }
 .emoji-1F1E8-1F1F7 { background-position: -180px -20px; }
 .emoji-1F1E8-1F1FA { background-position: -180px -40px; }
 .emoji-1F1E8-1F1FB { background-position: -180px -60px; }
@@ -88,7 +88,7 @@
 .emoji-1F1E8-1F1FE { background-position: -180px -120px; }
 .emoji-1F1E8-1F1FF { background-position: -180px -140px; }
 .emoji-1F1E9-1F1EA { background-position: -180px -160px; }
-.emoji-1F1E9-1F1EC { background-position: 0px -180px; }
+.emoji-1F1E9-1F1EC { background-position: 0 -180px; }
 .emoji-1F1E9-1F1EF { background-position: -20px -180px; }
 .emoji-1F1E9-1F1F0 { background-position: -40px -180px; }
 .emoji-1F1E9-1F1F2 { background-position: -60px -180px; }
@@ -98,7 +98,7 @@
 .emoji-1F1EA-1F1E8 { background-position: -140px -180px; }
 .emoji-1F1EA-1F1EA { background-position: -160px -180px; }
 .emoji-1F1EA-1F1EC { background-position: -180px -180px; }
-.emoji-1F1EA-1F1ED { background-position: -200px 0px; }
+.emoji-1F1EA-1F1ED { background-position: -200px 0; }
 .emoji-1F1EA-1F1F7 { background-position: -200px -20px; }
 .emoji-1F1EA-1F1F8 { background-position: -200px -40px; }
 .emoji-1F1EA-1F1F9 { background-position: -200px -60px; }
@@ -108,7 +108,7 @@
 .emoji-1F1EB-1F1F0 { background-position: -200px -140px; }
 .emoji-1F1EB-1F1F2 { background-position: -200px -160px; }
 .emoji-1F1EB-1F1F4 { background-position: -200px -180px; }
-.emoji-1F1EB-1F1F7 { background-position: 0px -200px; }
+.emoji-1F1EB-1F1F7 { background-position: 0 -200px; }
 .emoji-1F1EC-1F1E6 { background-position: -20px -200px; }
 .emoji-1F1EC-1F1E7 { background-position: -40px -200px; }
 .emoji-1F1EC-1F1E9 { background-position: -60px -200px; }
@@ -119,7 +119,7 @@
 .emoji-1F1EC-1F1EE { background-position: -160px -200px; }
 .emoji-1F1EC-1F1F1 { background-position: -180px -200px; }
 .emoji-1F1EC-1F1F2 { background-position: -200px -200px; }
-.emoji-1F1EC-1F1F3 { background-position: -220px 0px; }
+.emoji-1F1EC-1F1F3 { background-position: -220px 0; }
 .emoji-1F1EC-1F1F5 { background-position: -220px -20px; }
 .emoji-1F1EC-1F1F6 { background-position: -220px -40px; }
 .emoji-1F1EC-1F1F7 { background-position: -220px -60px; }
@@ -130,7 +130,7 @@
 .emoji-1F1EC-1F1FE { background-position: -220px -160px; }
 .emoji-1F1ED-1F1F0 { background-position: -220px -180px; }
 .emoji-1F1ED-1F1F2 { background-position: -220px -200px; }
-.emoji-1F1ED-1F1F3 { background-position: 0px -220px; }
+.emoji-1F1ED-1F1F3 { background-position: 0 -220px; }
 .emoji-1F1ED-1F1F7 { background-position: -20px -220px; }
 .emoji-1F1ED-1F1F9 { background-position: -40px -220px; }
 .emoji-1F1ED-1F1FA { background-position: -60px -220px; }
@@ -142,7 +142,7 @@
 .emoji-1F1EE-1F1F3 { background-position: -180px -220px; }
 .emoji-1F1EE-1F1F4 { background-position: -200px -220px; }
 .emoji-1F1EE-1F1F6 { background-position: -220px -220px; }
-.emoji-1F1EE-1F1F7 { background-position: -240px 0px; }
+.emoji-1F1EE-1F1F7 { background-position: -240px 0; }
 .emoji-1F1EE-1F1F8 { background-position: -240px -20px; }
 .emoji-1F1EE-1F1F9 { background-position: -240px -40px; }
 .emoji-1F1EF-1F1EA { background-position: -240px -60px; }
@@ -154,7 +154,7 @@
 .emoji-1F1F0-1F1ED { background-position: -240px -180px; }
 .emoji-1F1F0-1F1EE { background-position: -240px -200px; }
 .emoji-1F1F0-1F1F2 { background-position: -240px -220px; }
-.emoji-1F1F0-1F1F3 { background-position: 0px -240px; }
+.emoji-1F1F0-1F1F3 { background-position: 0 -240px; }
 .emoji-1F1F0-1F1F5 { background-position: -20px -240px; }
 .emoji-1F1F0-1F1F7 { background-position: -40px -240px; }
 .emoji-1F1F0-1F1FC { background-position: -60px -240px; }
@@ -167,7 +167,7 @@
 .emoji-1F1F1-1F1F0 { background-position: -200px -240px; }
 .emoji-1F1F1-1F1F7 { background-position: -220px -240px; }
 .emoji-1F1F1-1F1F8 { background-position: -240px -240px; }
-.emoji-1F1F1-1F1F9 { background-position: -260px 0px; }
+.emoji-1F1F1-1F1F9 { background-position: -260px 0; }
 .emoji-1F1F1-1F1FA { background-position: -260px -20px; }
 .emoji-1F1F1-1F1FB { background-position: -260px -40px; }
 .emoji-1F1F1-1F1FE { background-position: -260px -60px; }
@@ -180,7 +180,7 @@
 .emoji-1F1F2-1F1ED { background-position: -260px -200px; }
 .emoji-1F1F2-1F1F0 { background-position: -260px -220px; }
 .emoji-1F1F2-1F1F1 { background-position: -260px -240px; }
-.emoji-1F1F2-1F1F2 { background-position: 0px -260px; }
+.emoji-1F1F2-1F1F2 { background-position: 0 -260px; }
 .emoji-1F1F2-1F1F3 { background-position: -20px -260px; }
 .emoji-1F1F2-1F1F4 { background-position: -40px -260px; }
 .emoji-1F1F2-1F1F5 { background-position: -60px -260px; }
@@ -194,7 +194,7 @@
 .emoji-1F1F2-1F1FD { background-position: -220px -260px; }
 .emoji-1F1F2-1F1FE { background-position: -240px -260px; }
 .emoji-1F1F2-1F1FF { background-position: -260px -260px; }
-.emoji-1F1F3-1F1E6 { background-position: -280px 0px; }
+.emoji-1F1F3-1F1E6 { background-position: -280px 0; }
 .emoji-1F1F3-1F1E8 { background-position: -280px -20px; }
 .emoji-1F1F3-1F1EA { background-position: -280px -40px; }
 .emoji-1F1F3-1F1EB { background-position: -280px -60px; }
@@ -208,7 +208,7 @@
 .emoji-1F1F3-1F1FF { background-position: -280px -220px; }
 .emoji-1F1F4-1F1F2 { background-position: -280px -240px; }
 .emoji-1F1F5-1F1E6 { background-position: -280px -260px; }
-.emoji-1F1F5-1F1EA { background-position: 0px -280px; }
+.emoji-1F1F5-1F1EA { background-position: 0 -280px; }
 .emoji-1F1F5-1F1EB { background-position: -20px -280px; }
 .emoji-1F1F5-1F1EC { background-position: -40px -280px; }
 .emoji-1F1F5-1F1ED { background-position: -60px -280px; }
@@ -223,7 +223,7 @@
 .emoji-1F1F5-1F1FE { background-position: -240px -280px; }
 .emoji-1F1F6-1F1E6 { background-position: -260px -280px; }
 .emoji-1F1F7-1F1EA { background-position: -280px -280px; }
-.emoji-1F1F7-1F1F4 { background-position: -300px 0px; }
+.emoji-1F1F7-1F1F4 { background-position: -300px 0; }
 .emoji-1F1F7-1F1F8 { background-position: -300px -20px; }
 .emoji-1F1F7-1F1FA { background-position: -300px -40px; }
 .emoji-1F1F7-1F1FC { background-position: -300px -60px; }
@@ -238,7 +238,7 @@
 .emoji-1F1F8-1F1EF { background-position: -300px -240px; }
 .emoji-1F1F8-1F1F0 { background-position: -300px -260px; }
 .emoji-1F1F8-1F1F1 { background-position: -300px -280px; }
-.emoji-1F1F8-1F1F2 { background-position: 0px -300px; }
+.emoji-1F1F8-1F1F2 { background-position: 0 -300px; }
 .emoji-1F1F8-1F1F3 { background-position: -20px -300px; }
 .emoji-1F1F8-1F1F4 { background-position: -40px -300px; }
 .emoji-1F1F8-1F1F7 { background-position: -60px -300px; }
@@ -254,7 +254,7 @@
 .emoji-1F1F9-1F1EB { background-position: -260px -300px; }
 .emoji-1F1F9-1F1EC { background-position: -280px -300px; }
 .emoji-1F1F9-1F1ED { background-position: -300px -300px; }
-.emoji-1F1F9-1F1EF { background-position: -320px 0px; }
+.emoji-1F1F9-1F1EF { background-position: -320px 0; }
 .emoji-1F1F9-1F1F0 { background-position: -320px -20px; }
 .emoji-1F1F9-1F1F1 { background-position: -320px -40px; }
 .emoji-1F1F9-1F1F2 { background-position: -320px -60px; }
@@ -270,7 +270,7 @@
 .emoji-1F1FA-1F1F2 { background-position: -320px -260px; }
 .emoji-1F1FA-1F1F8 { background-position: -320px -280px; }
 .emoji-1F1FA-1F1FE { background-position: -320px -300px; }
-.emoji-1F1FA-1F1FF { background-position: 0px -320px; }
+.emoji-1F1FA-1F1FF { background-position: 0 -320px; }
 .emoji-1F1FB-1F1E6 { background-position: -20px -320px; }
 .emoji-1F1FB-1F1E8 { background-position: -40px -320px; }
 .emoji-1F1FB-1F1EA { background-position: -60px -320px; }
@@ -287,7 +287,7 @@
 .emoji-1F1FF-1F1F2 { background-position: -280px -320px; }
 .emoji-1F1FF-1F1FC { background-position: -300px -320px; }
 .emoji-1F201 { background-position: -320px -320px; }
-.emoji-1F202 { background-position: -340px 0px; }
+.emoji-1F202 { background-position: -340px 0; }
 .emoji-1F21A { background-position: -340px -20px; }
 .emoji-1F22F { background-position: -340px -40px; }
 .emoji-1F232 { background-position: -340px -60px; }
@@ -304,7 +304,7 @@
 .emoji-1F300 { background-position: -340px -280px; }
 .emoji-1F301 { background-position: -340px -300px; }
 .emoji-1F302 { background-position: -340px -320px; }
-.emoji-1F303 { background-position: 0px -340px; }
+.emoji-1F303 { background-position: 0 -340px; }
 .emoji-1F304 { background-position: -20px -340px; }
 .emoji-1F305 { background-position: -40px -340px; }
 .emoji-1F306 { background-position: -60px -340px; }
@@ -322,7 +322,7 @@
 .emoji-1F312 { background-position: -300px -340px; }
 .emoji-1F313 { background-position: -320px -340px; }
 .emoji-1F314 { background-position: -340px -340px; }
-.emoji-1F315 { background-position: -360px 0px; }
+.emoji-1F315 { background-position: -360px 0; }
 .emoji-1F316 { background-position: -360px -20px; }
 .emoji-1F317 { background-position: -360px -40px; }
 .emoji-1F318 { background-position: -360px -60px; }
@@ -340,7 +340,7 @@
 .emoji-1F326 { background-position: -360px -300px; }
 .emoji-1F327 { background-position: -360px -320px; }
 .emoji-1F328 { background-position: -360px -340px; }
-.emoji-1F329 { background-position: 0px -360px; }
+.emoji-1F329 { background-position: 0 -360px; }
 .emoji-1F32A { background-position: -20px -360px; }
 .emoji-1F32B { background-position: -40px -360px; }
 .emoji-1F32C { background-position: -60px -360px; }
@@ -359,7 +359,7 @@
 .emoji-1F339 { background-position: -320px -360px; }
 .emoji-1F33A { background-position: -340px -360px; }
 .emoji-1F33B { background-position: -360px -360px; }
-.emoji-1F33C { background-position: -380px 0px; }
+.emoji-1F33C { background-position: -380px 0; }
 .emoji-1F33D { background-position: -380px -20px; }
 .emoji-1F33E { background-position: -380px -40px; }
 .emoji-1F33F { background-position: -380px -60px; }
@@ -378,7 +378,7 @@
 .emoji-1F34C { background-position: -380px -320px; }
 .emoji-1F34D { background-position: -380px -340px; }
 .emoji-1F34E { background-position: -380px -360px; }
-.emoji-1F34F { background-position: 0px -380px; }
+.emoji-1F34F { background-position: 0 -380px; }
 .emoji-1F350 { background-position: -20px -380px; }
 .emoji-1F351 { background-position: -40px -380px; }
 .emoji-1F352 { background-position: -60px -380px; }
@@ -398,7 +398,7 @@
 .emoji-1F360 { background-position: -340px -380px; }
 .emoji-1F361 { background-position: -360px -380px; }
 .emoji-1F362 { background-position: -380px -380px; }
-.emoji-1F363 { background-position: -400px 0px; }
+.emoji-1F363 { background-position: -400px 0; }
 .emoji-1F364 { background-position: -400px -20px; }
 .emoji-1F365 { background-position: -400px -40px; }
 .emoji-1F366 { background-position: -400px -60px; }
@@ -418,7 +418,7 @@
 .emoji-1F374 { background-position: -400px -340px; }
 .emoji-1F375 { background-position: -400px -360px; }
 .emoji-1F376 { background-position: -400px -380px; }
-.emoji-1F377 { background-position: 0px -400px; }
+.emoji-1F377 { background-position: 0 -400px; }
 .emoji-1F378 { background-position: -20px -400px; }
 .emoji-1F379 { background-position: -40px -400px; }
 .emoji-1F37A { background-position: -60px -400px; }
@@ -439,7 +439,7 @@
 .emoji-1F385-1F3FE { background-position: -360px -400px; }
 .emoji-1F385-1F3FF { background-position: -380px -400px; }
 .emoji-1F386 { background-position: -400px -400px; }
-.emoji-1F387 { background-position: -420px 0px; }
+.emoji-1F387 { background-position: -420px 0; }
 .emoji-1F388 { background-position: -420px -20px; }
 .emoji-1F389 { background-position: -420px -40px; }
 .emoji-1F38A { background-position: -420px -60px; }
@@ -460,7 +460,7 @@
 .emoji-1F399 { background-position: -420px -360px; }
 .emoji-1F39A { background-position: -420px -380px; }
 .emoji-1F39B { background-position: -420px -400px; }
-.emoji-1F39C { background-position: 0px -420px; }
+.emoji-1F39C { background-position: 0 -420px; }
 .emoji-1F39D { background-position: -20px -420px; }
 .emoji-1F39E { background-position: -40px -420px; }
 .emoji-1F39F { background-position: -60px -420px; }
@@ -482,7 +482,7 @@
 .emoji-1F3AF { background-position: -380px -420px; }
 .emoji-1F3B0 { background-position: -400px -420px; }
 .emoji-1F3B1 { background-position: -420px -420px; }
-.emoji-1F3B2 { background-position: -440px 0px; }
+.emoji-1F3B2 { background-position: -440px 0; }
 .emoji-1F3B3 { background-position: -440px -20px; }
 .emoji-1F3B4 { background-position: -440px -40px; }
 .emoji-1F3B5 { background-position: -440px -60px; }
@@ -504,7 +504,7 @@
 .emoji-1F3C3-1F3FC { background-position: -440px -380px; }
 .emoji-1F3C3-1F3FD { background-position: -440px -400px; }
 .emoji-1F3C3-1F3FE { background-position: -440px -420px; }
-.emoji-1F3C3-1F3FF { background-position: 0px -440px; }
+.emoji-1F3C3-1F3FF { background-position: 0 -440px; }
 .emoji-1F3C4 { background-position: -20px -440px; }
 .emoji-1F3C4-1F3FB { background-position: -40px -440px; }
 .emoji-1F3C4-1F3FC { background-position: -60px -440px; }
@@ -527,7 +527,7 @@
 .emoji-1F3CA-1F3FD { background-position: -400px -440px; }
 .emoji-1F3CA-1F3FE { background-position: -420px -440px; }
 .emoji-1F3CA-1F3FF { background-position: -440px -440px; }
-.emoji-1F3CB { background-position: -460px 0px; }
+.emoji-1F3CB { background-position: -460px 0; }
 .emoji-1F3CB-1F3FB { background-position: -460px -20px; }
 .emoji-1F3CB-1F3FC { background-position: -460px -40px; }
 .emoji-1F3CB-1F3FD { background-position: -460px -60px; }
@@ -550,7 +550,7 @@
 .emoji-1F3DA { background-position: -460px -400px; }
 .emoji-1F3DB { background-position: -460px -420px; }
 .emoji-1F3DC { background-position: -460px -440px; }
-.emoji-1F3DD { background-position: 0px -460px; }
+.emoji-1F3DD { background-position: 0 -460px; }
 .emoji-1F3DE { background-position: -20px -460px; }
 .emoji-1F3DF { background-position: -40px -460px; }
 .emoji-1F3E0 { background-position: -60px -460px; }
@@ -574,7 +574,7 @@
 .emoji-1F3F2 { background-position: -420px -460px; }
 .emoji-1F3F3 { background-position: -440px -460px; }
 .emoji-1F3F4 { background-position: -460px -460px; }
-.emoji-1F3F5 { background-position: -480px 0px; }
+.emoji-1F3F5 { background-position: -480px 0; }
 .emoji-1F3F6 { background-position: -480px -20px; }
 .emoji-1F3F7 { background-position: -480px -40px; }
 .emoji-1F3F8 { background-position: -480px -60px; }
@@ -598,7 +598,7 @@
 .emoji-1F40A { background-position: -480px -420px; }
 .emoji-1F40B { background-position: -480px -440px; }
 .emoji-1F40C { background-position: -480px -460px; }
-.emoji-1F40D { background-position: 0px -480px; }
+.emoji-1F40D { background-position: 0 -480px; }
 .emoji-1F40E { background-position: -20px -480px; }
 .emoji-1F40F { background-position: -40px -480px; }
 .emoji-1F410 { background-position: -60px -480px; }
@@ -623,7 +623,7 @@
 .emoji-1F423 { background-position: -440px -480px; }
 .emoji-1F424 { background-position: -460px -480px; }
 .emoji-1F425 { background-position: -480px -480px; }
-.emoji-1F426 { background-position: -500px 0px; }
+.emoji-1F426 { background-position: -500px 0; }
 .emoji-1F427 { background-position: -500px -20px; }
 .emoji-1F428 { background-position: -500px -40px; }
 .emoji-1F429 { background-position: -500px -60px; }
@@ -648,7 +648,7 @@
 .emoji-1F43C { background-position: -500px -440px; }
 .emoji-1F43D { background-position: -500px -460px; }
 .emoji-1F43E { background-position: -500px -480px; }
-.emoji-1F43F { background-position: 0px -500px; }
+.emoji-1F43F { background-position: 0 -500px; }
 .emoji-1F440 { background-position: -20px -500px; }
 .emoji-1F441 { background-position: -40px -500px; }
 .emoji-1F441-1F5E8 { background-position: -60px -500px; }
@@ -674,7 +674,7 @@
 .emoji-1F446-1F3FF { background-position: -460px -500px; }
 .emoji-1F447 { background-position: -480px -500px; }
 .emoji-1F447-1F3FB { background-position: -500px -500px; }
-.emoji-1F447-1F3FC { background-position: -520px 0px; }
+.emoji-1F447-1F3FC { background-position: -520px 0; }
 .emoji-1F447-1F3FD { background-position: -520px -20px; }
 .emoji-1F447-1F3FE { background-position: -520px -40px; }
 .emoji-1F447-1F3FF { background-position: -520px -60px; }
@@ -700,7 +700,7 @@
 .emoji-1F44B-1F3FB { background-position: -520px -460px; }
 .emoji-1F44B-1F3FC { background-position: -520px -480px; }
 .emoji-1F44B-1F3FD { background-position: -520px -500px; }
-.emoji-1F44B-1F3FE { background-position: 0px -520px; }
+.emoji-1F44B-1F3FE { background-position: 0 -520px; }
 .emoji-1F44B-1F3FF { background-position: -20px -520px; }
 .emoji-1F44C { background-position: -40px -520px; }
 .emoji-1F44C-1F3FB { background-position: -60px -520px; }
@@ -727,7 +727,7 @@
 .emoji-1F44F-1F3FE { background-position: -480px -520px; }
 .emoji-1F44F-1F3FF { background-position: -500px -520px; }
 .emoji-1F450 { background-position: -520px -520px; }
-.emoji-1F450-1F3FB { background-position: -540px 0px; }
+.emoji-1F450-1F3FB { background-position: -540px 0; }
 .emoji-1F450-1F3FC { background-position: -540px -20px; }
 .emoji-1F450-1F3FD { background-position: -540px -40px; }
 .emoji-1F450-1F3FE { background-position: -540px -60px; }
@@ -754,7 +754,7 @@
 .emoji-1F464 { background-position: -540px -480px; }
 .emoji-1F465 { background-position: -540px -500px; }
 .emoji-1F466 { background-position: -540px -520px; }
-.emoji-1F466-1F3FB { background-position: 0px -540px; }
+.emoji-1F466-1F3FB { background-position: 0 -540px; }
 .emoji-1F466-1F3FC { background-position: -20px -540px; }
 .emoji-1F466-1F3FD { background-position: -40px -540px; }
 .emoji-1F466-1F3FE { background-position: -60px -540px; }
@@ -782,7 +782,7 @@
 .emoji-1F468-1F469-1F467-1F467 { background-position: -500px -540px; }
 .emoji-1F468-2764-1F468 { background-position: -520px -540px; }
 .emoji-1F468-2764-1F48B-1F468 { background-position: -540px -540px; }
-.emoji-1F469 { background-position: -560px 0px; }
+.emoji-1F469 { background-position: -560px 0; }
 .emoji-1F469-1F3FB { background-position: -560px -20px; }
 .emoji-1F469-1F3FC { background-position: -560px -40px; }
 .emoji-1F469-1F3FD { background-position: -560px -60px; }
@@ -810,7 +810,7 @@
 .emoji-1F470-1F3FB { background-position: -560px -500px; }
 .emoji-1F470-1F3FC { background-position: -560px -520px; }
 .emoji-1F470-1F3FD { background-position: -560px -540px; }
-.emoji-1F470-1F3FE { background-position: 0px -560px; }
+.emoji-1F470-1F3FE { background-position: 0 -560px; }
 .emoji-1F470-1F3FF { background-position: -20px -560px; }
 .emoji-1F471 { background-position: -40px -560px; }
 .emoji-1F471-1F3FB { background-position: -60px -560px; }
@@ -839,7 +839,7 @@
 .emoji-1F475 { background-position: -520px -560px; }
 .emoji-1F475-1F3FB { background-position: -540px -560px; }
 .emoji-1F475-1F3FC { background-position: -560px -560px; }
-.emoji-1F475-1F3FD { background-position: -580px 0px; }
+.emoji-1F475-1F3FD { background-position: -580px 0; }
 .emoji-1F475-1F3FE { background-position: -580px -20px; }
 .emoji-1F475-1F3FF { background-position: -580px -40px; }
 .emoji-1F476 { background-position: -580px -60px; }
@@ -868,7 +868,7 @@
 .emoji-1F47C-1F3FC { background-position: -580px -520px; }
 .emoji-1F47C-1F3FD { background-position: -580px -540px; }
 .emoji-1F47C-1F3FE { background-position: -580px -560px; }
-.emoji-1F47C-1F3FF { background-position: 0px -580px; }
+.emoji-1F47C-1F3FF { background-position: 0 -580px; }
 .emoji-1F47D { background-position: -20px -580px; }
 .emoji-1F47E { background-position: -40px -580px; }
 .emoji-1F47F { background-position: -60px -580px; }
@@ -898,7 +898,7 @@
 .emoji-1F485-1F3FD { background-position: -540px -580px; }
 .emoji-1F485-1F3FE { background-position: -560px -580px; }
 .emoji-1F485-1F3FF { background-position: -580px -580px; }
-.emoji-1F486 { background-position: -600px 0px; }
+.emoji-1F486 { background-position: -600px 0; }
 .emoji-1F486-1F3FB { background-position: -600px -20px; }
 .emoji-1F486-1F3FC { background-position: -600px -40px; }
 .emoji-1F486-1F3FD { background-position: -600px -60px; }
@@ -928,7 +928,7 @@
 .emoji-1F497 { background-position: -600px -540px; }
 .emoji-1F498 { background-position: -600px -560px; }
 .emoji-1F499 { background-position: -600px -580px; }
-.emoji-1F49A { background-position: 0px -600px; }
+.emoji-1F49A { background-position: 0 -600px; }
 .emoji-1F49B { background-position: -20px -600px; }
 .emoji-1F49C { background-position: -40px -600px; }
 .emoji-1F49D { background-position: -60px -600px; }
@@ -959,7 +959,7 @@
 .emoji-1F4B1 { background-position: -560px -600px; }
 .emoji-1F4B2 { background-position: -580px -600px; }
 .emoji-1F4B3 { background-position: -600px -600px; }
-.emoji-1F4B4 { background-position: -620px 0px; }
+.emoji-1F4B4 { background-position: -620px 0; }
 .emoji-1F4B5 { background-position: -620px -20px; }
 .emoji-1F4B6 { background-position: -620px -40px; }
 .emoji-1F4B7 { background-position: -620px -60px; }
@@ -990,7 +990,7 @@
 .emoji-1F4D0 { background-position: -620px -560px; }
 .emoji-1F4D1 { background-position: -620px -580px; }
 .emoji-1F4D2 { background-position: -620px -600px; }
-.emoji-1F4D3 { background-position: 0px -620px; }
+.emoji-1F4D3 { background-position: 0 -620px; }
 .emoji-1F4D4 { background-position: -20px -620px; }
 .emoji-1F4D5 { background-position: -40px -620px; }
 .emoji-1F4D6 { background-position: -60px -620px; }
@@ -1022,7 +1022,7 @@
 .emoji-1F4F0 { background-position: -580px -620px; }
 .emoji-1F4F1 { background-position: -600px -620px; }
 .emoji-1F4F2 { background-position: -620px -620px; }
-.emoji-1F4F3 { background-position: -640px 0px; }
+.emoji-1F4F3 { background-position: -640px 0; }
 .emoji-1F4F4 { background-position: -640px -20px; }
 .emoji-1F4F5 { background-position: -640px -40px; }
 .emoji-1F4F6 { background-position: -640px -60px; }
@@ -1054,7 +1054,7 @@
 .emoji-1F510 { background-position: -640px -580px; }
 .emoji-1F511 { background-position: -640px -600px; }
 .emoji-1F512 { background-position: -640px -620px; }
-.emoji-1F513 { background-position: 0px -640px; }
+.emoji-1F513 { background-position: 0 -640px; }
 .emoji-1F514 { background-position: -20px -640px; }
 .emoji-1F515 { background-position: -40px -640px; }
 .emoji-1F516 { background-position: -60px -640px; }
@@ -1087,7 +1087,7 @@
 .emoji-1F531 { background-position: -600px -640px; }
 .emoji-1F532 { background-position: -620px -640px; }
 .emoji-1F533 { background-position: -640px -640px; }
-.emoji-1F534 { background-position: -660px 0px; }
+.emoji-1F534 { background-position: -660px 0; }
 .emoji-1F535 { background-position: -660px -20px; }
 .emoji-1F536 { background-position: -660px -40px; }
 .emoji-1F537 { background-position: -660px -60px; }
@@ -1120,7 +1120,7 @@
 .emoji-1F55B { background-position: -660px -600px; }
 .emoji-1F55C { background-position: -660px -620px; }
 .emoji-1F55D { background-position: -660px -640px; }
-.emoji-1F55E { background-position: 0px -660px; }
+.emoji-1F55E { background-position: 0 -660px; }
 .emoji-1F55F { background-position: -20px -660px; }
 .emoji-1F560 { background-position: -40px -660px; }
 .emoji-1F561 { background-position: -60px -660px; }
@@ -1154,7 +1154,7 @@
 .emoji-1F578 { background-position: -620px -660px; }
 .emoji-1F579 { background-position: -640px -660px; }
 .emoji-1F57B { background-position: -660px -660px; }
-.emoji-1F57E { background-position: -680px 0px; }
+.emoji-1F57E { background-position: -680px 0; }
 .emoji-1F57F { background-position: -680px -20px; }
 .emoji-1F581 { background-position: -680px -40px; }
 .emoji-1F582 { background-position: -680px -60px; }
@@ -1188,7 +1188,7 @@
 .emoji-1F595-1F3FF { background-position: -680px -620px; }
 .emoji-1F596 { background-position: -680px -640px; }
 .emoji-1F596-1F3FB { background-position: -680px -660px; }
-.emoji-1F596-1F3FC { background-position: 0px -680px; }
+.emoji-1F596-1F3FC { background-position: 0 -680px; }
 .emoji-1F596-1F3FD { background-position: -20px -680px; }
 .emoji-1F596-1F3FE { background-position: -40px -680px; }
 .emoji-1F596-1F3FF { background-position: -60px -680px; }
@@ -1223,7 +1223,7 @@
 .emoji-1F5C4 { background-position: -640px -680px; }
 .emoji-1F5C6 { background-position: -660px -680px; }
 .emoji-1F5C7 { background-position: -680px -680px; }
-.emoji-1F5C9 { background-position: -700px 0px; }
+.emoji-1F5C9 { background-position: -700px 0; }
 .emoji-1F5CA { background-position: -700px -20px; }
 .emoji-1F5CE { background-position: -700px -40px; }
 .emoji-1F5CF { background-position: -700px -60px; }
@@ -1258,7 +1258,7 @@
 .emoji-1F5F8 { background-position: -700px -640px; }
 .emoji-1F5F9 { background-position: -700px -660px; }
 .emoji-1F5FA { background-position: -700px -680px; }
-.emoji-1F5FB { background-position: 0px -700px; }
+.emoji-1F5FB { background-position: 0 -700px; }
 .emoji-1F5FC { background-position: -20px -700px; }
 .emoji-1F5FD { background-position: -40px -700px; }
 .emoji-1F5FE { background-position: -60px -700px; }
@@ -1294,7 +1294,7 @@
 .emoji-1F61C { background-position: -660px -700px; }
 .emoji-1F61D { background-position: -680px -700px; }
 .emoji-1F61E { background-position: -700px -700px; }
-.emoji-1F61F { background-position: -720px 0px; }
+.emoji-1F61F { background-position: -720px 0; }
 .emoji-1F620 { background-position: -720px -20px; }
 .emoji-1F621 { background-position: -720px -40px; }
 .emoji-1F622 { background-position: -720px -60px; }
@@ -1330,7 +1330,7 @@
 .emoji-1F640 { background-position: -720px -660px; }
 .emoji-1F641 { background-position: -720px -680px; }
 .emoji-1F642 { background-position: -720px -700px; }
-.emoji-1F643 { background-position: 0px -720px; }
+.emoji-1F643 { background-position: 0 -720px; }
 .emoji-1F644 { background-position: -20px -720px; }
 .emoji-1F645 { background-position: -40px -720px; }
 .emoji-1F645-1F3FB { background-position: -60px -720px; }
@@ -1367,7 +1367,7 @@
 .emoji-1F64C-1F3FF { background-position: -680px -720px; }
 .emoji-1F64D { background-position: -700px -720px; }
 .emoji-1F64D-1F3FB { background-position: -720px -720px; }
-.emoji-1F64D-1F3FC { background-position: -740px 0px; }
+.emoji-1F64D-1F3FC { background-position: -740px 0; }
 .emoji-1F64D-1F3FD { background-position: -740px -20px; }
 .emoji-1F64D-1F3FE { background-position: -740px -40px; }
 .emoji-1F64D-1F3FF { background-position: -740px -60px; }
@@ -1404,7 +1404,7 @@
 .emoji-1F692 { background-position: -740px -680px; }
 .emoji-1F693 { background-position: -740px -700px; }
 .emoji-1F694 { background-position: -740px -720px; }
-.emoji-1F695 { background-position: 0px -740px; }
+.emoji-1F695 { background-position: 0 -740px; }
 .emoji-1F696 { background-position: -20px -740px; }
 .emoji-1F697 { background-position: -40px -740px; }
 .emoji-1F698 { background-position: -60px -740px; }
@@ -1442,7 +1442,7 @@
 .emoji-1F6B3 { background-position: -700px -740px; }
 .emoji-1F6B4 { background-position: -720px -740px; }
 .emoji-1F6B4-1F3FB { background-position: -740px -740px; }
-.emoji-1F6B4-1F3FC { background-position: -760px 0px; }
+.emoji-1F6B4-1F3FC { background-position: -760px 0; }
 .emoji-1F6B4-1F3FD { background-position: -760px -20px; }
 .emoji-1F6B4-1F3FE { background-position: -760px -40px; }
 .emoji-1F6B4-1F3FF { background-position: -760px -60px; }
@@ -1480,7 +1480,7 @@
 .emoji-1F6C5 { background-position: -760px -700px; }
 .emoji-1F6C6 { background-position: -760px -720px; }
 .emoji-1F6C7 { background-position: -760px -740px; }
-.emoji-1F6C8 { background-position: 0px -760px; }
+.emoji-1F6C8 { background-position: 0 -760px; }
 .emoji-1F6C9 { background-position: -20px -760px; }
 .emoji-1F6CA { background-position: -40px -760px; }
 .emoji-1F6CB { background-position: -60px -760px; }
@@ -1519,7 +1519,7 @@
 .emoji-1F918-1F3FC { background-position: -720px -760px; }
 .emoji-1F918-1F3FD { background-position: -740px -760px; }
 .emoji-1F918-1F3FE { background-position: -760px -760px; }
-.emoji-1F918-1F3FF { background-position: -780px 0px; }
+.emoji-1F918-1F3FF { background-position: -780px 0; }
 .emoji-1F980 { background-position: -780px -20px; }
 .emoji-1F981 { background-position: -780px -40px; }
 .emoji-1F982 { background-position: -780px -60px; }
@@ -1558,7 +1558,7 @@
 .emoji-24C2 { background-position: -780px -720px; }
 .emoji-25AA { background-position: -780px -740px; }
 .emoji-25AB { background-position: -780px -760px; }
-.emoji-25B6 { background-position: 0px -780px; }
+.emoji-25B6 { background-position: 0 -780px; }
 .emoji-25C0 { background-position: -20px -780px; }
 .emoji-25FB { background-position: -40px -780px; }
 .emoji-25FC { background-position: -60px -780px; }
@@ -1598,7 +1598,7 @@
 .emoji-264D { background-position: -740px -780px; }
 .emoji-264E { background-position: -760px -780px; }
 .emoji-264F { background-position: -780px -780px; }
-.emoji-2650 { background-position: -800px 0px; }
+.emoji-2650 { background-position: -800px 0; }
 .emoji-2651 { background-position: -800px -20px; }
 .emoji-2652 { background-position: -800px -40px; }
 .emoji-2653 { background-position: -800px -60px; }
@@ -1638,7 +1638,7 @@
 .emoji-26F0 { background-position: -800px -740px; }
 .emoji-26F1 { background-position: -800px -760px; }
 .emoji-26F2 { background-position: -800px -780px; }
-.emoji-26F3 { background-position: 0px -800px; }
+.emoji-26F3 { background-position: 0 -800px; }
 .emoji-26F4 { background-position: -20px -800px; }
 .emoji-26F5 { background-position: -40px -800px; }
 .emoji-26F7 { background-position: -60px -800px; }
@@ -1679,7 +1679,7 @@
 .emoji-270D-1F3FD { background-position: -760px -800px; }
 .emoji-270D-1F3FE { background-position: -780px -800px; }
 .emoji-270D-1F3FF { background-position: -800px -800px; }
-.emoji-270F { background-position: -820px 0px; }
+.emoji-270F { background-position: -820px 0; }
 .emoji-2712 { background-position: -820px -20px; }
 .emoji-2714 { background-position: -820px -40px; }
 .emoji-2716 { background-position: -820px -60px; }
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 35df9a61c86c538b87762b3d4a7a47a53734ee2e..040e1d38678af82b2820a0bdf86679b7986f28ad 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -6,7 +6,7 @@
   font-size: $gl-font-size;
   padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
   border-bottom: 1px solid $table-border-color;
-  color: #7f8fa4;
+  color: $list-text-color;
 
   &.event-inline {
     .avatar {
@@ -31,9 +31,10 @@
   .event-title {
     @include str-truncated(calc(100% - 174px));
     font-weight: 600;
+    color: $list-title-color;
 
-    .author_name {
-      color: #333;
+    a {
+      color: $list-title-color;
     }
   }
 
@@ -63,7 +64,7 @@
 
       .note-image-attach {
         margin-top: 4px;
-        margin-left: 0px;
+        margin-left: 0;
         max-width: 200px;
         float: none;
       }
@@ -83,10 +84,10 @@
   .event_icon {
     position: relative;
     float: right;
-    border: 1px solid #EEE;
+    border: 1px solid #eee;
     padding: 5px;
     @include border-radius(5px);
-    background: #F9F9F9;
+    background: #f9f9f9;
     margin-left: 10px;
     top: -6px;
     img {
@@ -94,7 +95,7 @@
     }
   }
 
-  &:last-child { border:none }
+  &:last-child { border: none }
 
   .event_commits {
     li {
@@ -138,7 +139,7 @@
     @include str-truncated(100%);
     padding: 5px 0;
     font-size: 13px;
-    float:left;
+    float: left;
     margin-right: -150px;
     padding-right: 150px;
     line-height: 20px;
@@ -160,7 +161,7 @@
 
     .event-body {
       margin: 0;
-      border-left: 2px solid #DDD;
+      border-left: 2px solid #ddd;
       padding-left: 10px;
     }
 
diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss
index c3b10d144e1b50de8e82d240beeb87e6ac6e6bbf..4e5c4ed84b65322cf9aed2005f26a1498a4453e0 100644
--- a/app/assets/stylesheets/pages/graph.scss
+++ b/app/assets/stylesheets/pages/graph.scss
@@ -6,11 +6,11 @@
     font-size: 14px;
     padding: 5px;
     border-bottom: 1px solid $border-color;
-    background: #EEE;
+    background: #eee;
   }
 
   .network-graph {
-    background: #FFF;
+    background: #fff;
     height: 500px;
     overflow-y: scroll;
     overflow-x: hidden;
diff --git a/app/assets/stylesheets/pages/import.scss b/app/assets/stylesheets/pages/import.scss
index 3df4bb84bd21edef358f8a236d09604d63a43e16..6a99cd9cb9450ab475f2a33ea7ca0444f498adf3 100644
--- a/app/assets/stylesheets/pages/import.scss
+++ b/app/assets/stylesheets/pages/import.scss
@@ -1,6 +1,6 @@
 i.icon-gitorious {
   display: inline-block;
-  background-position: 0px 0px;
+  background-position: 0 0;
   background-size: contain;
   background-repeat: no-repeat;
 }
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 1310e6ad7c7b3d2071a145958bc1607178d2626a..2760af8a48a37303c100c8c5a044156dccc1b2ce 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -1,34 +1,3 @@
-@media (max-width: $screen-sm-max) {
-  .issuable-affix {
-    margin-top: 20px;
-  }
-}
-
-@media (max-width: $screen-md-max) {
-  .issuable-affix {
-    position: static;
-  }
-}
-
-@media (min-width: $screen-md-max) {
-  .issuable-affix {
-    &.affix-top {
-      position: static;
-    }
-
-    &.affix {
-      position: fixed;
-      top: 70px;
-      margin-right: 35px;
-
-      &.no-affix {
-        position: relative;
-        top: 0;
-      }
-    }
-  }
-}
-
 .issuable-details {
   section {
     .issuable-discussion {
@@ -54,20 +23,25 @@
       padding: 6px 10px;
     }
   }
+
+  &.has-labels {
+    margin-bottom: -5px;
+  }
 }
 
 .issuable-sidebar {
   .block {
     @include clearfix;
-    padding:  $gl-padding 0;
+    padding: $gl-padding 0;
     border-bottom: 1px solid $border-gray-light;
     // This prevents the mess when resizing the sidebar
     // of elements repositioning themselves..
     width: $gutter_inner_width;
     // --
 
-    &:first-child {
-      padding-top: 5px;
+    &.issuable-sidebar-header {
+      padding-top: 0;
+      padding-bottom: 10px;
     }
 
     &:last-child {
@@ -75,7 +49,6 @@
     }
 
     span {
-      margin-top: 7px;
       display: inline-block;
     }
 
@@ -84,7 +57,7 @@
     }
 
     .issuable-count {
-
+      margin-top: 7px;
     }
 
     .gutter-toggle {
@@ -99,19 +72,19 @@
 
   .title {
     color: $gl-text-color;
-    margin-bottom: 8px;
+    margin-bottom: 10px;
+    line-height: 1;
 
     .avatar {
       margin-left: 0;
     }
 
-    label {
-      font-weight: normal;
-      margin-right: 4px;
-    }
-
     .edit-link {
       color: $gl-gray;
+
+      &:hover {
+        color: $md-link-color;
+      }
     }
   }
 
@@ -144,11 +117,6 @@
   .btn-clipboard {
     color: $gl-gray;
   }
-
-  .participants .avatar {
-    margin-top: 6px;
-    margin-right: 2px;
-  }
 }
 
 .right-sidebar {
@@ -163,8 +131,12 @@
   &.right-sidebar-expanded {
     width: $gutter_width;
 
-    hr {
-      display: none;
+    .value {
+      line-height: 1;
+    }
+
+    .bold {
+      font-weight: 600;
     }
 
     .sidebar-collapsed-icon {
@@ -172,8 +144,23 @@
     }
 
     .gutter-toggle {
+      margin-top: 7px;
       border-left: 1px solid $border-gray-light;
     }
+
+    .assignee .avatar {
+      float: left;
+      margin-right: 10px;
+      margin-bottom: 0;
+      margin-left: 0;
+    }
+
+    .username {
+      display: block;
+      margin-top: 4px;
+      font-size: 13px;
+      font-weight: normal;
+    }
   }
 
   .subscribe-button {
@@ -193,14 +180,6 @@
     width: $sidebar_collapsed_width;
     padding-top: 0;
 
-    hr {
-      margin: 0;
-      color: $gray-normal;
-      border-color: $gray-normal;
-      width: 62px;
-      margin-left: -20px
-    }
-
     .block {
       width: $sidebar_collapsed_width - 1px;
       margin-left: -19px;
@@ -209,12 +188,18 @@
       overflow: hidden;
     }
 
+    .participants {
+      border-bottom: 1px solid $border-gray-light;
+    }
+
     .hide-collapsed {
       display: none;
     }
 
     .gutter-toggle {
-      margin-left: -36px;
+      width: 100%;
+      margin-left: 0;
+      padding-left: 25px;
     }
 
     .sidebar-collapsed-icon {
@@ -222,13 +207,17 @@
       width: 100%;
       text-align: center;
       padding-bottom: 10px;
-      color: #999999;
+      color: #999;
 
       span {
         display: block;
         margin-top: 0;
       }
 
+      .author {
+        display: none;
+      }
+
       .btn-clipboard {
         border: none;
 
@@ -237,10 +226,15 @@
         }
 
         i {
-          color: #999999;
+          color: #999;
         }
       }
     }
+
+    .sidebar-collapsed-user {
+      padding-bottom: 0;
+      margin-bottom: 10px;
+    }
   }
 
   .btn {
@@ -251,6 +245,13 @@
       border: 1px solid $border-gray-dark;
     }
   }
+
+  a:not(.btn) {
+    &:hover {
+      color: $md-link-color;
+      text-decoration: none;
+    }
+  }
 }
 
 .btn-default.gutter-toggle {
@@ -262,3 +263,37 @@
     color: $gray-darkest;
   }
 }
+
+.edited-text {
+  color: $gray-darkest;
+
+  .author_link {
+    color: $gray-darkest;
+  }
+}
+
+.participants-list {
+  margin: -5px -5px;
+}
+
+.participants-author {
+  display: inline-block;
+  padding: 5px 5px;
+
+  .author_link {
+    display: block;
+  }
+
+  .avatar.avatar-inline {
+    margin: 0;
+  }
+}
+
+.participants-more {
+  margin-top: 5px;
+  margin-left: 5px;
+
+  a {
+    color: #8c8c8c;
+  }
+}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 1b686c58eaf00365a94e1b1c3d3a2d81c3b988c8..76bd6d9a8a7b4479f0e3f06a4d254f56273af69b 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -49,7 +49,7 @@ form.edit-issue {
   margin: 0;
 }
 
-.merge-requests-title {
+.merge-requests-title, .related-branches-title {
   font-size: 16px;
   font-weight: 600;
 }
@@ -68,18 +68,18 @@ form.edit-issue {
 .merge-request,
 .issue {
   &.today {
-    background: #EFE;
-    border-color: #CEC;
+    background: #efe;
+    border-color: #cec;
   }
 
   &.closed {
-    background: #F9F9F9;
-    border-color: #E5E5E5;
+    background: #f9f9f9;
+    border-color: #e5e5e5;
   }
 
   &.merged {
-    background: #F9F9F9;
-    border-color: #E5E5E5;
+    background: #f9f9f9;
+    border-color: #e5e5e5;
   }
 }
 
@@ -130,14 +130,14 @@ form.edit-issue {
 }
 
 .issue-closed-by-widget {
-  color: $secondary-text;
+  color: $gl-text-color;
   margin-left: 52px;
 }
 
 .editor-details {
   display: block;
-  
+
   @media (min-width: $screen-sm-min) {
     display: inline-block;
   }
-}
\ No newline at end of file
+}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 61bec02f6c5941e7f4521033ec8c2119c5e7a02d..bc41f7d306f842952eefbd76b69468a6f337fa8a 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -28,7 +28,7 @@
 
     img {
       max-width: 100%;
-      margin-bottom:  30px;
+      margin-bottom: 30px;
     }
 
     a {
@@ -39,7 +39,7 @@
   .login-box{
     background: #fafafa;
     border-radius: 10px;
-    box-shadow: 0 0px 2px #CCC;
+    box-shadow: 0 0 2px #ccc;
     padding: 15px;
 
     .login-heading h3 {
@@ -74,7 +74,7 @@
 
     &.top {
       @include border-radius(5px 5px 0 0);
-      margin-bottom: 0px;
+      margin-bottom: 0;
     }
 
     &.bottom {
@@ -85,12 +85,12 @@
 
     &.middle {
       border-top: 0;
-      margin-bottom:0px;
+      margin-bottom: 0;
       @include border-radius(0);
     }
 
     &:active, &:focus {
-      background-color: #FFF;
+      background-color: #fff;
     }
   }
 
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 2772623f4bde7dc35d297abe5d00bf21fc8f4c23..cee5c47cfb22c60b6302ae58cf455df2a76dabea 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -113,7 +113,7 @@
   }
 
   .mr-widget-footer {
-    border-top: 1px solid #EEE;
+    border-top: 1px solid #eee;
   }
 
   .ci-coverage {
@@ -222,7 +222,7 @@
     margin-bottom: 20px;
 
     span {
-      color: #B2B2B2;
+      color: #b2b2b2;
 
       a {
         color: $md-link-color;
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 158c2a478625ad8c6370f564c8c2aff11620d4da..61783ec46aae8499feb10600dc1818b5b812aea9 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -156,7 +156,7 @@
 
 .comment-hints {
   color: #999;
-  background: #FFF;
+  background: #fff;
   padding: 7px;
   margin-top: -7px;
   border: 1px solid $border-color;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index d5f9852ebed3163afc9fcf70fba34ac13d7c7914..d408853cc80c45467d12c38b4d7d462e481c27b5 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -3,16 +3,16 @@
  */
 
 @-webkit-keyframes targe3-note {
-  from { background:#fffff0; }
-  50% { background:#ffffd3; }
-  to { background:#fffff0; }
+  from { background: #fffff0; }
+  50% { background: #ffffd3; }
+  to { background: #fffff0; }
 }
 
 ul.notes {
   display: block;
   list-style: none;
-  margin: 0px;
-  padding: 0px;
+  margin: 0;
+  padding: 0;
 
   .timeline-icon {
     float: left;
@@ -30,7 +30,7 @@ ul.notes {
     font-size: 14px;
     padding-top: 10px;
     padding-bottom: 10px;
-    background: #FDFDFD;
+    background: #fdfdfd;
 
     .timeline-icon {
       .avatar {
@@ -93,12 +93,12 @@ ul.notes {
   .discussion {
     overflow: hidden;
     display: block;
-    position:relative;
+    position: relative;
   }
 
   .note {
     display: block;
-    position:relative;
+    position: relative;
 
     .note-body {
       overflow: auto;
@@ -108,6 +108,13 @@ ul.notes {
         word-wrap: break-word;
         @include md-typography;
 
+        // On diffs code should wrap nicely and not overflow
+        pre {
+          code {
+            white-space: pre-wrap;
+          }
+        }
+
         // Reset ul style types since we're nested inside a ul already
         & > ul {
           list-style-type: disc;
@@ -129,7 +136,7 @@ ul.notes {
 
         hr {
           // Darken 'whitesmoke' a bit to make it more visible in note bodies
-          border-color: darken(#F5F5F5, 8%);
+          border-color: darken(#f5f5f5, 8%);
           margin: 10px 0;
         }
       }
@@ -166,7 +173,7 @@ ul.notes {
       vertical-align: middle;
       text-align: center;
       padding: 10px 0;
-      background: #FFF;
+      background: #fff;
       color: $text-color;
     }
     &.notes_line2 {
@@ -232,7 +239,7 @@ ul.notes {
   .add-diff-note {
     margin-top: -4px;
     @include border-radius(40px);
-    background: #FFF;
+    background: #fff;
     padding: 4px;
     font-size: 16px;
     color: $gl-link-color;
@@ -249,7 +256,7 @@ ul.notes {
 
     &:hover {
       background: $gl-info;
-      color: #FFF;
+      color: #fff;
       @include show-add-diff-note;
     }
   }
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index ecfe0e37c85e04fda28046e705eef9bdef6fadfb..260179074cf6cc93d8ed7b1904e31379239adb15 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -30,7 +30,7 @@
   .btn {
     line-height: 40px;
     height: 42px;
-    padding: 0px 12px;
+    padding: 0 12px;
 
     img {
       width: 32px;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index b1b76edfb327789c8d732938459ece9349eae982..82c5069638daa01c2265faf91dbcd489d1447cfe 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -33,6 +33,13 @@
     .project-settings-dropdown {
       margin-left: 10px;
       display: inline-block;
+
+      .dropdown-menu {
+        left: auto;
+        width: auto;
+        right: 0px;
+        max-width: 240px;
+      }
     }
   }
 
@@ -85,7 +92,7 @@
 
   .project-repo-buttons {
     margin-top: 20px;
-    margin-bottom: 0px;
+    margin-bottom: 0;
 
     .count-buttons {
       display: block;
@@ -140,7 +147,7 @@
           left: 1px;
           margin-top: -9px;
           border-width: 10px 7px 10px 0;
-          border-right-color: #FFF;
+          border-right-color: #fff;
         }
       }
       .count {
@@ -162,10 +169,10 @@
         cursor: pointer;
         background-image: none;
         white-space: nowrap;
-        margin: 0 11px 0px 4px;
+        margin: 0 11px 0 4px;
 
         &:hover {
-          background: #FFF;
+          background: #fff;
         }
       }
     }
@@ -210,7 +217,7 @@
 }
 
 .project_member_row form {
-  margin: 0px;
+  margin: 0;
 }
 
 .transfer-project .select2-container {
@@ -286,11 +293,11 @@ table.table.protected-branches-list tr.no-border {
   padding-bottom: 4px;
 
   ul.nav {
-    display:inline-block;
+    display: inline-block;
   }
 
   .nav li {
-    display:inline;
+    display: inline;
   }
 
   .nav > li > a {
@@ -303,11 +310,11 @@ table.table.protected-branches-list tr.no-border {
   }
 
   li {
-    display:inline;
+    display: inline;
   }
 
   a {
-    float:left;
+    float: left;
     font-size: 17px;
   }
 
@@ -462,7 +469,7 @@ pre.light-well {
 
   .form-control {
     @extend .monospace;
-    background: #FFF;
+    background: #fff;
     font-size: 14px;
     margin-left: -1px;
     cursor: auto;
@@ -472,16 +479,16 @@ pre.light-well {
 
 .cannot-be-merged,
 .cannot-be-merged:hover {
-  color: #E62958;
+  color: #e62958;
   margin-top: 2px;
 }
 
 .private-forks-notice .private-fork-icon {
   i:nth-child(1) {
-    color: #2AA056;
+    color: #2aa056;
   }
 
   i:nth-child(2) {
-    color: #FFFFFF;
+    color: #fff;
   }
 }
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index a9111a7388fec3fb5cd8d5800b2f09803a7544de..eec22c5dc960384eb7caae00d6263a462afd4e51 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -1,7 +1,7 @@
 .runner-state {
   padding: 6px 12px;
   margin-right: 10px;
-  color: #FFF;
+  color: #fff;
 
   &.runner-state-shared {
     background: #32b186;
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index ff32bca98dc4dc7a985c43cdf9092f3d50aafd92..4a02f75719bd0d6036ad49233b2251a870f67f46 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -16,7 +16,7 @@
   margin-bottom: 20px;
 
   input {
-    border-color: #BBB;
+    border-color: #bbb;
     font-weight: bold;
   }
 }
diff --git a/app/assets/stylesheets/pages/sherlock.scss b/app/assets/stylesheets/pages/sherlock.scss
index 92d84d9640fc4cedf8d03bde1070ac7eda7eabf5..bed6470dbd31a54b7e3cb33952251af74e8b0d49 100644
--- a/app/assets/stylesheets/pages/sherlock.scss
+++ b/app/assets/stylesheets/pages/sherlock.scss
@@ -13,13 +13,13 @@ table .sherlock-code {
 }
 
 .sherlock-line-samples-table {
-  margin-bottom: 0px !important;
+  margin-bottom: 0 !important;
 
   thead tr th,
   tbody tr td {
     font-size: 13px !important;
     text-align: right;
-    padding: 0px 10px !important;
+    padding: 0 10px !important;
   }
 }
 
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index 4b6ef035673b595f1b835a7444e40abc0cb70ae4..6f777d11641883d45b7a247bcd6ae8c7c9986e64 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -1,7 +1,7 @@
 .ci-status {
   padding: 2px 7px;
   margin-right: 5px;
-  border: 1px solid #EEE;
+  border: 1px solid #eee;
   white-space: nowrap;
   @include border-radius(4px);
 
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 479c3c16d467bb0db4f95c7701942060d673ae0b..dbd6585fc31f23dfbafa8267cbda6ecd681fde9e 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -16,7 +16,7 @@
 .todo-item {
   font-size: $gl-font-size;
   padding-left: $gl-avatar-size + $gl-padding-top;
-  color: $secondary-text;
+  color: $gl-text-color;
 
   a {
     color: #4c4e54;
@@ -29,9 +29,10 @@
   .todo-title {
     @include str-truncated(calc(100% - 174px));
     font-weight: 600;
+    color: $list-title-color;
 
-    .author-name {
-      color: #333;
+    a {
+      color: $list-title-color;
     }
   }
 
@@ -61,7 +62,7 @@
 
       .note-image-attach {
         margin-top: 4px;
-        margin-left: 0px;
+        margin-left: 0;
         max-width: 200px;
         float: none;
       }
@@ -89,7 +90,7 @@
 
     .todo-body {
       margin: 0;
-      border-left: 2px solid #DDD;
+      border-left: 2px solid #ddd;
       padding-left: 10px;
     }
   }
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index ef63b0106007290efe22abf5ed01051dcc2949f6..73c7c9f687c2396ea7ea25bc00222992eaeb886a 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -46,7 +46,7 @@
 
       img {
         position: relative;
-        top:-1px;
+        top: -1px;
       }
     }
 
diff --git a/app/assets/stylesheets/pages/ui_dev_kit.scss b/app/assets/stylesheets/pages/ui_dev_kit.scss
index 05fa9312efbb845e4324b114cd9a451a1d85006a..587bd6a1e8a8fd882e291275ce4837b7faf87621 100644
--- a/app/assets/stylesheets/pages/ui_dev_kit.scss
+++ b/app/assets/stylesheets/pages/ui_dev_kit.scss
@@ -7,7 +7,7 @@
   .example {
     &:before {
       content: "Example";
-      color: #BBB;
+      color: #bbb;
     }
 
     padding: 15px;
diff --git a/app/assets/stylesheets/pages/xterm.scss b/app/assets/stylesheets/pages/xterm.scss
index 9a50096c0d07563086ca7ffa83bf997fd790ffbe..8886c1dff56fac22a31c6a510222615f5e5be208 100644
--- a/app/assets/stylesheets/pages/xterm.scss
+++ b/app/assets/stylesheets/pages/xterm.scss
@@ -2,23 +2,23 @@
   // color codes are based on http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
   // see also: https://gist.github.com/jasonm23/2868981
 
-  $black: #000000;
+  $black: #000;
   $red: #cd0000;
   $green: #00cd00;
   $yellow: #cdcd00;
-  $blue: #0000ee;   // according to wikipedia, this is the xterm standard
+  $blue: #00e;   // according to wikipedia, this is the xterm standard
   //$blue: #1e90ff; // this is used by all the terminals I tried (when configured with the xterm color profile)
   $magenta: #cd00cd;
   $cyan: #00cdcd;
   $white: #e5e5e5;
   $l-black: #7f7f7f;
-  $l-red: #ff0000;
-  $l-green: #00ff00;
-  $l-yellow: #ffff00;
+  $l-red: #f00;
+  $l-green: #0f0;
+  $l-yellow: #ff0;
   $l-blue: #5c5cff;
-  $l-magenta: #ff00ff;
-  $l-cyan: #00ffff;
-  $l-white: #ffffff;
+  $l-magenta: #f0f;
+  $l-cyan: #0ff;
+  $l-white: #fff;
 
   .term-bold {
       font-weight: bold;
@@ -136,7 +136,7 @@
 
 
   .xterm-fg-0 {
-    color: #000000;
+    color: #000;
   }
   .xterm-fg-1 {
     color: #800000;
@@ -163,28 +163,28 @@
     color: #808080;
   }
   .xterm-fg-9 {
-    color: #ff0000;
+    color: #f00;
   }
   .xterm-fg-10 {
-    color: #00ff00;
+    color: #0f0;
   }
   .xterm-fg-11 {
-    color: #ffff00;
+    color: #ff0;
   }
   .xterm-fg-12 {
-    color: #0000ff;
+    color: #00f;
   }
   .xterm-fg-13 {
-    color: #ff00ff;
+    color: #f0f;
   }
   .xterm-fg-14 {
-    color: #00ffff;
+    color: #0ff;
   }
   .xterm-fg-15 {
-    color: #ffffff;
+    color: #fff;
   }
   .xterm-fg-16 {
-    color: #000000;
+    color: #000;
   }
   .xterm-fg-17 {
     color: #00005f;
@@ -199,7 +199,7 @@
     color: #0000d7;
   }
   .xterm-fg-21 {
-    color: #0000ff;
+    color: #00f;
   }
   .xterm-fg-22 {
     color: #005f00;
@@ -274,7 +274,7 @@
     color: #00d7ff;
   }
   .xterm-fg-46 {
-    color: #00ff00;
+    color: #0f0;
   }
   .xterm-fg-47 {
     color: #00ff5f;
@@ -289,7 +289,7 @@
     color: #00ffd7;
   }
   .xterm-fg-51 {
-    color: #00ffff;
+    color: #0ff;
   }
   .xterm-fg-52 {
     color: #5f0000;
@@ -724,7 +724,7 @@
     color: #d7ffff;
   }
   .xterm-fg-196 {
-    color: #ff0000;
+    color: #f00;
   }
   .xterm-fg-197 {
     color: #ff005f;
@@ -739,7 +739,7 @@
     color: #ff00d7;
   }
   .xterm-fg-201 {
-    color: #ff00ff;
+    color: #f0f;
   }
   .xterm-fg-202 {
     color: #ff5f00;
@@ -814,7 +814,7 @@
     color: #ffd7ff;
   }
   .xterm-fg-226 {
-    color: #ffff00;
+    color: #ff0;
   }
   .xterm-fg-227 {
     color: #ffff5f;
@@ -829,7 +829,7 @@
     color: #ffffd7;
   }
   .xterm-fg-231 {
-    color: #ffffff;
+    color: #fff;
   }
   .xterm-fg-232 {
     color: #080808;
@@ -850,7 +850,7 @@
     color: #3a3a3a;
   }
   .xterm-fg-238 {
-    color: #444444;
+    color: #444;
   }
   .xterm-fg-239 {
     color: #4e4e4e;
@@ -901,6 +901,6 @@
     color: #e4e4e4;
   }
   .xterm-fg-255 {
-    color: #eeeeee;
+    color: #eee;
   }
 }
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 2463cfa87be6dcff55e93085ae8d4eee28c82b4c..e9b0972bdd8725da6fb376ec53ef11a51bfad42a 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -6,7 +6,7 @@ class Admin::AbuseReportsController < Admin::ApplicationController
   def destroy
     abuse_report = AbuseReport.find(params[:id])
 
-    abuse_report.remove_user if params[:remove_user]
+    abuse_report.remove_user(deleted_by: current_user) if params[:remove_user]
     abuse_report.destroy
 
     render nothing: true
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 87f4fb455b8e14ff60980bd88dbf8b5a341ee31b..9abf08d0e19a462d5b8f1c5664964ac300f82f40 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -119,10 +119,10 @@ class Admin::UsersController < Admin::ApplicationController
   end
 
   def destroy
-    DeleteUserService.new(current_user).execute(user)
+    DeleteUserWorker.perform_async(current_user.id, user.id)
 
     respond_to do |format|
-      format.html { redirect_to admin_users_path }
+      format.html { redirect_to admin_users_path, notice: "The user is being deleted." }
       format.json { head :ok }
     end
   end
@@ -150,7 +150,7 @@ class Admin::UsersController < Admin::ApplicationController
       :email, :remember_me, :bio, :name, :username,
       :skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
       :extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key, :hide_no_password,
-      :projects_limit, :can_create_group, :admin, :key_id
+      :projects_limit, :can_create_group, :admin, :key_id, :external
     )
   end
 
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 43cf8fa71af4d468ebf0a30d8df7e13c879cf508..be488483b0998e96fcf4a7b13736910164e0dd10 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -1,25 +1,34 @@
 class Dashboard::TodosController < Dashboard::ApplicationController
-  before_action :find_todos, only: [:index, :destroy_all]
+  before_action :find_todos, only: [:index, :destroy, :destroy_all]
 
   def index
     @todos = @todos.page(params[:page]).per(PER_PAGE)
   end
 
   def destroy
-    todo.done!
+    todo.done
+
+    todo_notice = 'Todo was successfully marked as done.'
 
     respond_to do |format|
-      format.html { redirect_to dashboard_todos_path, notice: 'Todo was successfully marked as done.' }
+      format.html { redirect_to dashboard_todos_path, notice: todo_notice }
       format.js { render nothing: true }
+      format.json do
+        render json: { count: @todos.size, done_count: current_user.todos.done.count }
+      end
     end
   end
 
   def destroy_all
-    @todos.each(&:done!)
+    @todos.each(&:done)
 
     respond_to do |format|
       format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
       format.js { render nothing: true }
+      format.json do
+        find_todos
+        render json: { count: @todos.size, done_count: current_user.todos.done.count }
+      end
     end
   end
 
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 139e40db180ffee38c873eab2cccecc95d84b957..36986d9a18d9cb992ee50f553ce3328e2c3352d2 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -3,7 +3,7 @@ class DashboardController < Dashboard::ApplicationController
   include MergeRequestsAction
 
   before_action :event_filter, only: :activity
-  before_action :projects, only: [:issues, :merge_requests]
+  before_action :projects, only: [:issues, :merge_requests, :labels, :milestones]
 
   respond_to :html
 
@@ -20,6 +20,22 @@ class DashboardController < Dashboard::ApplicationController
     end
   end
 
+  def labels
+    respond_to do |format|
+      format.json do
+        render json: view_context.projects_labels_options
+      end
+    end
+  end
+
+  def milestones
+    respond_to do |format|
+      format.json do
+        render json: view_context.projects_milestones_options
+      end
+    end
+  end
+
   protected
 
   def load_events
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index dc9c96df0038a104dd327c40a3457ced5f74127e..6ff47c4033abcc73a5ad982e627ca663013c1036 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -1,5 +1,5 @@
 class Projects::BadgesController < Projects::ApplicationController
-  before_action :set_no_cache
+  before_action :no_cache_headers
 
   def build
     respond_to do |format|
@@ -10,15 +10,4 @@ class Projects::BadgesController < Projects::ApplicationController
       end
     end
   end
-
-  private
-
-  def set_no_cache
-    expires_now
-
-    # Add some deprecated headers for older agents
-    #
-    response.headers['Pragma'] = 'no-cache'
-    response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
-  end
 end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 4db3b3bf23db19e3cec742473fd5b3531a28e431..43ea717cbd2ff52140ecf50c02d281df68e103d6 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -9,7 +9,7 @@ class Projects::BranchesController < Projects::ApplicationController
     @sort = params[:sort] || 'name'
     @branches = @repository.branches_sorted_by(@sort)
     @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(PER_PAGE)
-    
+
     @max_commits = @branches.reduce(0) do |memo, branch|
       diverging_commit_counts = repository.diverging_commit_counts(branch)
       [memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max
@@ -23,11 +23,15 @@ class Projects::BranchesController < Projects::ApplicationController
   def create
     branch_name = sanitize(strip_tags(params[:branch_name]))
     branch_name = Addressable::URI.unescape(branch_name)
-    ref = sanitize(strip_tags(params[:ref]))
-    ref = Addressable::URI.unescape(ref)
+
     result = CreateBranchService.new(project, current_user).
         execute(branch_name, ref)
 
+    if params[:issue_iid]
+      issue = @project.issues.find_by(iid: params[:issue_iid])
+      SystemNoteService.new_issue_branch(issue, @project, current_user, branch_name) if issue
+    end
+
     if result[:status] == :success
       @branch = result[:branch]
       redirect_to namespace_project_tree_path(@project.namespace, @project,
@@ -49,4 +53,15 @@ class Projects::BranchesController < Projects::ApplicationController
       format.js { render status: status[:return_code] }
     end
   end
+
+  private
+
+  def ref
+    if params[:ref]
+      ref_escaped = sanitize(strip_tags(params[:ref]))
+      Addressable::URI.unescape(ref_escaped)
+    else
+      @project.default_branch
+    end
+  end
 end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index b0a03ee45cce92e8ea042122c6ac10bd74f5d9f3..6603f28a0823652c27596af33a94cc5097525db5 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -5,7 +5,7 @@ class Projects::IssuesController < Projects::ApplicationController
   before_action :issue, only: [:edit, :update, :show]
 
   # Allow read any issue
-  before_action :authorize_read_issue!
+  before_action :authorize_read_issue!, only: [:show]
 
   # Allow write(create) issue
   before_action :authorize_create_issue!, only: [:new, :create]
@@ -65,6 +65,7 @@ class Projects::IssuesController < Projects::ApplicationController
     @notes = @issue.notes.nonawards.with_associations.fresh
     @noteable = @issue
     @merge_requests = @issue.referenced_merge_requests(current_user)
+    @related_branches = @issue.related_branches - @merge_requests.map(&:source_branch)
 
     respond_with(@issue)
   end
@@ -127,6 +128,10 @@ class Projects::IssuesController < Projects::ApplicationController
   end
   alias_method :subscribable_resource, :issue
 
+  def authorize_read_issue!
+    return render_404 unless can?(current_user, :read_issue, @issue)
+  end
+
   def authorize_update_issue!
     return render_404 unless can?(current_user, :update_issue, @issue)
   end
@@ -157,7 +162,7 @@ class Projects::IssuesController < Projects::ApplicationController
 
   def issue_params
     params.require(:issue).permit(
-      :title, :assignee_id, :position, :description,
+      :title, :assignee_id, :position, :description, :confidential,
       :milestone_id, :state_event, :task_num, label_ids: []
     )
   end
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 40d8098690aa1cedbbccc9f412307ca0ecd3c15f..5f471d405f5e9af37461f050464dbd1bf6f59047 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -12,6 +12,13 @@ class Projects::LabelsController < Projects::ApplicationController
 
   def index
     @labels = @project.labels.page(params[:page]).per(PER_PAGE)
+
+    respond_to do |format|
+      format.html
+      format.json do
+        render json: @project.labels
+      end
+    end
   end
 
   def new
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index da46731d945eacc310ebe013498c4ff23dd13be2..0998b191c0711f0e8167b46e639ee9b073e3c3e4 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -19,7 +19,15 @@ class Projects::MilestonesController < Projects::ApplicationController
       end
 
     @milestones = @milestones.includes(:project)
-    @milestones = @milestones.page(params[:page]).per(PER_PAGE)
+
+    respond_to do |format|
+      format.html do
+        @milestones = @milestones.page(params[:page]).per(PER_PAGE)
+      end
+      format.json do
+        render json: @milestones
+      end
+    end
   end
 
   def new
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 36f37221c584f68fd5f96b1679777e24ed09cf2e..c993048077060c57750f84ffbdbc0cb8a40993ec 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -134,7 +134,7 @@ class ProjectsController < ApplicationController
   def autocomplete_sources
     note_type = params['type']
     note_id = params['type_id']
-    autocomplete = ::Projects::AutocompleteService.new(@project)
+    autocomplete = ::Projects::AutocompleteService.new(@project, current_user)
     participants = ::Projects::ParticipantsService.new(@project, current_user).execute(note_type, note_id)
 
     @suggestions = {
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index 20a2b0ce8f0dbb21d25e8941954dd8b26b0128ca..c2befa5a5b3a4837010ecc1c035f36437c2f56d8 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -19,4 +19,10 @@ class IssuesFinder < IssuableFinder
   def klass
     Issue
   end
+
+  private
+
+  def init_collection
+    Issue.visible_to_user(current_user)
+  end
 end
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 2c55f088594624760914482d803814e3fe6b482d..3a5fc5b5907089e3ef6304bbcb8dba49e39b9863 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -40,25 +40,26 @@ class ProjectsFinder
   private
 
   def group_projects(current_user, group)
-    if current_user
-      [
-        group_projects_for_user(current_user, group),
-        group.projects.public_and_internal_only,
-        group.shared_projects.visible_to_user(current_user)
-      ]
+    return [group.projects.public_only] unless current_user
+
+    user_group_projects = [
+       group_projects_for_user(current_user, group),
+       group.shared_projects.visible_to_user(current_user)
+    ]
+    if current_user.external?
+      user_group_projects << group.projects.public_only
     else
-      [group.projects.public_only]
+      user_group_projects << group.projects.public_and_internal_only
     end
   end
 
   def all_projects(current_user)
-    if current_user
-      [
-        current_user.authorized_projects,
-        public_and_internal_projects
-      ]
+    return [public_projects] unless current_user
+
+    if current_user.external?
+      [current_user.authorized_projects, public_projects]
     else
-      [Project.public_only]
+      [current_user.authorized_projects, public_and_internal_projects]
     end
   end
 
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index d1b1c61b7106ee271a78a39753fd732b036baf7b..e6ceb21353209a7f44a5fbb3456b90399dba115f 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -182,7 +182,7 @@ module ApplicationHelper
   # Returns an HTML-safe String
   def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
     element = content_tag :time, time.to_s,
-      class: "#{html_class} js-timeago js-timeago-pending",
+      class: "#{html_class} js-timeago #{"js-timeago-pending" unless skip_js}",
       datetime: time.to_time.getutc.iso8601,
       title: time.in_time_zone.to_s(:medium),
       data: { toggle: 'tooltip', placement: placement, container: 'body' }
@@ -196,6 +196,22 @@ module ApplicationHelper
     element
   end
 
+  def edited_time_ago_with_tooltip(object, placement: 'top', html_class: 'time_ago', include_author: false)
+    return if object.updated_at == object.created_at
+
+    content_tag :small, class: "edited-text" do
+      output = content_tag(:span, "Edited ")
+      output << time_ago_with_tooltip(object.updated_at, placement: placement, html_class: html_class)
+
+      if include_author && object.updated_by && object.updated_by != object.author
+        output << content_tag(:span, " by ")
+        output << link_to_member(object.project, object.updated_by, avatar: false, author_class: nil)
+      end
+
+      output
+    end
+  end
+
   def render_markup(file_name, file_content)
     if gitlab_markdown?(file_name)
       Haml::Helpers.preserve(markdown(file_content))
@@ -285,7 +301,7 @@ module ApplicationHelper
       if project.nil?
         nil
       elsif current_controller?(:issues)
-        project.issues.send(entity).count
+        project.issues.visible_to_user(current_user).send(entity).count
       elsif current_controller?(:merge_requests)
         project.merge_requests.send(entity).count
       end
diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb
index 74f326e0b83815ebf8f491fe462ff2468b59e863..ceff1fbb1618a0d16b1f658a438eabc4e0fc4da5 100644
--- a/app/helpers/dropdowns_helper.rb
+++ b/app/helpers/dropdowns_helper.rb
@@ -24,7 +24,7 @@ module DropdownsHelper
           capture(&block) if block && !options.has_key?(:footer_content)
         end
 
-        if block && options.has_key?(:footer_content)
+        if block && options[:footer_content]
           output << content_tag(:div, class: "dropdown-footer") do
             capture(&block)
           end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 37a888d9c60bdd3d70ffa1c202e2ae3c53a0f77e..a67a6b208e256bdfb9aa4023569e57b16b071ed4 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -194,7 +194,7 @@ module EventsHelper
   end
 
   def event_to_atom(xml, event)
-    if event.proper?
+    if event.proper?(current_user)
       xml.entry do
         event_link = event_feed_url(event)
         event_title = event_feed_title(event)
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 2dfeddf7368684c23b47e716d1ee5abd872d638b..81df2094392dbfa79e966bf45137ec57330c251a 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -20,6 +20,23 @@ module IssuablesHelper
     base_issuable_scope(issuable).where('iid < ?', issuable.iid).first
   end
 
+  def user_dropdown_label(user_id, default_label)
+    return "Unassigned" if user_id == "0"
+
+    if @project
+      member = @project.team.find_member(user_id)
+      user = member.user if member
+    else
+      user = User.find_by(id: user_id)
+    end
+
+    if user
+      user.name
+    else
+      default_label
+    end
+  end
+
   private
 
   def sidebar_gutter_collapsed?
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index ae4ebc0854a9e03aa7999f5cbe982177e536a960..e00d320402703421fddf4c4739bb71547c542495 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -98,6 +98,10 @@ module IssuesHelper
     end.sort.to_sentence(last_word_connector: ', or ')
   end
 
+  def confidential_icon(issue)
+    icon('eye-slash') if issue.confidential?
+  end
+
   def emoji_icon(name, unicode = nil, aliases = [])
     unicode ||= Emoji.emoji_filename(name) rescue ""
 
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 4455dcd0e20e166af5b62321737dfd4ab9d22c12..49f701e9bee12bcb7b2795eab92f1395f18248ad 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -110,18 +110,19 @@ module LabelsHelper
   end
 
   def projects_labels_options
-    labels =
-      if @project
-        @project.labels
-      else
-        Label.where(project_id: @projects)
-      end
-
-    grouped_labels = GlobalLabel.build_collection(labels)
-    grouped_labels.unshift(Label::None)
-    grouped_labels.unshift(Label::Any)
+    if @project
+      @project.labels
+    else
+      Label.where(project_id: @projects)
+    end
+  end
 
-    options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name])
+  def labels_filter_path
+    if @project
+      namespace_project_labels_path(@project.namespace, @project, :json)
+    else
+      labels_dashboard_path(:json)
+    end
   end
 
   def label_subscription_status(label)
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index e8ac8788d9dcc3af98c0d8f257fbf426847197dd..de60be4eb25893e321f7a6fad01751508c0aa7ff 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -38,7 +38,7 @@ module MilestonesHelper
   def milestone_progress_bar(milestone)
     options = {
       class: 'progress-bar progress-bar-success',
-      style: "width: #{milestone.percent_complete}%;"
+      style: "width: #{milestone.percent_complete(current_user)}%;"
     }
 
     content_tag :div, class: 'progress' do
@@ -56,12 +56,15 @@ module MilestonesHelper
 
     epoch = DateTime.parse('1970-01-01')
     grouped_milestones = GlobalMilestone.build_collection(milestones)
-    grouped_milestones = grouped_milestones.sort_by { |x| x.due_date.nil? ? epoch : x.due_date }
-    grouped_milestones.unshift(Milestone::None)
-    grouped_milestones.unshift(Milestone::Any)
-    grouped_milestones.unshift(Milestone::Upcoming)
+    grouped_milestones.sort_by { |x| x.due_date.nil? ? epoch : x.due_date }
+  end
 
-    options_from_collection_for_select(grouped_milestones, 'name', 'title', params[:milestone_title])
+  def milestones_filter_dropdown_path
+    if @project
+      namespace_project_milestones_path(@project.namespace, @project, :json)
+    else
+      milestones_dashboard_path(:json)
+    end
   end
 
   def milestone_remaining_days(milestone)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index b5acb80b72092194cdc883aba2878f6984f88fa6..5473419ef247885db1d6830fd2c8546995ac8c8b 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -26,7 +26,7 @@ module ProjectsHelper
     image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
   end
 
-  def link_to_member(project, author, opts = {})
+  def link_to_member(project, author, opts = {}, &block)
     default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" }
     opts = default_opts.merge(opts)
 
@@ -44,6 +44,8 @@ module ProjectsHelper
       author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
     end
 
+    author_html << capture(&block) if block
+
     author_html = author_html.html_safe
 
     if opts[:name]
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 07ddc691d859845371d865f73f99e39e69b20eb2..edc5686cf08e68e294d78deb58e9bee0f986dffd 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -16,14 +16,19 @@ module TodosHelper
 
   def todo_target_link(todo)
     target = todo.target_type.titleize.downcase
-    link_to "#{target} #{todo.target.to_reference}", todo_target_path(todo), { title: h(todo.target.title) }
+    link_to "#{target} #{todo.target_reference}", todo_target_path(todo), { title: todo.target.title }
   end
 
   def todo_target_path(todo)
     anchor = dom_id(todo.note) if todo.note.present?
 
-    polymorphic_path([todo.project.namespace.becomes(Namespace),
-                      todo.project, todo.target], anchor: anchor)
+    if todo.for_commit?
+      namespace_project_commit_path(todo.project.namespace.becomes(Namespace), todo.project,
+                                    todo.target, anchor: anchor)
+    else
+      polymorphic_path([todo.project.namespace.becomes(Namespace),
+                        todo.project, todo.target], anchor: anchor)
+    end
   end
 
   def todos_filter_params
diff --git a/app/models/ability.rb b/app/models/ability.rb
index fe9e0aab71732052f451ece80c425aaa4ad16736..e22da4806e69502e5b377ec6b7896ce1443132c2 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -49,7 +49,6 @@ class Ability
         rules = [
           :read_project,
           :read_wiki,
-          :read_issue,
           :read_label,
           :read_milestone,
           :read_project_snippet,
@@ -63,6 +62,9 @@ class Ability
         # Allow to read builds by anonymous user if guests are allowed
         rules << :read_build if project.public_builds?
 
+        # Allow to read issues by anonymous user if issue is not confidential
+        rules << :read_issue unless subject.is_a?(Issue) && subject.confidential?
+
         rules - project_disabled_features_rules(project)
       else
         []
@@ -109,23 +111,10 @@ class Ability
       key = "/user/#{user.id}/project/#{project.id}"
 
       RequestStore.store[key] ||= begin
-        team = project.team
-
-        # Rules based on role in project
-        if team.master?(user)
-          rules.push(*project_master_rules)
-
-        elsif team.developer?(user)
-          rules.push(*project_dev_rules)
-
-        elsif team.reporter?(user)
-          rules.push(*project_report_rules)
+        # Push abilities on the users team role
+        rules.push(*project_team_rules(project.team, user))
 
-        elsif team.guest?(user)
-          rules.push(*project_guest_rules)
-        end
-
-        if project.public? || project.internal?
+        if project.public? || (project.internal? && !user.external?)
           rules.push(*public_project_rules)
 
           # Allow to read builds for internal projects
@@ -148,6 +137,19 @@ class Ability
       end
     end
 
+    def project_team_rules(team, user)
+      # Rules based on role in project
+      if team.master?(user)
+        project_master_rules
+      elsif team.developer?(user)
+        project_dev_rules
+      elsif team.reporter?(user)
+        project_report_rules
+      elsif team.guest?(user)
+        project_guest_rules
+      end
+    end
+
     def public_project_rules
       @public_project_rules ||= project_guest_rules + [
         :download_code,
@@ -321,6 +323,7 @@ class Ability
         end
 
         rules += project_abilities(user, subject.project)
+        rules = filter_confidential_issues_abilities(user, subject, rules) if subject.is_a?(Issue)
         rules
       end
     end
@@ -356,7 +359,7 @@ class Ability
         ]
       end
 
-      if snippet.public? || snippet.internal?
+      if snippet.public? || (snippet.internal? && !user.external?)
         rules << :read_personal_snippet
       end
 
@@ -439,5 +442,17 @@ class Ability
         :"admin_#{name}"
       ]
     end
+
+    def filter_confidential_issues_abilities(user, issue, rules)
+      return rules if user.admin? || !issue.confidential?
+
+      unless issue.author == user || issue.assignee == user || issue.project.team.member?(user.id)
+        rules.delete(:admin_issue)
+        rules.delete(:read_issue)
+        rules.delete(:update_issue)
+      end
+
+      rules
+    end
   end
 end
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index cc59aa4e9111ee9790357854a418ee7d141d2ff5..b61f51231278de1e99fb90f2efaafcfac2ffe47d 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -19,9 +19,9 @@ class AbuseReport < ActiveRecord::Base
   validates :message, presence: true
   validates :user_id, uniqueness: { message: 'has already been reported' }
 
-  def remove_user
+  def remove_user(deleted_by:)
     user.block
-    user.destroy
+    DeleteUserWorker.perform_async(deleted_by.id, user.id, delete_solo_owned_groups: true)
   end
 
   def notify
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 3b1aa0f5c80150dbd4c3d443014fc57d6d73582d..3377a85a55a7a103a451d44baf6060398d76223b 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -114,7 +114,7 @@ class CommitStatus < ActiveRecord::Base
   end
 
   def ignored?
-    failed? && allow_failure?
+    allow_failure? && (failed? || canceled?)
   end
 
   def duration
diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb
index d67df7c1d9c1933592f0ceebb40ebdd6f0af3b61..5b8e3f654ea6be9a667ad6a08557ef0bb245a789 100644
--- a/app/models/concerns/milestoneish.rb
+++ b/app/models/concerns/milestoneish.rb
@@ -1,18 +1,18 @@
 module Milestoneish
-  def closed_items_count
-    issues.closed.size + merge_requests.closed_and_merged.size
+  def closed_items_count(user = nil)
+    issues_visible_to_user(user).closed.size + merge_requests.closed_and_merged.size
   end
 
-  def total_items_count
-    issues.size + merge_requests.size
+  def total_items_count(user = nil)
+    issues_visible_to_user(user).size + merge_requests.size
   end
 
-  def complete?
-    total_items_count == closed_items_count
+  def complete?(user = nil)
+    total_items_count(user) == closed_items_count(user)
   end
 
-  def percent_complete
-    ((closed_items_count * 100) / total_items_count).abs
+  def percent_complete(user = nil)
+    ((closed_items_count(user) * 100) / total_items_count(user)).abs
   rescue ZeroDivisionError
     0
   end
@@ -22,4 +22,8 @@ module Milestoneish
 
     (due_date - Date.today).to_i
   end
+
+  def issues_visible_to_user(user = nil)
+    issues.visible_to_user(user)
+  end
 end
diff --git a/app/models/event.rb b/app/models/event.rb
index 9a0bbf50f8b529753256e3b0755af46acf9cc477..a5cfeaf388ea4563d4df915a35c03a1a8bec891a 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -73,15 +73,17 @@ class Event < ActiveRecord::Base
     end
   end
 
-  def proper?
+  def proper?(user = nil)
     if push?
       true
     elsif membership_changed?
       true
     elsif created_project?
       true
+    elsif issue?
+      Ability.abilities.allowed?(user, :read_issue, issue)
     else
-      ((issue? || merge_request? || note?) && target) || milestone?
+      ((merge_request? || note?) && target) || milestone?
     end
   end
 
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 5f58c0508fd0279966120d0e5bc7096c850dd4e9..053387cffd70c74d7ba05be3c1898da91d60363a 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -58,6 +58,13 @@ class Issue < ActiveRecord::Base
     attributes
   end
 
+  def self.visible_to_user(user)
+    return where(confidential: false) if user.blank?
+    return all if user.admin?
+
+    where('issues.confidential = false OR (issues.confidential = true AND (issues.author_id = :user_id OR issues.assignee_id = :user_id OR issues.project_id IN(:project_ids)))', user_id: user.id, project_ids: user.authorized_projects.select(:id))
+  end
+
   def self.reference_prefix
     '#'
   end
@@ -87,11 +94,21 @@ class Issue < ActiveRecord::Base
   end
 
   def referenced_merge_requests(current_user = nil)
-    Gitlab::ReferenceExtractor.lazily do
-      [self, *notes].flat_map do |note|
-        note.all_references(current_user).merge_requests
-      end
-    end.sort_by(&:iid)
+    @referenced_merge_requests ||= {}
+    @referenced_merge_requests[current_user] ||= begin
+      Gitlab::ReferenceExtractor.lazily do
+        [self, *notes].flat_map do |note|
+          note.all_references(current_user).merge_requests
+        end
+      end.sort_by(&:iid).uniq
+    end
+  end
+
+  def related_branches
+    return [] if self.project.empty_repo?
+    self.project.repository.branch_names.select do |branch|
+      branch =~ /\A#{iid}-(?!\d+-stable)/i
+    end
   end
 
   # Reset issue events cache
@@ -120,4 +137,15 @@ class Issue < ActiveRecord::Base
       note.all_references(current_user).merge_requests
     end.uniq.select { |mr| mr.open? && mr.closes_issue?(self) }
   end
+
+  def to_branch_name
+    "#{iid}-#{title.parameterize}"
+  end
+
+  def can_be_worked_on?(current_user)
+    !self.closed? &&
+      !self.project.forked? &&
+      self.related_branches.empty? &&
+      self.closed_by_merge_requests(current_user).empty?
+  end
 end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 188325045e2f80968ea0e48896755ec701c1f1d7..30a7bd47be7029fba3bfdb3c51b6cc34499a4166 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -520,7 +520,11 @@ class MergeRequest < ActiveRecord::Base
   end
 
   def source_sha
-    last_commit.try(:sha)
+    last_commit.try(:sha) || source_tip.try(:sha)
+  end
+
+  def source_tip
+    source_branch && source_project.repository.commit(source_branch)
   end
 
   def fetch_ref
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 374590ba0c51093c1990978062c9c6b20b4e0f76..de7183bf6b4e836b97700f6c816998c1afe5d771 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -121,8 +121,8 @@ class Milestone < ActiveRecord::Base
     active? && issues.opened.count.zero?
   end
 
-  def is_empty?
-    total_items_count.zero?
+  def is_empty?(user = nil)
+    total_items_count(user).zero?
   end
 
   def author_id
diff --git a/app/models/project.rb b/app/models/project.rb
index 89a55a510cdfa9c15e041059dea2ac3f16f2a290..412c6c6732ddbb1d282971682fb7be30520f8500 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -254,12 +254,6 @@ class Project < ActiveRecord::Base
       where('projects.last_activity_at < ?', 6.months.ago)
     end
 
-    def publicish(user)
-      visibility_levels = [Project::PUBLIC]
-      visibility_levels << Project::INTERNAL if user
-      where(visibility_level: visibility_levels)
-    end
-
     def with_push
       joins(:events).where('events.action = ?', Event::PUSHED)
     end
@@ -577,10 +571,7 @@ class Project < ActiveRecord::Base
   end
 
   def avatar_in_git
-    @avatar_file ||= 'logo.png' if repository.blob_at_branch('master', 'logo.png')
-    @avatar_file ||= 'logo.jpg' if repository.blob_at_branch('master', 'logo.jpg')
-    @avatar_file ||= 'logo.gif' if repository.blob_at_branch('master', 'logo.gif')
-    @avatar_file
+    repository.avatar
   end
 
   def avatar_url
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index c96e6f0b8ea3f6b954495690620fa520d65e6700..59b1b86d1fb5c9b9225d3d00c7b146bc0468100f 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -2,7 +2,7 @@ class ProjectWiki
   include Gitlab::ShellAdapter
 
   MARKUPS = {
-    'Markdown' => :md,
+    'Markdown' => :markdown,
     'RDoc'     => :rdoc,
     'AsciiDoc' => :asciidoc
   } unless defined?(MARKUPS)
@@ -47,7 +47,7 @@ class ProjectWiki
   def wiki
     @wiki ||= begin
       Gollum::Wiki.new(path_to_repo)
-    rescue Gollum::NoSuchPathError
+    rescue Rugged::OSError
       create_repo!
     end
   end
@@ -90,7 +90,7 @@ class ProjectWiki
   def create_page(title, content, format = :markdown, message = nil)
     commit = commit_details(:created, message, title)
 
-    wiki.write_page(title, format, content, commit)
+    wiki.write_page(title, format.to_sym, content, commit)
 
     update_project_activity
   rescue Gollum::DuplicatePageError => e
@@ -101,7 +101,7 @@ class ProjectWiki
   def update_page(page, content, format = :markdown, message = nil)
     commit = commit_details(:updated, message, page.title)
 
-    wiki.update_page(page, page.name, format, content, commit)
+    wiki.update_page(page, page.name, format.to_sym, content, commit)
 
     update_project_activity
   end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 6441cd87e87715601aaa943f2744812611c6afb7..25d24493f6e0a44d05eaedba6379e7a2708d58a4 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -3,6 +3,10 @@ require 'securerandom'
 class Repository
   class CommitError < StandardError; end
 
+  # Files to use as a project avatar in case no avatar was uploaded via the web
+  # UI.
+  AVATAR_FILES = %w{logo.png logo.jpg logo.gif}
+
   include Gitlab::ShellAdapter
 
   attr_accessor :path_with_namespace, :project
@@ -223,12 +227,6 @@ class Repository
         send(key)
       end
     end
-
-    branches.each do |branch|
-      unless cache.exist?(:"diverging_commit_counts_#{branch.name}")
-        send(:diverging_commit_counts, branch)
-      end
-    end
   end
 
   def expire_tags_cache
@@ -241,12 +239,13 @@ class Repository
     @branches = nil
   end
 
-  def expire_cache(branch_name = nil)
+  def expire_cache(branch_name = nil, revision = nil)
     cache_keys.each do |key|
       cache.expire(key)
     end
 
     expire_branch_cache(branch_name)
+    expire_avatar_cache(branch_name, revision)
 
     # This ensures this particular cache is flushed after the first commit to a
     # new repository.
@@ -296,18 +295,6 @@ class Repository
     @tag_count = nil
   end
 
-  def rebuild_cache
-    cache_keys.each do |key|
-      cache.expire(key)
-      send(key)
-    end
-
-    branches.each do |branch|
-      cache.expire(:"diverging_commit_counts_#{branch.name}")
-      diverging_commit_counts(branch)
-    end
-  end
-
   def lookup_cache
     @lookup_cache ||= {}
   end
@@ -316,6 +303,23 @@ class Repository
     cache.expire(:branch_names)
   end
 
+  def expire_avatar_cache(branch_name = nil, revision = nil)
+    # Avatars are pulled from the default branch, thus if somebody pushes to a
+    # different branch there's no need to expire anything.
+    return if branch_name && branch_name != root_ref
+
+    # We don't want to flush the cache if the commit didn't actually make any
+    # changes to any of the possible avatar files.
+    if revision && commit = self.commit(revision)
+      return unless commit.diffs.
+        any? { |diff| AVATAR_FILES.include?(diff.new_path) }
+    end
+
+    cache.expire(:avatar)
+
+    @avatar = nil
+  end
+
   # Runs code just before a repository is deleted.
   def before_delete
     expire_cache if exists?
@@ -350,8 +354,8 @@ class Repository
   end
 
   # Runs code after a new commit has been pushed.
-  def after_push_commit(branch_name)
-    expire_cache(branch_name)
+  def after_push_commit(branch_name, revision)
+    expire_cache(branch_name, revision)
   end
 
   # Runs code after a new branch has been created.
@@ -758,12 +762,15 @@ class Repository
   def parse_search_result(result)
     ref = nil
     filename = nil
+    basename = nil
     startline = 0
 
     result.each_line.each_with_index do |line, index|
       if line =~ /^.*:.*:\d+:/
         ref, filename, startline = line.split(':')
         startline = startline.to_i - index
+        extname = File.extname(filename)
+        basename = filename.sub(/#{extname}$/, '')
         break
       end
     end
@@ -776,6 +783,7 @@ class Repository
 
     OpenStruct.new(
       filename: filename,
+      basename: basename,
       ref: ref,
       startline: startline,
       data: data
@@ -853,6 +861,14 @@ class Repository
     end
   end
 
+  def avatar
+    @avatar ||= cache.fetch(:avatar) do
+      AVATAR_FILES.find do |file|
+        blob_at_branch('master', file)
+      end
+    end
+  end
+
   private
 
   def cache
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 5f91991f781811c79e8e85fbd40cca4582970f8e..d85f7bfdf57219688596245c6b4293f8ff5e18b9 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -5,14 +5,15 @@
 #  id          :integer          not null, primary key
 #  user_id     :integer          not null
 #  project_id  :integer          not null
-#  target_id   :integer          not null
+#  target_id   :integer
 #  target_type :string           not null
 #  author_id   :integer
-#  note_id     :integer
 #  action      :integer          not null
 #  state       :string           not null
 #  created_at  :datetime
 #  updated_at  :datetime
+#  note_id     :integer
+#  commit_id   :string
 #
 
 class Todo < ActiveRecord::Base
@@ -27,7 +28,9 @@ class Todo < ActiveRecord::Base
 
   delegate :name, :email, to: :author, prefix: true, allow_nil: true
 
-  validates :action, :project, :target, :user, presence: true
+  validates :action, :project, :target_type, :user, presence: true
+  validates :target_id, presence: true, unless: :for_commit?
+  validates :commit_id, presence: true, if: :for_commit?
 
   default_scope { reorder(id: :desc) }
 
@@ -36,7 +39,7 @@ class Todo < ActiveRecord::Base
 
   state_machine :state, initial: :pending do
     event :done do
-      transition [:pending, :done] => :done
+      transition [:pending] => :done
     end
 
     state :pending
@@ -50,4 +53,25 @@ class Todo < ActiveRecord::Base
       target.title
     end
   end
+
+  def for_commit?
+    target_type == "Commit"
+  end
+
+  # override to return commits, which are not active record
+  def target
+    if for_commit?
+      project.commit(commit_id) rescue nil
+    else
+      super
+    end
+  end
+
+  def target_reference
+    if for_commit?
+      target.short_id
+    else
+      target.to_reference
+    end
+  end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index 68b242888aae3d749efed996f48248e64150a21c..c011af03591cdb9a70b46857651b32d86a172067 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -59,6 +59,7 @@
 #  hide_project_limit          :boolean          default(FALSE)
 #  unlock_token                :string
 #  otp_grace_period_started_at :datetime
+#  external                    :boolean           default(FALSE)
 #
 
 require 'carrierwave/orm/activerecord'
@@ -77,6 +78,7 @@ class User < ActiveRecord::Base
   add_authentication_token_field :authentication_token
 
   default_value_for :admin, false
+  default_value_for :external, false
   default_value_for :can_create_group, gitlab_config.default_can_create_group
   default_value_for :can_create_team, false
   default_value_for :hide_no_ssh_key, false
@@ -171,6 +173,7 @@ class User < ActiveRecord::Base
 
   after_update :update_emails_with_primary_email, if: ->(user) { user.email_changed? }
   before_save :ensure_authentication_token
+  before_save :ensure_external_user_rights
   after_save :ensure_namespace_correct
   after_initialize :set_projects_limit
   after_create :post_create_hook
@@ -218,6 +221,7 @@ class User < ActiveRecord::Base
   # Scopes
   scope :admins, -> { where(admin: true) }
   scope :blocked, -> { with_states(:blocked, :ldap_blocked) }
+  scope :external, -> { where(external: true) }
   scope :active, -> { with_state(:active) }
   scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
   scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
@@ -273,6 +277,8 @@ class User < ActiveRecord::Base
         self.with_two_factor
       when 'wop'
         self.without_projects
+      when 'external'
+        self.external
       else
         self.active
       end
@@ -841,4 +847,11 @@ class User < ActiveRecord::Base
   def send_devise_notification(notification, *args)
     devise_mailer.send(notification, self, *args).deliver_later
   end
+
+  def ensure_external_user_rights
+    return unless self.external?
+
+    self.can_create_group   = false
+    self.projects_limit     = 0
+  end
 end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index dbd70dc5a44fff7f10cee1a390ad87edb292e27f..526760779a4d4cca53420e75d575c3e7fa9864cf 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -62,7 +62,7 @@ class WikiPage
   # The raw content of this page.
   def content
     @attributes[:content] ||= if @page
-                                @page.raw_data
+                                @page.text_data
                               end
   end
 
diff --git a/app/services/commits/revert_service.rb b/app/services/commits/revert_service.rb
index 9cb918d7a2e9d95b37736605384df97ab4ebe538..a3c950ede1f51b33d60a417633da867646e0b138 100644
--- a/app/services/commits/revert_service.rb
+++ b/app/services/commits/revert_service.rb
@@ -9,7 +9,8 @@ module Commits
       @commit = params[:commit]
       @create_merge_request = params[:create_merge_request].present?
 
-      validate and commit
+      check_push_permissions unless @create_merge_request
+      commit
     rescue Repository::CommitError, Gitlab::Git::Repository::InvalidBlobName, GitHooksService::PreReceiveError,
            ValidationError, ReversionError => ex
       error(ex.message)
@@ -45,11 +46,11 @@ module Commits
       end
     end
 
-    def validate
+    def check_push_permissions
       allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(@target_branch)
 
       unless allowed
-        raise_error('You are not allowed to push into this branch')
+        raise ValidationError.new('You are not allowed to push into this branch')
       end
 
       true
diff --git a/app/services/delete_user_service.rb b/app/services/delete_user_service.rb
index 173e50c9206ddd31f317d00ed88cfd9c2738c5fe..ce79287e35a4924f034abeeda22187c558607333 100644
--- a/app/services/delete_user_service.rb
+++ b/app/services/delete_user_service.rb
@@ -5,18 +5,22 @@ class DeleteUserService
     @current_user = current_user
   end
 
-  def execute(user)
-    if user.solo_owned_groups.present?
+  def execute(user, options = {})
+    if !options[:delete_solo_owned_groups] && user.solo_owned_groups.present?
       user.errors[:base] << 'You must transfer ownership or delete groups before you can remove user'
-      user
-    else
-      user.personal_projects.each do |project|
-        # Skip repository removal because we remove directory with namespace
-        # that contain all this repositories
-        ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete!
-      end
+      return user
+    end
+
+    user.solo_owned_groups.each do |group|
+      DestroyGroupService.new(group, current_user).execute
+    end
 
-      user.destroy
+    user.personal_projects.each do |project|
+      # Skip repository removal because we remove directory with namespace
+      # that contain all this repositories
+      ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete!
     end
+
+    user.destroy
   end
 end
diff --git a/app/services/destroy_group_service.rb b/app/services/destroy_group_service.rb
index 9189de390a2bfae5d723f0c386045dd11aa5f96b..3c42ac61be4e3e4ff070adcd6d404071d0a79cfe 100644
--- a/app/services/destroy_group_service.rb
+++ b/app/services/destroy_group_service.rb
@@ -6,12 +6,12 @@ class DestroyGroupService
   end
 
   def execute
-    @group.projects.each do |project|
+    group.projects.each do |project|
       # Skip repository removal because we remove directory with namespace
       # that contain all this repositories
       ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete!
     end
 
-    @group.destroy
+    group.destroy
   end
 end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index d840ab5e340de453b8affb58c1c0401a3e98035d..14e2a2c0699ec2d5ef6c2b339ff51a5c13dff327 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -17,7 +17,7 @@ class GitPushService < BaseService
   #  6. Checks if the project's main language has changed
   #
   def execute
-    @project.repository.after_push_commit(branch_name)
+    @project.repository.after_push_commit(branch_name, params[:newrev])
 
     if push_remove_branch?
       @project.repository.after_remove_branch
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 954746a39a5836b99a21913bc3eb6678ee6e33a5..fa34753c4fd2d3e4f5b4c2fe0a98d30438a1df9f 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -47,6 +47,21 @@ module MergeRequests
         merge_request.title = merge_request.source_branch.titleize.humanize
       end
 
+      # When your branch name starts with an iid followed by a dash this pattern will
+      # be interpreted as the use wants to close that issue on this project
+      # Pattern example: 112-fix-mep-mep
+      # Will lead to appending `Closes #112` to the description
+      if match = merge_request.source_branch.match(/\A(\d+)-/)
+        iid = match[1]
+        closes_issue = "Closes ##{iid}"
+
+        if merge_request.description.present?
+          merge_request.description << closes_issue.prepend("\n")
+        else
+          merge_request.description = closes_issue
+        end
+      end
+
       merge_request
     end
 
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index 7408e09ed1e9df60df177b33cade2521db187cda..ba50305dbd5fca2831c1534cd4a8a0eec4f94a57 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -1,11 +1,7 @@
 module Projects
   class AutocompleteService < BaseService
-    def initialize(project)
-      @project = project
-    end
-
     def issues
-      @project.issues.opened.select([:iid, :title])
+      @project.issues.visible_to_user(current_user).opened.select([:iid, :title])
     end
 
     def merge_requests
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index e1e94c5cc38dde3a444ab45f31a36079a2c984fd..aa9837038a6b4a9ba3b5732bec7d7eeba2a975bb 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -11,7 +11,7 @@ module Search
       projects = ProjectsFinder.new.execute(current_user)
       projects = projects.in_namespace(group.id) if group
 
-      Gitlab::SearchResults.new(projects, params[:search])
+      Gitlab::SearchResults.new(current_user, projects, params[:search])
     end
   end
 end
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index c08881dce4b8b2b398a9ebfb766f78c7d52b0958..4b500914cfbb4c7f006247c2a36826a28398c3a3 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -7,7 +7,8 @@ module Search
     end
 
     def execute
-      Gitlab::ProjectSearchResults.new(project,
+      Gitlab::ProjectSearchResults.new(current_user,
+                                       project,
                                        params[:search],
                                        params[:repository_ref])
     end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 58a861ee08e24dee09eef1a96d1a585619a268d5..f09b77c4a571611bf7200eed25920e3a96bda210 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -207,6 +207,18 @@ class SystemNoteService
     create_note(noteable: noteable, project: project, author: author, note: body)
   end
 
+  # Called when a branch is created from the 'new branch' button on a issue
+  # Example note text:
+  #
+  #   "Started branch `201-issue-branch-button`"
+  def self.new_issue_branch(issue, project, author, branch)
+    h = Gitlab::Application.routes.url_helpers
+    link = h.namespace_project_compare_url(project.namespace, project, from: project.default_branch, to: branch)
+
+    body = "Started branch [`#{branch}`](#{link})"
+    create_note(noteable: issue, project: project, author: author, note: body)
+  end
+
   # Called when a Mentionable references a Noteable
   #
   # noteable  - Noteable object being referenced
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index 4392e2d17fe0e1aef464e40cf8bf407bcf2fbd22..f2662922e90549beca1046c7b4054dff480b1e3f 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -103,24 +103,16 @@ class TodoService
   #  * mark all pending todos related to the target for the current user as done
   #
   def mark_pending_todos_as_done(target, user)
-    pending_todos(user, target.project, target).update_all(state: :done)
+    attributes = attributes_for_target(target)
+    pending_todos(user, attributes).update_all(state: :done)
   end
 
   private
 
-  def create_todos(project, target, author, users, action, note = nil)
+  def create_todos(users, attributes)
     Array(users).each do |user|
-      next if pending_todos(user, project, target).exists?
-
-      Todo.create(
-        project: project,
-        user_id: user.id,
-        author_id: author.id,
-        target_id: target.id,
-        target_type: target.class.name,
-        action: action,
-        note: note
-      )
+      next if pending_todos(user, attributes).exists?
+      Todo.create(attributes.merge(user_id: user.id))
     end
   end
 
@@ -130,8 +122,8 @@ class TodoService
   end
 
   def handle_note(note, author)
-    # Skip system notes, notes on commit, and notes on project snippet
-    return if note.system? || ['Commit', 'Snippet'].include?(note.noteable_type)
+    # Skip system notes, and notes on project snippet
+    return if note.system? || note.for_project_snippet?
 
     project = note.project
     target  = note.noteable
@@ -142,13 +134,39 @@ class TodoService
 
   def create_assignment_todo(issuable, author)
     if issuable.assignee && issuable.assignee != author
-      create_todos(issuable.project, issuable, author, issuable.assignee, Todo::ASSIGNED)
+      attributes = attributes_for_todo(issuable.project, issuable, author, Todo::ASSIGNED)
+      create_todos(issuable.assignee, attributes)
     end
   end
 
-  def create_mention_todos(project, issuable, author, note = nil)
-    mentioned_users = filter_mentioned_users(project, note || issuable, author)
-    create_todos(project, issuable, author, mentioned_users, Todo::MENTIONED, note)
+  def create_mention_todos(project, target, author, note = nil)
+    mentioned_users = filter_mentioned_users(project, note || target, author)
+    attributes = attributes_for_todo(project, target, author, Todo::MENTIONED, note)
+    create_todos(mentioned_users, attributes)
+  end
+
+  def attributes_for_target(target)
+    attributes = {
+      project_id: target.project.id,
+      target_id: target.id,
+      target_type: target.class.name,
+      commit_id: nil
+    }
+
+    if target.is_a?(Commit)
+      attributes.merge!(target_id: nil, commit_id: target.id)
+    end
+
+    attributes
+  end
+
+  def attributes_for_todo(project, target, author, action, note = nil)
+    attributes_for_target(target).merge!(
+      project_id: project.id,
+      author_id: author.id,
+      action: action,
+      note: note
+    )
   end
 
   def filter_mentioned_users(project, target, author)
@@ -160,11 +178,8 @@ class TodoService
     mentioned_users.uniq
   end
 
-  def pending_todos(user, project, target)
-    user.todos.pending.where(
-      project_id: project.id,
-      target_id: target.id,
-      target_type: target.class.name
-    )
+  def pending_todos(user, criteria = {})
+    valid_keys = [:project_id, :target_id, :target_type, :commit_id]
+    user.todos.pending.where(criteria.slice(*valid_keys))
   end
 end
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index e18dd9bc905d455a9d1b1af91d5990306806302b..d2527ede99559ea4980af70ea43239fb9f460889 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -58,9 +58,15 @@
         = f.label :admin, class: 'control-label'
         - if current_user == @user
           .col-sm-10= f.check_box :admin, disabled: true
-          .col-sm-10 You cannot remove your own admin rights
+          .col-sm-10 You cannot remove your own admin rights.
         - else
           .col-sm-10= f.check_box :admin
+
+      .form-group
+        = f.label :external, class: 'control-label'
+        .col-sm-10= f.check_box :external
+        .col-sm-10 External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects or groups.
+
     %fieldset
       %legend Profile
       .form-group
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index b6b1168bd37798174d8e60b7a118ffe3489931c4..0ee8dc962b9dfd28de198ac727dd5328d31c8b59 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -19,6 +19,10 @@
       = link_to admin_users_path(filter: 'two_factor_disabled') do
         2FA Disabled
         %small.badge= number_with_delimiter(User.without_two_factor.count)
+    %li.filter-external{class: "#{'active' if params[:filter] == 'external'}"}
+      = link_to admin_users_path(filter: 'external') do
+        External
+        %small.badge= number_with_delimiter(User.external.count)
     %li{class: "#{'active' if params[:filter] == "blocked"}"}
       = link_to admin_users_path(filter: "blocked") do
         Blocked
@@ -70,12 +74,14 @@
       %li
         .list-item-name
           - if user.blocked?
-            %i.fa.fa-lock.cred
+            = icon("lock", class: "cred")
           - else
-            %i.fa.fa-user.cgreen
+            = icon("user", class: "cgreen")
           = link_to user.name, [:admin, user]
           - if user.admin?
             %strong.cred (Admin)
+          - if user.external?
+            %strong.cred (External)
           - if user == current_user
             %span.cred It's you!
         .pull-right
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 2bdbae195880edfd7a83c81d57268d24fcd6403a..d37489bebea16cef5a112dc27cd098920787290e 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -47,6 +47,10 @@
             - else
               Disabled
 
+        %li
+          %span.light External User:
+          %strong
+            = @user.external? ? "Yes" : "No"
         %li
           %span.light Can create groups:
           %strong
diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml
index c3efa7727b1c2dc5b412c2f3165e37afaa57bd2e..d54c7cad7be48148d9caccb2d0d010c442f6c014 100644
--- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml
@@ -1,4 +1,4 @@
-- publicish_project_count = Project.publicish(current_user).count
+- publicish_project_count = ProjectsFinder.new.execute(current_user).count
 %h3.page-title Welcome to GitLab!
 %p.light Self hosted Git management application.
 %hr
@@ -18,7 +18,7 @@
     - if current_user.can_create_project?
       .link_holder
         = link_to new_project_path, class: "btn btn-new" do
-          %i.fa.fa-plus
+          = icon('plus')
           New Project
 
 - if current_user.can_create_group?
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 45cfe3da188f5eda4b055958dea63895182423bd..4c848a501817bd11ba0c41065f3adea681159bd9 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -16,7 +16,9 @@
 
     - if todo.pending?
       .todo-actions.pull-right
-        = link_to 'Done', [:dashboard, todo], method: :delete, class: 'btn'
+        = link_to [:dashboard, todo], method: :delete, class: 'btn btn-loading done-todo' do
+          Done
+          = icon('spinner spin')
 
     .todo-body
       .todo-note
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 946d7df393383c6e65c5af7c566d3fee951b4a57..623381375a5780da0bcd119d3010aba91cc72add 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -3,13 +3,15 @@
 
 .top-area
   %ul.nav-links
-    %li{class: ('active' if params[:state].blank? || params[:state] == 'pending')}
+    - todo_pending_active = ('active' if params[:state].blank? || params[:state] == 'pending')
+    %li{class: "todos-pending #{todo_pending_active}"}
       = link_to todos_filter_path(state: 'pending') do
         %span
           To do
         %span{class: 'badge'}
           = todos_pending_count
-    %li{class: ('active' if params[:state] == 'done')}
+    - todo_done_active = ('active' if params[:state] == 'done')
+    %li{class: "todos-done #{todo_done_active}"}
       = link_to todos_filter_path(state: 'done') do
         %span
           Done
@@ -18,7 +20,9 @@
 
   .nav-controls
     - if @todos.any?(&:pending?)
-      = link_to 'Mark all as done', destroy_all_dashboard_todos_path(todos_filter_params), class: 'btn', method: :delete
+      = link_to destroy_all_dashboard_todos_path(todos_filter_params), class: 'btn btn-loading js-todos-mark-all', method: :delete do
+        Mark all as done
+        = icon('spinner spin')
 
 .todos-filters
   .gray-content-block.second-block
@@ -42,7 +46,7 @@
 .prepend-top-default
   - if @todos.any?
     - @todos.group_by(&:project).each do |group|
-      .panel.panel-default.panel-small
+      .panel.panel-default.panel-small.js-todos-list
         - project = group[0]
         .panel-heading
           = link_to project.name_with_namespace, namespace_project_path(project.namespace, project)
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 36fb2d5162955f96ff9cdbc18818400fb22c333a..2d9d9dd634243eb44d8878f0851c065fff0446aa 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -1,4 +1,4 @@
-- if event.proper?
+- if event.proper?(current_user)
   .event-item{class: "#{event.body? ? "event-block" : "event-inline" }"}
     .event-item-timestamp
       #{time_ago_with_tooltip(event.created_at)}
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 77d01a7736c0339469041a1c4b9c226fa6714ed5..f3090b967021efb443947cc9e6ec9f3dae270826 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -46,6 +46,8 @@
       %h1.title= title
 
 = render 'shared/outdated_browser'
+
 - if @project && !@project.empty_repo?
-  :javascript
-    var findFileURL = "#{namespace_project_find_file_path(@project.namespace, @project, @ref || @project.repository.root_ref)}";
+  - if ref = @ref || @project.repository.root_ref
+    :javascript
+      var findFileURL = "#{namespace_project_find_file_path(@project.namespace, @project, ref)}";
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 0ae83ee01ebc6bd519a6333dbcc446ab6d1d40f0..86b46e8c75ec33cf5f4be6463a0c0546f4d98740 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -67,7 +67,7 @@
         %span
           Issues
           - if @project.default_issues_tracker?
-            %span.count.issue_counter= number_with_delimiter(@project.issues.opened.count)
+            %span.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
 
   - if project_nav_tab? :merge_requests
     = nav_link(controller: :merge_requests) do
diff --git a/app/views/projects/_builds_settings.html.haml b/app/views/projects/_builds_settings.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..95ab9ecf3e842a3cb9c418e57300eaaa083ab8cf
--- /dev/null
+++ b/app/views/projects/_builds_settings.html.haml
@@ -0,0 +1,60 @@
+%fieldset.builds-feature
+  %legend
+    Builds:
+  .form-group
+    .col-sm-offset-2.col-sm-10
+      %p Get recent application code using the following command:
+      .radio
+        = f.label :build_allow_git_fetch_false do
+          = f.radio_button :build_allow_git_fetch, 'false'
+          %strong git clone
+          %br
+          %span.descr Slower but makes sure you have a clean dir before every build
+      .radio
+        = f.label :build_allow_git_fetch_true do
+          = f.radio_button :build_allow_git_fetch, 'true'
+          %strong git fetch
+          %br
+          %span.descr Faster
+
+  .form-group
+    = f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
+    .col-sm-10
+      = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
+      %p.help-block per build in minutes
+  .form-group
+    = f.label :build_coverage_regex, "Test coverage parsing", class: 'control-label'
+    .col-sm-10
+      .input-group
+        %span.input-group-addon /
+        = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
+        %span.input-group-addon /
+      %p.help-block
+        We will use this regular expression to find test coverage output in build trace.
+        Leave blank if you want to disable this feature
+      .bs-callout.bs-callout-info
+        %p Below are examples of regex for existing tools:
+        %ul
+          %li
+            Simplecov (Ruby) -
+            %code \(\d+.\d+\%\) covered
+          %li
+            pytest-cov (Python) -
+            %code \d+\%\s*$
+          %li
+            phpunit --coverage-text --colors=never (PHP) -
+            %code ^\s*Lines:\s*\d+.\d+\%
+
+  .form-group
+    .col-sm-offset-2.col-sm-10
+      .checkbox
+        = f.label :public_builds do
+          = f.check_box :public_builds
+          %strong Public builds
+        .help-block Allow everyone to access builds for Public and Internal projects
+
+  .form-group
+    = f.label :runners_token, "Runners token", class: 'control-label'
+    .col-sm-10
+      = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
+      %p.help-block The secure token used to checkout project.
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 3ac058a3bf8c1b9a2b9088946adb1b4e4f021818..dc34032b1b8a51981ae63a7c41a053c978069484 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -42,13 +42,17 @@
   .diff-content.diff-wrap-lines
     -# Skipp all non non-supported blobs
     - return unless blob.respond_to?('text?')
-    - if blob_text_viewable?(blob)
-      - if diff_view == 'parallel'
-        = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
-      - else
-        = render "projects/diffs/text_file", diff_file: diff_file, index: i
-    - elsif blob.image?
-      - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
-      = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
+    - if diff_file.too_large?
+      .nothing-here-block
+        This diff could not be displayed because it is too large.
     - else
-      .nothing-here-block No preview for this file type
+      - if blob_text_viewable?(blob)
+        - if diff_view == 'parallel'
+          = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
+        - else
+          = render "projects/diffs/text_file", diff_file: diff_file, index: i
+      - elsif blob.image?
+        - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
+        = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
+      - else
+        .nothing-here-block No preview for this file type
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index f2e56081afe949aba3a562d9e708cff6dab1d127..6d872cd0b218839818a6ff258d261b8d4cec86b9 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -84,6 +84,8 @@
                     %br
                     %span.descr Share code pastes with others out of git repository
 
+          = render 'builds_settings', f: f
+
           %fieldset.features
             %legend
               Project avatar:
@@ -110,69 +112,6 @@
                   %hr
                   = link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
 
-          %fieldset.features
-            %legend
-              Continuous Integration
-            .form-group
-              .col-sm-offset-2.col-sm-10
-                %p Get recent application code using the following command:
-                .radio
-                  = f.label :build_allow_git_fetch_false do
-                    = f.radio_button :build_allow_git_fetch, 'false'
-                    %strong git clone
-                    %br
-                    %span.descr Slower but makes sure you have a clean dir before every build
-                .radio
-                  = f.label :build_allow_git_fetch_true do
-                    = f.radio_button :build_allow_git_fetch, 'true'
-                    %strong git fetch
-                    %br
-                    %span.descr Faster
-
-            .form-group
-              = f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
-              .col-sm-10
-                = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
-                %p.help-block per build in minutes
-            .form-group
-              = f.label :build_coverage_regex, "Test coverage parsing", class: 'control-label'
-              .col-sm-10
-                .input-group
-                  %span.input-group-addon /
-                  = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
-                  %span.input-group-addon /
-                %p.help-block
-                  We will use this regular expression to find test coverage output in build trace.
-                  Leave blank if you want to disable this feature
-                .bs-callout.bs-callout-info
-                  %p Below are examples of regex for existing tools:
-                  %ul
-                    %li
-                      Simplecov (Ruby) -
-                      %code \(\d+.\d+\%\) covered
-                    %li
-                      pytest-cov (Python) -
-                      %code \d+\%\s*$
-                    %li
-                      phpunit --coverage-text --colors=never (PHP) -
-                      %code ^\s*Lines:\s*\d+.\d+\%
-
-              .form-group
-                .col-sm-offset-2.col-sm-10
-                  .checkbox
-                    = f.label :public_builds do
-                      = f.check_box :public_builds
-                      %strong Public builds
-                    .help-block Allow everyone to access builds for Public and Internal projects
-
-          %fieldset.features
-            %legend
-              Advanced settings
-            .form-group
-              = f.label :runners_token, "CI token", class: 'control-label'
-              .col-sm-10
-                = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
-                %p.help-block The secure token used to checkout project.
 
           .form-actions
             = f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index a44f34c2a6843fbd3886598060842d19074a40c6..00e1a3d806906cfebed71aa37da94bde954f4441 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -5,6 +5,7 @@
 
   .issue-title
     %span.issue-title-text
+      = confidential_icon(issue)
       = link_to_gfm issue.title, issue_path(issue), class: "title"
     %ul.controls.light
       - if issue.closed?
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index d9868ad1f0a5eb621a3a21146102167e2ae1aad6..d6b38b327ff78680a521cd1c99cf48dbd9642468 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -1,4 +1,4 @@
--if @merge_requests.any?
+- if @merge_requests.any?
   %h2.merge-requests-title
     = pluralize(@merge_requests.count, 'Related Merge Request')
   %ul.unstyled-list
diff --git a/app/views/projects/issues/_new_branch.html.haml b/app/views/projects/issues/_new_branch.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e66e4669d487648495af378459f97c1c37e5615e
--- /dev/null
+++ b/app/views/projects/issues/_new_branch.html.haml
@@ -0,0 +1,5 @@
+- if current_user && can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user)
+  .pull-right
+    = link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn', title: @issue.to_branch_name do
+      = icon('code-fork')
+      New Branch
diff --git a/app/views/projects/issues/_related_branches.html.haml b/app/views/projects/issues/_related_branches.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..b10cd03515f28866dd98e0b732ef52f55f3abf96
--- /dev/null
+++ b/app/views/projects/issues/_related_branches.html.haml
@@ -0,0 +1,15 @@
+- if @related_branches.any?
+  %h2.related-branches-title
+    = pluralize(@related_branches.count, 'Related Branch')
+  %ul.unstyled-list
+    - @related_branches.each do |branch|
+      %li
+        - sha = @project.repository.find_branch(branch).target
+        - ci_commit = @project.ci_commit(sha) if sha
+        - if ci_commit
+          %span.related-branch-ci-status
+            = render_ci_status(ci_commit)
+        %span.related-branch-info
+          %strong
+            = link_to namespace_project_compare_path(@project.namespace, @project, from: @project.default_branch, to: branch), class: "label-branch" do
+              = branch
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 0242276cd84176c78e70b08f07b3b67b5aa9d457..52df3de8a27833c9bf0bd9dd60d66b5fa6b7188e 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -22,20 +22,20 @@
       = icon('angle-double-left')
 
     .issue-meta
+      = confidential_icon(@issue)
       %strong.identifier
         Issue ##{@issue.iid}
       %span.creator
-        by
+        opened
         .editor-details
           .editor-details
+            = time_ago_with_tooltip(@issue.created_at)
+            by
             %strong
               = link_to_member(@project, @issue.author, size: 24, mobile_classes: "hidden-xs")
-            %span.hidden-xs
-              = '@' + @issue.author.username
             %strong
               = link_to_member(@project, @issue.author, size: 24, mobile_classes: "hidden-sm hidden-md hidden-lg",
                 by_username: true, avatar: false)
-            = time_ago_with_tooltip(@issue.created_at)
 
     .pull-right.issue-btn-group
       - if can?(current_user, :create_issue, @project)
@@ -63,15 +63,14 @@
                 = markdown(@issue.description, cache_key: [@issue, "description"])
             %textarea.hidden.js-task-list-field
               = @issue.description
-      - if @issue.updated_at != @issue.created_at
-        %small
-          Edited
-          = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
+      = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue_edited_ago')
 
       .merge-requests
         = render 'merge_requests'
+        = render 'related_branches'
 
     .content-block.content-block-small
+      = render 'new_branch'
       = render 'votes/votes_block', votable: @issue
 
     .row
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index 602f787e6cfdb685c2bc3e49781b4a07d7a43027..a23bd8d18d0512f8969d40d6b822c02d52d2a1f9 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -11,7 +11,4 @@
         %textarea.hidden.js-task-list-field
           = @merge_request.description
 
-  - if @merge_request.updated_at != @merge_request.created_at
-    %small
-      Edited
-      = time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom')
+  = edited_time_ago_with_tooltip(@merge_request, placement: 'bottom')
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index a75c0d96c5767fbcbb66a34be7657a5e11da7426..eeb605e2dc5c93cb72e3a5dbb74cd963171ba024 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -8,18 +8,21 @@
     = icon('angle-double-left')
   .issue-meta
     %strong.identifier
-      Merge Request ##{@merge_request.iid}
+      %span.hidden-sm.hidden-md.hidden-lg
+        MR
+      %span.hidden-xs
+        Merge Request
+      !#{@merge_request.iid}
     %span.creator
-      by
+      opened
       .editor-details
+        = time_ago_with_tooltip(@merge_request.created_at)
+        by
         %strong
           = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-xs")
-        %span.hidden-xs
-          = '@' + @merge_request.author.username
         %strong
           = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-sm hidden-md hidden-lg",
             by_username: true, avatar: false)
-        = time_ago_with_tooltip(@merge_request.created_at)
 
   .issue-btn-group.pull-right
     - if can?(current_user, :update_merge_request, @merge_request)
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index b4597043a27af1ec6a0fc1cc541e056e4da12886..be63875ab34c0ab1f97104adb9fb6df13d8d478c 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -42,7 +42,7 @@
           = preserve do
             = markdown @milestone.description
 
-- if @milestone.complete? && @milestone.active?
+- if @milestone.complete?(current_user) && @milestone.active?
   .alert.alert-success.prepend-top-default
     %span All issues for this milestone are closed. You may close milestone now.
 
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 52972576aff1f25ecac81da658998e297fda1195..2cf32e6093dec09b3e7749a11041bca74fcf872f 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -27,20 +27,13 @@
         %span.note-last-update
           %a{name: dom_id(note), href: "##{dom_id(note)}", title: 'Link here'}
             = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
-          - if note.updated_at != note.created_at
-            %span.note-updated-at
-              &middot;
-              = icon('edit', title: 'edited')
-              = time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
-              - if note.updated_by && note.updated_by != note.author
-                by #{link_to_member(note.project, note.updated_by, avatar: false, author_class: nil)}
-
       .note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
         .note-text
           = preserve do
             = markdown(note.note, pipeline: :note, cache_key: [note, "note"])
         - if note_editable?(note)
           = render 'projects/notes/edit_form', note: note
+      = edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago', include_author: true)
 
       - if note.attachment.url
         .note-attachment
@@ -54,4 +47,3 @@
               = link_to delete_attachment_namespace_project_note_path(note.project.namespace, note.project, note),
                 title: 'Delete this attachment', method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove the attachment?' }, class: 'danger js-note-attachment-delete' do
                 = icon('trash-o', class: 'cred')
-      .clear
diff --git a/app/views/projects/repositories/_download_archive.html.haml b/app/views/projects/repositories/_download_archive.html.haml
index b9486a9b49265c92771b58c529b26fd9f51cb4de..24658319060b7c5f4fd4eb2bc786b3bb2e260eef 100644
--- a/app/views/projects/repositories/_download_archive.html.haml
+++ b/app/views/projects/repositories/_download_archive.html.haml
@@ -10,7 +10,7 @@
       %span.caret
       %span.sr-only
         Select Archive Format
-    %ul.col-xs-10.dropdown-menu{ role: 'menu' }
+    %ul.col-xs-10.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
       %li
         = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), rel: 'nofollow' do
           %i.fa.fa-download
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index 45d700781f3e3d14547268ef9444810112a8e32e..710f5613c817238893531ba540af9573f796150d 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -1,5 +1,6 @@
 .search-result-row
   %h4
+    = confidential_icon(issue)
     = link_to [issue.project.namespace.becomes(Namespace), issue.project, issue] do
       %span.term.str-truncated= issue.title
     .pull-right ##{issue.iid}
diff --git a/app/views/search/results/_wiki_blob.html.haml b/app/views/search/results/_wiki_blob.html.haml
index f5859481d465edd97ac8b6c9713fd529da555f6c..235106c4f746553abf0ecf928cbf989516d9d82d 100644
--- a/app/views/search/results/_wiki_blob.html.haml
+++ b/app/views/search/results/_wiki_blob.html.haml
@@ -2,9 +2,9 @@
 .blob-result
   .file-holder
     .file-title
-      = link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.filename) do
+      = link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.basename) do
         %i.fa.fa-file
         %strong
-          = wiki_blob.filename
+          = wiki_blob.basename
     .file-content.code.term
       = render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index 42a3c2c3f02a022cb891cfb504bcaee6f9c25100..ac20f7d1f7e39d3d26a60cb830e2f7e8215da9fd 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -9,75 +9,20 @@
         .filter-item.inline
           - if params[:author_id]
             = hidden_field_tag(:author_id, params[:author_id])
-          = dropdown_tag("Author", options: { toggle_class: "js-user-search js-filter-submit js-author-search", title: "Filter by author", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-author",
-            placeholder: "Search authors", data: { any_user: "Any Author", first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: "author_id" } })
+          = dropdown_tag(user_dropdown_label(params[:author_id], "Author"), options: { toggle_class: "js-user-search js-filter-submit js-author-search", title: "Filter by author", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-author",
+            placeholder: "Search authors", data: { any_user: "Any Author", first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: "author_id", default_label: "Author" } })
 
         .filter-item.inline
           - if params[:assignee_id]
             = hidden_field_tag(:assignee_id, params[:assignee_id])
-          = dropdown_tag("Assignee", options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee",
-            placeholder: "Search assignee", data: { any_user: "Any Author", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id" } })
+          = dropdown_tag(user_dropdown_label(params[:assignee_id], "Assignee"), options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee",
+            placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } })
 
         .filter-item.inline.milestone-filter
-          - if params[:milestone_title]
-            = hidden_field_tag(:milestone_title, params[:milestone_title])
-          = dropdown_tag("Milestone", options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
-            placeholder: "Search milestones", footer_content: true, data: { show_no: true, show_any: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: (@project.id if @project), milestones: (namespace_project_milestones_path(@project.namespace, @project, :js) if @project) } }) do
-            - if @project
-              %ul.dropdown-footer-list
-                - if can? current_user, :admin_milestone, @project
-                  %li
-                    = link_to new_namespace_project_milestone_path(@project.namespace, @project), title: "New Milestone" do
-                      Create new
-                %li
-                  = link_to namespace_project_milestones_path(@project.namespace, @project) do
-                    - if can? current_user, :admin_milestone, @project
-                      Manage milestones
-                    - else
-                      View milestones
+          = render "shared/issuable/milestone_dropdown"
 
         .filter-item.inline.labels-filter
-          - if params[:label_name]
-            = hidden_field_tag(:label_name, params[:label_name])
-          .dropdown
-            %button.dropdown-menu-toggle.js-label-select.js-filter-submit{type: "button", data: {toggle: "dropdown", field_name: "label_name", show_no: "true", show_any: "true", selected: params[:label_name], project_id: (@project.id if @project), labels: (namespace_project_labels_path(@project.namespace, @project, :js) if @project)}}
-              %span.dropdown-toggle-text
-                Label
-              = icon('chevron-down')
-            .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
-              .dropdown-page-one
-                = dropdown_title("Filter by label")
-                = dropdown_filter("Search labels")
-                = dropdown_content
-                - if @project
-                  = dropdown_footer do
-                    %ul.dropdown-footer-list
-                      - if can? current_user, :admin_label, @project
-                        %li
-                          %a.dropdown-toggle-page{href: "#"}
-                            Create new
-                      %li
-                        = link_to namespace_project_labels_path(@project.namespace, @project) do
-                          - if can? current_user, :admin_label, @project
-                            Manage labels
-                          - else
-                            View labels
-              - if can? current_user, :admin_label, @project
-                .dropdown-page-two
-                  = dropdown_title("Create new label", back: true)
-                  = dropdown_content do
-                    %input#new_label_color{type: "hidden"}
-                    %input#new_label_name.dropdown-input-field{type: "text", placeholder: "Name new label"}
-                    .dropdown-label-color-preview.js-dropdown-label-color-preview
-                    .suggest-colors.suggest-colors-dropdown
-                      - suggested_colors.each do |color|
-                        = link_to '#', style: "background-color: #{color}", data: { color: color } do
-                          &nbsp
-                    %button.btn.btn-primary.js-new-label-btn{type: "button"}
-                      Create
-              = dropdown_loading
-              .dropdown-loading
-                = icon('spinner spin')
+          = render "shared/issuable/label_dropdown"
 
         .pull-right
           = render 'shared/sort_dropdown'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index d5a4aad05d9f9824357219a47d1a0d0b4fc0cf6e..9ef729e960cdb3e6e3a667c2ef06472cd31aba0c 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -29,6 +29,15 @@
       = render 'projects/notes/hints'
       .clearfix
       .error-alert
+
+- if issuable.is_a?(Issue) && !issuable.project.private?
+  .form-group
+    .col-sm-offset-2.col-sm-10
+      .checkbox
+        = f.label :confidential do
+          = f.check_box :confidential
+          This issue is confidential and should only be visible to team members
+
 - if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
   %hr
   .form-group
diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..876173151817caabf4ed92388f1a671d3f528856
--- /dev/null
+++ b/app/views/shared/issuable/_label_dropdown.html.haml
@@ -0,0 +1,39 @@
+- if params[:label_name]
+  = hidden_field_tag(:label_name, params[:label_name])
+.dropdown
+  %button.dropdown-menu-toggle.js-label-select.js-filter-submit{type: "button", data: {toggle: "dropdown", field_name: "label_name", show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}}
+    %span.dropdown-toggle-text
+      = h(params[:label_name].presence || "Label")
+    = icon('chevron-down')
+  .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
+    .dropdown-page-one
+      = dropdown_title("Filter by label")
+      = dropdown_filter("Search labels")
+      = dropdown_content
+      - if @project
+        = dropdown_footer do
+          %ul.dropdown-footer-list
+            - if can? current_user, :admin_label, @project
+              %li
+                %a.dropdown-toggle-page{href: "#"}
+                  Create new
+            %li
+              = link_to namespace_project_labels_path(@project.namespace, @project) do
+                - if can? current_user, :admin_label, @project
+                  Manage labels
+                - else
+                  View labels
+    - if can? current_user, :admin_label, @project and @project
+      .dropdown-page-two
+        = dropdown_title("Create new label", back: true)
+        = dropdown_content do
+          %input#new_label_color{type: "hidden"}
+          %input#new_label_name.dropdown-input-field{type: "text", placeholder: "Name new label"}
+          .dropdown-label-color-preview.js-dropdown-label-color-preview
+          .suggest-colors.suggest-colors-dropdown
+            - suggested_colors.each do |color|
+              = link_to '#', style: "background-color: #{color}", data: { color: color } do
+                &nbsp
+          %button.btn.btn-primary.js-new-label-btn{type: "button"}
+            Create
+    = dropdown_loading
diff --git a/app/views/shared/issuable/_milestone_dropdown.html.haml b/app/views/shared/issuable/_milestone_dropdown.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..0434506c8d766ec602789a58ea9691bae255aa91
--- /dev/null
+++ b/app/views/shared/issuable/_milestone_dropdown.html.haml
@@ -0,0 +1,16 @@
+- if params[:milestone_title]
+  = hidden_field_tag(:milestone_title, params[:milestone_title])
+= dropdown_tag(h(params[:milestone_title].presence || "Milestone"), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
+  placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
+  - if @project
+    %ul.dropdown-footer-list
+      - if can? current_user, :admin_milestone, @project
+        %li
+          = link_to new_namespace_project_milestone_path(@project.namespace, @project), title: "New Milestone" do
+            Create new
+      %li
+        = link_to namespace_project_milestones_path(@project.namespace, @project) do
+          - if can? current_user, :admin_milestone, @project
+            Manage milestones
+          - else
+            View milestones
diff --git a/app/views/shared/issuable/_participants.html.haml b/app/views/shared/issuable/_participants.html.haml
index f1d92ef48b2f6cae0b15d7874f1e6b72c5cd7202..3fb409ff7279c843b4c6c00110542b3361144b03 100644
--- a/app/views/shared/issuable/_participants.html.haml
+++ b/app/views/shared/issuable/_participants.html.haml
@@ -1,3 +1,6 @@
+- participants_row = 7
+- participants_size = participants.size
+- participants_extra = participants_size - participants_row
 .block.participants
   .sidebar-collapsed-icon
     = icon('users')
@@ -5,6 +8,13 @@
       = participants.count
   .title.hide-collapsed
     = pluralize participants.count, "participant"
-  - participants.each do |participant|
-    %span.hide-collapsed
-      = link_to_member(@project, participant, name: false, size: 24)
+  .hide-collapsed.participants-list
+    - participants.each do |participant|
+      .participants-author.js-participants-author
+        = link_to_member(@project, participant, name: false, size: 24)
+    - if participants_extra > 0
+      %div.participants-more
+        %a.js-participants-more{href: "#", data: {original_text: "+ #{participants_size - 7} more", less_text: "- show less"}}
+          + #{participants_extra} more
+:javascript
+  Issue.prototype.PARTICIPANTS_ROW_COUNT = #{participants_row};
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 23b1ed1e51bca395ff0a4efec2ed0b033ac20db5..2b95b19facc640f39a520e9009583ca82ae23185 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -1,13 +1,12 @@
 %aside.right-sidebar{ class: sidebar_gutter_collapsed_class }
   .issuable-sidebar
-    .block
+    .block.issuable-sidebar-header
       %span.issuable-count.hide-collapsed.pull-left
         = issuable.iid
         of
         = issuables_count(issuable)
-      %span.pull-right
-        %a.gutter-toggle.js-sidebar-toggle{href: '#'}
-          = sidebar_gutter_toggle_icon
+      %a.gutter-toggle.pull-right.js-sidebar-toggle{href: '#'}
+        = sidebar_gutter_toggle_icon
       .issuable-nav.hide-collapsed.pull-right.btn-group{role: 'group', "aria-label" => '...'}
         - if prev_issuable = prev_issuable_for(issuable)
           = link_to 'Prev', [@project.namespace.becomes(Namespace), @project, prev_issuable], class: 'btn btn-default prev-btn'
@@ -22,20 +21,20 @@
 
     = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
       .block.assignee
-        .sidebar-collapsed-icon
+        .sidebar-collapsed-icon.sidebar-collapsed-user{data: {toggle: "tooltip", placement: "left", container: "body"}, title: (issuable.assignee.to_reference if issuable.assignee)}
           - if issuable.assignee
-            = link_to_member_avatar(issuable.assignee, size: 24)
+            = link_to_member(@project, issuable.assignee, size: 24)
           - else
             = icon('user')
         .title.hide-collapsed
-          %label
-            Assignee
+          Assignee
           - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
-            .pull-right
-              = link_to 'Edit', '#', class: 'edit-link'
-        .value.hide-collapsed
+            = link_to 'Edit', '#', class: 'edit-link pull-right'
+        .value.bold.hide-collapsed
           - if issuable.assignee
-            %strong= link_to_member(@project, issuable.assignee, size: 24)
+            = link_to_member(@project, issuable.assignee, size: 32) do
+              %span.username
+                = issuable.assignee.to_reference
             - if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee)
               %a.pull-right.cannot-be-merged{href: '#', data: {toggle: 'tooltip'}, title: 'Not allowed to merge'}
                 = icon('exclamation-triangle')
@@ -54,18 +53,13 @@
             - else
               No
         .title.hide-collapsed
-          %label
-            Milestone
+          Milestone
           - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
-            .pull-right
-              = link_to 'Edit', '#', class: 'edit-link'
-        .value.hide-collapsed
+            = link_to 'Edit', '#', class: 'edit-link pull-right'
+        .value.bold.hide-collapsed
           - if issuable.milestone
-            %span.back-to-milestone
-              = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
-                %strong
-                  = icon('clock-o')
-                  = issuable.milestone.title
+            = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
+              = issuable.milestone.title
           - else
             .light None
         .selectbox.hide-collapsed
@@ -80,11 +74,10 @@
             %span
               = issuable.labels.count
           .title.hide-collapsed
-            %label Labels
+            Labels
             - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
-              .pull-right
-                = link_to 'Edit', '#', class: 'edit-link'
-          .value.issuable-show-labels.hide-collapsed
+              = link_to 'Edit', '#', class: 'edit-link pull-right'
+          .value.issuable-show-labels.hide-collapsed{class: ("has-labels" if issuable.labels.any?)}
             - if issuable.labels.any?
               - issuable.labels.each do |label|
                 = link_to_label(label, type: issuable.to_ability_name)
@@ -95,14 +88,13 @@
               { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" }
 
       = render "shared/issuable/participants", participants: issuable.participants(current_user)
-      %hr
       - if current_user
         - subscribed = issuable.subscribed?(current_user)
         .block.light.subscription{data: {url: toggle_subscription_path(issuable)}}
           .sidebar-collapsed-icon
             = icon('rss')
           .title.hide-collapsed
-            %label.light Notifications
+            Notifications
           - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
           %button.btn.btn-block.btn-gray.subscribe-button.hide-collapsed{:type => 'button'}
             %span= subscribed ? 'Unsubscribe' : 'Subscribe'
diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml
index f7c6fc14adf196b0ea186f01f6312e8800bb3a2c..85888096722f5120bdeea56791de5c820c554335 100644
--- a/app/views/shared/milestones/_issuable.html.haml
+++ b/app/views/shared/milestones/_issuable.html.haml
@@ -10,6 +10,8 @@
       %strong #{project.name} &middot;
     - elsif show_full_project_name
       %strong #{project.name_with_namespace} &middot;
+    - if issuable.is_a?(Issue)
+      = confidential_icon(issuable)
     = link_to_gfm issuable.title, [project.namespace.becomes(Namespace), project, issuable], title: issuable.title
   %div{class: 'issuable-detail'}
     = link_to [project.namespace.becomes(Namespace), project, issuable] do
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index f01138af3f09c20d2eaef18d63366c44d733aa9f..6b25745c55420f400ff8605739b345d8e5547e00 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -6,10 +6,10 @@
     .col-sm-6
       %strong= link_to_gfm truncate(milestone.title, length: 100), milestone_path
     .col-sm-6
-      .pull-right.light #{milestone.percent_complete}% complete
+      .pull-right.light #{milestone.percent_complete(current_user)}% complete
   .row
     .col-sm-6
-      = link_to pluralize(milestone.issues.size, 'Issue'), issues_path
+      = link_to pluralize(milestone.issues_visible_to_user(current_user).size, 'Issue'), issues_path
       &middot;
       = link_to pluralize(milestone.merge_requests.size, 'Merge Request'), merge_requests_path
     .col-sm-6= milestone_progress_bar(milestone)
diff --git a/app/views/shared/milestones/_summary.html.haml b/app/views/shared/milestones/_summary.html.haml
index 59d4ae29f791f349d13e0bc8903011c5655f3636..385c65966067485788a8bc4b3c44d164e4b3c083 100644
--- a/app/views/shared/milestones/_summary.html.haml
+++ b/app/views/shared/milestones/_summary.html.haml
@@ -3,15 +3,15 @@
 .context.prepend-top-default
   .milestone-summary
     %h4 Progress
-    %strong= milestone.issues.size
+    %strong= milestone.issues_visible_to_user(current_user).size
     issues:
     %span.milestone-stat
-      %strong= milestone.issues.opened.size
+      %strong= milestone.issues_visible_to_user(current_user).opened.size
       open and
-      %strong= milestone.issues.closed.size
+      %strong= milestone.issues_visible_to_user(current_user).closed.size
       closed
     %span.milestone-stat
-      %strong== #{milestone.percent_complete}%
+      %strong== #{milestone.percent_complete(current_user)}%
       complete
 
     %span.milestone-stat
diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml
index 57d7ee85a3b3ac27289d39c02e5b5ce21a9c3c31..2b6ce2d7e7a38cf6304802b540d5f8dbb32745c1 100644
--- a/app/views/shared/milestones/_tabs.html.haml
+++ b/app/views/shared/milestones/_tabs.html.haml
@@ -2,7 +2,7 @@
   %li.active
     = link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
       Issues
-      %span.badge= milestone.issues.size
+      %span.badge= milestone.issues_visible_to_user(current_user).size
   %li
     = link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-show' => '.tab-merge-requests-buttons' do
       Merge Requests
@@ -21,7 +21,7 @@
 
 .tab-content.milestone-content
   .tab-pane.active#tab-issues
-    = render 'shared/milestones/issues_tab', issues: milestone.issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name
+    = render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user), show_project_name: show_project_name, show_full_project_name: show_full_project_name
   .tab-pane#tab-merge-requests
     = render 'shared/milestones/merge_requests_tab', merge_requests: milestone.merge_requests, show_project_name: show_project_name, show_full_project_name: show_full_project_name
   .tab-pane#tab-participants
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index 4cf1d948b5b952d84f08931b556433b79f0b9e4b..cab8743a0772dca5e169fe3d4b3fbc16ab993154 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -28,7 +28,7 @@
   %h2.title
     = markdown escape_once(milestone.title), pipeline: :single_line
 
-- if milestone.complete? && milestone.active?
+- if milestone.complete?(current_user) && milestone.active?
   .alert.alert-success.prepend-top-default
     - close_msg = group ? 'You may close the milestone now.' : 'Navigate to the project to close the milestone.'
     %span All issues for this milestone are closed. #{close_msg}
@@ -47,7 +47,7 @@
           - project_name = group ? ms.project.name : ms.project.name_with_namespace
           = link_to project_name, namespace_project_milestone_path(ms.project.namespace, ms.project, ms)
         %td
-          = ms.issues.opened.count
+          = ms.issues_visible_to_user(current_user).opened.count
         %td
           - if ms.closed?
             Closed
diff --git a/app/workers/delete_user_worker.rb b/app/workers/delete_user_worker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6ff361e4d8009f392f901465f14bae774aa01a09
--- /dev/null
+++ b/app/workers/delete_user_worker.rb
@@ -0,0 +1,10 @@
+class DeleteUserWorker
+  include Sidekiq::Worker
+
+  def perform(current_user_id, delete_user_id, options = {})
+    delete_user  = User.find(delete_user_id)
+    current_user = User.find(current_user_id)
+
+    DeleteUserService.new(current_user).execute(delete_user, options.symbolize_keys)
+  end
+end
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 14d7813412e35a69da8cb540461777155c8cb04f..3cc232ef1aeb662b774d1c0849fe222b5b9d0344 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -1,6 +1,5 @@
 class PostReceive
   include Sidekiq::Worker
-  include Gitlab::Identifier
 
   sidekiq_options queue: :post_receive
 
@@ -11,51 +10,44 @@ class PostReceive
       log("Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"")
     end
 
-    repo_path.gsub!(/\.git\z/, "")
-    repo_path.gsub!(/\A\//, "")
+    post_received = Gitlab::GitPostReceive.new(repo_path, identifier, changes)
 
-    project = Project.find_with_namespace(repo_path)
-
-    if project.nil?
+    if post_received.project.nil?
       log("Triggered hook for non-existing project with full path \"#{repo_path} \"")
       return false
     end
 
-    changes = Base64.decode64(changes) unless changes.include?(" ")
-    changes = utf8_encode_changes(changes)
-    changes = changes.lines
+    if post_received.wiki?
+      # Nothing defined here yet.
+    elsif post_received.regular_project?
+      process_project_changes(post_received)
+    else
+      log("Triggered hook for unidentifiable repository type with full path \"#{repo_path} \"")
+      false
+    end
+  end
 
-    changes.each do |change|
+  def process_project_changes(post_received)
+    post_received.changes.each do |change|
       oldrev, newrev, ref = change.strip.split(' ')
 
-      @user ||= identify(identifier, project, newrev)
+      @user ||= post_received.identify(newrev)
 
       unless @user
-        log("Triggered hook for non-existing user \"#{identifier} \"")
+        log("Triggered hook for non-existing user \"#{post_received.identifier} \"")
         return false
       end
 
       if Gitlab::Git.tag_ref?(ref)
-        GitTagPushService.new.execute(project, @user, oldrev, newrev, ref)
+        GitTagPushService.new.execute(post_received.project, @user, oldrev, newrev, ref)
       else
-        GitPushService.new(project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute
+        GitPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute
       end
     end
   end
 
-  def utf8_encode_changes(changes)
-    changes = changes.dup
-
-    changes.force_encoding("UTF-8")
-    return changes if changes.valid_encoding?
-
-    # Convert non-UTF-8 branch/tag names to UTF-8 so they can be dumped as JSON.
-    detection = CharlockHolmes::EncodingDetector.detect(changes)
-    return changes unless detection && detection[:encoding]
-
-    CharlockHolmes::Converter.convert(changes, detection[:encoding], 'UTF-8')
-  end
-
+  private
+  
   def log(message)
     Gitlab::GitLogger.error("POST-RECEIVE: #{message}")
   end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 05f127d622a9b6f78d53818297a988e0f9ca71f8..500b745f55e9a83127d7cee20153a38405ca19c9 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -357,6 +357,12 @@ production: &base
       #       crowd_server_url: 'CROWD SERVER URL',
       #       application_name: 'YOUR_APP_NAME',
       #       application_password: 'YOUR_APP_PASSWORD' } }
+      #
+      # - { name: 'auth0',
+      #     args: {
+      #       client_id: 'YOUR_AUTH0_CLIENT_ID',
+      #       client_secret: 'YOUR_AUTH0_CLIENT_SECRET',
+      #       namespace: 'YOUR_AUTH0_DOMAIN' } }
 
     # SSO maximum session duration in seconds. Defaults to CAS default of 8 hours.
     # cas3:
diff --git a/config/initializers/gollum.rb b/config/initializers/gollum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..703f24f93b27e4fae2dfc99379e1bb2d34396d46
--- /dev/null
+++ b/config/initializers/gollum.rb
@@ -0,0 +1,13 @@
+module Gollum
+  GIT_ADAPTER = "rugged"
+end
+require "gollum-lib"
+
+module Gollum
+  class Committer
+    # Patch for UTF-8 path
+    def method_missing(name, *args)
+      index.send(name, *args)
+    end
+  end
+end
diff --git a/config/routes.rb b/config/routes.rb
index 2ae282f48a6db81779fef960597f4eddd7b50548..ec79522002e118dae0152feb7e487e9044bb0371 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -351,6 +351,8 @@ Rails.application.routes.draw do
     get :issues
     get :merge_requests
     get :activity
+    get :labels
+    get :milestones
 
     scope module: :dashboard do
       resources :milestones, only: [:index, :show]
diff --git a/db/migrate/20160223192159_add_confidential_to_issues.rb b/db/migrate/20160223192159_add_confidential_to_issues.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e9d47fd589aff45f4de9c10db52b066074e05131
--- /dev/null
+++ b/db/migrate/20160223192159_add_confidential_to_issues.rb
@@ -0,0 +1,6 @@
+class AddConfidentialToIssues < ActiveRecord::Migration
+  def change
+    add_column :issues, :confidential, :boolean, default: false
+    add_index :issues, :confidential
+  end
+end
diff --git a/db/migrate/20160310185910_add_external_flag_to_users.rb b/db/migrate/20160310185910_add_external_flag_to_users.rb
new file mode 100644
index 0000000000000000000000000000000000000000..54937f1eb711f974da2a85f1ea064c46597f8c23
--- /dev/null
+++ b/db/migrate/20160310185910_add_external_flag_to_users.rb
@@ -0,0 +1,5 @@
+class AddExternalFlagToUsers < ActiveRecord::Migration
+  def change
+    add_column :users, :external, :boolean, default: false
+  end
+end
diff --git a/db/migrate/20160316123110_ci_runners_token_index.rb b/db/migrate/20160316123110_ci_runners_token_index.rb
new file mode 100644
index 0000000000000000000000000000000000000000..67bf5b4f97827560b2d4df1cf768d18c9a5eb009
--- /dev/null
+++ b/db/migrate/20160316123110_ci_runners_token_index.rb
@@ -0,0 +1,13 @@
+class CiRunnersTokenIndex < ActiveRecord::Migration
+  disable_ddl_transaction!
+
+  def change
+    args = [:ci_runners, :token]
+
+    if Gitlab::Database.postgresql?
+      args << { algorithm: :concurrently }
+    end
+
+    add_index(*args)
+  end
+end
diff --git a/db/migrate/20160316192622_change_target_id_to_null_on_todos.rb b/db/migrate/20160316192622_change_target_id_to_null_on_todos.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6871b3920df145b0d609cddb8b7ba8dc881f0851
--- /dev/null
+++ b/db/migrate/20160316192622_change_target_id_to_null_on_todos.rb
@@ -0,0 +1,5 @@
+class ChangeTargetIdToNullOnTodos < ActiveRecord::Migration
+  def change
+    change_column_null :todos, :target_id, true
+  end
+end
diff --git a/db/migrate/20160316204731_add_commit_id_to_todos.rb b/db/migrate/20160316204731_add_commit_id_to_todos.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ae19fdd1abd3c525a4955a527ec2b89215e285f3
--- /dev/null
+++ b/db/migrate/20160316204731_add_commit_id_to_todos.rb
@@ -0,0 +1,6 @@
+class AddCommitIdToTodos < ActiveRecord::Migration
+  def change
+    add_column :todos, :commit_id, :string
+    add_index :todos, :commit_id
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5027d2ba32fc5f2cf2c0d8a6c4f3eee6664ed4b6..5b2f5aa3ddd3991e958c231a31e6db49ea1797db 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: 20160314143402) do
+ActiveRecord::Schema.define(version: 20160316204731) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -260,6 +260,7 @@ ActiveRecord::Schema.define(version: 20160314143402) do
   end
 
   add_index "ci_runners", ["description"], name: "index_ci_runners_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
+  add_index "ci_runners", ["token"], name: "index_ci_runners_on_token", using: :btree
   add_index "ci_runners", ["token"], name: "index_ci_runners_on_token_trigram", using: :gin, opclasses: {"token"=>"gin_trgm_ops"}
 
   create_table "ci_services", force: :cascade do |t|
@@ -415,10 +416,12 @@ ActiveRecord::Schema.define(version: 20160314143402) do
     t.string   "state"
     t.integer  "iid"
     t.integer  "updated_by_id"
+    t.boolean  "confidential",              default: false
   end
 
   add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
   add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree
+  add_index "issues", ["confidential"], name: "index_issues_on_confidential", using: :btree
   add_index "issues", ["created_at", "id"], name: "index_issues_on_created_at_and_id", using: :btree
   add_index "issues", ["created_at"], name: "index_issues_on_created_at", using: :btree
   add_index "issues", ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
@@ -775,9 +778,9 @@ ActiveRecord::Schema.define(version: 20160314143402) do
     t.string   "type"
     t.string   "title"
     t.integer  "project_id"
-    t.datetime "created_at"
-    t.datetime "updated_at"
-    t.boolean  "active",                default: false,    null: false
+    t.datetime "created_at",                               null: false
+    t.datetime "updated_at",                               null: false
+    t.boolean  "active",                                   null: false
     t.text     "properties"
     t.boolean  "template",              default: false
     t.boolean  "push_events",           default: true
@@ -864,7 +867,7 @@ ActiveRecord::Schema.define(version: 20160314143402) do
   create_table "todos", force: :cascade do |t|
     t.integer  "user_id",     null: false
     t.integer  "project_id",  null: false
-    t.integer  "target_id",   null: false
+    t.integer  "target_id"
     t.string   "target_type", null: false
     t.integer  "author_id"
     t.integer  "action",      null: false
@@ -872,9 +875,11 @@ ActiveRecord::Schema.define(version: 20160314143402) do
     t.datetime "created_at"
     t.datetime "updated_at"
     t.integer  "note_id"
+    t.string   "commit_id"
   end
 
   add_index "todos", ["author_id"], name: "index_todos_on_author_id", using: :btree
+  add_index "todos", ["commit_id"], name: "index_todos_on_commit_id", using: :btree
   add_index "todos", ["note_id"], name: "index_todos_on_note_id", using: :btree
   add_index "todos", ["project_id"], name: "index_todos_on_project_id", using: :btree
   add_index "todos", ["state"], name: "index_todos_on_state", using: :btree
@@ -939,6 +944,7 @@ ActiveRecord::Schema.define(version: 20160314143402) do
     t.string   "unlock_token"
     t.datetime "otp_grace_period_started_at"
     t.boolean  "ldap_email",                  default: false, null: false
+    t.boolean  "external",                    default: false
   end
 
   add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/README.md b/doc/README.md
index 0ca30e4e0f230178d2d15016597036c4097c81fa..08d0a6a5bfbd958d8e477442298360e93c9edca3 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -3,12 +3,13 @@
 ## User documentation
 
 - [API](api/README.md) Automate GitLab via a simple and powerful API.
+- [CI](ci/README.md)
 - [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
 - [GitLab Basics](gitlab-basics/README.md) Find step by step how to start working on your commandline and on GitLab.
 - [Importing to GitLab](workflow/importing/README.md).
 - [Markdown](markdown/markdown.md) GitLab's advanced formatting system.
 - [Migrating from SVN](workflow/importing/migrating_from_svn.md) Convert a SVN repository to Git and GitLab
-- [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do.
+- [Permissions](permissions/permissions.md) Learn what each role in a project (external/guest/reporter/developer/master/owner) can do.
 - [Profile Settings](profile/README.md)
 - [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
 - [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects.
@@ -16,42 +17,6 @@
 - [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
 - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
 
-## CI User documentation
-
-- [Get started with GitLab CI](ci/quick_start/README.md)
-- [Learn how to enable or disable GitLab CI](ci/enable_or_disable_ci.md)
-- [Learn how `.gitlab-ci.yml` works](ci/yaml/README.md)
-- [Configure a Runner, the application that runs your builds](ci/runners/README.md)
-- [Use Docker images with GitLab Runner](ci/docker/using_docker_images.md)
-- [Use CI to build Docker images](ci/docker/using_docker_build.md)
-- [Use variables in your `.gitlab-ci.yml`](ci/variables/README.md)
-- [Use SSH keys in your build environment](ci/ssh_keys/README.md)
-- [Trigger builds through the API](ci/triggers/README.md)
-- [Build artifacts](ci/build_artifacts/README.md)
-- [User permissions](ci/permissions/README.md)
-- [API](ci/api/README.md)
-
-### CI Examples
-
-- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
-- [Test your PHP applications](ci/examples/php.md)
-- [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md)
-- [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md)
-- [Test Clojure applications](ci/examples/test-clojure-application.md)
-- [Using `dpl` as deployment tool](ci/deployment/README.md)
-- Help your favorite programming language and GitLab by sending a merge request
-  with a guide for that language.
-
-### CI Services
-
-GitLab CI uses the `services` keyword to define what docker containers should
-be linked with your base image. Below is a list of examples you may use:
-
-- [Using MySQL](ci/services/mysql.md)
-- [Using PostgreSQL](ci/services/postgres.md)
-- [Using Redis](ci/services/redis.md)
-- [Using Other Services](ci/docker/using_docker_images.md#how-to-use-other-images-as-services)
-
 ## Administrator documentation
 
 - [Custom git hooks](hooks/custom_hooks.md) Custom git hooks (on the filesystem) for when webhooks aren't enough.
diff --git a/doc/api/users.md b/doc/api/users.md
index 82c57a2fd43784a2ad95103ae4c3d515e4b89e96..383e7c76ab0e005ca45feb475f5355ccbd0dda7f 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -194,6 +194,7 @@ Parameters:
 - `admin` (optional)            - User is admin - true or false (default)
 - `can_create_group` (optional) - User can create groups - true or false
 - `confirm` (optional)          - Require confirmation - true (default) or false
+- `external` (optional)         - Flags the user as external - true or false(default)
 
 ## User modification
 
@@ -219,6 +220,7 @@ Parameters:
 - `bio`                         - User's biography
 - `admin` (optional)            - User is admin - true or false (default)
 - `can_create_group` (optional) - User can create groups - true or false
+- `external` (optional)         - Flags the user as external - true or false(default)
 
 Note, at the moment this method does only return a 404 error,
 even in cases where a 409 (Conflict) would be more appropriate,
@@ -560,7 +562,7 @@ Parameters:
 
 - `uid` (required) - id of specified user
 
-Will return `200 OK` on success, `404 User Not Found` is user cannot be found or 
+Will return `200 OK` on success, `404 User Not Found` is user cannot be found or
 `403 Forbidden` when trying to block an already blocked user by LDAP synchronization.
 
 ## Unblock user
diff --git a/doc/ci/deployment/README.md b/doc/ci/deployment/README.md
index ffd841ca9e754844c08a3e9a44dcbeffd0fe4d38..7d91ce6710fdb580d50e0215bef86fdb96f8f20e 100644
--- a/doc/ci/deployment/README.md
+++ b/doc/ci/deployment/README.md
@@ -89,7 +89,7 @@ We also use two secure variables:
 In GitLab CI 7.12 a new feature was introduced: Secure Variables.
 Secure Variables can added by going to `Project > Variables > Add Variable`. 
 **This feature requires `gitlab-runner` with version equal or greater than 0.4.0.**
-The variables that are defined in the project settings are send along with the build script to the runner.
+The variables that are defined in the project settings are sent along with the build script to the runner.
 The secure variables are stored out of the repository. Never store secrets in your projects' .gitlab-ci.yml.
 It is also important that secret's value is hidden in the build log.
 
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 5158e3c387c4c70bc96fad52a3159d253196a0c3..a9b79bbdb1b800fa8fca23f657a67fb51d65e523 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -135,6 +135,9 @@ thus allowing to fine tune them.
 
 ### cache
 
+>**Note:**
+Introduced in GitLab Runner v0.7.0.
+
 `cache` is used to specify a list of files and directories which should be
 cached between builds.
 
@@ -143,15 +146,55 @@ cached between builds.
 If `cache` is defined outside the scope of the jobs, it means it is set
 globally and all jobs will use its definition.
 
-To cache all git untracked files and files in `binaries`:
+Cache all files in `binaries` and `.config`:
+
+```yaml
+rspec:
+  script: test
+  cache:
+    paths:
+    - binaries/
+    - .config
+```
+
+Cache all Git untracked files:
+
+```yaml
+rspec:
+  script: test
+  cache:
+    untracked: true
+```
+
+Cache all Git untracked files and files in `binaries`:
+
+```yaml
+rspec:
+  script: test
+  cache:
+    untracked: true
+    paths:
+    - binaries/
+```
+
+Locally defined cache overwrites globally defined options. This will cache only
+`binaries/`:
 
 ```yaml
 cache:
-  untracked: true
   paths:
-  - binaries/
+  - my/files
+
+rspec:
+  script: test
+  cache:
+    paths:
+    - binaries/
 ```
 
+The cache is provided on best effort basis, so don't expect that cache will be
+always present. For implementation details please check GitLab Runner.
+
 #### cache:key
 
 >**Note:**
@@ -418,14 +461,14 @@ artifacts:
   - .config
 ```
 
-Send all git untracked files:
+Send all Git untracked files:
 
 ```yaml
 artifacts:
   untracked: true
 ```
 
-Send all git untracked files and files in `binaries`:
+Send all Git untracked files and files in `binaries`:
 
 ```yaml
 artifacts:
@@ -579,63 +622,6 @@ deploy:
   script: make deploy
 ```
 
-### cache
-
->**Note:**
-Introduced in GitLab Runner v0.7.0.
-
-`cache` is used to specify list of files and directories which should be cached
-between builds. Below are some examples:
-
-Cache all files in `binaries` and `.config`:
-
-```yaml
-rspec:
-  script: test
-  cache:
-    paths:
-    - binaries/
-    - .config
-```
-
-Cache all git untracked files:
-
-```yaml
-rspec:
-  script: test
-  cache:
-    untracked: true
-```
-
-Cache all git untracked files and files in `binaries`:
-
-```yaml
-rspec:
-  script: test
-  cache:
-    untracked: true
-    paths:
-    - binaries/
-```
-
-Locally defined cache overwrites globally defined options. This will cache only
-`binaries/`:
-
-```yaml
-cache:
-  paths:
-  - my/files
-
-rspec:
-  script: test
-  cache:
-    paths:
-    - binaries/
-```
-
-The cache is provided on best effort basis, so don't expect that cache will be
-always present. For implementation details please check GitLab Runner.
-
 ## Hidden jobs
 
 >**Note:**
diff --git a/doc/hooks/custom_hooks.md b/doc/hooks/custom_hooks.md
index 15051dd76f97abaf65dd5c083ee63cb7e40872cf..dcdf49d3379702ffa9a7b6b6964a115037a632ec 100644
--- a/doc/hooks/custom_hooks.md
+++ b/doc/hooks/custom_hooks.md
@@ -2,7 +2,7 @@
 
 **Note: Custom git hooks must be configured on the filesystem of the GitLab
 server. Only GitLab server administrators will be able to complete these tasks.
-Please explore [webhooks](doc/web_hooks/web_hooks.md) as an option if you do not have filesystem access. For a user configurable Git Hooks interface, please see [GitLab Enterprise Edition Git Hooks](http://doc.gitlab.com/ee/git_hooks/git_hooks.html).**
+Please explore [webhooks](../web_hooks/web_hooks.md) as an option if you do not have filesystem access. For a user configurable Git Hooks interface, please see [GitLab Enterprise Edition Git Hooks](http://doc.gitlab.com/ee/git_hooks/git_hooks.html).**
 
 Git natively supports hooks that are executed on different actions.
 Examples of server-side git hooks include pre-receive, post-receive, and update.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 4f01139726986d60f195094c14c610af66375988..c567846f624f0cdec216bf919e3decb0f0b8ed6f 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -22,7 +22,7 @@ If the highest number stable branch is unclear please check the [GitLab Blog](ht
 
 This guide is long because it covers many cases and includes all commands you need, this is [one of the few installation scripts that actually works out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
 
-This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements. If you want to install on RHEL/CentOS we recommend using the [Omnibus packages](https://about.gitlab.com/downloads/).
+This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [requirements.md](requirements.md) for hardware and operating system requirements. If you want to install on RHEL/CentOS we recommend using the [Omnibus packages](https://about.gitlab.com/downloads/).
 
 This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please see [the installation section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#installation).
 
@@ -76,7 +76,7 @@ Make sure you have the right version of Git installed
     # Install Git
     sudo apt-get install -y git-core
 
-    # Make sure Git is version 1.7.10 or higher, for example 1.7.12 or 2.0.0
+    # Make sure Git is version 2.7.4 or higher
     git --version
 
 Is the system packaged Git too old? Remove it and compile from source.
@@ -89,8 +89,9 @@ Is the system packaged Git too old? Remove it and compile from source.
 
     # Download and compile from source
     cd /tmp
-    curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.4.3.tar.gz | tar xz
-    cd git-2.4.3/
+    curl -O --progress https://www.kernel.org/pub/software/scm/git/git-2.7.4.tar.gz
+    echo '7104c4f5d948a75b499a954524cb281fe30c6649d8abe20982936f75ec1f275b  git-2.7.4.tar.gz' | shasum -a256 -c - && tar -xzf git-2.7.4.tar.gz
+    cd git-2.7.4/
     ./configure
     make prefix=/usr/local all
 
@@ -143,7 +144,7 @@ use 64-bit Linux. You can find downloads for other platforms at the [Go download
 page](https://golang.org/dl).
 
     curl -O --progress https://storage.googleapis.com/golang/go1.5.3.linux-amd64.tar.gz
-    echo '43afe0c5017e502630b1aea4d44b8a7f059bf60d7f29dfd58db454d4e4e0ae53  go1.5.3.linux-amd64.tar.gz' | shasum -c - && \
+    echo '43afe0c5017e502630b1aea4d44b8a7f059bf60d7f29dfd58db454d4e4e0ae53  go1.5.3.linux-amd64.tar.gz' | shasum -a256 -c - && \
       sudo tar -C /usr/local -xzf go1.5.3.linux-amd64.tar.gz
     sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
     rm go1.5.3.linux-amd64.tar.gz
@@ -161,18 +162,11 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
     # Install the database packages
     sudo apt-get install -y postgresql postgresql-client libpq-dev
 
-    # Login to PostgreSQL
-    sudo -u postgres psql -d template1
-
     # Create a user for GitLab
-    # Do not type the 'template1=#', this is part of the prompt
-    template1=# CREATE USER git CREATEDB;
+    sudo -u postgres psql -d template1 -c "CREATE USER git CREATEDB;"
 
     # Create the GitLab production database & grant all privileges on database
-    template1=# CREATE DATABASE gitlabhq_production OWNER git;
-
-    # Quit the database session
-    template1=# \q
+    sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;"
 
     # Try connecting to the new database with the new user
     sudo -u git -H psql -d gitlabhq_production
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index d59b7f0e84dcc778623ea25f950da8571e44fe4f..03cb08dd1f1df0e006020f57fe9c15c225784130 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -22,7 +22,7 @@ For the installations options please see [the installation page on the GitLab we
 - FreeBSD
 
 On the above unsupported distributions is still possible to install GitLab yourself.
-Please see the [installation from source guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) and the [unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) on the public wiki for more information.
+Please see the [installation from source guide](installation.md) and the [installation guides](https://about.gitlab.com/installation/) for more information.
 
 ### Non-Unix operating systems such as Windows
 
diff --git a/doc/integration/auth0.md b/doc/integration/auth0.md
new file mode 100644
index 0000000000000000000000000000000000000000..e5247082a89e2d89112111cda2a61e739eda8c07
--- /dev/null
+++ b/doc/integration/auth0.md
@@ -0,0 +1,89 @@
+# Auth0 OmniAuth Provider
+
+To enable the Auth0 OmniAuth provider, you must create an Auth0 account, and an
+application.
+
+1. Sign in to the [Auth0 Console](https://manage.auth0.com). If you need to
+create an account, you can do so at the same link.
+
+1. Select "New App/API".
+
+1. Provide the Application Name ('GitLab' works fine).
+
+1. Once created, you should see the Quick Start options. Disregard them and
+select 'Settings' above the Quick Start options.
+
+1. At the top of the Settings screen, you should see your Domain, Client ID and
+Client Secret. Take note of these as you'll need to put them in the
+configuration file. For example:
+    - Domain: `test1234.auth0.com`
+    - Client ID: `t6X8L2465bNePWLOvt9yi41i`
+    - Client Secret: `KbveM3nqfjwCbrhaUy_gDu2dss8TIlHIdzlyf33pB7dEK5u_NyQdp65O_o02hXs2`
+
+1. Fill in the Allowed Callback URLs:
+    - http://`YOUR_GITLAB_URL`/users/auth/auth0/callback (or)
+    - https://`YOUR_GITLAB_URL`/users/auth/auth0/callback
+
+1. Fill in the Allowed Origins (CORS):
+    - http://`YOUR_GITLAB_URL` (or)
+    - https://`YOUR_GITLAB_URL`
+
+1. On your GitLab server, open the configuration file.
+
+    For omnibus package:
+
+    ```sh
+      sudo editor /etc/gitlab/gitlab.rb
+    ```
+
+    For installations from source:
+
+    ```sh
+      cd /home/git/gitlab
+      sudo -u git -H editor config/gitlab.yml
+    ```
+
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration)
+for initial settings.
+
+1. Add the provider configuration:
+
+    For omnibus package:
+
+    ```ruby
+      gitlab_rails['omniauth_providers'] = [
+        {
+          "name" => "auth0",
+          "args" => { client_id: 'YOUR_AUTH0_CLIENT_ID'',
+                      client_secret: 'YOUR_AUTH0_CLIENT_SECRET',
+                      namespace: 'YOUR_AUTH0_DOMAIN'
+                    }
+        }
+      ]
+    ```
+
+    For installations from source:
+
+    ```yaml
+      - { name: 'auth0',
+          args: {
+            client_id: 'YOUR_AUTH0_CLIENT_ID',
+            client_secret: 'YOUR_AUTH0_CLIENT_SECRET',
+            namespace: 'YOUR_AUTH0_DOMAIN'
+            }
+        }
+    ```
+
+1. Change `YOUR_AUTH0_CLIENT_ID` to the client ID from the Auth0 Console page
+from step 5.
+
+1. Change `YOUR_AUTH0_CLIENT_SECRET` to the client secret from the Auth0 Console
+page from step 5.
+
+1. Save the file and [reconfigure GitLab](../administration/restart_gitlab.md)
+for the changes to take effect.
+
+On the sign in page there should now be an Auth0 icon below the regular sign in
+form. Click the icon to begin the authentication process. Auth0 will ask the
+user to sign in and authorize the GitLab application. If everything goes well
+the user will be returned to GitLab and will be signed in.
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index ba47cb16265940573f88aca49cb208d60fecd493..25f359883056511932fb9d192e4677bc0ea3c145 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -28,6 +28,7 @@ contains some settings that are common for all providers.
 - [SAML](saml.md)
 - [Crowd](crowd.md)
 - [Azure](azure.md)
+- [Auth0](auth0.md)
 
 ## Initial OmniAuth Configuration
 
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index ac0fd3d175654a12b9853509f11b6c5e747bb7dd..3d375e47c8ec3a810fdcce0cc67641747fc9a202 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -71,3 +71,24 @@ Any user can remove themselves from a group, unless they are the last Owner of t
 | Create project in group |       |          |           | ✓      | ✓     |
 | Manage group members    |       |          |           |        | ✓     |
 | Remove group            |       |          |           |        | ✓     |
+
+## External Users
+
+In cases where it is desired that a user has access only to some internal or
+private projects, there is the option of creating **External Users**. This
+feature may be useful when for example a contractor is working on a given
+project and should only have access to that project.
+
+External users can only access projects to which they are explicitly granted
+access, thus hiding all other internal or private ones from them. Access can be
+granted by adding the user as member to the project or group.
+
+They will, like usual users, receive a role in the project or group with all
+the abilities that are mentioned in the table above. They cannot however create
+groups or projects, and they have the same access as logged out users in all
+other cases.
+
+An administrator can flag a user as external [through the API](../api/users.md)
+or by checking the checkbox on the admin panel. As an administrator, navigate
+to **Admin > Users** to create a new user or edit an existing one. There, you
+will find the option to flag the user as external.
diff --git a/doc/release/security.md b/doc/release/security.md
index b1a62b333e64f1489986d4873c51c81887bcf54f..118c016ba4f2bc54a760383a718b549b8c720139 100644
--- a/doc/release/security.md
+++ b/doc/release/security.md
@@ -15,7 +15,7 @@ Please report suspected security vulnerabilities in private to <support@gitlab.c
 1. Verify that the issue can be reproduced
 1. Acknowledge the issue to the researcher that disclosed it
 1. Inform the release manager that there needs to be a security release
-1. Do the steps from [patch release document](doc/release/patch.md), starting with "Create an issue on private GitLab development server"
+1. Do the steps from [patch release document](../release/patch.md), starting with "Create an issue on private GitLab development server"
 1. The MR with the security fix should get a 'security' label and be assigned to the release manager
 1. Build the package for GitLab.com and do a deploy
 1. Build the package for ci.gitLab.com and do a deploy
diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md
index 8365bdb7b1b38b504cf1cf9db1b6ad154868623d..c8499380c18f597d96fd1e8de77153856f1044c7 100644
--- a/doc/security/two_factor_authentication.md
+++ b/doc/security/two_factor_authentication.md
@@ -6,7 +6,7 @@ password to login, they'll be prompted for a code generated by an application on
 their phone.
 
 You can read more about it here:
-[Two-factor Authentication (2FA)](doc/profile/two_factor_authentication.md)
+[Two-factor Authentication (2FA)](../profile/two_factor_authentication.md)
 
 ## Enabling 2FA
 
diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md
index 2ca4e1f37702308a506594766e9c70221605be6e..9f5c6c4dc84ba652c11bab96406f32601c9a277f 100644
--- a/doc/update/8.2-to-8.3.md
+++ b/doc/update/8.2-to-8.3.md
@@ -1,5 +1,14 @@
 # From 8.2 to 8.3
 
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
 **NOTE:** GitLab 8.0 introduced several significant changes related to
 installation and configuration which *are not duplicated here*. Be sure you're
 already running a working version of at least 8.0 before proceeding with this
diff --git a/doc/update/8.3-to-8.4.md b/doc/update/8.3-to-8.4.md
index 269deec7a9c59413e36a8b01a71d0985ae1acfc7..9f6517d9487e636e0b10027bae5dcfaf2545519f 100644
--- a/doc/update/8.3-to-8.4.md
+++ b/doc/update/8.3-to-8.4.md
@@ -1,5 +1,14 @@
 # From 8.3 to 8.4
 
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
 ### 1. Stop server
 
     sudo service gitlab stop
diff --git a/doc/update/8.4-to-8.5.md b/doc/update/8.4-to-8.5.md
index 0a9cb5683e7a8e314d51bd6c6012d9cd5f5f42c5..0cb137a03cc337cd609873864d9f375c760b6c28 100644
--- a/doc/update/8.4-to-8.5.md
+++ b/doc/update/8.4-to-8.5.md
@@ -1,5 +1,14 @@
 # From 8.4 to 8.5
 
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
 ### 1. Stop server
 
     sudo service gitlab stop
diff --git a/doc/update/8.5-to-8.6.md b/doc/update/8.5-to-8.6.md
index 024f6e8a4333fa0d38a93d2fb041e85ead78e667..7d63915af5ede8a2a0ab2e8196f2e7b2479e3fca 100644
--- a/doc/update/8.5-to-8.6.md
+++ b/doc/update/8.5-to-8.6.md
@@ -1,5 +1,14 @@
 # From 8.5 to 8.6
 
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
 ### 1. Stop server
 
     sudo service gitlab stop
diff --git a/doc/workflow/importing/import_projects_from_bitbucket.md b/doc/workflow/importing/import_projects_from_bitbucket.md
index 1e9825e2e1049c2be12b6899147eabafd5be8978..520c42162957bf9e1981a53dca79c03ff2d7a9fe 100644
--- a/doc/workflow/importing/import_projects_from_bitbucket.md
+++ b/doc/workflow/importing/import_projects_from_bitbucket.md
@@ -1,6 +1,6 @@
 # Import your project from Bitbucket to GitLab
 
-It takes just a few steps to import your existing Bitbucket projects to GitLab. But keep in mind that it is possible only if Bitbucket support is enabled on your GitLab instance. You can read more about Bitbucket support [here](doc/integration/bitbucket.md).
+It takes just a few steps to import your existing Bitbucket projects to GitLab. But keep in mind that it is possible only if Bitbucket support is enabled on your GitLab instance. You can read more about Bitbucket support [here](../../integration/bitbucket.md).
 
 * Sign in to GitLab.com and go to your dashboard
 
diff --git a/doc/workflow/protected_branches.md b/doc/workflow/protected_branches.md
index fdf9a8d391cb490ec6b24115c3de49bff92056ac..d854ec1e0250643b27ea072c0d530cbb063694da 100644
--- a/doc/workflow/protected_branches.md
+++ b/doc/workflow/protected_branches.md
@@ -12,7 +12,7 @@ A protected branch does three simple things:
 
 You can make any branch a protected branch. GitLab makes the master branch a protected branch by default.
 
-To protect a branch, user needs to have at least a Master permission level, see [permissions document](doc/permissions/permissions.md).
+To protect a branch, user needs to have at least a Master permission level, see [permissions document](../permissions/permissions.md).
 
 ![protected branches page](protected_branches/protected_branches1.png)
 
diff --git a/features/project/issues/award_emoji.feature b/features/project/issues/award_emoji.feature
index 2945bb3753a93bfe3439c92445d791f9edaf2fdf..f0fd414a9f913fe50a5b463a4369932d7bed73cb 100644
--- a/features/project/issues/award_emoji.feature
+++ b/features/project/issues/award_emoji.feature
@@ -18,21 +18,24 @@ Feature: Award Emoji
   @javascript
   Scenario: I add and remove custom award in the issue
     Given I click to emoji-picker
-    Then The search field is focused
-    And I click to emoji in the picker
+    Then The emoji menu is visible
+    And The search field is focused
+    Then I click to emoji in the picker
     Then I have award added
     And I can remove it by clicking to icon
 
   @javascript
   Scenario: I can see the list of emoji categories
     Given I click to emoji-picker
-    Then The search field is focused
+    Then The emoji menu is visible
+    And The search field is focused
     Then I can see the activity and food categories
 
   @javascript
   Scenario: I can search emoji
     Given I click to emoji-picker
-    Then The search field is focused
+    Then The emoji menu is visible
+    And The search field is focused
     And I search "hand"
     Then I see search result for "hand"
 
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 74685d24a7d86aabd24adab183907a76782383e0..823658b4f240657b768e5d8f59a48ffed4bba3bf 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -325,3 +325,11 @@ Feature: Project Merge Requests
     When I click the "Target branch" dropdown
     And I select a new target branch
     Then I should see new target branch changes
+
+  @javascript
+  Scenario: I can close merge request after commenting
+    Given I visit merge request page "Bug NS-04"
+    And I leave a comment like "XML attached"
+    Then I should see comment "XML attached"
+    And I click link "Close"
+    Then I should see closed merge request "Bug NS-04"
diff --git a/features/steps/dashboard/todos.rb b/features/steps/dashboard/todos.rb
index 9722a5a848c546df507c36e7c8f2c2ede3079e67..963e4f21365293d148e7b9c74a94a0455491e852 100644
--- a/features/steps/dashboard/todos.rb
+++ b/features/steps/dashboard/todos.rb
@@ -41,7 +41,6 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
       click_link 'Done'
     end
 
-    expect(page).to have_content 'Todo was successfully marked as done.'
     expect(page).to have_content 'To do 3'
     expect(page).to have_content 'Done 1'
     should_not_see_todo "John Doe assigned you merge request !#{merge_request.iid}"
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index 7a6ae15ffa53e18fd2d31b6eecf396fc2e61979d..e5b7db4c5e39a5157f7751dd760c1f49fe0183d4 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -35,7 +35,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
   end
 
   step 'I should see projects activity feed' do
-    expect(page).to have_content 'closed issue'
+    expect(page).to have_content 'joined project'
   end
 
   step 'I should see issues from group "Owned" assigned to me' do
diff --git a/features/steps/project/badges/build.rb b/features/steps/project/badges/build.rb
index 47540f356e902c82fd9296cf9819be35dc53e03f..66a48a176e58703e062660a7cd51e2f2f6957e47 100644
--- a/features/steps/project/badges/build.rb
+++ b/features/steps/project/badges/build.rb
@@ -21,7 +21,7 @@ class Spinach::Features::ProjectBadgesBuild < Spinach::FeatureSteps
   end
 
   step 'I should see a badge that has not been cached' do
-    expect(page.response_headers).to include('Cache-Control' => 'no-cache')
+    expect(page.response_headers['Cache-Control']).to include 'no-cache'
   end
 
   def expect_badge(status)
diff --git a/features/steps/project/issues/award_emoji.rb b/features/steps/project/issues/award_emoji.rb
index ce2554bc80dd89248d7d118f97d87ac4cbc518fb..c5d45709b445675d6e6dde3ce0662c9ced86a87b 100644
--- a/features/steps/project/issues/award_emoji.rb
+++ b/features/steps/project/issues/award_emoji.rb
@@ -92,6 +92,10 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
     end
   end
 
+  step 'The emoji menu is visible' do
+    page.find(".emoji-menu.is-visible")
+  end
+
   step 'The search field is focused' do
     expect(page).to have_selector('#emoji_search')
     expect(page.evaluate_script('document.activeElement.id')).to eq('emoji_search')
diff --git a/features/steps/search.rb b/features/steps/search.rb
index 48ea3fa3876c196f177afaf37a93a76b57fad110..0ad837ebe1d7056e9a804442d1e08de9266c0027 100644
--- a/features/steps/search.rb
+++ b/features/steps/search.rb
@@ -100,7 +100,7 @@ class Spinach::Features::Search < Spinach::FeatureSteps
 
   step 'I should see "test_wiki" link in the search results' do
     page.within('.results') do
-      find(:css, '.search-results').should have_link 'test_wiki.md'
+      expect(find(:css, '.search-results')).to have_link 'test_wiki'
     end
   end
 
diff --git a/features/support/capybara.rb b/features/support/capybara.rb
index f33379f76c92ac2c1754711ce8fe2ad39193d8f2..fe9e39cf50946207870e775d369de4711b538c1b 100644
--- a/features/support/capybara.rb
+++ b/features/support/capybara.rb
@@ -9,7 +9,7 @@ Capybara.register_driver :poltergeist do |app|
   Capybara::Poltergeist::Driver.new(app, js_errors: true, timeout: timeout, window_size: [1366, 768])
 end
 
-Capybara.default_wait_time = timeout
+Capybara.default_max_wait_time = timeout
 Capybara.ignore_hidden_elements = false
 
 unless ENV['CI'] || ENV['CI_SERVER']
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 9805e53624e3b343d4e37c4c794bb527d36bb5a2..71197205f3433e7f3587cf986c8b82fa1fb029b0 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -31,6 +31,7 @@ module API
       expose :can_create_group?, as: :can_create_group
       expose :can_create_project?, as: :can_create_project
       expose :two_factor_enabled
+      expose :external
     end
 
     class UserLogin < UserFull
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 252744515da88088f8a8b3aa8eb49161db9ab1e4..fda6f8414384a7190f8558fb316d1364e39bd870 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -82,7 +82,7 @@ module API
       #   GET /projects/:id/issues?milestone=1.0.0&state=closed
       #   GET /issues?iid=42
       get ":id/issues" do
-        issues = user_project.issues
+        issues = user_project.issues.visible_to_user(current_user)
         issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
         issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
         issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
@@ -104,6 +104,7 @@ module API
       #   GET /projects/:id/issues/:issue_id
       get ":id/issues/:issue_id" do
         @issue = user_project.issues.find(params[:issue_id])
+        not_found! unless can?(current_user, :read_issue, @issue)
         present @issue, with: Entities::Issue
       end
 
diff --git a/lib/api/users.rb b/lib/api/users.rb
index fd2128bd1795b5e13b8b71f79f5db3f28341f44d..13ab17c6904f392faf17328ac4a3a0058321fc38 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -61,19 +61,20 @@ module API
       #   admin                             - User is admin - true or false (default)
       #   can_create_group                  - User can create groups - true or false
       #   confirm                           - Require user confirmation - true (default) or false
+      #   external                          - Flags the user as external - true or false(default)
       # Example Request:
       #   POST /users
       post do
         authenticated_as_admin!
         required_attributes! [:email, :password, :name, :username]
-        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :bio, :can_create_group, :admin, :confirm]
+        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :bio, :can_create_group, :admin, :confirm, :external]
         admin = attrs.delete(:admin)
         confirm = !(attrs.delete(:confirm) =~ (/(false|f|no|0)$/i))
         user = User.build_user(attrs)
         user.admin = admin unless admin.nil?
         user.skip_confirmation! unless confirm
-
         identity_attrs = attributes_for_keys [:provider, :extern_uid]
+
         if identity_attrs.any?
           user.identities.build(identity_attrs)
         end
@@ -107,12 +108,13 @@ module API
       #   bio                               - Bio
       #   admin                             - User is admin - true or false (default)
       #   can_create_group                  - User can create groups - true or false
+      #   external                          - Flags the user as external - true or false(default)
       # Example Request:
       #   PUT /users/:id
       put ":id" do
         authenticated_as_admin!
 
-        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :website_url, :projects_limit, :username, :bio, :can_create_group, :admin]
+        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :website_url, :projects_limit, :username, :bio, :can_create_group, :admin, :external]
         user = User.find(params[:id])
         not_found!('User') unless user
 
diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb
index 9f08aa36e8b5bfd9cc541ee08bc65452d2f27212..2732e0b51455cadfebabf4b936fbf319e854f19c 100644
--- a/lib/banzai/filter/issue_reference_filter.rb
+++ b/lib/banzai/filter/issue_reference_filter.rb
@@ -9,6 +9,11 @@ module Banzai
         Issue
       end
 
+      def self.user_can_see_reference?(user, node, context)
+        issue = Issue.find(node.attr('data-issue')) rescue nil
+        Ability.abilities.allowed?(user, :read_issue, issue)
+      end
+
       def find_object(project, id)
         project.get_issue(id)
       end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index faa2830c16e434ab02beb48685ba4a790a56061a..d2e85cabf72c18b5d4885925a6321fa7b8b58287 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -24,6 +24,10 @@ module Gitlab
         @lines ||= parser.parse(raw_diff.each_line).to_a
       end
 
+      def too_large?
+        diff.too_large?
+      end
+
       def highlighted_diff_lines
         Gitlab::Diff::Highlight.new(self).highlight
       end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
index d0f6ba23ab4c5a21a4305158d2bf06a4ecdd1ab6..d0815fc7eeae1b1751656e3cb57d35fa8171f015 100644
--- a/lib/gitlab/diff/parser.rb
+++ b/lib/gitlab/diff/parser.rb
@@ -4,6 +4,8 @@ module Gitlab
       include Enumerable
 
       def parse(lines)
+        return [] if lines.blank?
+
         @lines = lines
         line_obj_index = 0
         line_old = 1
diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a088e19d1e7959d228df335b73a398df2d40ba9a
--- /dev/null
+++ b/lib/gitlab/git_post_receive.rb
@@ -0,0 +1,60 @@
+module Gitlab
+  class GitPostReceive
+    include Gitlab::Identifier
+    attr_reader :repo_path, :identifier, :changes, :project
+
+    def initialize(repo_path, identifier, changes)
+      repo_path.gsub!(/\.git\z/, '')
+      repo_path.gsub!(/\A\//, '')
+
+      @repo_path = repo_path
+      @identifier = identifier
+      @changes = deserialize_changes(changes)
+
+      retrieve_project_and_type
+    end
+
+    def wiki?
+      @type == :wiki
+    end
+
+    def regular_project?
+      @type == :project
+    end
+
+    def identify(revision)
+      super(identifier, project, revision)
+    end
+
+    private
+
+    def retrieve_project_and_type
+      @type = :project
+      @project = Project.find_with_namespace(@repo_path)
+
+      if @repo_path.end_with?('.wiki') && !@project
+        @type = :wiki
+        @project = Project.find_with_namespace(@repo_path.gsub(/\.wiki\z/, ''))
+      end
+    end
+
+    def deserialize_changes(changes)
+      changes = Base64.decode64(changes) unless changes.include?(' ')
+      changes = utf8_encode_changes(changes)
+      changes.lines
+    end
+
+    def utf8_encode_changes(changes)
+      changes = changes.dup
+
+      changes.force_encoding('UTF-8')
+      return changes if changes.valid_encoding?
+
+      # Convert non-UTF-8 branch/tag names to UTF-8 so they can be dumped as JSON.
+      detection = CharlockHolmes::EncodingDetector.detect(changes)
+      return changes unless detection && detection[:encoding]
+
+      CharlockHolmes::Converter.convert(changes, detection[:encoding], 'UTF-8')
+    end
+  end
+end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 0607a8b95927940941509ff216ad98dd3fd839b0..71c5b6801fb66ef94cba8c8533d530be688a17fb 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -2,7 +2,8 @@ module Gitlab
   class ProjectSearchResults < SearchResults
     attr_reader :project, :repository_ref
 
-    def initialize(project, query, repository_ref = nil)
+    def initialize(current_user, project, query, repository_ref = nil)
+      @current_user = current_user
       @project = project
       @repository_ref = if repository_ref.present?
                           repository_ref
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index f13528a2eea549b2a929ea501edc1d6cc7da6747..f8ab2b1f09ec0acafaee12bcb8d7eb3375983c7d 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -1,12 +1,13 @@
 module Gitlab
   class SearchResults
-    attr_reader :query
+    attr_reader :current_user, :query
 
     # Limit search results by passed projects
     # It allows us to search only for projects user has access to
     attr_reader :limit_projects
 
-    def initialize(limit_projects, query)
+    def initialize(current_user, limit_projects, query)
+      @current_user = current_user
       @limit_projects = limit_projects || Project.all
       @query = Shellwords.shellescape(query) if query.present?
     end
@@ -58,7 +59,7 @@ module Gitlab
     end
 
     def issues
-      issues = Issue.where(project_id: project_ids_relation)
+      issues = Issue.visible_to_user(current_user).where(project_id: project_ids_relation)
 
       if query =~ /#(\d+)\z/
         issues = issues.where(iid: $1)
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index fc5475c4eef881b2b67e8bcc231f622144b93fa0..1324e4cd267dab602e6ff13487d6b2d397ff75dd 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -30,7 +30,6 @@ server {
   listen [::]:80 default_server;
   server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
   server_tokens off; ## Don't show the nginx version number, a security best practice
-  root /home/git/gitlab/public;
 
   ## See app/controllers/application_controller.rb for headers set
 
@@ -57,4 +56,14 @@ server {
 
     proxy_pass http://gitlab-workhorse;
   }
+
+  error_page 404 /404.html;
+  error_page 422 /422.html;
+  error_page 500 /500.html;
+  error_page 502 /502.html;
+  location ~ ^/(404|422|500|502)\.html$ {
+    root /home/git/gitlab/public;
+    internal;
+  }
+
 }
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 1e5f85413ec6dd8d124c4795f3b9dbfa32acfa86..af6ea9ed7064d3f0d043370a8b4ea4cd8d503979 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -45,7 +45,6 @@ server {
   listen [::]:443 ipv6only=on ssl default_server;
   server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
   server_tokens off; ## Don't show the nginx version number, a security best practice
-  root /home/git/gitlab/public;
 
   ## Strong SSL Security
   ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
@@ -101,4 +100,13 @@ server {
     proxy_set_header    X-Forwarded-Proto   $scheme;
     proxy_pass http://gitlab-workhorse;
   }
+
+  error_page 404 /404.html;
+  error_page 422 /422.html;
+  error_page 500 /500.html;
+  error_page 502 /502.html;
+  location ~ ^/(404|422|500|502)\.html$ {
+    root /home/git/gitlab/public;
+    internal;
+  }
 }
diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake
index ebe301c1fc7ca2aeea67a6e85d66fefe5d450101..cfaf4a129b15188496ce76c4567fde1abf6c7851 100644
--- a/lib/tasks/gemojione.rake
+++ b/lib/tasks/gemojione.rake
@@ -47,6 +47,7 @@ namespace :gemojione do
       # let's simplify it
       system(%Q(sed -i '' "s/width: #{SIZE}px; height: #{SIZE}px; background: image-url('emoji.png')/background-position:/" #{style_path}))
       system(%Q(sed -i '' "s/ no-repeat//" #{style_path}))
+      system(%Q(sed -i '' "s/ 0px/ 0/" #{style_path}))
 
       # Append a generic rule that applies to all Emojis
       File.open(style_path, 'a') do |f|
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 581ab26db796ec2202102446d22b5e3ab9f468ff..27ed57efe555c69011f63425b1935acfd84728b9 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -913,7 +913,7 @@ namespace :gitlab do
   end
 
   def check_git_version
-    required_version = Gitlab::VersionInfo.new(1, 7, 10)
+    required_version = Gitlab::VersionInfo.new(2, 7, 3)
     current_version = Gitlab::VersionInfo.parse(run(%W(#{Gitlab.config.git.bin_path} --version)))
 
     puts "Your git bin path is \"#{Gitlab.config.git.bin_path}\""
diff --git a/public/404.html b/public/404.html
index a0106bc760dc719c0f577ecbea4832fdb92fb16d..4862770cc2a7d55621fded6960c4c32e92040f0a 100644
--- a/public/404.html
+++ b/public/404.html
@@ -2,11 +2,51 @@
 <html>
 <head>
   <title>The page you're looking for could not be found (404)</title>
-  <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
+  <style>
+      body {
+        color: #666;
+        text-align: center;
+        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+        margin: 0;
+        width: 800px;
+        margin: auto;
+        font-size: 14px;
+      }
+
+      h1 {
+        font-size: 56px;
+        line-height: 100px;
+        font-weight: normal;
+        color: #456;
+      }
+
+      h2 {
+        font-size: 24px;
+        color: #666;
+        line-height: 1.5em;
+      }
+
+      h3 {
+        color: #456;
+        font-size: 20px;
+        font-weight: normal;
+        line-height: 28px;
+      }
+
+      hr {
+        margin: 18px 0;
+        border: 0;
+        border-top: 1px solid #EEE;
+        border-bottom: 1px solid white;
+      }
+  </style>
 </head>
 
 <body>
-  <h1>404</h1>
+  <h1>
+    <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
+    404
+  </h1>
   <h3>The page you're looking for could not be found.</h3>
   <hr/>
   <p>Make sure the address is correct and that the page hasn't moved.</p>
diff --git a/public/422.html b/public/422.html
index 026997b48e318aefc0a75619b4fbbfa39f2fc0a9..055b0bde165159e82a4aefc50872b710ae6025bb 100644
--- a/public/422.html
+++ b/public/422.html
@@ -2,12 +2,51 @@
 <html>
 <head>
   <title>The change you requested was rejected (422)</title>
-  <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
+  <style>
+    body {
+      color: #666;
+       text-align: center;
+       font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+       margin: 0;
+       width: 800px;
+       margin: auto;
+       font-size: 14px;
+     }
+
+     h1 {
+       font-size: 56px;
+       line-height: 100px;
+       font-weight: normal;
+       color: #456;
+     }
+
+     h2 {
+       font-size: 24px;
+       color: #666;
+       line-height: 1.5em;
+     }
+
+     h3 {
+       color: #456;
+       font-size: 20px;
+       font-weight: normal;
+       line-height: 28px;
+     }
+
+     hr {
+       margin: 18px 0;
+       border: 0;
+       border-top: 1px solid #EEE;
+       border-bottom: 1px solid white;
+     }
+   </style>
 </head>
 
 <body>
-  <!-- This file lives in public/422.html -->
-  <h1>422</h1>
+  <h1>
+    <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
+    422
+  </h1>
   <h3>The change you requested was rejected.</h3>
   <hr />
   <p>Make sure you have access to the thing you tried to change.</p>
diff --git a/public/500.html b/public/500.html
index 08c11bbd05a330b5bdcc21b38e1fab4e78e64d88..3d59d1392f5ee7b0be736c595971a9ddb7d3cc1a 100644
--- a/public/500.html
+++ b/public/500.html
@@ -2,10 +2,50 @@
 <html>
 <head>
   <title>Something went wrong (500)</title>
-  <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
+  <style>
+     body {
+       color: #666;
+       text-align: center;
+       font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+       margin: 0;
+       width: 800px;
+       margin: auto;
+       font-size: 14px;
+     }
+
+     h1 {
+       font-size: 56px;
+       line-height: 100px;
+       font-weight: normal;
+       color: #456;
+     }
+
+     h2 {
+       font-size: 24px;
+       color: #666;
+       line-height: 1.5em;
+     }
+
+     h3 {
+       color: #456;
+       font-size: 20px;
+       font-weight: normal;
+       line-height: 28px;
+     }
+
+     hr {
+      margin: 18px 0;
+      border: 0;
+      border-top: 1px solid #EEE;
+      border-bottom: 1px solid white;
+    }
+  </style>
 </head>
 <body>
-  <h1>500</h1>
+  <h1>
+    <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
+    500
+  </h1>
   <h3>Whoops, something went wrong on our end.</h3>
   <hr/>
   <p>Try refreshing the page, or going back and attempting the action again.</p>
diff --git a/public/502.html b/public/502.html
index 9480a928439e29f269ef76f962fd63f2d4d4a393..67dfd8a27438c6846b7b932f4bbdf50dc7ab3d47 100644
--- a/public/502.html
+++ b/public/502.html
@@ -2,10 +2,50 @@
 <html>
 <head>
   <title>GitLab is not responding (502)</title>
-  <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
+  <style>
+    body {
+      color: #666;
+      text-align: center;
+      font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+      margin: 0;
+      width: 800px;
+      margin: auto;
+      font-size: 14px;
+    }
+
+    h1 {
+      font-size: 56px;
+      line-height: 100px;
+      font-weight: normal;
+      color: #456;
+    }
+
+    h2 {
+      font-size: 24px;
+      color: #666;
+      line-height: 1.5em;
+    }
+
+    h3 {
+      color: #456;
+      font-size: 20px;
+      font-weight: normal;
+      line-height: 28px;
+    }
+
+    hr {
+      margin: 18px 0;
+      border: 0;
+      border-top: 1px solid #EEE;
+      border-bottom: 1px solid white;
+    }
+  </style>
 </head>
 <body>
-  <h1>502</h1>
+  <h1>
+    <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
+    502
+  </h1>
   <h3>Whoops, GitLab is taking too much time to respond.</h3>
   <hr/>
   <p>Try refreshing the page, or going back and attempting the action again.</p>
diff --git a/public/deploy.html b/public/deploy.html
index 3822ed4b64d673a685faae079a0f2f0f58c6594e..48976dacf41f89a8f1f90c99fb5220c68b70b5bb 100644
--- a/public/deploy.html
+++ b/public/deploy.html
@@ -2,12 +2,49 @@
 <html>
   <head>
     <title>Deploy in progress</title>
-    <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
+    <style>
+     body {
+        color: #666;
+        text-align: center;
+        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+        margin: 0;
+        width: 800px;
+        margin: auto;
+        font-size: 14px;
+      }
+
+      h1 {
+        font-size: 56px;
+        line-height: 100px;
+        font-weight: normal;
+        color: #456;
+      }
+
+      h2 {
+        font-size: 24px;
+        color: #666;
+        line-height: 1.5em;
+      }
+
+      h3 {
+        color: #456;
+        font-size: 20px;
+        font-weight: normal;
+        line-height: 28px;
+      }
+
+      hr {
+        margin: 18px 0;
+        border: 0;
+        border-top: 1px solid #EEE;
+        border-bottom: 1px solid white;
+      }
+    </style>
   </head>
 
   <body>
     <h1>
-      <img src="/logo.svg" /><br />
+      <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
       Deploy in progress
     </h1>
     <h3>Please try again in a few minutes.</h3>
diff --git a/public/logo.svg b/public/logo.svg
deleted file mode 100644
index fc4553137f73dfbf2f13a0c0f4ea878742032243..0000000000000000000000000000000000000000
--- a/public/logo.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<svg width="210" height="210" viewBox="0 0 210 210" xmlns="http://www.w3.org/2000/svg">
-  <path d="M105.0614 203.655l38.64-118.921h-77.28l38.64 118.921z" fill="#e24329"/>
-  <path d="M105.0614 203.6548l-38.64-118.921h-54.153l92.793 118.921z" fill="#fc6d26"/>
-  <path d="M12.2685 84.7341l-11.742 36.139c-1.071 3.296.102 6.907 2.906 8.944l101.629 73.838-92.793-118.921z" fill="#fca326"/>
-  <path d="M12.2685 84.7342h54.153l-23.273-71.625c-1.197-3.686-6.411-3.685-7.608 0l-23.272 71.625z" fill="#e24329"/>
-  <path d="M105.0614 203.6548l38.64-118.921h54.153l-92.793 118.921z" fill="#fc6d26"/>
-  <path d="M197.8544 84.7341l11.742 36.139c1.071 3.296-.102 6.907-2.906 8.944l-101.629 73.838 92.793-118.921z" fill="#fca326"/>
-  <path d="M197.8544 84.7342h-54.153l23.273-71.625c1.197-3.686 6.411-3.685 7.608 0l23.272 71.625z" fill="#e24329"/>
-</svg>
diff --git a/public/static.css b/public/static.css
deleted file mode 100644
index 0a2b6060d486005f104e486c1aeb81274917f2c7..0000000000000000000000000000000000000000
--- a/public/static.css
+++ /dev/null
@@ -1,36 +0,0 @@
-body {
-  color: #666;
-  text-align: center;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  margin: 0;
-  width: 800px;
-  margin: auto;
-  font-size: 14px;
-}
-
-h1 {
-  font-size: 56px;
-  line-height: 100px;
-  font-weight: normal;
-  color: #456;
-}
-
-h2 { 
-  font-size: 24px; 
-  color: #666; 
-  line-height: 1.5em;
-}
-
-h3 {
-  color: #456;
-  font-size: 20px;
-  font-weight: normal;
-  line-height: 28px;
-}
-
-hr {
-  margin: 18px 0;
-  border: 0;
-  border-top: 1px solid #EEE;
-  border-bottom: 1px solid white;
-}
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index 8e06d4bdc77693546dc679ddee5c53df184f19af..98ae424ed7c8a0af537e44851496add5be9fbd11 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -17,49 +17,79 @@ describe Projects::BranchesController do
   describe "POST create" do
     render_views
 
-    before do
-      post :create,
-        namespace_id: project.namespace.to_param,
-        project_id: project.to_param,
-        branch_name: branch,
-        ref: ref
-    end
+    context "on creation of a new branch" do
+      before do
+        post :create,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param,
+          branch_name: branch,
+          ref: ref
+      end
 
-    context "valid branch name, valid source" do
-      let(:branch) { "merge_branch" }
-      let(:ref) { "master" }
-      it 'redirects' do
-        expect(subject).
-          to redirect_to("/#{project.path_with_namespace}/tree/merge_branch")
+      context "valid branch name, valid source" do
+        let(:branch) { "merge_branch" }
+        let(:ref) { "master" }
+        it 'redirects' do
+          expect(subject).
+            to redirect_to("/#{project.path_with_namespace}/tree/merge_branch")
+        end
+      end
+
+      context "invalid branch name, valid ref" do
+        let(:branch) { "<script>alert('merge');</script>" }
+        let(:ref) { "master" }
+        it 'redirects' do
+          expect(subject).
+            to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');")
+        end
+      end
+
+      context "valid branch name, invalid ref" do
+        let(:branch) { "merge_branch" }
+        let(:ref) { "<script>alert('ref');</script>" }
+        it { is_expected.to render_template('new') }
+      end
+
+      context "invalid branch name, invalid ref" do
+        let(:branch) { "<script>alert('merge');</script>" }
+        let(:ref) { "<script>alert('ref');</script>" }
+        it { is_expected.to render_template('new') }
+      end
+
+      context "valid branch name with encoded slashes" do
+        let(:branch) { "feature%2Ftest" }
+        let(:ref) { "<script>alert('ref');</script>" }
+        it { is_expected.to render_template('new') }
+        it { project.repository.branch_names.include?('feature/test') }
       end
     end
 
-    context "invalid branch name, valid ref" do
-      let(:branch) { "<script>alert('merge');</script>" }
-      let(:ref) { "master" }
+    describe "created from the new branch button on issues" do
+      let(:branch) { "1-feature-branch" }
+      let!(:issue) { create(:issue, project: project) }
+
+
       it 'redirects' do
+        post :create,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param,
+          branch_name: branch,
+          issue_iid: issue.iid
+
         expect(subject).
-          to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');")
+          to redirect_to("/#{project.path_with_namespace}/tree/1-feature-branch")
       end
-    end
 
-    context "valid branch name, invalid ref" do
-      let(:branch) { "merge_branch" }
-      let(:ref) { "<script>alert('ref');</script>" }
-      it { is_expected.to render_template('new') }
-    end
+      it 'posts a system note' do
+        expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch")
 
-    context "invalid branch name, invalid ref" do
-      let(:branch) { "<script>alert('merge');</script>" }
-      let(:ref) { "<script>alert('ref');</script>" }
-      it { is_expected.to render_template('new') }
-    end
+        post :create,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param,
+          branch_name: branch,
+          issue_iid: issue.iid
+      end
 
-    context "valid branch name with encoded slashes" do
-      let(:branch) { "feature%2Ftest" }
-      let(:ref) { "<script>alert('ref');</script>" }
-      it { is_expected.to render_template('new') }
-      it { project.repository.branch_names.include?('feature/test')}
     end
   end
 
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 76d56bc989d97507a399a8aa60ba96122164f194..2cd81231144c418bcfe9c4357794a9d6c32e6f87 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1,16 +1,16 @@
 require('spec_helper')
 
 describe Projects::IssuesController do
-  let(:project) { create(:project) }
-  let(:user)    { create(:user) }
-  let(:issue) { create(:issue, project: project) }
+  describe "GET #index" do
+    let(:project) { create(:project) }
+    let(:user) { create(:user) }
+    let(:issue) { create(:issue, project: project) }
 
-  before do
-    sign_in(user)
-    project.team << [user, :developer]
-  end
+    before do
+      sign_in(user)
+      project.team << [user, :developer]
+    end
 
-  describe "GET #index" do
     it "returns index" do
       get :index, namespace_id: project.namespace.path, project_id: project.path
 
@@ -38,6 +38,152 @@ describe Projects::IssuesController do
       get :index, namespace_id: project.namespace.path, project_id: project.path
       expect(response.status).to eq(404)
     end
+  end
+
+  describe 'Confidential Issues' do
+    let(:project) { create(:empty_project, :public) }
+    let(:assignee) { create(:assignee) }
+    let(:author) { create(:user) }
+    let(:non_member) { create(:user) }
+    let(:member) { create(:user) }
+    let(:admin) { create(:admin) }
+    let!(:issue) { create(:issue, project: project) }
+    let!(:unescaped_parameter_value) { create(:issue, :confidential, project: project, author: author) }
+    let!(:request_forgery_timing_attack) { create(:issue, :confidential, project: project, assignee: assignee) }
+
+    describe 'GET #index' do
+      it 'should not list confidential issues for guests' do
+        sign_out(:user)
+        get_issues
+
+        expect(assigns(:issues)).to eq [issue]
+      end
+
+      it 'should not list confidential issues for non project members' do
+        sign_in(non_member)
+        get_issues
+
+        expect(assigns(:issues)).to eq [issue]
+      end
+
+      it 'should list confidential issues for author' do
+        sign_in(author)
+        get_issues
+
+        expect(assigns(:issues)).to include unescaped_parameter_value
+        expect(assigns(:issues)).not_to include request_forgery_timing_attack
+      end
+
+      it 'should list confidential issues for assignee' do
+        sign_in(assignee)
+        get_issues
+
+        expect(assigns(:issues)).not_to include unescaped_parameter_value
+        expect(assigns(:issues)).to include request_forgery_timing_attack
+      end
+
+      it 'should list confidential issues for project members' do
+        sign_in(member)
+        project.team << [member, :developer]
+
+        get_issues
+
+        expect(assigns(:issues)).to include unescaped_parameter_value
+        expect(assigns(:issues)).to include request_forgery_timing_attack
+      end
+
+      it 'should list confidential issues for admin' do
+        sign_in(admin)
+        get_issues
+
+        expect(assigns(:issues)).to include unescaped_parameter_value
+        expect(assigns(:issues)).to include request_forgery_timing_attack
+      end
+
+      def get_issues
+        get :index,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param
+      end
+    end
 
+    shared_examples_for 'restricted action' do |http_status|
+      it 'returns 404 for guests' do
+        sign_out :user
+        go(id: unescaped_parameter_value.to_param)
+
+        expect(response).to have_http_status :not_found
+      end
+
+      it 'returns 404 for non project members' do
+        sign_in(non_member)
+        go(id: unescaped_parameter_value.to_param)
+
+        expect(response).to have_http_status :not_found
+      end
+
+      it "returns #{http_status[:success]} for author" do
+        sign_in(author)
+        go(id: unescaped_parameter_value.to_param)
+
+        expect(response).to have_http_status http_status[:success]
+      end
+
+      it "returns #{http_status[:success]} for assignee" do
+        sign_in(assignee)
+        go(id: request_forgery_timing_attack.to_param)
+
+        expect(response).to have_http_status http_status[:success]
+      end
+
+      it "returns #{http_status[:success]} for project members" do
+        sign_in(member)
+        project.team << [member, :developer]
+        go(id: unescaped_parameter_value.to_param)
+
+        expect(response).to have_http_status http_status[:success]
+      end
+
+      it "returns #{http_status[:success]} for admin" do
+        sign_in(admin)
+        go(id: unescaped_parameter_value.to_param)
+
+        expect(response).to have_http_status http_status[:success]
+      end
+    end
+
+    describe 'GET #show' do
+      it_behaves_like 'restricted action', success: 200
+
+      def go(id:)
+        get :show,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param,
+          id: id
+      end
+    end
+
+    describe 'GET #edit' do
+      it_behaves_like 'restricted action', success: 200
+
+      def go(id:)
+        get :edit,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param,
+          id: id
+      end
+    end
+
+    describe 'PUT #update' do
+      it_behaves_like 'restricted action', success: 302
+
+      def go(id:)
+        put :update,
+          namespace_id: project.namespace.to_param,
+          project_id: project.to_param,
+          id: id,
+          issue: { title: 'New title' }
+      end
+    end
   end
 end
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 722095de5905efa1f2937a14862ef391008590c8..e72aa9479b757973db6330557595826e4e17a9c7 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -4,6 +4,10 @@ FactoryGirl.define do
     author
     project
 
+    trait :confidential do
+      confidential true
+    end
+
     trait :closed do
       state :closed
     end
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index a9df5fa1d3a8572cdfc6debdd25d9a112f0bc2da..e281e2f227b6cb0ddcf487d19bf35af5c3907c3f 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -51,6 +51,11 @@ FactoryGirl.define do
     trait :with_diffs do
     end
 
+    trait :without_diffs do
+      source_branch "improve/awesome"
+      target_branch "master"
+    end
+
     trait :conflict do
       source_branch "feature_conflict"
       target_branch "feature"
diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb
index bd85b1d798af4047b0d28c40662fce8c86abbc70..7ae06c278408caae9fd352c6db57df80086a2bd7 100644
--- a/spec/factories/todos.rb
+++ b/spec/factories/todos.rb
@@ -5,14 +5,15 @@
 #  id          :integer          not null, primary key
 #  user_id     :integer          not null
 #  project_id  :integer          not null
-#  target_id   :integer          not null
+#  target_id   :integer
 #  target_type :string           not null
 #  author_id   :integer
-#  note_id     :integer
 #  action      :integer          not null
 #  state       :string           not null
 #  created_at  :datetime
 #  updated_at  :datetime
+#  note_id     :integer
+#  commit_id   :string
 #
 
 FactoryGirl.define do
@@ -30,5 +31,10 @@ FactoryGirl.define do
     trait :mentioned do
       action { Todo::MENTIONED }
     end
+
+    trait :on_commit do
+      commit_id RepoHelpers.sample_commit.id
+      target_type "Commit"
+    end
   end
 end
diff --git a/spec/features/issues/new_branch_button_spec.rb b/spec/features/issues/new_branch_button_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9219b767547782a9c795dbb7da98fc8a5c6a8686
--- /dev/null
+++ b/spec/features/issues/new_branch_button_spec.rb
@@ -0,0 +1,49 @@
+require 'rails_helper'
+
+feature 'Start new branch from an issue', feature: true do
+  let!(:project)   { create(:project) }
+  let!(:issue)     { create(:issue, project: project) }
+  let!(:user)      { create(:user)}
+
+  context "for team members" do
+    before do
+      project.team << [user, :master]
+      login_as(user)
+    end
+
+    it 'shown the new branch button', js: false do
+      visit namespace_project_issue_path(project.namespace, project, issue)
+
+      expect(page).to have_link "New Branch"
+    end
+
+    context "when there is a referenced merge request" do
+      let(:note) do
+        create(:note, :on_issue, :system, project: project,
+                                          note: "mentioned in !#{referenced_mr.iid}")
+      end
+      let(:referenced_mr) do
+        create(:merge_request, :simple, source_project: project, target_project: project,
+                                        description: "Fixes ##{issue.iid}", author: user)
+      end
+
+      before do
+        issue.notes << note
+
+        visit namespace_project_issue_path(project.namespace, project, issue)
+      end
+
+      it "hides the new branch button", js: true do
+        expect(page).not_to have_link "New Branch"
+        expect(page).to have_content /1 Related Merge Request/
+      end
+    end
+  end
+
+  context "for visiters" do
+    it 'no button is shown', js: false do
+      visit namespace_project_issue_path(project.namespace, project, issue)
+      expect(page).not_to have_link "New Branch"
+    end
+  end
+end
diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb
index 1b2fd1bab1086bd22b9e7e6c2d25364477cc37e3..b76e4c74c79656a4b1e11436858c7e791590a6ce 100644
--- a/spec/features/merge_requests/filter_by_milestone_spec.rb
+++ b/spec/features/merge_requests/filter_by_milestone_spec.rb
@@ -30,8 +30,6 @@ feature 'Merge Request filtering by Milestone', feature: true do
 
   def filter_by_milestone(title)
     find(".js-milestone-select").click
-    sleep 0.5
     find(".milestone-filter a", text: title).click
-    sleep 1
   end
 end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 57563add74c2945adf77a4999ab4a9c96fcdb1c0..f88c591d897fa7973295528fc233b2f6e24019d2 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -8,10 +8,12 @@ describe "Internal Project Access", feature: true  do
   let(:master) { create(:user) }
   let(:guest) { create(:user) }
   let(:reporter) { create(:user) }
+  let(:external_team_member) { create(:user, external: true) }
 
   before do
     # full access
     project.team << [master, :master]
+    project.team << [external_team_member, :master]
 
     # readonly
     project.team << [reporter, :reporter]
@@ -34,6 +36,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -45,6 +49,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -56,6 +62,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -67,6 +75,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -78,6 +88,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -89,22 +101,23 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
   describe "GET /:project_path/blob" do
-    before do
-      commit = project.repository.commit
-      path = '.gitignore'
-      @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
-    end
+    let(:commit) { project.repository.commit }
+    subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore')) }
 
-    it { expect(@blob_path).to be_allowed_for master }
-    it { expect(@blob_path).to be_allowed_for reporter }
-    it { expect(@blob_path).to be_allowed_for :admin }
-    it { expect(@blob_path).to be_allowed_for guest }
-    it { expect(@blob_path).to be_allowed_for :user }
-    it { expect(@blob_path).to be_denied_for :visitor }
+    it { is_expected.to be_allowed_for master }
+    it { is_expected.to be_allowed_for reporter }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for guest }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
+    it { is_expected.to be_denied_for :visitor }
   end
 
   describe "GET /:project_path/edit" do
@@ -115,6 +128,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -126,6 +141,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -137,6 +154,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -149,6 +168,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -160,6 +181,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -171,6 +194,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -182,6 +207,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -193,6 +220,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -209,6 +238,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -225,6 +256,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -236,6 +269,8 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 end
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index a1e111c6cab84eefefac95b8d60fa0fee52b3033..19f287ce7a47d7e0c5f3a2378654dd0c1b0fec46 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -8,10 +8,12 @@ describe "Private Project Access", feature: true  do
   let(:master)   { create(:user) }
   let(:guest)    { create(:user) }
   let(:reporter) { create(:user) }
+  let(:external_team_member) { create(:user, external: true) }
 
   before do
     # full access
     project.team << [master, :master]
+    project.team << [external_team_member, :master]
 
     # readonly
     project.team << [reporter, :reporter]
@@ -34,6 +36,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -45,6 +49,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -56,6 +62,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -67,6 +75,7 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -78,6 +87,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -89,22 +100,23 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
   describe "GET /:project_path/blob" do
-    before do
-      commit = project.repository.commit
-      path = '.gitignore'
-      @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
-    end
+    let(:commit) { project.repository.commit }
+    subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore'))}
 
-    it { expect(@blob_path).to be_allowed_for master }
-    it { expect(@blob_path).to be_allowed_for reporter }
-    it { expect(@blob_path).to be_allowed_for :admin }
-    it { expect(@blob_path).to be_denied_for guest }
-    it { expect(@blob_path).to be_denied_for :user }
-    it { expect(@blob_path).to be_denied_for :visitor }
+    it { is_expected.to be_allowed_for master }
+    it { is_expected.to be_allowed_for reporter }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_denied_for guest }
+    it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
+    it { is_expected.to be_denied_for :visitor }
   end
 
   describe "GET /:project_path/edit" do
@@ -115,6 +127,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -126,6 +140,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -137,6 +153,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -149,6 +167,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -160,6 +180,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -171,6 +193,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -187,6 +211,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -203,6 +229,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -214,6 +242,8 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_allowed_for external_team_member }
     it { is_expected.to be_denied_for :visitor }
   end
 end
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index b98476f854e7d20c6ee65701a01676df2a47cf70..4e13507636751484ff360fcc5733c00217d1351c 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -38,6 +38,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -49,6 +50,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -60,6 +62,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -71,6 +74,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -82,6 +86,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -93,6 +98,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -107,6 +113,7 @@ describe "Public Project Access", feature: true  do
       it { is_expected.to be_allowed_for :admin }
       it { is_expected.to be_allowed_for guest }
       it { is_expected.to be_allowed_for :user }
+      it { is_expected.to be_allowed_for :external }
       it { is_expected.to be_allowed_for :visitor }
     end
 
@@ -118,6 +125,7 @@ describe "Public Project Access", feature: true  do
       it { is_expected.to be_allowed_for :admin }
       it { is_expected.to be_denied_for guest }
       it { is_expected.to be_denied_for :user }
+      it { is_expected.to be_denied_for :external }
       it { is_expected.to be_denied_for :visitor }
     end
   end
@@ -135,6 +143,7 @@ describe "Public Project Access", feature: true  do
       it { is_expected.to be_allowed_for :admin }
       it { is_expected.to be_allowed_for guest }
       it { is_expected.to be_allowed_for :user }
+      it { is_expected.to be_allowed_for :external }
       it { is_expected.to be_allowed_for :visitor }
     end
 
@@ -146,23 +155,22 @@ describe "Public Project Access", feature: true  do
       it { is_expected.to be_allowed_for :admin }
       it { is_expected.to be_denied_for guest }
       it { is_expected.to be_denied_for :user }
+      it { is_expected.to be_denied_for :external }
       it { is_expected.to be_denied_for :visitor }
     end
   end
 
   describe "GET /:project_path/blob" do
-    before do
-      commit = project.repository.commit
-      path = '.gitignore'
-      @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
-    end
+    let(:commit) { project.repository.commit }
+
+    subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore')) }
 
-    it { expect(@blob_path).to be_allowed_for master }
-    it { expect(@blob_path).to be_allowed_for reporter }
-    it { expect(@blob_path).to be_allowed_for :admin }
-    it { expect(@blob_path).to be_allowed_for guest }
-    it { expect(@blob_path).to be_allowed_for :user }
-    it { expect(@blob_path).to be_allowed_for :visitor }
+    it { is_expected.to be_allowed_for master }
+    it { is_expected.to be_allowed_for reporter }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for guest }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :visitor }
   end
 
   describe "GET /:project_path/edit" do
@@ -173,6 +181,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -184,6 +193,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -195,6 +205,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -207,6 +218,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -218,6 +230,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -229,6 +242,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -240,6 +254,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -251,6 +266,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 
@@ -267,6 +283,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -283,6 +300,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_allowed_for guest }
     it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
     it { is_expected.to be_allowed_for :visitor }
   end
 
@@ -294,6 +312,7 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_allowed_for :admin }
     it { is_expected.to be_denied_for guest }
     it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
 end
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index e9bb388e361b44743f791ad087411799049df26b..9acf6304bcb19fc9b79792f7141f4850f00d0755 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -44,8 +44,78 @@ describe Banzai::Filter::RedactorFilter, lib: true do
     end
   end
 
-  context "for user references" do
+  context 'with data-issue' do
+    context 'for confidential issues' do
+      it 'removes references for non project members' do
+        non_member = create(:user)
+        project = create(:empty_project, :public)
+        issue = create(:issue, :confidential, project: project)
+
+        link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+        doc = filter(link, current_user: non_member)
+
+        expect(doc.css('a').length).to eq 0
+      end
+
+      it 'allows references for author' do
+        author = create(:user)
+        project = create(:empty_project, :public)
+        issue = create(:issue, :confidential, project: project, author: author)
+
+        link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+        doc = filter(link, current_user: author)
+
+        expect(doc.css('a').length).to eq 1
+      end
+
+      it 'allows references for assignee' do
+        assignee = create(:user)
+        project = create(:empty_project, :public)
+        issue = create(:issue, :confidential, project: project, assignee: assignee)
+
+        link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+        doc = filter(link, current_user: assignee)
 
+        expect(doc.css('a').length).to eq 1
+      end
+
+      it 'allows references for project members' do
+        member = create(:user)
+        project = create(:empty_project, :public)
+        project.team << [member, :developer]
+        issue = create(:issue, :confidential, project: project)
+
+        link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+        doc = filter(link, current_user: member)
+
+        expect(doc.css('a').length).to eq 1
+      end
+
+      it 'allows references for admin' do
+        admin = create(:admin)
+        project = create(:empty_project, :public)
+        issue = create(:issue, :confidential, project: project)
+
+        link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+        doc = filter(link, current_user: admin)
+
+        expect(doc.css('a').length).to eq 1
+      end
+    end
+
+    it 'allows references for non confidential issues' do
+      user = create(:user)
+      project = create(:empty_project, :public)
+      issue = create(:issue, project: project)
+
+      link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+      doc = filter(link, current_user: user)
+
+      expect(doc.css('a').length).to eq 1
+    end
+  end
+
+  context "for user references" do
     context 'with data-group' do
       it 'removes unpermitted Group references' do
         user = create(:user)
diff --git a/spec/lib/ci/status_spec.rb b/spec/lib/ci/status_spec.rb
index 1539720bb8dd300de1316c4bd6d0d79f00e8cc83..47f3df6e3ce008ec265c683b9544fd097b453a6d 100644
--- a/spec/lib/ci/status_spec.rb
+++ b/spec/lib/ci/status_spec.rb
@@ -48,6 +48,29 @@ describe Ci::Status do
         it { is_expected.to eq 'success' }
       end
 
+      context 'success and canceled' do
+        let(:statuses) do
+          [create(type, status: :success), create(type, status: :canceled)]
+        end
+        it { is_expected.to eq 'failed' }
+      end
+
+      context 'all canceled' do
+        let(:statuses) do
+          [create(type, status: :canceled), create(type, status: :canceled)]
+        end
+        it { is_expected.to eq 'canceled' }
+      end
+
+      context 'success and canceled but allowed to fail' do
+        let(:statuses) do
+          [create(type, status: :success),
+           create(type, status: :canceled, allow_failure: true)]
+        end
+
+        it { is_expected.to eq 'success' }
+      end
+
       context 'one finished and second running but allowed to fail' do
         let(:statuses) do
           [create(type, status: :success),
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 04cf11fc6f17525039eaa017a8bbf071f7f99d91..844fd79c991af8b69f1be01d296f51c4e1c302ca 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -11,6 +11,7 @@ describe Gitlab::ClosingIssueExtractor, lib: true do
   subject { described_class.new(project, project.creator) }
 
   before do
+    project.team  << [project.creator, :developer]
     project2.team << [project.creator, :master]
   end
 
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 0d9694f2c1304d44023ac55ee33bc3e11d79282e..a0cbef6e6a441d830c474d37cc0c00712616f39d 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -18,4 +18,18 @@ describe Gitlab::Diff::File, lib: true do
   describe :mode_changed? do
     it { expect(diff_file.mode_changed?).to be_falsey }
   end
+
+  describe '#too_large?' do
+    it 'returns true for a file that is too large' do
+      expect(diff).to receive(:too_large?).and_return(true)
+
+      expect(diff_file.too_large?).to eq(true)
+    end
+
+    it 'returns false for a file that is small enough' do
+      expect(diff).to receive(:too_large?).and_return(false)
+
+      expect(diff_file.too_large?).to eq(false)
+    end
+  end
 end
diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb
index f576c39284e244bc347a7a4061a27e7d2b865ff9..cdff063a9ed548d5dfa75fa9124a27b3eaeaebd1 100644
--- a/spec/lib/gitlab/diff/parser_spec.rb
+++ b/spec/lib/gitlab/diff/parser_spec.rb
@@ -90,4 +90,9 @@ eos
       end
     end
   end
+
+  context 'when lines is empty' do
+    it { expect(parser.parse([])).to eq([]) }
+    it { expect(parser.parse(nil)).to eq([]) }
+  end
 end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 09adbc07dcbbdb1c7f5bc58a5ca9526d3430d472..db0ff95b4f5c6c83be75122b2ad560f05dea14a4 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -1,11 +1,12 @@
 require 'spec_helper'
 
 describe Gitlab::ProjectSearchResults, lib: true do
+  let(:user) { create(:user) }
   let(:project) { create(:project) }
   let(:query) { 'hello world' }
 
   describe 'initialize with empty ref' do
-    let(:results) { Gitlab::ProjectSearchResults.new(project, query, '') }
+    let(:results) { Gitlab::ProjectSearchResults.new(user, project, query, '') }
 
     it { expect(results.project).to eq(project) }
     it { expect(results.repository_ref).to be_nil }
@@ -14,10 +15,74 @@ describe Gitlab::ProjectSearchResults, lib: true do
 
   describe 'initialize with ref' do
     let(:ref) { 'refs/heads/test' }
-    let(:results) { Gitlab::ProjectSearchResults.new(project, query, ref) }
+    let(:results) { Gitlab::ProjectSearchResults.new(user, project, query, ref) }
 
     it { expect(results.project).to eq(project) }
     it { expect(results.repository_ref).to eq(ref) }
     it { expect(results.query).to eq('hello world') }
   end
+
+  describe 'confidential issues' do
+    let(:query) { 'issue' }
+    let(:author) { create(:user) }
+    let(:assignee) { create(:user) }
+    let(:non_member) { create(:user) }
+    let(:member) { create(:user) }
+    let(:admin) { create(:admin) }
+    let!(:issue) { create(:issue, project: project, title: 'Issue 1') }
+    let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
+    let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignee: assignee) }
+
+    it 'should not list project confidential issues for non project members' do
+      results = described_class.new(non_member, project, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).not_to include security_issue_1
+      expect(issues).not_to include security_issue_2
+      expect(results.issues_count).to eq 1
+    end
+
+    it 'should list project confidential issues for author' do
+      results = described_class.new(author, project, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).to include security_issue_1
+      expect(issues).not_to include security_issue_2
+      expect(results.issues_count).to eq 2
+    end
+
+    it 'should list project confidential issues for assignee' do
+      results = described_class.new(assignee, project.id, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).not_to include security_issue_1
+      expect(issues).to include security_issue_2
+      expect(results.issues_count).to eq 2
+    end
+
+    it 'should list project confidential issues for project members' do
+      project.team << [member, :developer]
+
+      results = described_class.new(member, project, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).to include security_issue_1
+      expect(issues).to include security_issue_2
+      expect(results.issues_count).to eq 3
+    end
+
+    it 'should list all project issues for admin' do
+      results = described_class.new(admin, project, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).to include security_issue_1
+      expect(issues).to include security_issue_2
+      expect(results.issues_count).to eq 3
+    end
+  end
 end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 7d963795e17b48265d15c55ac92d4b4598716409..65af37e24f14e6139511c8b401357a0d59db7aee 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
 
 describe Gitlab::ReferenceExtractor, lib: true do
   let(:project) { create(:project) }
+
   subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
 
   it 'accesses valid user objects' do
@@ -41,6 +42,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
   end
 
   it 'accesses valid issue objects' do
+    project.team << [project.creator, :developer]
     @i0 = create(:issue, project: project)
     @i1 = create(:issue, project: project)
 
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index bb18f41785824b1c5e37e9d1ae38f214db8ed333..f4afe597e8d8c415c40b5f3bc48c2e00ac3be71f 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -1,6 +1,7 @@
 require 'spec_helper'
 
 describe Gitlab::SearchResults do
+  let(:user) { create(:user) }
   let!(:project) { create(:project, name: 'foo') }
   let!(:issue) { create(:issue, project: project, title: 'foo') }
 
@@ -9,7 +10,7 @@ describe Gitlab::SearchResults do
   end
 
   let!(:milestone) { create(:milestone, project: project, title: 'foo') }
-  let(:results) { described_class.new(Project.all, 'foo') }
+  let(:results) { described_class.new(user, Project.all, 'foo') }
 
   describe '#total_count' do
     it 'returns the total amount of search hits' do
@@ -52,4 +53,92 @@ describe Gitlab::SearchResults do
       expect(results.empty?).to eq(false)
     end
   end
+
+  describe 'confidential issues' do
+    let(:project_1) { create(:empty_project) }
+    let(:project_2) { create(:empty_project) }
+    let(:project_3) { create(:empty_project) }
+    let(:project_4) { create(:empty_project) }
+    let(:query) { 'issue' }
+    let(:limit_projects) { Project.where(id: [project_1.id, project_2.id, project_3.id]) }
+    let(:author) { create(:user) }
+    let(:assignee) { create(:user) }
+    let(:non_member) { create(:user) }
+    let(:member) { create(:user) }
+    let(:admin) { create(:admin) }
+    let!(:issue) { create(:issue, project: project_1, title: 'Issue 1') }
+    let!(:security_issue_1) { create(:issue, :confidential, project: project_1, title: 'Security issue 1', author: author) }
+    let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project_1, assignee: assignee) }
+    let!(:security_issue_3) { create(:issue, :confidential, project: project_2, title: 'Security issue 3', author: author) }
+    let!(:security_issue_4) { create(:issue, :confidential, project: project_3, title: 'Security issue 4', assignee: assignee) }
+    let!(:security_issue_5) { create(:issue, :confidential, project: project_4, title: 'Security issue 5') }
+
+    it 'should not list confidential issues for non project members' do
+      results = described_class.new(non_member, limit_projects, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).not_to include security_issue_1
+      expect(issues).not_to include security_issue_2
+      expect(issues).not_to include security_issue_3
+      expect(issues).not_to include security_issue_4
+      expect(issues).not_to include security_issue_5
+      expect(results.issues_count).to eq 1
+    end
+
+    it 'should list confidential issues for author' do
+      results = described_class.new(author, limit_projects, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).to include security_issue_1
+      expect(issues).not_to include security_issue_2
+      expect(issues).to include security_issue_3
+      expect(issues).not_to include security_issue_4
+      expect(issues).not_to include security_issue_5
+      expect(results.issues_count).to eq 3
+    end
+
+    it 'should list confidential issues for assignee' do
+      results = described_class.new(assignee, limit_projects, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).not_to include security_issue_1
+      expect(issues).to include security_issue_2
+      expect(issues).not_to include security_issue_3
+      expect(issues).to include security_issue_4
+      expect(issues).not_to include security_issue_5
+      expect(results.issues_count).to eq 3
+    end
+
+    it 'should list confidential issues for project members' do
+      project_1.team << [member, :developer]
+      project_2.team << [member, :developer]
+
+      results = described_class.new(member, limit_projects, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).to include security_issue_1
+      expect(issues).to include security_issue_2
+      expect(issues).to include security_issue_3
+      expect(issues).not_to include security_issue_4
+      expect(issues).not_to include security_issue_5
+      expect(results.issues_count).to eq 4
+    end
+
+    it 'should list all issues for admin' do
+      results = described_class.new(admin, limit_projects, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).to include security_issue_1
+      expect(issues).to include security_issue_2
+      expect(issues).to include security_issue_3
+      expect(issues).to include security_issue_4
+      expect(issues).not_to include security_issue_5
+      expect(results.issues_count).to eq 5
+    end
+  end
 end
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 4799bbaa57c89622e1d758dbdf9bcb77dbfb381f..ac12ab6c7579790e243052aee3f77449b2f75eba 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -13,7 +13,8 @@
 require 'rails_helper'
 
 RSpec.describe AbuseReport, type: :model do
-  subject { create(:abuse_report) }
+  subject     { create(:abuse_report) }
+  let(:user)  { create(:user) }
 
   it { expect(subject).to be_valid }
 
@@ -31,17 +32,14 @@ RSpec.describe AbuseReport, type: :model do
 
   describe '#remove_user' do
     it 'blocks the user' do
-      report = build(:abuse_report)
-
-      allow(report.user).to receive(:destroy)
-
-      expect { report.remove_user }.to change { report.user.blocked? }.to(true)
+      expect { subject.remove_user(deleted_by: user) }.to change { subject.user.blocked? }.to(true)
     end
 
-    it 'removes the user' do
-      report = build(:abuse_report)
+    it 'lets a worker delete the user' do
+      expect(DeleteUserWorker).to receive(:perform_async).with(user.id, subject.user.id,
+                                                              delete_solo_owned_groups: true)
 
-      expect { report.remove_user }.to change { User.count }.by(-1)
+      subject.remove_user(deleted_by: user)
     end
   end
 
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 253902512c337b178a752f65b5b108050a6c638a..0e9111c8029332a962f3a7cc9d2815c8cdeb569c 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -86,10 +86,21 @@ eos
     let(:issue) { create :issue, project: project }
     let(:other_project) { create :project, :public }
     let(:other_issue) { create :issue, project: other_project }
+    let(:commiter) { create :user }
+
+    before do
+      project.team << [commiter, :developer]
+      other_project.team << [commiter, :developer]
+    end
 
     it 'detects issues that this commit is marked as closing' do
       ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
-      allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid} and #{ext_ref}")
+
+      allow(commit).to receive_messages(
+        safe_message: "Fixes ##{issue.iid} and #{ext_ref}",
+        committer_email: commiter.email
+      )
+
       expect(commit.closes_issues).to include(issue)
       expect(commit.closes_issues).to include(other_issue)
     end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 20f0c561e44b16e3f9970f387ecc0a8d57e14fd8..cb33edde820d225b73a6fa529ef77aafa714a95c 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -48,7 +48,8 @@ describe Issue, "Mentionable" do
 
   describe '#create_new_cross_references!' do
     let(:project) { create(:project) }
-    let(:issues)  { create_list(:issue, 2, project: project) }
+    let(:author)  { create(:author) }
+    let(:issues)  { create_list(:issue, 2, project: project, author: author) }
 
     context 'before changes are persisted' do
       it 'ignores pre-existing references' do
@@ -91,7 +92,7 @@ describe Issue, "Mentionable" do
     end
 
     def create_issue(description:)
-      create(:issue, project: project, description: description)
+      create(:issue, project: project, description: description, author: author)
     end
   end
 end
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..47c3be673c56815d3828be81793f5c2fe9f87303
--- /dev/null
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -0,0 +1,104 @@
+require 'spec_helper'
+
+describe Milestone, 'Milestoneish' do
+  let(:author) { create(:user) }
+  let(:assignee) { create(:user) }
+  let(:non_member) { create(:user) }
+  let(:member) { create(:user) }
+  let(:admin) { create(:admin) }
+  let(:project) { create(:project, :public) }
+  let(:milestone) { create(:milestone, project: project) }
+  let!(:issue) { create(:issue, project: project, milestone: milestone) }
+  let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) }
+  let!(:security_issue_2) { create(:issue, :confidential, project: project, assignee: assignee, milestone: milestone) }
+  let!(:closed_issue_1) { create(:issue, :closed, project: project, milestone: milestone) }
+  let!(:closed_issue_2) { create(:issue, :closed, project: project, milestone: milestone) }
+  let!(:closed_security_issue_1) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
+  let!(:closed_security_issue_2) { create(:issue, :confidential, :closed, project: project, assignee: assignee, milestone: milestone) }
+  let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
+  let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignee: assignee, milestone: milestone) }
+  let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
+
+  before do
+    project.team << [member, :developer]
+  end
+
+  describe '#closed_items_count' do
+    it 'should not count confidential issues for non project members' do
+      expect(milestone.closed_items_count(non_member)).to eq 2
+    end
+
+    it 'should count confidential issues for author' do
+      expect(milestone.closed_items_count(author)).to eq 4
+    end
+
+    it 'should count confidential issues for assignee' do
+      expect(milestone.closed_items_count(assignee)).to eq 4
+    end
+
+    it 'should count confidential issues for project members' do
+      expect(milestone.closed_items_count(member)).to eq 6
+    end
+
+    it 'should count all issues for admin' do
+      expect(milestone.closed_items_count(admin)).to eq 6
+    end
+  end
+
+  describe '#total_items_count' do
+    it 'should not count confidential issues for non project members' do
+      expect(milestone.total_items_count(non_member)).to eq 4
+    end
+
+    it 'should count confidential issues for author' do
+      expect(milestone.total_items_count(author)).to eq 7
+    end
+
+    it 'should count confidential issues for assignee' do
+      expect(milestone.total_items_count(assignee)).to eq 7
+    end
+
+    it 'should count confidential issues for project members' do
+      expect(milestone.total_items_count(member)).to eq 10
+    end
+
+    it 'should count all issues for admin' do
+      expect(milestone.total_items_count(admin)).to eq 10
+    end
+  end
+
+  describe '#complete?' do
+    it 'returns false when has items opened' do
+      expect(milestone.complete?(non_member)).to eq false
+    end
+
+    it 'returns true when all items are closed' do
+      issue.close
+      merge_request.close
+
+      expect(milestone.complete?(non_member)).to eq true
+    end
+  end
+
+  describe '#percent_complete' do
+    it 'should not count confidential issues for non project members' do
+      expect(milestone.percent_complete(non_member)).to eq 50
+    end
+
+    it 'should count confidential issues for author' do
+      expect(milestone.percent_complete(author)).to eq 57
+    end
+
+    it 'should count confidential issues for assignee' do
+      expect(milestone.percent_complete(assignee)).to eq 57
+    end
+
+    it 'should count confidential issues for project members' do
+      expect(milestone.percent_complete(member)).to eq 60
+    end
+
+    it 'should count confidential issues for admin' do
+      expect(milestone.percent_complete(admin)).to eq 60
+    end
+  end
+end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index ec2a923f91bb4a4c4af968f034afda442e865316..5fe442467385f9f75f0ab24dd669e92ad429ff18 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -65,6 +65,42 @@ describe Event, models: true do
     it { expect(@event.author).to eq(@user) }
   end
 
+  describe '#proper?' do
+    context 'issue event' do
+      let(:project) { create(:empty_project, :public) }
+      let(:non_member) { create(:user) }
+      let(:member)  { create(:user) }
+      let(:author) { create(:author) }
+      let(:assignee) { create(:user) }
+      let(:admin) { create(:admin) }
+      let(:event) { Event.new(project: project, action: Event::CREATED, target: issue, author_id: author.id) }
+
+      before do
+        project.team << [member, :developer]
+      end
+
+      context 'for non confidential issues' do
+        let(:issue) { create(:issue, project: project, author: author, assignee: assignee) }
+
+        it { expect(event.proper?(non_member)).to eq true }
+        it { expect(event.proper?(author)).to eq true }
+        it { expect(event.proper?(assignee)).to eq true }
+        it { expect(event.proper?(member)).to eq true }
+        it { expect(event.proper?(admin)).to eq true }
+      end
+
+      context 'for confidential issues' do
+        let(:issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) }
+
+        it { expect(event.proper?(non_member)).to eq false }
+        it { expect(event.proper?(author)).to eq true }
+        it { expect(event.proper?(assignee)).to eq true }
+        it { expect(event.proper?(member)).to eq true }
+        it { expect(event.proper?(admin)).to eq true }
+      end
+    end
+  end
+
   describe '.limit_recent' do
     let!(:event1) { create(:closed_issue_event) }
     let!(:event2) { create(:closed_issue_event) }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 7f44ca2f7dbe0eeb31a8729dd2edbeb985b39f5b..2ccdec1eeff6008309fb71d91e2bfddf0b32cde6 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -130,6 +130,15 @@ describe Issue, models: true do
     end
   end
 
+  describe '#related_branches' do
+    it "should " do
+      allow(subject.project.repository).to receive(:branch_names).
+                                    and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name])
+
+      expect(subject.related_branches).to eq [subject.to_branch_name]
+    end
+  end
+
   it_behaves_like 'an editable mentionable' do
     subject { create(:issue) }
 
@@ -140,4 +149,12 @@ describe Issue, models: true do
   it_behaves_like 'a Taskable' do
     let(:subject) { create :issue }
   end
+
+  describe "#to_branch_name" do
+    let(:issue) { build(:issue, title: 'a' * 30) }
+
+    it "starts with the issue iid" do
+      expect(issue.to_branch_name).to match /\A#{issue.iid}-a+\z/
+    end
+  end
 end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 8bf68013fd2668519203cf29839db612cec822dc..654c71b6825d365d07f6bda4a08073a2890d3784 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -86,6 +86,31 @@ describe MergeRequest, models: true do
     end
   end
 
+  describe '#source_sha' do
+    let(:last_branch_commit) { subject.source_project.repository.commit(subject.source_branch) }
+
+    context 'with diffs' do
+      subject { create(:merge_request, :with_diffs) }
+      it 'returns the sha of the source branch last commit' do
+        expect(subject.source_sha).to eq(last_branch_commit.sha)
+      end
+    end
+
+    context 'without diffs' do
+      subject { create(:merge_request, :without_diffs) }
+      it 'returns the sha of the source branch last commit' do
+        expect(subject.source_sha).to eq(last_branch_commit.sha)
+      end
+    end
+
+    context 'when the merge request is being created' do
+      subject { build(:merge_request, source_branch: nil, compare_commits: []) }
+      it 'returns nil' do
+        expect(subject.source_sha).to be_nil
+      end
+    end
+  end
+
   describe '#to_reference' do
     it 'returns a String reference to the object' do
       expect(subject.to_reference).to eq "!#{subject.iid}"
@@ -150,6 +175,7 @@ describe MergeRequest, models: true do
     let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") }
 
     before do
+      subject.project.team << [subject.author, :developer]
       allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
     end
 
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index de1757bf67a5f36f98bd9c51553fa0d170978494..72a4ea702281ae5d8dd3b8fbe2c6e86768e1821b 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -32,6 +32,7 @@ describe Milestone, models: true do
 
   let(:milestone) { create(:milestone) }
   let(:issue) { create(:issue) }
+  let(:user) { create(:user) }
 
   describe "unique milestone title per project" do
     it "shouldn't accept the same title in a project twice" do
@@ -50,18 +51,17 @@ describe Milestone, models: true do
   describe "#percent_complete" do
     it "should not count open issues" do
       milestone.issues << issue
-      expect(milestone.percent_complete).to eq(0)
+      expect(milestone.percent_complete(user)).to eq(0)
     end
 
     it "should count closed issues" do
       issue.close
       milestone.issues << issue
-      expect(milestone.percent_complete).to eq(100)
+      expect(milestone.percent_complete(user)).to eq(100)
     end
 
     it "should recover from dividing by zero" do
-      expect(milestone.issues).to receive(:size).and_return(0)
-      expect(milestone.percent_complete).to eq(0)
+      expect(milestone.percent_complete(user)).to eq(0)
     end
   end
 
@@ -103,7 +103,7 @@ describe Milestone, models: true do
       )
     end
 
-    it { expect(milestone.percent_complete).to eq(75) }
+    it { expect(milestone.percent_complete(user)).to eq(75) }
   end
 
   describe :items_count do
@@ -113,23 +113,23 @@ describe Milestone, models: true do
       milestone.merge_requests << create(:merge_request)
     end
 
-    it { expect(milestone.closed_items_count).to eq(1) }
-    it { expect(milestone.total_items_count).to eq(3) }
-    it { expect(milestone.is_empty?).to be_falsey }
+    it { expect(milestone.closed_items_count(user)).to eq(1) }
+    it { expect(milestone.total_items_count(user)).to eq(3) }
+    it { expect(milestone.is_empty?(user)).to be_falsey }
   end
 
   describe :can_be_closed? do
     it { expect(milestone.can_be_closed?).to be_truthy }
   end
 
-  describe :is_empty? do
+  describe :total_items_count do
     before do
       create :closed_issue, milestone: milestone
       create :merge_request, milestone: milestone
     end
 
     it 'Should return total count of issues and merge requests assigned to milestone' do
-      expect(milestone.total_items_count).to eq 2
+      expect(milestone.total_items_count(user)).to eq 2
     end
   end
 
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 34866be3395536e1d4a84dc8cc8bef9e9dd8cd59..a57229a4fdf9c09d5c4586c67b9cc687fd7e36f8 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -101,13 +101,29 @@ describe Repository, models: true do
     end
 
     describe 'parsing result' do
-      subject { repository.parse_search_result(results.first) }
+      subject { repository.parse_search_result(search_result) }
+      let(:search_result) { results.first }
 
       it { is_expected.to be_an OpenStruct }
       it { expect(subject.filename).to eq('CHANGELOG') }
+      it { expect(subject.basename).to eq('CHANGELOG') }
       it { expect(subject.ref).to eq('master') }
       it { expect(subject.startline).to eq(186) }
       it { expect(subject.data.lines[2]).to eq("  - Feature: Replace teams with group membership\n") }
+
+      context "when filename has extension" do
+        let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
+
+        it { expect(subject.filename).to eq('CONTRIBUTE.md') }
+        it { expect(subject.basename).to eq('CONTRIBUTE') }
+      end
+
+      context "when file under directory" do
+        let(:search_result) { "master:a/b/c.md:5:a b c\n" }
+
+        it { expect(subject.filename).to eq('a/b/c.md') }
+        it { expect(subject.basename).to eq('a/b/c') }
+      end
     end
 
   end
@@ -581,9 +597,9 @@ describe Repository, models: true do
 
   describe '#after_push_commit' do
     it 'flushes the cache' do
-      expect(repository).to receive(:expire_cache).with('master')
+      expect(repository).to receive(:expire_cache).with('master', '123')
 
-      repository.after_push_commit('master')
+      repository.after_push_commit('master', '123')
     end
   end
 
@@ -687,4 +703,111 @@ describe Repository, models: true do
       repository.rm_tag('8.5')
     end
   end
+
+  describe '#avatar' do
+    it 'returns the first avatar file found in the repository' do
+      expect(repository).to receive(:blob_at_branch).
+        with('master', 'logo.png').
+        and_return(true)
+
+      expect(repository.avatar).to eq('logo.png')
+    end
+
+    it 'caches the output' do
+      allow(repository).to receive(:blob_at_branch).
+        with('master', 'logo.png').
+        and_return(true)
+
+      expect(repository.avatar).to eq('logo.png')
+
+      expect(repository).to_not receive(:blob_at_branch)
+      expect(repository.avatar).to eq('logo.png')
+    end
+  end
+
+  describe '#expire_avatar_cache' do
+    let(:cache) { repository.send(:cache) }
+
+    before do
+      allow(repository).to receive(:cache).and_return(cache)
+    end
+
+    context 'without a branch or revision' do
+      it 'flushes the cache' do
+        expect(cache).to receive(:expire).with(:avatar)
+
+        repository.expire_avatar_cache
+      end
+    end
+
+    context 'with a branch' do
+      it 'does not flush the cache if the branch is not the default branch' do
+        expect(cache).not_to receive(:expire)
+
+        repository.expire_avatar_cache('cats')
+      end
+
+      it 'flushes the cache if the branch equals the default branch' do
+        expect(cache).to receive(:expire).with(:avatar)
+
+        repository.expire_avatar_cache(repository.root_ref)
+      end
+    end
+
+    context 'with a branch and revision' do
+      let(:commit) { double(:commit) }
+
+      before do
+        allow(repository).to receive(:commit).and_return(commit)
+      end
+
+      it 'does not flush the cache if the commit does not change any logos' do
+        diff = double(:diff, new_path: 'test.txt')
+
+        expect(commit).to receive(:diffs).and_return([diff])
+        expect(cache).not_to receive(:expire)
+
+        repository.expire_avatar_cache(repository.root_ref, '123')
+      end
+
+      it 'flushes the cache if the commit changes any of the logos' do
+        diff = double(:diff, new_path: Repository::AVATAR_FILES[0])
+
+        expect(commit).to receive(:diffs).and_return([diff])
+        expect(cache).to receive(:expire).with(:avatar)
+
+        repository.expire_avatar_cache(repository.root_ref, '123')
+      end
+    end
+  end
+
+  describe '#build_cache' do
+    let(:cache) { repository.send(:cache) }
+
+    it 'builds the caches if they do not already exist' do
+      expect(cache).to receive(:exist?).
+        exactly(repository.cache_keys.length).
+        times.
+        and_return(false)
+
+      repository.cache_keys.each do |key|
+        expect(repository).to receive(key)
+      end
+
+      repository.build_cache
+    end
+
+    it 'does not build any caches that already exist' do
+      expect(cache).to receive(:exist?).
+        exactly(repository.cache_keys.length).
+        times.
+        and_return(true)
+
+      repository.cache_keys.each do |key|
+        expect(repository).to_not receive(key)
+      end
+
+      repository.build_cache
+    end
+  end
 end
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index fe9ea7e7d1ec4b2d9ae4366a2eb0acab8291329f..d9b86b9368fd0f704180edf5b346790e7fa23fda 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -5,19 +5,24 @@
 #  id          :integer          not null, primary key
 #  user_id     :integer          not null
 #  project_id  :integer          not null
-#  target_id   :integer          not null
+#  target_id   :integer
 #  target_type :string           not null
 #  author_id   :integer
-#  note_id     :integer
 #  action      :integer          not null
 #  state       :string           not null
 #  created_at  :datetime
 #  updated_at  :datetime
+#  note_id     :integer
+#  commit_id   :string
 #
 
 require 'spec_helper'
 
 describe Todo, models: true do
+  let(:project) { create(:project) }
+  let(:commit) { project.commit }
+  let(:issue) { create(:issue) }
+
   describe 'relationships' do
     it { is_expected.to belong_to(:author).class_name("User") }
     it { is_expected.to belong_to(:note) }
@@ -33,8 +38,22 @@ describe Todo, models: true do
 
   describe 'validations' do
     it { is_expected.to validate_presence_of(:action) }
-    it { is_expected.to validate_presence_of(:target) }
+    it { is_expected.to validate_presence_of(:target_type) }
     it { is_expected.to validate_presence_of(:user) }
+
+    context 'for commits' do
+      subject { described_class.new(target_type: 'Commit') }
+
+      it { is_expected.to validate_presence_of(:commit_id) }
+      it { is_expected.not_to validate_presence_of(:target_id) }
+    end
+
+    context 'for issuables' do
+      subject { described_class.new(target: issue) }
+
+      it { is_expected.to validate_presence_of(:target_id) }
+      it { is_expected.not_to validate_presence_of(:commit_id) }
+    end
   end
 
   describe '#body' do
@@ -55,15 +74,69 @@ describe Todo, models: true do
     end
   end
 
-  describe '#done!' do
+  describe '#done' do
     it 'changes state to done' do
       todo = create(:todo, state: :pending)
-      expect { todo.done! }.to change(todo, :state).from('pending').to('done')
+      expect { todo.done }.to change(todo, :state).from('pending').to('done')
     end
 
     it 'does not raise error when is already done' do
       todo = create(:todo, state: :done)
-      expect { todo.done! }.not_to raise_error
+      expect { todo.done }.not_to raise_error
+    end
+  end
+
+  describe '#for_commit?' do
+    it 'returns true when target is a commit' do
+      subject.target_type = 'Commit'
+      expect(subject.for_commit?).to eq true
+    end
+
+    it 'returns false when target is an issuable' do
+      subject.target_type = 'Issue'
+      expect(subject.for_commit?).to eq false
+    end
+  end
+
+  describe '#target' do
+    context 'for commits' do
+      it 'returns an instance of Commit when exists' do
+        subject.project = project
+        subject.target_type = 'Commit'
+        subject.commit_id = commit.id
+
+        expect(subject.target).to be_a(Commit)
+        expect(subject.target).to eq commit
+      end
+
+      it 'returns nil when does not exists' do
+        subject.project = project
+        subject.target_type = 'Commit'
+        subject.commit_id = 'xxxx'
+
+        expect(subject.target).to be_nil
+      end
+    end
+
+    it 'returns the issuable for issuables' do
+      subject.target_id = issue.id
+      subject.target_type = issue.class.name
+      expect(subject.target).to eq issue
+    end
+  end
+
+  describe '#target_reference' do
+    it 'returns the short commit id for commits' do
+      subject.project = project
+      subject.target_type = 'Commit'
+      subject.commit_id = commit.id
+
+      expect(subject.target_reference).to eq commit.short_id
+    end
+
+    it 'returns reference for issuables' do
+      subject.target = issue
+      expect(subject.target_reference).to eq issue.to_reference
     end
   end
 end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 6290ab3ebec21d15a92abae9623f320919ea0884..0ab7fd88ce66b70eb66e8a6a38fd14afe76b01e6 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -180,6 +180,20 @@ describe User, models: true do
     it { is_expected.to respond_to(:is_admin?) }
     it { is_expected.to respond_to(:name) }
     it { is_expected.to respond_to(:private_token) }
+    it { is_expected.to respond_to(:external?) }
+  end
+
+  describe 'before save hook' do
+    context 'when saving an external user' do
+      let(:user)          { create(:user) }
+      let(:external_user) { create(:user, external: true) }
+
+      it "sets other properties aswell" do
+        expect(external_user.can_create_team).to be_falsey
+        expect(external_user.can_create_group).to be_falsey
+        expect(external_user.projects_limit).to be 0
+      end
+    end
   end
 
   describe '#confirm' do
@@ -404,6 +418,7 @@ describe User, models: true do
         expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit)
         expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group)
         expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme)
+        expect(user.external).to be_falsey
       end
     end
 
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 571ea2dae4c75263c4bb3c58b596bbe5d5513937..bb2ab058003cfef93f65e18cd16be5c10abca49f 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -3,7 +3,11 @@ require 'spec_helper'
 describe API::API, api: true  do
   include ApiHelpers
   let(:user) { create(:user) }
-  let!(:project) { create(:project, namespace: user.namespace ) }
+  let(:non_member) { create(:user) }
+  let(:author) { create(:author) }
+  let(:assignee) { create(:assignee) }
+  let(:admin) { create(:admin) }
+  let!(:project) { create(:project, :public, namespace: user.namespace ) }
   let!(:closed_issue) do
     create :closed_issue,
            author: user,
@@ -12,6 +16,13 @@ describe API::API, api: true  do
            state: :closed,
            milestone: milestone
   end
+  let!(:confidential_issue) do
+    create :issue,
+           :confidential,
+           project: project,
+           author: author,
+           assignee: assignee
+  end
   let!(:issue) do
     create :issue,
            author: user,
@@ -123,10 +134,43 @@ describe API::API, api: true  do
     let(:base_url) { "/projects/#{project.id}" }
     let(:title) { milestone.title }
 
-    it "should return project issues" do
+    it 'should return project issues without confidential issues for non project members' do
+      get api("#{base_url}/issues", non_member)
+      expect(response.status).to eq(200)
+      expect(json_response).to be_an Array
+      expect(json_response.length).to eq(2)
+      expect(json_response.first['title']).to eq(issue.title)
+    end
+
+    it 'should return project confidential issues for author' do
+      get api("#{base_url}/issues", author)
+      expect(response.status).to eq(200)
+      expect(json_response).to be_an Array
+      expect(json_response.length).to eq(3)
+      expect(json_response.first['title']).to eq(issue.title)
+    end
+
+    it 'should return project confidential issues for assignee' do
+      get api("#{base_url}/issues", assignee)
+      expect(response.status).to eq(200)
+      expect(json_response).to be_an Array
+      expect(json_response.length).to eq(3)
+      expect(json_response.first['title']).to eq(issue.title)
+    end
+
+    it 'should return project issues with confidential issues for project members' do
       get api("#{base_url}/issues", user)
       expect(response.status).to eq(200)
       expect(json_response).to be_an Array
+      expect(json_response.length).to eq(3)
+      expect(json_response.first['title']).to eq(issue.title)
+    end
+
+    it 'should return project confidential issues for admin' do
+      get api("#{base_url}/issues", admin)
+      expect(response.status).to eq(200)
+      expect(json_response).to be_an Array
+      expect(json_response.length).to eq(3)
       expect(json_response.first['title']).to eq(issue.title)
     end
 
@@ -206,6 +250,41 @@ describe API::API, api: true  do
       get api("/projects/#{project.id}/issues/54321", user)
       expect(response.status).to eq(404)
     end
+
+    context 'confidential issues' do
+      it "should return 404 for non project members" do
+        get api("/projects/#{project.id}/issues/#{confidential_issue.id}", non_member)
+        expect(response.status).to eq(404)
+      end
+
+      it "should return confidential issue for project members" do
+        get api("/projects/#{project.id}/issues/#{confidential_issue.id}", user)
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq(confidential_issue.title)
+        expect(json_response['iid']).to eq(confidential_issue.iid)
+      end
+
+      it "should return confidential issue for author" do
+        get api("/projects/#{project.id}/issues/#{confidential_issue.id}", author)
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq(confidential_issue.title)
+        expect(json_response['iid']).to eq(confidential_issue.iid)
+      end
+
+      it "should return confidential issue for assignee" do
+        get api("/projects/#{project.id}/issues/#{confidential_issue.id}", assignee)
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq(confidential_issue.title)
+        expect(json_response['iid']).to eq(confidential_issue.iid)
+      end
+
+      it "should return confidential issue for admin" do
+        get api("/projects/#{project.id}/issues/#{confidential_issue.id}", admin)
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq(confidential_issue.title)
+        expect(json_response['iid']).to eq(confidential_issue.iid)
+      end
+    end
   end
 
   describe "POST /projects/:id/issues" do
@@ -294,6 +373,35 @@ describe API::API, api: true  do
       expect(response.status).to eq(400)
       expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
     end
+
+    context 'confidential issues' do
+      it "should return 403 for non project members" do
+        put api("/projects/#{project.id}/issues/#{confidential_issue.id}", non_member),
+          title: 'updated title'
+        expect(response.status).to eq(403)
+      end
+
+      it "should update a confidential issue for project members" do
+        put api("/projects/#{project.id}/issues/#{confidential_issue.id}", user),
+          title: 'updated title'
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq('updated title')
+      end
+
+      it "should update a confidential issue for author" do
+        put api("/projects/#{project.id}/issues/#{confidential_issue.id}", author),
+          title: 'updated title'
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq('updated title')
+      end
+
+      it "should update a confidential issue for admin" do
+        put api("/projects/#{project.id}/issues/#{confidential_issue.id}", admin),
+          title: 'updated title'
+        expect(response.status).to eq(200)
+        expect(json_response['title']).to eq('updated title')
+      end
+    end
   end
 
   describe 'PUT /projects/:id/issues/:issue_id to update labels' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 96e8c8c51f86ecd81a12304e20bac518476fa956..679227bf8815f7aa06e0deb14b73355f3a7e225f 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -120,6 +120,26 @@ describe API::API, api: true  do
       expect(response.status).to eq(201)
     end
 
+    it 'creates non-external users by default' do
+      post api("/users", admin), attributes_for(:user)
+      expect(response.status).to eq(201)
+
+      user_id = json_response['id']
+      new_user = User.find(user_id)
+      expect(new_user).not_to eq nil
+      expect(new_user.external).to be_falsy
+    end
+
+    it 'should allow an external user to be created' do
+      post api("/users", admin), attributes_for(:user, external: true)
+      expect(response.status).to eq(201)
+
+      user_id = json_response['id']
+      new_user = User.find(user_id)
+      expect(new_user).not_to eq nil
+      expect(new_user.external).to be_truthy
+    end
+
     it "should not create user with invalid email" do
       post api('/users', admin),
         email: 'invalid email',
@@ -262,6 +282,13 @@ describe API::API, api: true  do
       expect(user.reload.admin).to eq(true)
     end
 
+    it "should update external status" do
+      put api("/users/#{user.id}", admin), { external: true }
+      expect(response.status).to eq 200
+      expect(json_response['external']).to eq(true)
+      expect(user.reload.external?).to be_truthy
+    end
+
     it "should not update admin status" do
       put api("/users/#{admin_user.id}", admin), { can_create_group: false }
       expect(response.status).to eq(200)
diff --git a/spec/services/delete_user_service_spec.rb b/spec/services/delete_user_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a65938fa03b4ed6452f798449de831f1908f1068
--- /dev/null
+++ b/spec/services/delete_user_service_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+
+describe DeleteUserService, services: true do
+  describe "Deletes a user and all their personal projects" do
+    let!(:user)         { create(:user) }
+    let!(:current_user) { create(:user) }
+    let!(:namespace)    { create(:namespace, owner: user) }
+    let!(:project)      { create(:project, namespace: namespace) }
+
+    context 'no options are given' do
+      it 'deletes the user' do
+        DeleteUserService.new(current_user).execute(user)
+
+        expect { User.find(user.id)       }.to  raise_error(ActiveRecord::RecordNotFound)
+      end
+
+      it 'will delete the project in the near future' do
+        expect_any_instance_of(Projects::DestroyService).to receive(:pending_delete!).once
+
+        DeleteUserService.new(current_user).execute(user)
+      end
+    end
+
+    context "solo owned groups present" do
+      let(:solo_owned)  { create(:group) }
+      let(:member)      { create(:group_member) }
+      let(:user)        { member.user }
+
+      before do
+        solo_owned.group_members = [member]
+        DeleteUserService.new(current_user).execute(user)
+      end
+
+      it 'does not delete the user' do
+        expect(User.find(user.id)).to eq user
+      end
+    end
+
+    context "deletions with solo owned groups" do
+      let(:solo_owned)      { create(:group) }
+      let(:member)          { create(:group_member) }
+      let(:user)            { member.user }
+
+      before do
+        solo_owned.group_members = [member]
+        DeleteUserService.new(current_user).execute(user, delete_solo_owned_groups: true)
+      end
+
+      it 'deletes solo owned groups' do
+        expect { Project.find(solo_owned.id) }.to raise_error(ActiveRecord::RecordNotFound)
+      end
+
+      it 'deletes the user' do
+        expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
+      end
+    end
+  end
+end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 145bc9375605763eb0c62dccc9a4fb2f43f9e8c5..8490a729e517f766e0d56f005c4f5ded72aeb13c 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -29,7 +29,8 @@ describe GitPushService, services: true do
       it { is_expected.to be_truthy }
 
       it 'flushes general cached data' do
-        expect(project.repository).to receive(:expire_cache).with('master')
+        expect(project.repository).to receive(:expire_cache).
+          with('master', newrev)
 
         subject
       end
@@ -46,7 +47,8 @@ describe GitPushService, services: true do
       it { is_expected.to be_truthy }
 
       it 'flushes general cached data' do
-        expect(project.repository).to receive(:expire_cache).with('master')
+        expect(project.repository).to receive(:expire_cache).
+          with('master', newrev)
 
         subject
       end
@@ -65,7 +67,8 @@ describe GitPushService, services: true do
       end
 
       it 'flushes general cached data' do
-        expect(project.repository).to receive(:expire_cache).with('master')
+        expect(project.repository).to receive(:expire_cache).
+          with('master', newrev)
 
         subject
       end
@@ -212,12 +215,16 @@ describe GitPushService, services: true do
     let(:commit) { project.commit }
 
     before do
+      project.team << [commit_author, :developer]
+      project.team << [user, :developer]
+
       allow(commit).to receive_messages(
         safe_message: "this commit \n mentions #{issue.to_reference}",
         references: [issue],
         author_name: commit_author.name,
         author_email: commit_author.email
       )
+
       allow(project.repository).to receive(:commits_between).and_return([commit])
     end
 
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6108c26a78b862808dacd7b9b1d80e6757df8f5f
--- /dev/null
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -0,0 +1,79 @@
+require 'spec_helper'
+
+describe Projects::AutocompleteService, services: true do
+  describe '#issues' do
+    describe 'confidential issues' do
+      let(:author) { create(:user) }
+      let(:assignee) { create(:user) }
+      let(:non_member) { create(:user) }
+      let(:member) { create(:user) }
+      let(:admin) { create(:admin) }
+      let(:project) { create(:empty_project, :public) }
+      let!(:issue) { create(:issue, project: project, title: 'Issue 1') }
+      let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
+      let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignee: assignee) }
+
+      it 'should not list project confidential issues for guests' do
+        autocomplete = described_class.new(project, nil)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).not_to include security_issue_1.iid
+        expect(issues).not_to include security_issue_2.iid
+        expect(issues.count).to eq 1
+      end
+
+      it 'should not list project confidential issues for non project members' do
+        autocomplete = described_class.new(project, non_member)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).not_to include security_issue_1.iid
+        expect(issues).not_to include security_issue_2.iid
+        expect(issues.count).to eq 1
+      end
+
+      it 'should list project confidential issues for author' do
+        autocomplete = described_class.new(project, author)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).to include security_issue_1.iid
+        expect(issues).not_to include security_issue_2.iid
+        expect(issues.count).to eq 2
+      end
+
+      it 'should list project confidential issues for assignee' do
+        autocomplete = described_class.new(project, assignee)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).not_to include security_issue_1.iid
+        expect(issues).to include security_issue_2.iid
+        expect(issues.count).to eq 2
+      end
+
+      it 'should list project confidential issues for project members' do
+        project.team << [member, :developer]
+
+        autocomplete = described_class.new(project, member)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).to include security_issue_1.iid
+        expect(issues).to include security_issue_2.iid
+        expect(issues.count).to eq 3
+      end
+
+      it 'should list all project issues for admin' do
+        autocomplete = described_class.new(project, admin)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).to include security_issue_1.iid
+        expect(issues).to include security_issue_2.iid
+        expect(issues.count).to eq 3
+      end
+    end
+  end
+end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 5dcc39f5fdc182e7c693f883f5a9553b1c3be7d9..8e6292014d4fddd13a4191a79bf23014c5fb7dd1 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -280,6 +280,18 @@ describe SystemNoteService, services: true do
     end
   end
 
+  describe '.new_issue_branch' do
+    subject { described_class.new_issue_branch(noteable, project, author, "1-mepmep") }
+
+    it_behaves_like 'a system note'
+
+    context 'when a branch is created from the new branch button' do
+      it 'sets the note text' do
+        expect(subject.note).to match /\AStarted branch [`1-mepmep`]/
+      end
+    end
+  end
+
   describe '.cross_reference' do
     subject { described_class.cross_reference(noteable, mentioner, author) }
 
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 96420acb31dc6e473edea2106652f7d7059221d9..b4728807b8b892e87c8da5db95772765bff90068 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -148,8 +148,13 @@ describe TodoService, services: true do
         should_not_create_todo(user: stranger, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
       end
 
-      it 'does not create todo when leaving a note on commit' do
-        should_not_create_any_todo { service.new_note(note_on_commit, john_doe) }
+      it 'creates a todo for each valid mentioned user when leaving a note on commit' do
+        service.new_note(note_on_commit, john_doe)
+
+        should_create_todo(user: michael, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
+        should_create_todo(user: author, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
+        should_not_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
+        should_not_create_todo(user: stranger, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
       end
 
       it 'does not create todo when leaving a note on snippet' do
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 65d59e6813cb2f96855ccc012c0562b53eb761ab..e1f90e17cceae7d9b3b7eac0b44589ac714d1998 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -10,7 +10,7 @@ Capybara.register_driver :poltergeist do |app|
   Capybara::Poltergeist::Driver.new(app, js_errors: true, timeout: timeout, window_size: [1366, 768])
 end
 
-Capybara.default_wait_time = timeout
+Capybara.default_max_wait_time = timeout
 Capybara.ignore_hidden_elements = true
 
 unless ENV['CI'] || ENV['CI_SERVER']
diff --git a/spec/support/matchers/access_matchers.rb b/spec/support/matchers/access_matchers.rb
index 558e8b1612f406c75ebdf6e0f7e7ef962c4225aa..4e007c777e3f5c13b5b2f6082d93ebfb84738743 100644
--- a/spec/support/matchers/access_matchers.rb
+++ b/spec/support/matchers/access_matchers.rb
@@ -15,6 +15,8 @@ module AccessMatchers
       logout
     when :admin
       login_as(create(:admin))
+    when :external
+      login_as(create(:user, external: true))
     when User
       login_as(user)
     else
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index fce91015fd4b9c2a20d2e053834cffe31473fbad..e876d44c166dc384ebc21c8509638b7a532d88f0 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -52,6 +52,8 @@ shared_context 'mentionable context' do
     end
 
     set_mentionable_text.call(ref_string)
+
+    project.team << [author, :developer]
   end
 end
 
diff --git a/spec/support/wait_for_ajax.rb b/spec/support/wait_for_ajax.rb
index 692d219e9f1ffa16bd7023df43f4305c1d8f8492..b90fc1126716d1511e5af745ef3e28026ce3bef6 100644
--- a/spec/support/wait_for_ajax.rb
+++ b/spec/support/wait_for_ajax.rb
@@ -1,6 +1,6 @@
 module WaitForAjax
   def wait_for_ajax
-    Timeout.timeout(Capybara.default_wait_time) do
+    Timeout.timeout(Capybara.default_max_wait_time) do
       loop until finished_all_ajax_requests?
     end
   end
diff --git a/spec/workers/delete_user_worker_spec.rb b/spec/workers/delete_user_worker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..14c565212803b35ba3b345dedb87dbc53c7a4ef9
--- /dev/null
+++ b/spec/workers/delete_user_worker_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe DeleteUserWorker do
+  let!(:user)         { create(:user) }
+  let!(:current_user) { create(:user) }
+
+  it "calls the DeleteUserWorker with the params it was given" do
+    expect_any_instance_of(DeleteUserService).to receive(:execute).
+                                                      with(user, {})
+
+    DeleteUserWorker.new.perform(current_user.id, user.id)
+  end
+
+  it "uses symbolized keys" do
+    expect_any_instance_of(DeleteUserService).to receive(:execute).
+                                                      with(user, test: "test")
+
+    DeleteUserWorker.new.perform(current_user.id, user.id, "test" => "test")
+  end
+end