diff --git a/CHANGELOG b/CHANGELOG
index ce2fc5b194f410e060cd04dae9dcaf51b1ccf328..e317b1f6ce00e01f13fa802b631883e38c7fc228 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,13 +1,56 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
 v 8.12.0 (unreleased)
+  - Add two-factor recovery endpoint to internal API !5510
   - Change merge_error column from string to text type
+  - Reduce contributions calendar data payload (ClemMakesApps)
+  - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
+  - Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling)
+  - Add hover color to emoji icon (ClemMakesApps)
   - Optimistic locking for Issues and Merge Requests (title and description overriding prevention)
+  - Add `wiki_page_events` to project hook APIs (Ben Boeckel)
+  - Remove Gitorious import
+  - Add Sentry logging to API calls
+  - Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
+  - Fix groups sort dropdown alignment (ClemMakesApps)
   - Added tests for diff notes
   - Add pipeline events to Slack integration !5525
 
 v 8.11.1 (unreleased)
+  - Add delimiter to project stars and forks count (ClemMakesApps)
+  - Fix badge count alignment (ClemMakesApps)
+  - Fix branch title trailing space on hover (ClemMakesApps)
+  - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
+  - Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
+  - Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
+  - Update merge_requests.md with a simpler way to check out a merge request. !5944
+  - Fix button missing type (ClemMakesApps)
+  - Move to project dropdown with infinite scroll for better performance
+  - Load branches asynchronously in Cherry Pick and Revert dialogs.
+  - Add merge request versions !5467
+  - Change using size to use count and caching it for number of group members. !5935
+  - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck)
+  - Reduce number of database queries on builds tab
+  - Capitalize mentioned issue timeline notes (ClemMakesApps)
+  - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger)
+  - Adds response mime type to transaction metric action when it's not HTML
+
+v 8.11.3 (unreleased)
+  - Allow system info page to handle case where info is unavailable
+  - Label list shows all issues (opened or closed) with that label
+  - Don't show resolve conflicts link before MR status is updated
+  - Don't prevent viewing the MR when git refs for conflicts can't be found on disk
+  - Fix external issue tracker "Issues" link leading to 404s
+
+v 8.11.2
+  - Show "Create Merge Request" widget for push events to fork projects on the source project. !5978
+  - Use gitlab-workhorse 0.7.11 !5983
+  - Does not halt the GitHub import process when an error occurs. !5763
   - Fix file links on project page when default view is Files !5933
+  - Fixed enter key in search input not working !5888
+
+v 8.11.1
+  - Pulled due to packaging error.
 
 v 8.11.0
   - Use test coverage value from the latest successful pipeline in badge. !5862
@@ -16,7 +59,6 @@ v 8.11.0
   - Add Koding (online IDE) integration
   - Ability to specify branches for Pivotal Tracker integration (Egor Lynko)
   - Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
-  - Add delimiter to project stars and forks count (ClemMakesApps)
   - Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
   - Fix adding line comments on the initial commit to a repo !5900
   - Fix the title of the toggle dropdown button. !5515 (herminiotorres)
@@ -32,7 +74,6 @@ v 8.11.0
   - Use long options for curl examples in documentation !5703 (winniehell)
   - Added tooltip listing label names to the labels value in the collapsed issuable sidebar
   - Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell)
-  - Fix badge count alignment (ClemMakesApps)
   - GitLab Performance Monitoring can now track custom events such as the number of tags pushed to a repository
   - Add support for relative links starting with ./ or / to RelativeLinkFilter (winniehell)
   - Allow naming U2F devices !5833
@@ -73,7 +114,6 @@ v 8.11.0
   - Enforce 2FA restrictions on API authentication endpoints !5820
   - Limit git rev-list output count to one in forced push check
   - Show deployment status on merge requests with external URLs
-  - Fix branch title trailing space on hover (ClemMakesApps)
   - Clean up unused routes (Josef Strzibny)
   - Fix issue on empty project to allow developers to only push to protected branches if given permission
   - API: Add enpoints for pipelines
@@ -90,7 +130,6 @@ v 8.11.0
   - Fix devise deprecation warnings.
   - Check for 2FA when using Git over HTTP and only allow PersonalAccessTokens as password in that case !5764
   - Update version_sorter and use new interface for faster tag sorting
-  - Load branches asynchronously in Cherry Pick and Revert dialogs.
   - Optimize checking if a user has read access to a list of issues !5370
   - Store all DB secrets in secrets.yml, under descriptive names !5274
   - Fix syntax highlighting in file editor
@@ -111,8 +150,6 @@ v 8.11.0
   - Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le)
   - Load project invited groups and members eagerly in `ProjectTeam#fetch_members`
   - Add pipeline events hook
-  - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
-  - Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
   - Bump gitlab_git to speedup DiffCollection iterations
   - Rewrite description of a blocked user in admin settings. (Elias Werberich)
   - Make branches sortable without push permission !5462 (winniehell)
@@ -124,14 +161,12 @@ v 8.11.0
   - Fix search for notes which belongs to deleted objects
   - Allow Akismet to be trained by submitting issues as spam or ham !5538
   - Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska)
-  - Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
   - Allow branch names ending with .json for graph and network page !5579 (winniehell)
   - Add the `sprockets-es6` gem
   - Improve OAuth2 client documentation (muteor)
   - Fix diff comments inverted toggle bug (ClemMakesApps)
   - Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska)
   - Profile requests when a header is passed
-  - Fix button missing type (ClemMakesApps)
   - Avoid calculation of line_code and position for _line partial when showing diff notes on discussion tab.
   - Speedup DiffNote#active? on discussions, preloading noteables and avoid touching git repository to return diff_refs when possible
   - Add commit stats in commit api. !5517 (dixpac)
@@ -140,7 +175,6 @@ v 8.11.0
   - edit_blob_link will use blob passed onto the options parameter
   - Make error pages responsive (Takuya Noguchi)
   - The performance of the project dropdown used for moving issues has been improved
-  - Move to project dropdown with infinite scroll for better performance
   - Fix skip_repo parameter being ignored when destroying a namespace
   - Add all builds into stage/job dropdowns on builds page
   - Change requests_profiles resource constraint to catch virtually any file
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 5b209ea2067d605a31380261d594aab1fc9fec3e..b4d6d12101febdd4c5792ced9aae7600069d928e 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-0.7.10
+0.7.11
diff --git a/Gemfile b/Gemfile
index 68547b6fac8447f3c95ffa5e2385ab5774da1288..194379dd687b668529eea386ee1ed5d0980d26a0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -349,5 +349,5 @@ gem 'paranoia', '~> 2.0'
 gem 'health_check', '~> 2.1.0'
 
 # System information
-gem 'vmstat', '~> 2.1.1'
+gem 'vmstat', '~> 2.2'
 gem 'sys-filesystem', '~> 1.1.6'
diff --git a/Gemfile.lock b/Gemfile.lock
index 5511d71893818bebc5cb1ae67c7c86d6ababba75..0c28975060cfea0762871c5d1b89ae14919dfb88 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -772,7 +772,7 @@ GEM
       coercible (~> 1.0)
       descendants_tracker (~> 0.0, >= 0.0.3)
       equalizer (~> 0.0, >= 0.0.9)
-    vmstat (2.1.1)
+    vmstat (2.2.0)
     warden (1.2.6)
       rack (>= 1.0)
     web-console (2.3.0)
@@ -980,7 +980,7 @@ DEPENDENCIES
   unicorn-worker-killer (~> 0.4.2)
   version_sorter (~> 2.1.0)
   virtus (~> 1.0.1)
-  vmstat (~> 2.1.1)
+  vmstat (~> 2.2)
   web-console (~> 2.0)
   webmock (~> 1.21.0)
   wikicloth (= 0.8.1)
diff --git a/README.md b/README.md
index fee93d5f9c304c61f6e1a863620cfc2e3ec86df5..3df8bfa04c748663267a71f1bf7f871f6211c789 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 # GitLab
 
 [![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
+[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
 [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
 
 ## Canonical source
@@ -69,7 +70,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
 GitLab is a Ruby on Rails application that runs on the following software:
 
 - Ubuntu/Debian/CentOS/RHEL
-- Ruby (MRI) 2.1
+- Ruby (MRI) 2.3
 - Git 2.7.4+
 - Redis 2.8+
 - MySQL or PostgreSQL
diff --git a/app/assets/javascripts/abuse_reports.js.es6 b/app/assets/javascripts/abuse_reports.js.es6
index 748084b0307350b7979762a91cab7510609b1515..2fe46b9fd06164ee2eba8c6eed8c2869f7bb1b60 100644
--- a/app/assets/javascripts/abuse_reports.js.es6
+++ b/app/assets/javascripts/abuse_reports.js.es6
@@ -1,4 +1,3 @@
-window.gl = window.gl || {};
 ((global) => {
   const MAX_MESSAGE_LENGTH = 500;
   const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
@@ -36,4 +35,4 @@ window.gl = window.gl || {};
   }
 
   global.AbuseReports = AbuseReports;
-})(window.gl);
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js
index 1ab3c2197d82f60cfd44757db75e8dd340018b92..5ea6086ab779d5026eeccf662a304a06ebb530f9 100644
--- a/app/assets/javascripts/activities.js
+++ b/app/assets/javascripts/activities.js
@@ -26,7 +26,7 @@
       event_filters = $.cookie("event_filter");
       filter = sender.attr("id").split("_")[0];
       $.cookie("event_filter", (event_filters !== filter ? filter : ""), {
-        path: '/'
+        path: gon.relative_url_root || '/'
       });
       if (event_filters !== filter) {
         return sender.closest('li').toggleClass("active");
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index fc354dfd67766daa150ac0ad6daee27207f78d26..43a679501a77c0b6aa3af292a70067cece3b2320 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -288,7 +288,7 @@
     new Aside();
     if ($window.width() < 1024 && $.cookie('pin_nav') === 'true') {
       $.cookie('pin_nav', 'false', {
-        path: '/',
+        path: gon.relative_url_root || '/',
         expires: 365 * 10
       });
       $('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned');
@@ -313,7 +313,7 @@
         $topNav.removeClass('header-pinned-nav').toggleClass('header-collapsed header-expanded');
       }
       $.cookie('pin_nav', doPinNav, {
-        path: '/',
+        path: gon.relative_url_root || '/',
         expires: 365 * 10
       });
       if ($.cookie('pin_nav') === 'true' || doPinNav) {
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index aee1c29eee3be894b6b76a652f336985f2f89fa9..ad12cb906e15bd9c0740840aa9cf9fa58ea094b5 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -320,6 +320,7 @@
       frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
       frequentlyUsedEmojis.push(emoji);
       return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), {
+        path: gon.relative_url_root || '/',
         expires: 365
       });
     };
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js
index 1b7b63489ea3fc5eb300a90ed84ada71f3af53fb..8ac1ba7665e352fdeb4b3c8067a21aa81895b66a 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.js
+++ b/app/assets/javascripts/behaviors/toggler_behavior.js
@@ -1,10 +1,26 @@
-(function() {
+(function(w) {
   $(function() {
-    return $("body").on("click", ".js-toggle-button", function(e) {
-      $(this).find('i').toggleClass('fa fa-chevron-down').toggleClass('fa fa-chevron-up');
-      $(this).closest(".js-toggle-container").find(".js-toggle-content").toggle();
-      return e.preventDefault();
+    $('.js-toggle-button').on('click', function(e) {
+      e.preventDefault();
+      $(this)
+        .find('.fa')
+          .toggleClass('fa-chevron-down fa-chevron-up')
+        .end()
+        .closest('.js-toggle-container')
+          .find('.js-toggle-content')
+            .toggle()
+      ;
     });
-  });
 
-}).call(this);
+    // If we're accessing a permalink, ensure it is not inside a
+    // closed js-toggle-container!
+    var hash = w.gl.utils.getLocationHash();
+    var anchor = hash && document.getElementById(hash);
+    var container = anchor && $(anchor).closest('.js-toggle-container');
+
+    if (container && container.find('.js-toggle-content').is(':hidden')) {
+      container.find('.js-toggle-button').trigger('click');
+      anchor.scrollIntoView();
+    }
+  });
+})(window);
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 10afa7e432985da0f7eeb3d721e77161ec98b3bd..d4d5927d3b03e7abfed017f1bdb941210f7f2d24 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -67,6 +67,14 @@
       $.timeago.settings.strings = tmpLocale;
     };
 
+    w.gl.utils.getDayDifference = function(a, b) {
+      var millisecondsPerDay = 1000 * 60 * 60 * 24;
+      var date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
+      var date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
+
+      return Math.floor((date2 - date1) / millisecondsPerDay);
+    }
+
   })(window);
 
 }).call(this);
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index fffbfd19745d7887c2533f130ef3ecefb44a886e..533310cc87c22d88a863663d13698f1a64c1ef42 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -43,7 +43,7 @@
       }
       return newUrl;
     };
-    return w.gl.utils.removeParamQueryString = function(url, param) {
+    w.gl.utils.removeParamQueryString = function(url, param) {
       var urlVariables, variables;
       url = decodeURIComponent(url);
       urlVariables = url.split('&');
@@ -59,6 +59,16 @@
         return results;
       })()).join('&');
     };
+    w.gl.utils.getLocationHash = function(url) {
+      var hashIndex;
+      if (typeof url === 'undefined') {
+        // Note: We can't use window.location.hash here because it's
+        // not consistent across browsers - Firefox will pre-decode it
+        url = window.location.href;
+      }
+      hashIndex = url.indexOf('#');
+      return hashIndex === -1 ? null : url.substring(hashIndex + 1);
+    };
   })(window);
 
 }).call(this);
diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js
index 4e1de4dfb7279864edd04818abcf1ab188242ba6..66e097c0a289d529c8cc47455c609bca573e5924 100644
--- a/app/assets/javascripts/project.js
+++ b/app/assets/javascripts/project.js
@@ -17,19 +17,15 @@
         return $(this).parents('form').submit();
       });
       $('.hide-no-ssh-message').on('click', function(e) {
-        var path;
-        path = '/';
         $.cookie('hide_no_ssh_message', 'false', {
-          path: path
+          path: gon.relative_url_root || '/'
         });
         $(this).parents('.no-ssh-key-message').remove();
         return e.preventDefault();
       });
       $('.hide-no-password-message').on('click', function(e) {
-        var path;
-        path = '/';
         $.cookie('hide_no_password_message', 'false', {
-          path: path
+          path: gon.relative_url_root || '/'
         });
         $(this).parents('.no-password-message').remove();
         return e.preventDefault();
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index dc4d51138261f1f71a90684367ac5b289a97c5e1..e3d5f413c77d373bedd0c53e1696421e722e723d 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -30,7 +30,7 @@
         }
         if (!triggered) {
           return $.cookie("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed'), {
-            path: '/'
+            path: gon.relative_url_root || '/'
           });
         }
       });
diff --git a/app/assets/javascripts/user.js b/app/assets/javascripts/user.js
index b46390ad8f43008ab8d2be72560fa1047c299806..6c4d88cf407b5f6fed01eacc96441f832e2e675a 100644
--- a/app/assets/javascripts/user.js
+++ b/app/assets/javascripts/user.js
@@ -7,10 +7,8 @@
       });
       this.initTabs();
       $('.hide-project-limit-message').on('click', function(e) {
-        var path;
-        path = '/';
         $.cookie('hide_project_limit_message', 'false', {
-          path: path
+          path: gon.relative_url_root || '/'
         });
         $(this).parents('.project-limit-message').remove();
         return e.preventDefault();
diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js
index 8b3dbf5f5ae1f096a9dde213887ed708a12f686d..74ecf4f4cf90112908c64c0ecb559001e5bf7e51 100644
--- a/app/assets/javascripts/users/calendar.js
+++ b/app/assets/javascripts/users/calendar.js
@@ -3,7 +3,6 @@
 
   this.Calendar = (function() {
     function Calendar(timestamps, calendar_activities_path) {
-      var group, i;
       this.calendar_activities_path = calendar_activities_path;
       this.clickDay = bind(this.clickDay, this);
       this.currentSelectedDate = '';
@@ -13,26 +12,36 @@
       this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
       this.months = [];
       this.timestampsTmp = [];
-      i = 0;
-      group = 0;
-      _.each(timestamps, (function(_this) {
-        return function(count, date) {
-          var day, innerArray, newDate;
-          newDate = new Date(parseInt(date) * 1000);
-          day = newDate.getDay();
-          if ((day === 0 && i !== 0) || i === 0) {
-            _this.timestampsTmp.push([]);
-            group++;
-          }
-          innerArray = _this.timestampsTmp[group - 1];
-          innerArray.push({
-            count: count,
-            date: newDate,
-            day: day
-          });
-          return i++;
-        };
-      })(this));
+      var group = 0;
+
+      var today = new Date()
+      today.setHours(0, 0, 0, 0, 0);
+
+      var oneYearAgo = new Date(today);
+      oneYearAgo.setFullYear(today.getFullYear() - 1);
+
+      var days = gl.utils.getDayDifference(oneYearAgo, today);
+
+      for(var i = 0; i <= days; i++) {
+        var date = new Date(oneYearAgo);
+        date.setDate(date.getDate() + i);
+
+        var day = date.getDay();
+        var count = timestamps[date.getTime() * 0.001];
+
+        if ((day === 0 && i !== 0) || i === 0) {
+          this.timestampsTmp.push([]);
+          group++;
+        }
+
+        var innerArray = this.timestampsTmp[group - 1];
+        innerArray.push({
+          count: count || 0,
+          date: date,
+          day: day
+        });
+      }
+
       this.colorKey = this.initColorKey();
       this.color = this.initColor();
       this.renderSvg(group);
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index c1e5305644ba5348549593893b0ac0397fe228f9..8984bce616c9803dcdd07c21cc546c758f71b433 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -248,7 +248,7 @@ li.note {
 
 img.emoji {
   height: 20px;
-  vertical-align: middle;
+  vertical-align: top;
   width: 20px;
 }
 
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 7d3a063d6c2c25cdaccce9334b8ce5ad5c15850b..be5c64c56d3c795f78d7472ed3743eeeb07ffa32 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -17,6 +17,12 @@
 
 .dropdown {
   position: relative;
+
+  .btn-link {
+    &:hover {
+      cursor: pointer;
+    }
+  }
 }
 
 .open {
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index c1bb250b42d35b151a58729906fd9efe4ff7f96a..8c33e7d9a2e977978eeb14a730eb138b6ddf96e9 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -150,7 +150,7 @@
     border-top: 1px solid $border-color;
     border-bottom: 1px solid $border-color;
     max-height: 300px;
-    overflow: scroll;
+    overflow: auto;
 
     svg {
       position: relative;
diff --git a/app/assets/stylesheets/pages/import.scss b/app/assets/stylesheets/pages/import.scss
index 84cc35239f94ceed3198faa50359d8b0282fa028..a4f76a9495a4ad4ad803fee9d001e8d3b1daa655 100644
--- a/app/assets/stylesheets/pages/import.scss
+++ b/app/assets/stylesheets/pages/import.scss
@@ -1,22 +1,3 @@
-i.icon-gitorious {
-  display: inline-block;
-  background-position: 0 0;
-  background-size: contain;
-  background-repeat: no-repeat;
-}
-
-i.icon-gitorious-small {
-  background-image: image-url('gitorious-logo-blue.png');
-  width: 13px;
-  height: 13px;
-}
-
-i.icon-gitorious-big {
-  background-image: image-url('gitorious-logo-black.png');
-  width: 18px;
-  height: 18px;
-}
-
 .import-jobs-from-col,
 .import-jobs-to-col {
   width: 40%;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index fcdaf671538a66e1fdafd5bd5c3e0a484b5c8e43..7fdd79fa8b902ef5c2da13685ea0466ae6dfac94 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -269,7 +269,7 @@
 
 .builds {
   .table-holder {
-    overflow-x: scroll;
+    overflow-x: auto;
   }
 }
 
@@ -375,6 +375,16 @@
   }
 }
 
+.mr-version-switch {
+  background: $background-color;
+  padding: $gl-btn-padding;
+  color: $gl-placeholder-color;
+
+  a.btn-link {
+    color: $gl-dark-link-color;
+  }
+}
+
 .merge-request-details {
 
   .title {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 08d1692c888c5110268116aff95c6cf890140fb0..54124a3d65828cc18afb338f8ded90815849b5ab 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -281,19 +281,13 @@ ul.notes {
     font-size: 17px;
   }
 
-  &.js-note-delete {
-    i {
-      &:hover {
-        color: $gl-text-red;
-      }
+  &:hover {
+    .danger-highlight {
+      color: $gl-text-red;
     }
-  }
 
-  &.js-note-edit {
-    i {
-      &:hover {
-        color: $gl-link-color;
-      }
+    .link-highlight {
+      color: $gl-link-color;
     }
   }
 }
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 6fa097e3bf165a1b877fe7978a4fa97c2e489abf..9bdf0d250bb639da72ac59781bf67167403dd4ca 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -254,7 +254,6 @@
   width: 100%;
   overflow: auto;
   white-space: nowrap;
-  max-height: 500px;
   transition: max-height 0.3s, padding 0.3s;
 
   &.graph-collapsed {
@@ -265,7 +264,6 @@
 
 .pipeline-visualization {
   position: relative;
-  min-width: 1220px;
 
   ul {
     padding: 0;
diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb
index e4c730088269169b3b5b3953d77e1e540b6776f7..ca04a17caa14b8b395b53ed1201beda33c1e79ae 100644
--- a/app/controllers/admin/system_info_controller.rb
+++ b/app/controllers/admin/system_info_controller.rb
@@ -29,7 +29,8 @@ class Admin::SystemInfoController < Admin::ApplicationController
   ]
 
   def show
-    system_info = Vmstat.snapshot
+    @cpus = Vmstat.cpu rescue nil
+    @memory = Vmstat.memory rescue nil
     mounts = Sys::Filesystem.mounts
 
     @disks = []
@@ -50,10 +51,5 @@ class Admin::SystemInfoController < Admin::ApplicationController
       rescue Sys::Filesystem::Error
       end
     end
-
-    @cpus = system_info.cpus.length
-
-    @mem_used = system_info.memory.active_bytes
-    @mem_total = system_info.memory.total_bytes
   end
 end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 634d36a44671ed450597061fcbb3f6bd9f9903fa..ebc2a4651ba5959b3d351b1f06d63316cc2bd643 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -6,6 +6,7 @@ class ApplicationController < ActionController::Base
   include Gitlab::GonHelper
   include GitlabRoutingHelper
   include PageLayoutHelper
+  include SentryHelper
   include WorkhorseHelper
 
   before_action :authenticate_user_from_private_token!
@@ -24,7 +25,7 @@ class ApplicationController < ActionController::Base
   protect_from_forgery with: :exception
 
   helper_method :abilities, :can?, :current_application_settings
-  helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?
+  helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?
 
   rescue_from Encoding::CompatibilityError do |exception|
     log_exception(exception)
@@ -46,28 +47,6 @@ class ApplicationController < ActionController::Base
 
   protected
 
-  def sentry_context
-    if Rails.env.production? && current_application_settings.sentry_enabled
-      if current_user
-        Raven.user_context(
-          id: current_user.id,
-          email: current_user.email,
-          username: current_user.username,
-        )
-      end
-
-      Raven.tags_context(program: sentry_program_context)
-    end
-  end
-
-  def sentry_program_context
-    if Sidekiq.server?
-      'sidekiq'
-    else
-      'rails'
-    end
-  end
-
   # This filter handles both private tokens and personal access tokens
   def authenticate_user_from_private_token!
     token_string = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence
@@ -271,10 +250,6 @@ class ApplicationController < ActionController::Base
     Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
   end
 
-  def gitorious_import_enabled?
-    current_application_settings.import_sources.include?('gitorious')
-  end
-
   def google_code_import_enabled?
     current_application_settings.import_sources.include?('google_code')
   end
diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb
deleted file mode 100644
index a4c4ad230279d342b8e8ef43b135a4552b95c0a2..0000000000000000000000000000000000000000
--- a/app/controllers/import/gitorious_controller.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-class Import::GitoriousController < Import::BaseController
-  before_action :verify_gitorious_import_enabled
-
-  def new
-    redirect_to client.authorize_url(callback_import_gitorious_url)
-  end
-
-  def callback
-    session[:gitorious_repos] = params[:repos]
-    redirect_to status_import_gitorious_path
-  end
-
-  def status
-    @repos = client.repos
-
-    @already_added_projects = current_user.created_projects.where(import_type: "gitorious")
-    already_added_projects_names = @already_added_projects.pluck(:import_source)
-
-    @repos.reject! { |repo| already_added_projects_names.include? repo.full_name }
-  end
-
-  def jobs
-    jobs = current_user.created_projects.where(import_type: "gitorious").to_json(only: [:id, :import_status])
-    render json: jobs
-  end
-
-  def create
-    @repo_id = params[:repo_id]
-    repo = client.repo(@repo_id)
-    @target_namespace = params[:new_namespace].presence || repo.namespace
-    @project_name = repo.name
-
-    namespace = get_or_create_namespace || (render and return)
-
-    @project = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, current_user).execute
-  end
-
-  private
-
-  def client
-    @client ||= Gitlab::GitoriousImport::Client.new(session[:gitorious_repos])
-  end
-
-  def verify_gitorious_import_enabled
-    render_404 unless gitorious_import_enabled?
-  end
-end
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index 5962f74c39bfa431debf2732d265efd00fee2e4d..ada7db3c552bf6c18dbd53b9e94cd8452abf5ecc 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -4,7 +4,7 @@ class Projects::AvatarsController < Projects::ApplicationController
   before_action :authorize_admin_project!, only: [:destroy]
 
   def show
-    @blob = @repository.blob_at_branch('master', @project.avatar_in_git)
+    @blob = @repository.blob_at_branch(@repository.root_ref, @project.avatar_in_git)
     if @blob
       headers['X-Content-Type-Options'] = 'nosniff'
 
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 7b0189150f801c64d148a620a41f885202170af7..7c03dcd2e64cc36f685b09143ac1acc8877a8f8a 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -212,7 +212,7 @@ class Projects::IssuesController < Projects::ApplicationController
     if action_name == 'new'
       redirect_to external.new_issue_path
     else
-      redirect_to external.issues_url
+      redirect_to external.project_path
     end
   end
 
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 6a8c7166b395ba724ca3b568e61ff4f7a71a911c..4f5f3b6aa09d5a650ec3fb55fe4c2d826260b549 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -83,12 +83,22 @@ class Projects::MergeRequestsController < Projects::ApplicationController
   def diffs
     apply_diff_view_cookie!
 
-    @merge_request_diff = @merge_request.merge_request_diff
+    @merge_request_diff =
+      if params[:diff_id]
+        @merge_request.merge_request_diffs.find(params[:diff_id])
+      else
+        @merge_request.merge_request_diff
+      end
 
     respond_to do |format|
       format.html { define_discussion_vars }
       format.json do
-        @diffs = @merge_request.diffs(diff_options)
+        unless @merge_request_diff.latest?
+          # Disable comments if browsing older version of the diff
+          @diff_notes_disabled = true
+        end
+
+        @diffs = @merge_request_diff.diffs(diff_options)
 
         render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") }
       end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 2a6385c1029514ef981ec8cdbb5776b0ecec6da9..fc52cd2f367f2e629d97985882799c3f9b748d4a 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -5,7 +5,7 @@ class ProjectsController < Projects::ApplicationController
   before_action :project, except: [:new, :create]
   before_action :repository, except: [:new, :create]
   before_action :assign_ref_vars, only: [:show], if: :repo_exists?
-  before_action :assign_tree_vars, only: [:show], if: [:repo_exists?, :project_view_files?]
+  before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?]
 
   # Authorize
   before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
@@ -332,11 +332,4 @@ class ProjectsController < Projects::ApplicationController
   def get_id
     project.repository.root_ref
   end
-
-  # ExtractsPath will set @id = project.path on the show route, but it has to be the
-  # branch name for the tree view to work correctly.
-  def assign_tree_vars
-    @id = get_id
-    tree
-  end
 end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 249d18c4486975ef40a63283a818757397384623..356f27f2d5dad79bbc5011261f4afb0431223a6b 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -116,6 +116,17 @@ module ProjectsHelper
     license.nickname || license.name
   end
 
+  def last_push_event
+    return unless current_user
+
+    project_ids = [@project.id]
+    if fork = current_user.fork_of(@project)
+      project_ids << fork.id
+    end
+
+    current_user.recent_push(project_ids)
+  end
+
   private
 
   def get_project_nav_tabs(project, current_user)
@@ -351,16 +362,6 @@ module ProjectsHelper
     namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'LICENSE')
   end
 
-  def last_push_event
-    return unless current_user
-
-    if fork = current_user.fork_of(@project)
-      current_user.recent_push(fork.id)
-    else
-      current_user.recent_push(@project.id)
-    end
-  end
-
   def readme_cache_key
     sha = @project.commit.try(:sha) || 'nil'
     [@project.path_with_namespace, sha, "readme"].join('-')
diff --git a/app/helpers/sentry_helper.rb b/app/helpers/sentry_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f8cccade15b5520ffb8405d393fab7fbc34f0ea9
--- /dev/null
+++ b/app/helpers/sentry_helper.rb
@@ -0,0 +1,27 @@
+module SentryHelper
+  def sentry_enabled?
+    Rails.env.production? && current_application_settings.sentry_enabled?
+  end
+
+  def sentry_context
+    return unless sentry_enabled?
+
+    if current_user
+      Raven.user_context(
+        id: current_user.id,
+        email: current_user.email,
+        username: current_user.username,
+      )
+    end
+
+    Raven.tags_context(program: sentry_program_context)
+  end
+
+  def sentry_program_context
+    if Sidekiq.server?
+      'sidekiq'
+    else
+      'rails'
+    end
+  end
+end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index f0bcb2d7cdac7ffa6110450750c73a0378d9392f..246477ffe88e05b2952e21bb610cbef01f55564a 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -146,7 +146,7 @@ class ApplicationSetting < ActiveRecord::Base
       default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
       default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
       domain_whitelist: Settings.gitlab['domain_whitelist'],
-      import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project],
+      import_sources: %w[github bitbucket gitlab google_code fogbugz git gitlab_project],
       shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
       max_artifacts_size: Settings.artifacts['max_size'],
       require_two_factor_authentication: false,
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 096b3b801af1f5fbec964f70438e32a3a8fe00a5..23c8de6f6503e72248655d87c89567e9a50a1cc3 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -352,7 +352,7 @@ module Ci
     end
 
     def artifacts?
-      !artifacts_expired? && artifacts_file.exists?
+      !artifacts_expired? && self[:artifacts_file].present?
     end
 
     def artifacts_metadata?
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 087abe4cbb1b9f03e27d56a5e41338471b7aee9d..03812cd195f8f2adab3bbee66986c875f7df91e4 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -1,7 +1,7 @@
 module Ci
   class Pipeline < ActiveRecord::Base
     extend Ci::Model
-    include Statuseable
+    include HasStatus
 
     self.table_name = 'ci_commits'
 
@@ -83,7 +83,7 @@ module Ci
     end
 
     def stages_with_latest_statuses
-      statuses.latest.order(:stage_idx).group_by(&:stage)
+      statuses.latest.includes(project: :namespace).order(:stage_idx).group_by(&:stage)
     end
 
     def project_id
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 84ceeac7d3eb29dd005e57514107a834a96b89e8..4a6289244997c61c220fb36513cd2cc722722d46 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -1,5 +1,5 @@
 class CommitStatus < ActiveRecord::Base
-  include Statuseable
+  include HasStatus
   include Importable
 
   self.table_name = 'ci_builds'
@@ -25,6 +25,8 @@ class CommitStatus < ActiveRecord::Base
   scope :retried, -> { where.not(id: latest) }
   scope :ordered, -> { order(:name) }
   scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
+  scope :latest_ci_stages, -> { latest.ordered.includes(project: :namespace) }
+  scope :retried_ci_stages, -> { retried.ordered.includes(project: :namespace) }
 
   state_machine :status do
     event :enqueue do
diff --git a/app/models/concerns/statuseable.rb b/app/models/concerns/has_status.rb
similarity index 99%
rename from app/models/concerns/statuseable.rb
rename to app/models/concerns/has_status.rb
index 750f937b72407bbdd9e827c41093c4edc86b5bd9..f7b8352405c6ea665697a6467b1d92f1e7792ad2 100644
--- a/app/models/concerns/statuseable.rb
+++ b/app/models/concerns/has_status.rb
@@ -1,4 +1,4 @@
-module Statuseable
+module HasStatus
   extend ActiveSupport::Concern
 
   AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped]
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 5330a07ee35ffd97b8a472cf79ad463b9bd19323..1d05e4a85d1bbb2baf8ef2d7e353826368d43c99 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -10,14 +10,16 @@ class MergeRequest < ActiveRecord::Base
   belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
   belongs_to :merge_user, class_name: "User"
 
-  has_one :merge_request_diff, dependent: :destroy
+  has_many :merge_request_diffs, dependent: :destroy
+  has_one :merge_request_diff,
+    -> { order('merge_request_diffs.id DESC') }
 
   has_many :events, as: :target, dependent: :destroy
 
   serialize :merge_params, Hash
 
-  after_create :create_merge_request_diff, unless: :importing?
-  after_update :update_merge_request_diff
+  after_create :ensure_merge_request_diff, unless: :importing?
+  after_update :reload_diff_if_branch_changed
 
   delegate :commits, :real_size, to: :merge_request_diff, prefix: nil
 
@@ -170,10 +172,10 @@ class MergeRequest < ActiveRecord::Base
   end
 
   def diffs(diff_options = nil)
-    if self.compare
-      self.compare.diffs(diff_options)
+    if compare
+      compare.diffs(diff_options)
     else
-      Gitlab::Diff::FileCollection::MergeRequest.new(self, diff_options: diff_options)
+      merge_request_diff.diffs(diff_options)
     end
   end
 
@@ -184,8 +186,8 @@ class MergeRequest < ActiveRecord::Base
   def diff_base_commit
     if persisted?
       merge_request_diff.base_commit
-    elsif diff_start_commit && diff_head_commit
-      self.target_project.merge_base_commit(diff_start_sha, diff_head_sha)
+    else
+      branch_merge_base_commit
     end
   end
 
@@ -246,6 +248,15 @@ class MergeRequest < ActiveRecord::Base
     target_project.repository.commit(target_branch) if target_branch_ref
   end
 
+  def branch_merge_base_commit
+    start_sha = target_branch_sha
+    head_sha  = source_branch_sha
+
+    if start_sha && head_sha
+      target_project.merge_base_commit(start_sha, head_sha)
+    end
+  end
+
   def target_branch_sha
     @target_branch_sha || target_branch_head.try(:sha)
   end
@@ -267,16 +278,16 @@ class MergeRequest < ActiveRecord::Base
   # Return diff_refs instance trying to not touch the git repository
   def diff_sha_refs
     if merge_request_diff && merge_request_diff.diff_refs_by_sha?
-      return Gitlab::Diff::DiffRefs.new(
-        base_sha:  merge_request_diff.base_commit_sha,
-        start_sha: merge_request_diff.start_commit_sha,
-        head_sha:  merge_request_diff.head_commit_sha
-      )
+      merge_request_diff.diff_refs
     else
       diff_refs
     end
   end
 
+  def branch_merge_base_sha
+    branch_merge_base_commit.try(:sha)
+  end
+
   def validate_branches
     if target_project == source_project && target_branch == source_branch
       errors.add :branch_conflict, "You can not use same project/branch for source and target"
@@ -309,21 +320,31 @@ class MergeRequest < ActiveRecord::Base
     end
   end
 
-  def update_merge_request_diff
+  def ensure_merge_request_diff
+    merge_request_diff || create_merge_request_diff
+  end
+
+  def create_merge_request_diff
+    merge_request_diffs.create
+    reload_merge_request_diff
+  end
+
+  def reload_merge_request_diff
+    merge_request_diff(true)
+  end
+
+  def reload_diff_if_branch_changed
     if source_branch_changed? || target_branch_changed?
       reload_diff
     end
   end
 
   def reload_diff
-    return unless merge_request_diff && open?
+    return unless open?
 
     old_diff_refs = self.diff_refs
-
-    merge_request_diff.reload_content
-
+    create_merge_request_diff
     MergeRequests::MergeRequestDiffCacheService.new.execute(self)
-
     new_diff_refs = self.diff_refs
 
     update_diff_notes_positions(
@@ -777,8 +798,12 @@ class MergeRequest < ActiveRecord::Base
     return @conflicts_can_be_resolved_in_ui = false unless has_complete_diff_refs?
 
     begin
-      @conflicts_can_be_resolved_in_ui = conflicts.files.each(&:lines)
-    rescue Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing
+      # Try to parse each conflict. If the MR's mergeable status hasn't been updated,
+      # ensure that we don't say there are conflicts to resolve when there are no conflict
+      # files.
+      conflicts.files.each(&:lines)
+      @conflicts_can_be_resolved_in_ui = conflicts.files.length > 0
+    rescue Rugged::OdbError, Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing
       @conflicts_can_be_resolved_in_ui = false
     end
   end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 32cc6a3bfead9693385210c04a5b11bc3fbe5f53..445179a4487b47016525e83b3ed156cc23c09544 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -8,8 +8,6 @@ class MergeRequestDiff < ActiveRecord::Base
 
   belongs_to :merge_request
 
-  delegate :source_branch_sha, :target_branch_sha, :target_branch, :source_branch, to: :merge_request, prefix: nil
-
   state_machine :state, initial: :empty do
     state :collected
     state :overflow
@@ -24,12 +22,47 @@ class MergeRequestDiff < ActiveRecord::Base
   serialize :st_commits
   serialize :st_diffs
 
-  after_create :reload_content, unless: :importing?
-  after_save :keep_around_commits, unless: :importing?
+  # All diff information is collected from repository after object is created.
+  # It allows you to override variables like head_commit_sha before getting diff.
+  after_create :save_git_content, unless: :importing?
+
+  def self.select_without_diff
+    select(column_names - ['st_diffs'])
+  end
 
-  def reload_content
+  # Collect information about commits and diff from repository
+  # and save it to the database as serialized data
+  def save_git_content
+    ensure_commits_sha
+    save_commits
     reload_commits
-    reload_diffs
+    save_diffs
+    keep_around_commits
+  end
+
+  def ensure_commits_sha
+    merge_request.fetch_ref
+    self.start_commit_sha ||= merge_request.target_branch_sha
+    self.head_commit_sha  ||= merge_request.source_branch_sha
+    self.base_commit_sha  ||= find_base_sha
+    save
+  end
+
+  # Override head_commit_sha to keep compatibility with merge request diff
+  # created before version 8.4 that does not store head_commit_sha in separate db field.
+  def head_commit_sha
+    if persisted? && super.nil?
+      last_commit.try(:sha)
+    else
+      super
+    end
+  end
+
+  # This method will rely on repository branch sha
+  # in case start_commit_sha is nil. Its necesarry for old merge request diff
+  # created before version 8.4 to work
+  def safe_start_commit_sha
+    start_commit_sha || merge_request.target_branch_sha
   end
 
   def size
@@ -38,14 +71,11 @@ class MergeRequestDiff < ActiveRecord::Base
 
   def raw_diffs(options = {})
     if options[:ignore_whitespace_change]
-      @raw_diffs_no_whitespace ||= begin
-        compare = Gitlab::Git::Compare.new(
+      @diffs_no_whitespace ||=
+        Gitlab::Git::Compare.new(
           repository.raw_repository,
-          self.start_commit_sha || self.target_branch_sha,
-          self.head_commit_sha || self.source_branch_sha,
-        )
-        compare.diffs(options)
-      end
+          safe_start_commit_sha,
+          head_commit_sha).diffs(options)
     else
       @raw_diffs ||= {}
       @raw_diffs[options] ||= load_diffs(st_diffs, options)
@@ -56,6 +86,11 @@ class MergeRequestDiff < ActiveRecord::Base
     @commits ||= load_commits(st_commits || [])
   end
 
+  def reload_commits
+    @commits = nil
+    commits
+  end
+
   def last_commit
     commits.first
   end
@@ -65,55 +100,60 @@ class MergeRequestDiff < ActiveRecord::Base
   end
 
   def base_commit
-    return unless self.base_commit_sha
+    return unless base_commit_sha
 
-    project.commit(self.base_commit_sha)
+    project.commit(base_commit_sha)
   end
 
   def start_commit
-    return unless self.start_commit_sha
+    return unless start_commit_sha
 
-    project.commit(self.start_commit_sha)
+    project.commit(start_commit_sha)
   end
 
   def head_commit
-    return last_commit unless self.head_commit_sha
+    return unless head_commit_sha
+
+    project.commit(head_commit_sha)
+  end
+
+  def diff_refs
+    return unless start_commit_sha || base_commit_sha
 
-    project.commit(self.head_commit_sha)
+    Gitlab::Diff::DiffRefs.new(
+      base_sha:  base_commit_sha,
+      start_sha: start_commit_sha,
+      head_sha:  head_commit_sha
+    )
   end
 
   def diff_refs_by_sha?
     base_commit_sha? && head_commit_sha? && start_commit_sha?
   end
 
+  def diffs(diff_options = nil)
+    Gitlab::Diff::FileCollection::MergeRequestDiff.new(self, diff_options: diff_options)
+  end
+
+  def project
+    merge_request.target_project
+  end
+
   def compare
     @compare ||=
-      begin
-        # Update ref for merge request
-        merge_request.fetch_ref
+      Gitlab::Git::Compare.new(
+        repository.raw_repository,
+        safe_start_commit_sha,
+        head_commit_sha
+      )
+  end
 
-        Gitlab::Git::Compare.new(
-          repository.raw_repository,
-          self.target_branch_sha,
-          self.source_branch_sha
-        )
-      end
+  def latest?
+    self == merge_request.merge_request_diff
   end
 
   private
 
-  # Collect array of Git::Commit objects
-  # between target and source branches
-  def unmerged_commits
-    commits = compare.commits
-
-    if commits.present?
-      commits = Commit.decorate(commits, merge_request.source_project).reverse
-    end
-
-    commits
-  end
-
   def dump_commits(commits)
     commits.map(&:to_hash)
   end
@@ -122,26 +162,21 @@ class MergeRequestDiff < ActiveRecord::Base
     array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash), merge_request.source_project) }
   end
 
-  # Reload all commits related to current merge request from repo
+  # Load all commits related to current merge request diff from repo
   # and save it as array of hashes in st_commits db field
-  def reload_commits
+  def save_commits
     new_attributes = {}
 
-    commit_objects = unmerged_commits
+    commits = compare.commits
 
-    if commit_objects.present?
-      new_attributes[:st_commits] = dump_commits(commit_objects)
+    if commits.present?
+      commits = Commit.decorate(commits, merge_request.source_project).reverse
+      new_attributes[:st_commits] = dump_commits(commits)
     end
 
     update_columns_serialized(new_attributes)
   end
 
-  # Collect array of Git::Diff objects
-  # between target and source branches
-  def unmerged_diffs
-    compare.diffs(Commit.max_diff_options)
-  end
-
   def dump_diffs(diffs)
     if diffs.respond_to?(:map)
       diffs.map(&:to_hash)
@@ -162,16 +197,16 @@ class MergeRequestDiff < ActiveRecord::Base
     end
   end
 
-  # Reload diffs between branches related to current merge request from repo
+  # Load diffs between branches related to current merge request diff from repo
   # and save it as array of hashes in st_diffs db field
-  def reload_diffs
+  def save_diffs
     new_attributes = {}
     new_diffs = []
 
     if commits.size.zero?
       new_attributes[:state] = :empty
     else
-      diff_collection = unmerged_diffs
+      diff_collection = compare.diffs(Commit.max_diff_options)
 
       if diff_collection.overflow?
         # Set our state to 'overflow' to make the #empty? and #collected?
@@ -188,32 +223,17 @@ class MergeRequestDiff < ActiveRecord::Base
     end
 
     new_attributes[:st_diffs] = new_diffs
-
-    new_attributes[:start_commit_sha] = self.target_branch_sha
-    new_attributes[:head_commit_sha] = self.source_branch_sha
-    new_attributes[:base_commit_sha] = branch_base_sha
-
     update_columns_serialized(new_attributes)
-
-    keep_around_commits
-  end
-
-  def project
-    merge_request.target_project
   end
 
   def repository
     project.repository
   end
 
-  def branch_base_commit
-    return unless self.source_branch_sha && self.target_branch_sha
-
-    project.merge_base_commit(self.source_branch_sha, self.target_branch_sha)
-  end
+  def find_base_sha
+    return unless head_commit_sha && start_commit_sha
 
-  def branch_base_sha
-    branch_base_commit.try(:sha)
+    project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha)
   end
 
   def utf8_st_diffs
@@ -248,8 +268,8 @@ class MergeRequestDiff < ActiveRecord::Base
   end
 
   def keep_around_commits
-    repository.keep_around(target_branch_sha)
-    repository.keep_around(source_branch_sha)
-    repository.keep_around(branch_base_sha)
+    repository.keep_around(start_commit_sha)
+    repository.keep_around(head_commit_sha)
+    repository.keep_around(base_commit_sha)
   end
 end
diff --git a/app/models/project.rb b/app/models/project.rb
index 1855760e694208039f33241fc3ac8f0ee5246c7a..0e4fb94f8eb5ddf56b07b25b6e07a1be23e04ba3 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -471,8 +471,6 @@ class Project < ActiveRecord::Base
   end
 
   def reset_cache_and_import_attrs
-    update(import_error: nil)
-
     ProjectCacheWorker.perform_async(self.id)
 
     self.import_data.destroy if self.import_data
@@ -1037,6 +1035,7 @@ class Project < ActiveRecord::Base
                                         "refs/heads/#{branch}",
                                         force: true)
     repository.copy_gitattributes(branch)
+    repository.expire_avatar_cache(branch)
     reload_default_branch
   end
 
diff --git a/app/models/repository.rb b/app/models/repository.rb
index bdc3b9d1c1cb5c47809fdb4c274f47e543c86676..91bdafdac99b9f7e394f062f92a4594daf267c49 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1065,7 +1065,7 @@ class Repository
 
     @avatar ||= cache.fetch(:avatar) do
       AVATAR_FILES.find do |file|
-        blob_at_branch('master', file)
+        blob_at_branch(root_ref, file)
       end
     end
   end
diff --git a/app/models/user.rb b/app/models/user.rb
index 48e83ab7e56278a22f3f20cd429d8e5dd884c112..ad3cfbc03e4c6a5cfefc31194107164b4fb34b4e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -489,10 +489,10 @@ class User < ActiveRecord::Base
     (personal_projects.count.to_f / projects_limit) * 100
   end
 
-  def recent_push(project_id = nil)
+  def recent_push(project_ids = nil)
     # Get push events not earlier than 2 hours ago
     events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
-    events = events.where(project_id: project_id) if project_id
+    events = events.where(project_id: project_ids) if project_ids
 
     # Use the latest event that has not been pushed or merged recently
     events.recent.find do |event|
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index 435a8c6e6819849f6aa1bb3a38a434b42ac57deb..34efd09ed9f64362d4da4523ff3c4e44d8babb54 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -36,7 +36,12 @@ module Boards
       end
 
       def set_state
-        params[:state] = list.done? ? 'closed' : 'opened'
+        params[:state] =
+          case list.list_type.to_sym
+          when :backlog then 'opened'
+          when :done then 'closed'
+          else 'all'
+          end
       end
 
       def board_label_ids
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
index 6f7610d42ba0ced02417ff428267fb0a6e9d34fc..f049ed628db19863bcb6c7f6e321780f6c9fb6d8 100644
--- a/app/services/ci/process_pipeline_service.rb
+++ b/app/services/ci/process_pipeline_service.rb
@@ -34,7 +34,7 @@ module Ci
     end
 
     def process_build(build, current_status)
-      return false unless Statuseable::COMPLETED_STATUSES.include?(current_status)
+      return false unless HasStatus::COMPLETED_STATUSES.include?(current_status)
 
       if valid_statuses_for_when(build.when).include?(current_status)
         build.enqueue
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 546a8f11330e14c23bc0bc429c150816a447c214..0c8446e7c3d6457ed76326bc7ef6f9dc43cdc6d0 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -269,11 +269,11 @@ module SystemNoteService
   #
   # Example Note text:
   #
-  #   "mentioned in #1"
+  #   "Mentioned in #1"
   #
-  #   "mentioned in !2"
+  #   "Mentioned in !2"
   #
-  #   "mentioned in 54f7727c"
+  #   "Mentioned in 54f7727c"
   #
   # See cross_reference_note_content.
   #
@@ -308,7 +308,7 @@ module SystemNoteService
 
   # Check if a cross-reference is disallowed
   #
-  # This method prevents adding a "mentioned in !1" note on every single commit
+  # This method prevents adding a "Mentioned in !1" note on every single commit
   # in a merge request. Additionally, it prevents the creation of references to
   # external issues (which would fail).
   #
@@ -417,7 +417,7 @@ module SystemNoteService
   end
 
   def cross_reference_note_prefix
-    'mentioned in '
+    'Mentioned in '
   end
 
   def cross_reference_note_content(gfm_reference)
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index e0ccb65459004da1543048b0f2a3f9d0464f9942..2aab8c736d6a56036de37df5a109620804cc9f73 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -148,7 +148,8 @@ class TodoService
   def mark_todos_as_done_by_ids(ids, current_user)
     todos = current_user.todos.where(id: ids)
 
-    marked_todos = todos.update_all(state: :done)
+    # Only return those that are not really on that state
+    marked_todos = todos.where.not(state: :done).update_all(state: :done)
     current_user.update_todos_count_cache
     marked_todos
   end
diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml
index 6956e5ab7958a003ae5eead0e8789b5a4daf0e20..bfc6142067a53bf82b91a5256e782ec999997a95 100644
--- a/app/views/admin/system_info/show.html.haml
+++ b/app/views/admin/system_info/show.html.haml
@@ -9,12 +9,20 @@
       .light-well
         %h4 CPU
         .data
-          %h1= "#{@cpus} cores"
+          - if @cpus
+            %h1= "#{@cpus.length} cores"
+          - else
+            = icon('warning', class: 'text-warning')
+            Unable to collect CPU info
     .col-sm-4
       .light-well
         %h4 Memory
         .data
-          %h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}"
+          - if @memory
+            %h1= "#{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}"
+          - else
+            = icon('warning', class: 'text-warning')
+            Unable to collect memory info
     .col-sm-4
       .light-well
         %h4 Disks
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 57f6e7e0612646983d79cab934c96d0f3852efda..b8248a80a275eeafc4d804ce07f07a64b544d4ae 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -24,7 +24,7 @@
         - else
           = sort_title_recently_created
         %b.caret
-      %ul.dropdown-menu
+      %ul.dropdown-menu.dropdown-menu-align-right
         %li
           = link_to explore_groups_path(sort: sort_value_recently_created) do
             = sort_title_recently_created
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 90f362c052be70f24ba822a0d6e8bfaa02cbf5dd..f789796e9429f006e248983bfcb12145f59f116f 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -17,7 +17,7 @@
     .panel-heading
       %strong #{@group.name}
       group members
-      %span.badge= @members.size
+      %span.badge= @members.total_count
       .controls
         = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form'  do
           .form-group
diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml
deleted file mode 100644
index ed3afb0ce3386338fa6359f1991750bbe00b9b9f..0000000000000000000000000000000000000000
--- a/app/views/import/gitorious/status.html.haml
+++ /dev/null
@@ -1,54 +0,0 @@
-- page_title "Gitorious import"
-- header_title "Projects", root_path
-%h3.page-title
-  %i.icon-gitorious.icon-gitorious-big
-  Import projects from Gitorious.org
-
-%p.light
-  Select projects you want to import.
-%hr
-%p
-  = button_tag class: "btn btn-import btn-success js-import-all" do
-    Import all projects
-    = icon("spinner spin", class: "loading-icon")
-
-.table-responsive
-  %table.table.import-jobs
-    %colgroup.import-jobs-from-col
-    %colgroup.import-jobs-to-col
-    %colgroup.import-jobs-status-col
-    %thead
-      %tr
-        %th From Gitorious.org
-        %th To GitLab
-        %th Status
-    %tbody
-      - @already_added_projects.each do |project|
-        %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
-          %td
-            = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
-          %td
-            = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
-          %td.job-status
-            - if project.import_status == 'finished'
-              %span
-                %i.fa.fa-check
-                done
-            - elsif project.import_status == 'started'
-              %i.fa.fa-spinner.fa-spin
-              started
-            - else
-              = project.human_import_status_name
-
-      - @repos.each do |repo|
-        %tr{id: "repo_#{repo.id}"}
-          %td
-            = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
-          %td.import-target
-            = repo.full_name
-          %td.import-actions.job-status
-            = button_tag class: "btn btn-import js-add-to-import" do
-              Import
-              = icon("spinner spin", class: "loading-icon")
-
-.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitorious_path}", import_path: "#{import_gitorious_path}" } }
diff --git a/app/views/projects/commit/_ci_stage.html.haml b/app/views/projects/commit/_ci_stage.html.haml
index 9d925cacc0d2adfef5c06620a6709019a3a7c47f..6bb900e3fc1f34f2b77cfb4ccfc6d47308bb4825 100644
--- a/app/views/projects/commit/_ci_stage.html.haml
+++ b/app/views/projects/commit/_ci_stage.html.haml
@@ -8,8 +8,8 @@
       - if stage
         &nbsp;
         = stage.titleize
-  = render statuses.latest.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
-  = render statuses.retried.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
+  = render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
+  = render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
   %tr
     %td{colspan: 10}
       &nbsp;
diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml
index 013b05628fae0750eb0f720e6e9c948cd1c662d9..99c71e1454a8dea52e53c92c9066ae1ecf5a3523 100644
--- a/app/views/projects/merge_requests/show/_diffs.html.haml
+++ b/app/views/projects/merge_requests/show/_diffs.html.haml
@@ -1,4 +1,5 @@
 - if @merge_request_diff.collected?
+  = render 'projects/merge_requests/show/versions'
   = render "projects/diffs/diffs", diffs: @diffs
 - elsif @merge_request_diff.empty?
   .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..2da70ce7137adba857a99d4eba2d13266f8260ac
--- /dev/null
+++ b/app/views/projects/merge_requests/show/_versions.html.haml
@@ -0,0 +1,31 @@
+- merge_request_diffs = @merge_request.merge_request_diffs.select_without_diff
+
+- if merge_request_diffs.size > 1
+  .mr-version-switch
+    Version:
+    %span.dropdown.inline
+      %a.btn-link.dropdown-toggle{ data: {toggle: :dropdown} }
+        %strong.monospace<
+          - if @merge_request_diff.latest?
+            #{"latest"}
+          - else
+            #{@merge_request_diff.head_commit.short_id}
+        %span.caret
+      %ul.dropdown-menu.dropdown-menu-selectable
+        - merge_request_diffs.each do |merge_request_diff|
+          %li
+            = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id), class: ('is-active' if merge_request_diff == @merge_request_diff) do
+              %strong.monospace
+                #{merge_request_diff.head_commit.short_id}
+              %br
+              %small
+                #{number_with_delimiter(merge_request_diff.commits.count)} #{'commit'.pluralize(merge_request_diff.commits.count)},
+                = time_ago_with_tooltip(merge_request_diff.created_at)
+
+    - unless @merge_request_diff.latest?
+      %span.prepend-left-default
+        = icon('info-circle')
+        This version is not the latest one. Comments are disabled
+    .pull-right
+      %span.monospace
+        #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id}
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index ea4898f2107fa678044c84cb38670bb2ead09170..0a1e2bb2cc6632ecb50ffe49153c523da66fe4fe 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -59,11 +59,6 @@
                       = icon('gitlab', text: 'GitLab.com')
                     - unless gitlab_import_configured?
                       = render 'gitlab_import_modal'
-                %div
-                  - if gitorious_import_enabled?
-                    = link_to new_import_gitorious_path, class: 'btn import_gitorious' do
-                      %i.icon-gitorious.icon-gitorious-small
-                      Gitorious.org
                 %div
                   - if google_code_import_enabled?
                     = link_to new_import_google_code_path, class: 'btn import_google_code' do
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index d2ac1ce2b9a9c001581d0e1834f9fb69a0140f02..7c82177f9ea390ce50173ae7e4f1aaf6ceb8bc41 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -52,11 +52,11 @@
               - if note.emoji_awardable?
                 = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do
                   = icon('spinner spin')
-                  = icon('smile-o')
+                  = icon('smile-o', class: 'link-highlight')
 
               - if note_editable
                 = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do
-                  = icon('pencil')
+                  = icon('pencil', class: 'link-highlight')
                 = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do
                   = icon('trash-o')
       .note-body{class: note_editable ? 'js-task-list-container' : ''}
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index e6701078f71f86b972cb02d268127e5ab7a40f8e..d2ca8813ab9db2a955b037e3af95df7449f788bf 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -14,6 +14,8 @@ class RepositoryImportWorker
                               import_url: @project.import_url,
                               path: @project.path_with_namespace)
 
+    project.update_column(:import_error, nil)
+
     result = Projects::ImportService.new(project, current_user).execute
 
     if result[:status] == :error
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 7a9376def02634dbb11aa5689b9f9c2a8cb8d9f5..4a01b9e40fb3f4ca3b0fd39dc2a1bb9ca8c585d5 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -212,7 +212,7 @@ Settings.gitlab.default_projects_features['builds']             = true if Settin
 Settings.gitlab.default_projects_features['container_registry'] = true if Settings.gitlab.default_projects_features['container_registry'].nil?
 Settings.gitlab.default_projects_features['visibility_level']   = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
 Settings.gitlab['domain_whitelist'] ||= []
-Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project]
+Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab google_code fogbugz git gitlab_project]
 Settings.gitlab['trusted_proxies'] ||= []
 
 #
diff --git a/config/routes.rb b/config/routes.rb
index e93b640fbc0958a413da4af9ddfc125bfb19a0a9..24f9b44a53a4e59fb8c31daf4d3524b43ec84776 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -157,12 +157,6 @@ Rails.application.routes.draw do
       get :jobs
     end
 
-    resource :gitorious, only: [:create, :new], controller: :gitorious do
-      get :status
-      get :callback
-      get :jobs
-    end
-
     resource :google_code, only: [:create, :new], controller: :google_code do
       get :status
       post :callback
diff --git a/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c8cbd2718ff0825038d3d78a6c426427049e5909
--- /dev/null
+++ b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
@@ -0,0 +1,21 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class MergeRequestDiffRemoveUniq < ActiveRecord::Migration
+  include Gitlab::Database::MigrationHelpers
+  disable_ddl_transaction!
+
+  DOWNTIME = false
+
+  def up
+    if index_exists?(:merge_request_diffs, :merge_request_id)
+      remove_index :merge_request_diffs, :merge_request_id
+    end
+  end
+
+  def down
+    unless index_exists?(:merge_request_diffs, :merge_request_id)
+      add_concurrent_index :merge_request_diffs, :merge_request_id, unique: true
+    end
+  end
+end
diff --git a/db/migrate/20160725104452_merge_request_diff_add_index.rb b/db/migrate/20160725104452_merge_request_diff_add_index.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6d04242dd25af8e410da13ec58d03e4023ef4f6a
--- /dev/null
+++ b/db/migrate/20160725104452_merge_request_diff_add_index.rb
@@ -0,0 +1,17 @@
+class MergeRequestDiffAddIndex < ActiveRecord::Migration
+  include Gitlab::Database::MigrationHelpers
+  disable_ddl_transaction!
+
+  # Set this constant to true if this migration requires downtime.
+  DOWNTIME = false
+
+  def up
+    add_concurrent_index :merge_request_diffs, :merge_request_id
+  end
+
+  def down
+    if index_exists?(:merge_request_diffs, :merge_request_id)
+      remove_index :merge_request_diffs, :merge_request_id
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 802c928b2fc8c77ca257b8438051208acfb1dd45..5a105a91ad1bf25ee8d4b9e7e50df78a2601caee 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -593,7 +593,7 @@ ActiveRecord::Schema.define(version: 20160823081327) do
     t.string   "start_commit_sha"
   end
 
-  add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree
+  add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", using: :btree
 
   create_table "merge_requests", force: :cascade do |t|
     t.string   "target_branch",                                null: false
diff --git a/doc/README.md b/doc/README.md
index 195b7c7af62c7f915791af7c261a30ab3fe02a95..254394eb63e7e027df8148cc820eef6d1171328b 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -2,6 +2,7 @@
 
 ## User documentation
 
+- [Account Security](user/account/security.md) Securing your account via two-factor authentication, etc.
 - [API](api/README.md) Automate GitLab via a simple and powerful API.
 - [CI/CD](ci/README.md) GitLab Continuous Integration (CI) and Continuous Delivery (CD) getting started, `.gitlab-ci.yml` options, and examples.
 - [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
@@ -18,7 +19,6 @@
 - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
 - [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.
-- [Koding](user/project/koding.md) Learn how to use Koding, the online IDE.
 
 ## Administrator documentation
 
diff --git a/doc/api/issues.md b/doc/api/issues.md
index a665645ad0ef618be6f51dc8d6b218891958693a..b194799ccbf93215d087c17294066d0939f6b02d 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -79,7 +79,8 @@ Example response:
       "labels" : [],
       "subscribed" : false,
       "user_notes_count": 1,
-      "due_date": "2016-07-22"
+      "due_date": "2016-07-22",
+      "web_url": "http://example.com/example/example/issues/6"
    }
 ]
 ```
@@ -156,7 +157,8 @@ Example response:
       "created_at" : "2016-01-04T15:31:46.176Z",
       "subscribed" : false,
       "user_notes_count": 1,
-      "due_date": null
+      "due_date": null,
+      "web_url": "http://example.com/example/example/issues/1"
    }
 ]
 ```
@@ -235,7 +237,8 @@ Example response:
       "created_at" : "2016-01-04T15:31:46.176Z",
       "subscribed" : false,
       "user_notes_count": 1,
-      "due_date": "2016-07-22"
+      "due_date": "2016-07-22",
+      "web_url": "http://example.com/example/example/issues/1"
    }
 ]
 ```
@@ -299,7 +302,8 @@ Example response:
    "created_at" : "2016-01-04T15:31:46.176Z",
    "subscribed": false,
    "user_notes_count": 1,
-   "due_date": null
+   "due_date": null,
+   "web_url": "http://example.com/example/example/issues/1"
 }
 ```
 
@@ -323,8 +327,8 @@ POST /projects/:id/issues
 | `assignee_id`   | integer | no  | The ID of a user to assign issue |
 | `milestone_id`  | integer | no  | The ID of a milestone to assign issue |
 | `labels`        | string  | no  | Comma-separated label names for an issue  |
-| `created_at`    | string  | no  | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
-| `due_date`      | string  | no   | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
+| `created_at`    | string  | no  | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
+| `due_date`      | string  | no  | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
 
 ```bash
 curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
@@ -357,7 +361,8 @@ Example response:
    "milestone" : null,
    "subscribed" : true,
    "user_notes_count": 0,
-   "due_date": null
+   "due_date": null,
+   "web_url": "http://example.com/example/example/issues/14"
 }
 ```
 
@@ -384,8 +389,8 @@ PUT /projects/:id/issues/:issue_id
 | `milestone_id`  | integer | no  | The ID of a milestone to assign the issue to |
 | `labels`        | string  | no  | Comma-separated label names for an issue  |
 | `state_event`   | string  | no  | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
-| `updated_at`    | string  | no  | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
-| `due_date`      | string  | no   | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
+| `updated_at`    | string  | no  | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
+| `due_date`      | string  | no  | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
 
 ```bash
 curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close
@@ -418,7 +423,8 @@ Example response:
    "milestone" : null,
    "subscribed" : true,
    "user_notes_count": 0,
-   "due_date": "2016-07-22"
+   "due_date": "2016-07-22",
+   "web_url": "http://example.com/example/example/issues/15"
 }
 ```
 
@@ -496,7 +502,8 @@ Example response:
     "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
     "web_url": "https://gitlab.example.com/u/solon.cremin"
   },
-  "due_date": null
+  "due_date": null,
+  "web_url": "http://example.com/example/example/issues/11"
 }
 ```
 
@@ -551,7 +558,8 @@ Example response:
     "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
     "web_url": "https://gitlab.example.com/u/solon.cremin"
   },
-  "due_date": null
+  "due_date": null,
+  "web_url": "http://example.com/example/example/issues/11"
 }
 ```
 
@@ -607,7 +615,8 @@ Example response:
     "web_url": "https://gitlab.example.com/u/orville"
   },
   "subscribed": false,
-  "due_date": null
+  "due_date": null,
+  "web_url": "http://example.com/example/example/issues/12"
 }
 ```
 
@@ -693,7 +702,9 @@ Example response:
     "subscribed": true,
     "user_notes_count": 7,
     "upvotes": 0,
-    "downvotes": 0
+    "downvotes": 0,
+    "due_date": null,
+    "web_url": "http://example.com/example/example/issues/110"
   },
   "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/issues/10",
   "body": "Vel voluptas atque dicta mollitia adipisci qui at.",
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 3e88a7589365942c256c13bbbcaf4276ea41a25e..f4760ceac7c7152f6e96afe7cd8066baf70a1b86 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -70,7 +70,8 @@ Parameters:
     "subscribed" : false,
     "user_notes_count": 1,
     "should_remove_source_branch": true,
-    "force_remove_source_branch": false
+    "force_remove_source_branch": false,
+    "web_url": "http://example.com/example/example/merge_requests/1"
   }
 ]
 ```
@@ -136,7 +137,8 @@ Parameters:
   "subscribed" : true,
   "user_notes_count": 1,
   "should_remove_source_branch": true,
-  "force_remove_source_branch": false
+  "force_remove_source_branch": false,
+  "web_url": "http://example.com/example/example/merge_requests/1"
 }
 ```
 
@@ -239,6 +241,7 @@ Parameters:
   "user_notes_count": 1,
   "should_remove_source_branch": true,
   "force_remove_source_branch": false,
+  "web_url": "http://example.com/example/example/merge_requests/1",
   "changes": [
     {
     "old_path": "VERSION",
@@ -321,7 +324,8 @@ Parameters:
   "subscribed" : true,
   "user_notes_count": 0,
   "should_remove_source_branch": true,
-  "force_remove_source_branch": false
+  "force_remove_source_branch": false,
+  "web_url": "http://example.com/example/example/merge_requests/1"
 }
 ```
 
@@ -395,7 +399,8 @@ Parameters:
   "subscribed" : true,
   "user_notes_count": 1,
   "should_remove_source_branch": true,
-  "force_remove_source_branch": false
+  "force_remove_source_branch": false,
+  "web_url": "http://example.com/example/example/merge_requests/1"
 }
 ```
 
@@ -496,7 +501,8 @@ Parameters:
   "subscribed" : true,
   "user_notes_count": 1,
   "should_remove_source_branch": true,
-  "force_remove_source_branch": false
+  "force_remove_source_branch": false,
+  "web_url": "http://example.com/example/example/merge_requests/1"
 }
 ```
 
@@ -565,7 +571,8 @@ Parameters:
   "subscribed" : true,
   "user_notes_count": 1,
   "should_remove_source_branch": true,
-  "force_remove_source_branch": false
+  "force_remove_source_branch": false,
+  "web_url": "http://example.com/example/example/merge_requests/1"
 }
 ```
 
@@ -886,7 +893,8 @@ Example response:
     "subscribed": true,
     "user_notes_count": 7,
     "should_remove_source_branch": true,
-    "force_remove_source_branch": false
+    "force_remove_source_branch": false,
+    "web_url": "http://example.com/example/example/merge_requests/1"
   },
   "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/merge_requests/7",
   "body": "Et voluptas laudantium minus nihil recusandae ut accusamus earum aut non.",
@@ -894,3 +902,112 @@ Example response:
   "created_at": "2016-07-01T11:14:15.530Z"
 }
 ```
+
+## Get MR diff versions
+
+Get a list of merge request diff versions.
+
+```
+GET /projects/:id/merge_requests/:merge_request_id/versions
+```
+
+| Attribute | Type    | Required | Description           |
+| --------- | ------- | -------- | --------------------- |
+| `id`      | String  | yes      | The ID of the project |
+| `merge_request_id` | integer | yes | The ID of the merge request |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions
+```
+
+Example response:
+
+```json
+[{
+  "id": 110,
+  "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
+  "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "created_at": "2016-07-26T14:44:48.926Z",
+  "merge_request_id": 105,
+  "state": "collected",
+  "real_size": "1"
+}, {
+  "id": 108,
+  "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24",
+  "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "created_at": "2016-07-25T14:21:33.028Z",
+  "merge_request_id": 105,
+  "state": "collected",
+  "real_size": "1"
+}]
+```
+
+## Get a single MR diff version
+
+Get a single merge request diff version.
+
+```
+GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id
+```
+
+| Attribute | Type    | Required | Description           |
+| --------- | ------- | -------- | --------------------- |
+| `id`      | String  | yes      | The ID of the project |
+| `merge_request_id` | integer | yes | The ID of the merge request |
+| `version_id` | integer | yes | The ID of the merge request diff version |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions/1
+```
+
+Example response:
+
+```json
+{
+  "id": 110,
+  "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
+  "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "created_at": "2016-07-26T14:44:48.926Z",
+  "merge_request_id": 105,
+  "state": "collected",
+  "real_size": "1",
+  "commits": [{
+    "id": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
+    "short_id": "33e2ee85",
+    "title": "Change year to 2018",
+    "author_name": "Administrator",
+    "author_email": "admin@example.com",
+    "created_at": "2016-07-26T17:44:29.000+03:00",
+    "message": "Change year to 2018"
+  }, {
+    "id": "aa24655de48b36335556ac8a3cd8bb521f977cbd",
+    "short_id": "aa24655d",
+    "title": "Update LICENSE",
+    "author_name": "Administrator",
+    "author_email": "admin@example.com",
+    "created_at": "2016-07-25T17:21:53.000+03:00",
+    "message": "Update LICENSE"
+  }, {
+    "id": "3eed087b29835c48015768f839d76e5ea8f07a24",
+    "short_id": "3eed087b",
+    "title": "Add license",
+    "author_name": "Administrator",
+    "author_email": "admin@example.com",
+    "created_at": "2016-07-25T17:21:20.000+03:00",
+    "message": "Add license"
+  }],
+  "diffs": [{
+    "old_path": "LICENSE",
+    "new_path": "LICENSE",
+    "a_mode": "0",
+    "b_mode": "100644",
+    "diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2018 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n",
+    "new_file": true,
+    "renamed_file": false,
+    "deleted_file": false
+  }]
+}
+```
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index a7acf37b5bcc05b9e81fae2e1849b7d39607e4cf..c6685f54a9d297d26499754524d85b0b6db4061a 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -53,7 +53,8 @@ Parameters:
   },
   "expires_at": null,
   "updated_at": "2012-06-28T10:52:04Z",
-  "created_at": "2012-06-28T10:52:04Z"
+  "created_at": "2012-06-28T10:52:04Z",
+  "web_url": "http://example.com/example/example/snippets/1"
 }
 ```
 
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 37d97b2db44691b66a02b54b2aa090c7bd9e92ab..0e4806e31c51810229e99704dc33640bf27b6de0 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -84,7 +84,8 @@ Parameters:
     "star_count": 0,
     "runners_token": "b8547b1dc37721d05889db52fa2f02",
     "public_builds": true,
-    "shared_with_groups": []
+    "shared_with_groups": [],
+    "only_allow_merge_if_build_succeeds": false
   },
   {
     "id": 6,
@@ -144,7 +145,8 @@ Parameters:
     "star_count": 0,
     "runners_token": "b8547b1dc37721d05889db52fa2f02",
     "public_builds": true,
-    "shared_with_groups": []
+    "shared_with_groups": [],
+    "only_allow_merge_if_build_succeeds": false
   }
 ]
 ```
@@ -280,7 +282,8 @@ Parameters:
       "group_name": "Gitlab Org",
       "group_access_level": 10
     }
-  ]
+  ],
+  "only_allow_merge_if_build_succeeds": false
 }
 ```
 
@@ -448,6 +451,7 @@ Parameters:
 - `visibility_level` (optional)
 - `import_url` (optional)
 - `public_builds` (optional)
+- `only_allow_merge_if_build_succeeds` (optional)
 
 ### Create project for user
 
@@ -473,6 +477,7 @@ Parameters:
 - `visibility_level` (optional)
 - `import_url` (optional)
 - `public_builds` (optional)
+- `only_allow_merge_if_build_succeeds` (optional)
 
 ### Edit project
 
@@ -499,6 +504,7 @@ Parameters:
 - `public` (optional) - if `true` same as setting visibility_level = 20
 - `visibility_level` (optional)
 - `public_builds` (optional)
+- `only_allow_merge_if_build_succeeds` (optional)
 
 On success, method returns 200 with the updated project. If parameters are
 invalid, 400 is returned.
@@ -577,7 +583,8 @@ Example response:
   "forks_count": 0,
   "star_count": 1,
   "public_builds": true,
-  "shared_with_groups": []
+  "shared_with_groups": [],
+  "only_allow_merge_if_build_succeeds": false
 }
 ```
 
@@ -643,7 +650,8 @@ Example response:
   "forks_count": 0,
   "star_count": 0,
   "public_builds": true,
-  "shared_with_groups": []
+  "shared_with_groups": [],
+  "only_allow_merge_if_build_succeeds": false
 }
 ```
 
@@ -729,7 +737,8 @@ Example response:
   "star_count": 0,
   "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
   "public_builds": true,
-  "shared_with_groups": []
+  "shared_with_groups": [],
+  "only_allow_merge_if_build_succeeds": false
 }
 ```
 
@@ -815,7 +824,8 @@ Example response:
   "star_count": 0,
   "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
   "public_builds": true,
-  "shared_with_groups": []
+  "shared_with_groups": [],
+  "only_allow_merge_if_build_succeeds": false
 }
 ```
 
@@ -914,7 +924,11 @@ Parameters:
   "push_events": true,
   "issues_events": true,
   "merge_requests_events": true,
+  "tag_push_events": true,
   "note_events": true,
+  "build_events": true,
+  "pipeline_events": true,
+  "wiki_page_events": true,
   "enable_ssl_verification": true,
   "created_at": "2012-10-12T17:04:47Z"
 }
@@ -937,6 +951,9 @@ Parameters:
 - `merge_requests_events` - Trigger hook on merge_requests events
 - `tag_push_events` - Trigger hook on push_tag events
 - `note_events` - Trigger hook on note events
+- `build_events` - Trigger hook on build events
+- `pipeline_events` - Trigger hook on pipeline events
+- `wiki_page_events` - Trigger hook on wiki page events
 - `enable_ssl_verification` - Do SSL verification when triggering the hook
 
 ### Edit project hook
@@ -957,6 +974,9 @@ Parameters:
 - `merge_requests_events` - Trigger hook on merge_requests events
 - `tag_push_events` - Trigger hook on push_tag events
 - `note_events` - Trigger hook on note events
+- `build_events` - Trigger hook on build events
+- `pipeline_events` - Trigger hook on pipeline events
+- `wiki_page_events` - Trigger hook on wiki page events
 - `enable_ssl_verification` - Do SSL verification when triggering the hook
 
 ### Delete project hook
diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md
index 927a18724135411c679050b6a36f7cba28004b12..dc7d832ce3acd65d262d2eebeced45518c8b52f8 100644
--- a/doc/development/doc_styleguide.md
+++ b/doc/development/doc_styleguide.md
@@ -6,7 +6,7 @@ it organized and easy to find.
 ## Location and naming of documents
 
 >**Note:**
-These guidelines derive from the discussion taken place in issue [#3349](ce-3349).
+These guidelines derive from the discussion taken place in issue [#3349][ce-3349].
 
 The documentation hierarchy can be vastly improved by providing a better layout
 and organization of directories.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index b0ec9b4a9611de3c2666858f94a421eacaba7396..d4b89fa834562e9c8974bb7bb4e7a29db44a89e5 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -397,7 +397,7 @@ If you are not using Linux you may have to run `gmake` instead of
     cd /home/git
     sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
     cd gitlab-workhorse
-    sudo -u git -H git checkout v0.7.10
+    sudo -u git -H git checkout v0.7.11
     sudo -u git -H make
 
 ### Initialize Database and Activate Advanced Features
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index a65ac8a5f79adc5c6736de05efa39506f1e7ce9c..571f1a38358a620c257747d18a7f905f12e16506 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -32,7 +32,7 @@ Please consider using a virtual machine to run GitLab.
 
 ## Ruby versions
 
-GitLab requires Ruby (MRI) 2.1.x and currently does not work with versions 2.2 or 2.3.
+GitLab requires Ruby (MRI) 2.3. Support for Ruby versions below 2.3 (2.1, 2.2) will stop with GitLab 8.13.
 
 You will have to use the standard MRI implementation of Ruby.
 We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/) but GitLab
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 70895abbcadc3bb365ebd9fd0ffc254e790f9b39..c2fd299db07a1240770433265f83ba42f2e73cca 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -15,7 +15,7 @@ See the documentation below for details on how to configure these services.
 - [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
 - [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users
 - [Akismet](akismet.md) Configure Akismet to stop spam
-- [Koding](koding.md) Configure Koding to use IDE integration
+- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration
 
 GitLab Enterprise Edition contains [advanced Jenkins support][jenkins].
 
diff --git a/doc/user/account/security.md b/doc/user/account/security.md
new file mode 100644
index 0000000000000000000000000000000000000000..816094bf8d2e33135b680511c21cc786b8eac29a
--- /dev/null
+++ b/doc/user/account/security.md
@@ -0,0 +1,3 @@
+# Account Security
+
+- [Two-Factor Authentication](two_factor_authentication.md)
diff --git a/doc/user/account/two_factor_authentication.md b/doc/user/account/two_factor_authentication.md
new file mode 100644
index 0000000000000000000000000000000000000000..881358ed94dd9156913b57f9597172b09e3dd89e
--- /dev/null
+++ b/doc/user/account/two_factor_authentication.md
@@ -0,0 +1,68 @@
+# Two-Factor Authentication
+
+## Recovery options
+
+If you lose your code generation device (such as your mobile phone) and you need
+to disable two-factor authentication on your account, you have several options.
+
+### Use a saved recovery code
+
+When you enabled two-factor authentication for your account, a series of
+recovery codes were generated. If you saved those codes somewhere safe, you
+may use one to sign in.
+
+First, enter your username/email and password on the GitLab sign in page. When
+prompted for a two-factor code, enter one of the recovery codes you saved
+previously.
+
+> **Note:** Once a particular recovery code has been used, it cannot be used again.
+  You may still use the other saved recovery codes at a later time.
+
+### Generate new recovery codes using SSH
+
+It's not uncommon for users to forget to save the recovery codes when enabling
+two-factor authentication. If you have an SSH key added to your GitLab account,
+you can generate a new set of recovery codes using SSH.
+
+Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to
+confirm that you wish to generate new codes. If you choose to continue, any
+previously saved codes will be invalidated.
+
+```bash
+$ ssh git@gitlab.example.com 2fa_recovery_codes
+Are you sure you want to generate new two-factor recovery codes?
+Any existing recovery codes you saved will be invalidated. (yes/no)
+yes
+
+Your two-factor authentication recovery codes are:
+
+119135e5a3ebce8e
+11f6v2a498810dcd
+3924c7ab2089c902
+e79a3398bfe4f224
+34bd7b74adbc8861
+f061691d5107df1a
+169bf32a18e63e7f
+b510e7422e81c947
+20dbed24c5e74663
+df9d3b9403b9c9f0
+
+During sign in, use one of the codes above when prompted for
+your two-factor code. Then, visit your Profile Settings and add
+a new device so you do not lose access to your account again.
+```
+
+Next, go to the GitLab sign in page and enter your username/email and password.
+When prompted for a two-factor code, enter one of the recovery codes obtained
+from the command line output.
+
+> **Note:** After signing in, you should immediately visit your **Profile Settings
+  -> Account** to set up two-factor authentication with a new device.
+
+### Ask a GitLab administrator to disable two-factor on your account
+
+If the above two methods are not possible, you may ask a GitLab global
+administrator to disable two-factor authentication for your account. Please
+be aware that this will temporarily leave your account in a less secure state.
+You should sign in and re-enable two-factor authentication as soon as possible
+after the administrator disables it.
diff --git a/doc/user/project/img/issue_board.png b/doc/user/project/img/issue_board.png
index accd0900cbbda0d74e19cc41ef545b827ffe243b..63c269f6dbc41a8f9d8db31f485ae95f012473c5 100644
Binary files a/doc/user/project/img/issue_board.png and b/doc/user/project/img/issue_board.png differ
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 9df9ed9c9da1d1eaa10d6715afc2ff6ef9bbdfdd..cac926b3e28fc055747881809ffb467e8198cf28 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -31,10 +31,9 @@ Below is a table of the definitions used for GitLab's Issue Board.
 There are three types of lists, the ones you create based on your labels, and
 two default:
 
-- **Backlog** (default): shows all issues that do not fall in one of the other
-  lists. Always appears on the very left.
-- **Done** (default): shows all closed issues. Always appears on the very right.
-- Label list: a list based on a label. It shows all issues with that label.
+- **Backlog** (default): shows all opened issues that do not fall in one of the other lists. Always appears on the very left.
+- **Done** (default): shows all closed issues that do not fall in one of the other lists. Always appears on the very right.
+- Label list: a list based on a label. It shows all opened or closed issues with that label.
 
 ![GitLab Issue Board](img/issue_board.png)
 
diff --git a/doc/user/project/merge_requests/resolve_conflicts.md b/doc/user/project/merge_requests/resolve_conflicts.md
index 44b76ffc8e689e867b2be786f8e8fb8bd6536f97..4d7225bd820dd7ac334cd40d7425b30b2ddc2cc6 100644
--- a/doc/user/project/merge_requests/resolve_conflicts.md
+++ b/doc/user/project/merge_requests/resolve_conflicts.md
@@ -26,6 +26,7 @@ this is similar to performing `git checkout feature; git merge master` locally.
 GitLab allows resolving conflicts in a file where all of the below are true:
 
 - The file is text, not binary
+- The file is in a UTF-8 compatible encoding
 - The file does not already contain conflict markers
 - The file, with conflict markers added, is not over 200 KB in size
 - The file exists under the same path in both branches
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index 8119324bb62055bd6260554f3af00916a47d5272..7c0eb90d540e85ca0983370311630cb2b80ddd46 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -115,7 +115,7 @@ In this flow it is not common to have a production branch (or git flow master br
 
 Merge or pull requests are created in a git management application and ask an assigned person to merge two branches.
 Tools such as GitHub and Bitbucket choose the name pull request since the first manual action would be to pull the feature branch.
-Tools such as GitLab and Gitorious choose the name merge request since that is the final action that is requested of the assignee.
+Tools such as GitLab and others choose the name merge request since that is the final action that is requested of the assignee.
 In this article we'll refer to them as merge requests.
 
 If you work on a feature branch for more than a few hours it is good to share the intermediate result with the rest of the team.
diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md
index d2ec56e650456cf173004b3ceacce8d0d8bfcddc..40a5e4476be1f67657b6ec060895c9bcde2bd393 100644
--- a/doc/workflow/merge_requests.md
+++ b/doc/workflow/merge_requests.md
@@ -15,6 +15,25 @@ Please note that you need to have builds configured to enable this feature.
 
 ## Checkout merge requests locally
 
+### By adding a git alias
+
+Add the following alias to your `~/.gitconfig`:
+
+```
+[alias]
+    mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' -
+```
+
+Now you can check out a particular merge request from any repository and any remote, e.g. to check out a merge request number 5 as shown in GitLab from the `upstream` remote, do:
+
+```
+$ git mr upstream 5
+```
+
+This will fetch the merge request into a local `mr-upstream-5` branch and check it out.
+
+### By modifying `.git/config` for a given repository
+
 Locate the section for your GitLab remote in the `.git/config` file. It looks like this:
 
 ```
@@ -34,7 +53,7 @@ It should look like this:
   fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
 ```
 
-Now you can fetch all the merge requests requests:
+Now you can fetch all the merge requests:
 
 ```
 $ git fetch origin
@@ -61,3 +80,11 @@ If you click the "Hide whitespace changes" button, you can see the diff without
 It is also working on commits compare view.
 
 ![Commit Compare](merge_requests/commit_compare.png)
+
+## Merge Requests versions
+
+Every time you push to merge request branch, a new version of merge request diff
+is created. When you visit the merge request page you see latest version of changes.
+However you can select an older one from version dropdown
+
+![Merge Request Versions](merge_requests/versions.png)
diff --git a/doc/workflow/merge_requests/versions.png b/doc/workflow/merge_requests/versions.png
new file mode 100644
index 0000000000000000000000000000000000000000..c0a6dfe6806a0baf710b4c1f93fb10836ed7ce8d
Binary files /dev/null and b/doc/workflow/merge_requests/versions.png differ
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 967f2edb243f8f693381d496d4076e967d064085..5aa592e9067ccc9d8cc9f49af8c0e46535b06ad8 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -24,7 +24,7 @@ Feature: Project Merge Requests
   Scenario: I should see target branch when it is different from default
     Given project "Shop" have "Bug NS-06" open merge request
     When I visit project "Shop" merge requests page
-    Then I should see "other_branch" branch
+    Then I should see "feature_conflict" branch
 
   Scenario: I should not see the numbers of diverged commits if the branch is rebased on the target
     Given project "Shop" have "Bug NS-07" open merge request with rebased branch
diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb
index f0d8d498e4623b7e220621ca102f5adec1c0abf0..2f0941e4113df348ddf949ef6ce3718e097d3e37 100644
--- a/features/steps/dashboard/new_project.rb
+++ b/features/steps/dashboard/new_project.rb
@@ -18,7 +18,6 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps
     expect(page).to have_link('GitHub')
     expect(page).to have_link('Bitbucket')
     expect(page).to have_link('GitLab.com')
-    expect(page).to have_link('Gitorious.org')
     expect(page).to have_link('Google Code')
     expect(page).to have_link('Repo by URL')
   end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 9778ff4a6c7d89e5266a31807198df25519686ac..56b289495858ddde4c21dd73e202a3c760673341 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -58,8 +58,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
     expect(find('.merge-request-info')).not_to have_content "master"
   end
 
-  step 'I should see "other_branch" branch' do
-    expect(page).to have_content "other_branch"
+  step 'I should see "feature_conflict" branch' do
+    expect(page).to have_content "feature_conflict"
   end
 
   step 'I should see "Bug NS-04" in merge requests' do
@@ -124,7 +124,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
            source_project: project,
            target_project: project,
            source_branch: 'fix',
-           target_branch: 'other_branch',
+           target_branch: 'feature_conflict',
            author: project.users.first,
            description: "# Description header"
           )
diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb
index aa666a954bca40aed5e359a1b44c8b9c3bee039c..df9845ba569dac0788ce79c6e311246af309a87e 100644
--- a/features/steps/shared/issuable.rb
+++ b/features/steps/shared/issuable.rb
@@ -179,7 +179,7 @@ module SharedIssuable
     project = Project.find_by(name: from_project_name)
 
     expect(page).to have_content(user_name)
-    expect(page).to have_content("mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}")
+    expect(page).to have_content("Mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}")
   end
 
   def expect_sidebar_content(content)
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 6b8bfbbdae6110e5fa5067653d10987d18b77d67..4602e627fdb71b39c1f3b5ee3ccd54eb4c17aaf4 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -18,22 +18,14 @@ module API
     end
 
     rescue_from :all do |exception|
-      # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
-      # why is this not wrapped in something reusable?
-      trace = exception.backtrace
-
-      message = "\n#{exception.class} (#{exception.message}):\n"
-      message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
-      message << "  " << trace.join("\n  ")
-
-      API.logger.add Logger::FATAL, message
-      rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500)
+      handle_api_exception(exception)
     end
 
     format :json
     content_type :txt, "text/plain"
 
     # Ensure the namespace is right, otherwise we might load Grape::API::Helpers
+    helpers ::SentryHelper
     helpers ::API::Helpers
 
     mount ::API::AccessRequests
@@ -75,5 +67,6 @@ module API
     mount ::API::Triggers
     mount ::API::Users
     mount ::API::Variables
+    mount ::API::MergeRequestDiffs
   end
 end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 66b85ab17935e1fc25434d469dc293afffec1853..cbb324dd06d63d48066c28a035978193beecc738 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -49,7 +49,7 @@ module API
     class ProjectHook < Hook
       expose :project_id, :push_events
       expose :issues_events, :merge_requests_events, :tag_push_events
-      expose :note_events, :build_events, :pipeline_events
+      expose :note_events, :build_events, :pipeline_events, :wiki_page_events
       expose :enable_ssl_verification
     end
 
@@ -90,6 +90,7 @@ module API
       expose :shared_with_groups do |project, options|
         SharedGroup.represent(project.project_group_links.all, options)
       end
+      expose :only_allow_merge_if_build_succeeds
     end
 
     class Member < UserBasic
@@ -177,6 +178,10 @@ module API
 
       # TODO (rspeicher): Deprecated; remove in 9.0
       expose(:expires_at) { |snippet| nil }
+
+      expose :web_url do |snippet, options|
+        Gitlab::UrlBuilder.build(snippet)
+      end
     end
 
     class ProjectEntity < Grape::Entity
@@ -206,6 +211,10 @@ module API
       expose :user_notes_count
       expose :upvotes, :downvotes
       expose :due_date
+
+      expose :web_url do |issue, options|
+        Gitlab::UrlBuilder.build(issue)
+      end
     end
 
     class ExternalIssue < Grape::Entity
@@ -229,6 +238,10 @@ module API
       expose :user_notes_count
       expose :should_remove_source_branch?, as: :should_remove_source_branch
       expose :force_remove_source_branch?, as: :force_remove_source_branch
+
+      expose :web_url do |merge_request, options|
+        Gitlab::UrlBuilder.build(merge_request)
+      end
     end
 
     class MergeRequestChanges < MergeRequest
@@ -237,6 +250,19 @@ module API
       end
     end
 
+    class MergeRequestDiff < Grape::Entity
+      expose :id, :head_commit_sha, :base_commit_sha, :start_commit_sha,
+        :created_at, :merge_request_id, :state, :real_size
+    end
+
+    class MergeRequestDiffFull < MergeRequestDiff
+      expose :commits, using: Entities::RepoCommit
+
+      expose :diffs, using: Entities::RepoDiff do |compare, _|
+        compare.raw_diffs(all_diffs: true).to_a
+      end
+    end
+
     class SSHKey < Grape::Entity
       expose :id, :title, :key, :created_at
     end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index d0469d6602d0df0feb595a1285a0c8420703c02b..da4b1bf9902c8493fcaa3fb49dd96e79efad0622 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -279,6 +279,24 @@ module API
       error!({ 'message' => message }, status)
     end
 
+    def handle_api_exception(exception)
+      if sentry_enabled? && report_exception?(exception)
+        define_params_for_grape_middleware
+        sentry_context
+        Raven.capture_exception(exception)
+      end
+
+      # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
+      trace = exception.backtrace
+
+      message = "\n#{exception.class} (#{exception.message}):\n"
+      message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
+      message << "  " << trace.join("\n  ")
+
+      API.logger.add Logger::FATAL, message
+      rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500)
+    end
+
     # Projects helpers
 
     def filter_projects(projects)
@@ -419,5 +437,19 @@ module API
         Entities::Issue
       end
     end
+
+    # The Grape Error Middleware only has access to env but no params. We workaround this by
+    # defining a method that returns the right value.
+    def define_params_for_grape_middleware
+      self.define_singleton_method(:params) { Rack::Request.new(env).params.symbolize_keys }
+    end
+
+    # We could get a Grape or a standard Ruby exception. We should only report anything that
+    # is clearly an error.
+    def report_exception?(exception)
+      return true unless exception.respond_to?(:status)
+
+      exception.status == 500
+    end
   end
 end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index d8e9ac406c4c4067df971508e6c52af123a35224..5b54c11ef62a84c9613b2035bae97147af0faa45 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -101,6 +101,31 @@ module API
           {}
         end
       end
+
+      post '/two_factor_recovery_codes' do
+        status 200
+
+        key = Key.find(params[:key_id])
+        user = key.user
+
+        # Make sure this isn't a deploy key
+        unless key.type.nil?
+          return { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
+        end
+
+        unless user.present?
+          return { success: false, message: 'Could not find a user for the given key' }
+        end
+
+        unless user.two_factor_enabled?
+          return { success: false, message: 'Two-factor authentication is not enabled for this user' }
+        end
+
+        codes = user.generate_otp_backup_codes!
+        user.save!
+
+        { success: true, recovery_codes: codes }
+      end
     end
   end
 end
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
new file mode 100644
index 0000000000000000000000000000000000000000..07435d78468ea343777a66303fc611bba9f9feb1
--- /dev/null
+++ b/lib/api/merge_request_diffs.rb
@@ -0,0 +1,45 @@
+module API
+  # MergeRequestDiff API
+  class MergeRequestDiffs < Grape::API
+    before { authenticate! }
+
+    resource :projects do
+      desc 'Get a list of merge request diff versions' do
+        detail 'This feature was introduced in GitLab 8.12.'
+        success Entities::MergeRequestDiff
+      end
+
+      params do
+        requires :id, type: String, desc: 'The ID of a project'
+        requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
+      end
+
+      get ":id/merge_requests/:merge_request_id/versions" do
+        merge_request = user_project.merge_requests.
+          find(params[:merge_request_id])
+
+        authorize! :read_merge_request, merge_request
+        present merge_request.merge_request_diffs, with: Entities::MergeRequestDiff
+      end
+
+      desc 'Get a single merge request diff version' do
+        detail 'This feature was introduced in GitLab 8.12.'
+        success Entities::MergeRequestDiffFull
+      end
+
+      params do
+        requires :id, type: String, desc: 'The ID of a project'
+        requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
+        requires :version_id, type: Integer, desc: 'The ID of a merge request diff version'
+      end
+
+      get ":id/merge_requests/:merge_request_id/versions/:version_id" do
+        merge_request = user_project.merge_requests.
+          find(params[:merge_request_id])
+
+        authorize! :read_merge_request, merge_request
+        present merge_request.merge_request_diffs.find(params[:version_id]), with: Entities::MergeRequestDiffFull
+      end
+    end
+  end
+end
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 3f63cd678e8f3ae2fa5295911af695f6db7aeeba..14f5be3b5f64bef5a0cc2e8bfba22eda9c276863 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -46,6 +46,7 @@ module API
           :note_events,
           :build_events,
           :pipeline_events,
+          :wiki_page_events,
           :enable_ssl_verification
         ]
         @hook = user_project.hooks.new(attrs)
@@ -80,6 +81,7 @@ module API
           :note_events,
           :build_events,
           :pipeline_events,
+          :wiki_page_events,
           :enable_ssl_verification
         ]
 
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 60cfc103afd27f94a8b5afc360f970a41c7fca4a..71efd4f33ca6d2c5d0905e8ee58c17c0b1668f79 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -123,7 +123,8 @@ module API
                                      :public,
                                      :visibility_level,
                                      :import_url,
-                                     :public_builds]
+                                     :public_builds,
+                                     :only_allow_merge_if_build_succeeds]
         attrs = map_public_to_visibility_level(attrs)
         @project = ::Projects::CreateService.new(current_user, attrs).execute
         if @project.saved?
@@ -172,7 +173,8 @@ module API
                                      :public,
                                      :visibility_level,
                                      :import_url,
-                                     :public_builds]
+                                     :public_builds,
+                                     :only_allow_merge_if_build_succeeds]
         attrs = map_public_to_visibility_level(attrs)
         @project = ::Projects::CreateService.new(user, attrs).execute
         if @project.saved?
@@ -234,7 +236,8 @@ module API
                                      :shared_runners_enabled,
                                      :public,
                                      :visibility_level,
-                                     :public_builds]
+                                     :public_builds,
+                                     :only_allow_merge_if_build_succeeds]
         attrs = map_public_to_visibility_level(attrs)
         authorize_admin_project
         authorize! :rename_project, user_project if attrs[:name].present?
diff --git a/lib/ci/api/api.rb b/lib/ci/api/api.rb
index 17bb99a2ae50248da39cb42fe1e545daa8b7f57e..a6b9beecded18128ccd4ee5d3b7217e05918edff 100644
--- a/lib/ci/api/api.rb
+++ b/lib/ci/api/api.rb
@@ -9,22 +9,14 @@ module Ci
       end
 
       rescue_from :all do |exception|
-        # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
-        # why is this not wrapped in something reusable?
-        trace = exception.backtrace
-
-        message = "\n#{exception.class} (#{exception.message}):\n"
-        message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
-        message << "  " << trace.join("\n  ")
-
-        API.logger.add Logger::FATAL, message
-        rack_response({ 'message' => '500 Internal Server Error' }, 500)
+        handle_api_exception(exception)
       end
 
       content_type :txt,  'text/plain'
       content_type :json, 'application/json'
       format :json
 
+      helpers ::SentryHelper
       helpers ::Ci::API::Helpers
       helpers ::API::Helpers
       helpers Gitlab::CurrentSettings
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index a293fa2752f8ab7878d4cfb7c358049f2b649247..a4558d157c0480408bd6b18433e7f6f22cc62588 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -94,9 +94,7 @@ module ExtractsPath
     @options = params.select {|key, value| allowed_options.include?(key) && !value.blank? }
     @options = HashWithIndifferentAccess.new(@options)
 
-    @id = params[:id] || params[:ref]
-    @id += "/" + params[:path] unless params[:path].blank?
-
+    @id = get_id
     @ref, @path = extract_ref(@id)
     @repo = @project.repository
     if @options[:extended_sha1].blank?
@@ -118,4 +116,13 @@ module ExtractsPath
   def tree
     @tree ||= @repo.tree(@commit.id, @path)
   end
+
+  private
+
+  # overriden in subclasses, do not remove
+  def get_id
+    id = params[:id] || params[:ref]
+    id += "/" + params[:path] unless params[:path].blank?
+    id
+  end
 end
diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb
index 0a1fd27ced542e1e8c8848217f6d96eb97187075..dff9e29c6a5f8fdf0562c6ab0616405e802de26d 100644
--- a/lib/gitlab/conflict/file.rb
+++ b/lib/gitlab/conflict/file.rb
@@ -181,6 +181,17 @@ module Gitlab
           sections: sections
         }
       end
+
+      # Don't try to print merge_request or repository.
+      def inspect
+        instance_variables = [:merge_file_result, :their_path, :our_path, :our_mode].map do |instance_variable|
+          value = instance_variable_get("@#{instance_variable}")
+
+          "#{instance_variable}=\"#{value}\""
+        end
+
+        "#<#{self.class} #{instance_variables.join(' ')}>"
+      end
     end
   end
 end
diff --git a/lib/gitlab/conflict/parser.rb b/lib/gitlab/conflict/parser.rb
index 6eccded7872791b5c6fab5ec2da4a1dc5e8f01fb..2d4d55daeeb998be824eed7385e62ac7b29f36fd 100644
--- a/lib/gitlab/conflict/parser.rb
+++ b/lib/gitlab/conflict/parser.rb
@@ -13,10 +13,19 @@ module Gitlab
       class UnmergeableFile < ParserError
       end
 
+      class UnsupportedEncoding < ParserError
+      end
+
       def parse(text, our_path:, their_path:, parent_file: nil)
         raise UnmergeableFile if text.blank? # Typically a binary file
         raise UnmergeableFile if text.length > 102400
 
+        begin
+          text.to_json
+        rescue Encoding::UndefinedConversionError
+          raise UnsupportedEncoding
+        end
+
         line_obj_index = 0
         line_old = 1
         line_new = 1
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 9dc2602867e07da8731da1eedb2cb31796a03596..bd681f03173a41b71c0b552543371a91e8828cad 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -23,7 +23,6 @@ module Gitlab
 
       dates.each do |date|
         date_id = date.to_time.to_i.to_s
-        @timestamps[date_id] = 0
         day_events = events.find { |day_events| day_events["date"] == date }
 
         if day_events
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 27acd817e516511ee304fefd3f465a8d79ad28a1..12fbb78c53e2e56f723b862fbdd5af654ccce9b6 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -41,7 +41,7 @@ module Gitlab
         default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
         default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
         domain_whitelist: Settings.gitlab['domain_whitelist'],
-        import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project],
+        import_sources: %w[github bitbucket gitlab google_code fogbugz git gitlab_project],
         shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
         max_artifacts_size: Settings.artifacts['max_size'],
         require_two_factor_authentication: false,
diff --git a/lib/gitlab/diff/file_collection/merge_request.rb b/lib/gitlab/diff/file_collection/merge_request_diff.rb
similarity index 83%
rename from lib/gitlab/diff/file_collection/merge_request.rb
rename to lib/gitlab/diff/file_collection/merge_request_diff.rb
index 4f946908e2f9c63eb42ad71030d0511ad71402f3..36348b339430d4fe9be533d2bb51426000a3146e 100644
--- a/lib/gitlab/diff/file_collection/merge_request.rb
+++ b/lib/gitlab/diff/file_collection/merge_request_diff.rb
@@ -1,14 +1,14 @@
 module Gitlab
   module Diff
     module FileCollection
-      class MergeRequest < Base
-        def initialize(merge_request, diff_options:)
-          @merge_request = merge_request
+      class MergeRequestDiff < Base
+        def initialize(merge_request_diff, diff_options:)
+          @merge_request_diff = merge_request_diff
 
-          super(merge_request,
-            project: merge_request.project,
+          super(merge_request_diff,
+            project: merge_request_diff.project,
             diff_options: diff_options,
-            diff_refs: merge_request.diff_refs)
+            diff_refs: merge_request_diff.diff_refs)
         end
 
         def diff_files
@@ -61,11 +61,11 @@ module Gitlab
         end
 
         def cacheable?
-          @merge_request.merge_request_diff.present?
+          @merge_request_diff.present?
         end
 
         def cache_key
-          [@merge_request.merge_request_diff, 'highlighted-diff-files', diff_options]
+          [@merge_request_diff, 'highlighted-diff-files', diff_options]
         end
       end
     end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 9ddc8905bd6149f32bf58fbb896afc45787613c5..02ffb43d89bd42e3c4da8ca049cd02d9e5cc7bfb 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -3,12 +3,13 @@ module Gitlab
     class Importer
       include Gitlab::ShellAdapter
 
-      attr_reader :client, :project, :repo, :repo_url
+      attr_reader :client, :errors, :project, :repo, :repo_url
 
       def initialize(project)
         @project  = project
         @repo     = project.import_source
         @repo_url = project.import_url
+        @errors   = []
 
         if credentials
           @client = Client.new(credentials[:user])
@@ -18,8 +19,14 @@ module Gitlab
       end
 
       def execute
-        import_labels && import_milestones && import_issues &&
-          import_pull_requests && import_wiki
+        import_labels
+        import_milestones
+        import_issues
+        import_pull_requests
+        import_wiki
+        handle_errors
+
+        true
       end
 
       private
@@ -28,22 +35,37 @@ module Gitlab
         @credentials ||= project.import_data.credentials if project.import_data
       end
 
+      def handle_errors
+        return unless errors.any?
+
+        project.update_column(:import_error, {
+          message: 'The remote data could not be fully imported.',
+          errors: errors
+        }.to_json)
+      end
+
       def import_labels
         labels = client.labels(repo, per_page: 100)
-        labels.each { |raw| LabelFormatter.new(project, raw).create! }
 
-        true
-      rescue ActiveRecord::RecordInvalid => e
-        raise Projects::ImportService::Error, e.message
+        labels.each do |raw|
+          begin
+            LabelFormatter.new(project, raw).create!
+          rescue => e
+            errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
+          end
+        end
       end
 
       def import_milestones
         milestones = client.milestones(repo, state: :all, per_page: 100)
-        milestones.each { |raw| MilestoneFormatter.new(project, raw).create! }
 
-        true
-      rescue ActiveRecord::RecordInvalid => e
-        raise Projects::ImportService::Error, e.message
+        milestones.each do |raw|
+          begin
+            MilestoneFormatter.new(project, raw).create!
+          rescue => e
+            errors << { type: :milestone, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
+          end
+        end
       end
 
       def import_issues
@@ -53,15 +75,15 @@ module Gitlab
           gh_issue = IssueFormatter.new(project, raw)
 
           if gh_issue.valid?
-            issue = gh_issue.create!
-            apply_labels(issue)
-            import_comments(issue) if gh_issue.has_comments?
+            begin
+              issue = gh_issue.create!
+              apply_labels(issue)
+              import_comments(issue) if gh_issue.has_comments?
+            rescue => e
+              errors << { type: :issue, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
+            end
           end
         end
-
-        true
-      rescue ActiveRecord::RecordInvalid => e
-        raise Projects::ImportService::Error, e.message
       end
 
       def import_pull_requests
@@ -77,14 +99,12 @@ module Gitlab
             apply_labels(merge_request)
             import_comments(merge_request)
             import_comments_on_diff(merge_request)
-          rescue ActiveRecord::RecordInvalid => e
-            raise Projects::ImportService::Error, e.message
+          rescue => e
+            errors << { type: :pull_request, url: Gitlab::UrlSanitizer.sanitize(pull_request.url), errors: e.message }
           ensure
             clean_up_restored_branches(pull_request)
           end
         end
-
-        true
       end
 
       def restore_source_branch(pull_request)
@@ -98,7 +118,7 @@ module Gitlab
       def remove_branch(name)
         project.repository.delete_branch(name)
       rescue Rugged::ReferenceError
-        nil
+        errors << { type: :remove_branch, name: name }
       end
 
       def clean_up_restored_branches(pull_request)
@@ -112,9 +132,10 @@ module Gitlab
         issue = client.issue(repo, issuable.iid)
 
         if issue.labels.count > 0
-          label_ids = issue.labels.map do |raw|
-            Label.find_by(LabelFormatter.new(project, raw).attributes).try(:id)
-          end
+          label_ids = issue.labels
+            .map { |raw| LabelFormatter.new(project, raw).attributes }
+            .map { |attrs| Label.find_by(attrs).try(:id) }
+            .compact
 
           issuable.update_attribute(:label_ids, label_ids)
         end
@@ -132,8 +153,12 @@ module Gitlab
 
       def create_comments(issuable, comments)
         comments.each do |raw|
-          comment = CommentFormatter.new(project, raw)
-          issuable.notes.create!(comment.attributes)
+          begin
+            comment = CommentFormatter.new(project, raw)
+            issuable.notes.create!(comment.attributes)
+          rescue => e
+            errors << { type: :comment, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
+          end
         end
       end
 
@@ -143,16 +168,12 @@ module Gitlab
           gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url)
           project.update_attribute(:wiki_enabled, true)
         end
-
-        true
       rescue Gitlab::Shell::Error => e
         # GitHub error message when the wiki repo has not been created,
         # this means that repo has wiki enabled, but have no pages. So,
         # we can skip the import.
         if e.message !~ /repository not exported/
-          raise Projects::ImportService::Error, e.message
-        else
-          true
+          errors << { type: :wiki, errors: e.message }
         end
       end
     end
diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb
index b84538a090a268a0e97af332dd2528579941ecb1..04aa3664f640388dfa0de539512496f60048f594 100644
--- a/lib/gitlab/github_import/pull_request_formatter.rb
+++ b/lib/gitlab/github_import/pull_request_formatter.rb
@@ -56,6 +56,10 @@ module Gitlab
         end
       end
 
+      def url
+        raw_data.url
+      end
+
       private
 
       def assigned?
diff --git a/lib/gitlab/gitorious_import.rb b/lib/gitlab/gitorious_import.rb
deleted file mode 100644
index 8d0132a744cac5ca1848541c6c01404e6125b0d7..0000000000000000000000000000000000000000
--- a/lib/gitlab/gitorious_import.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module Gitlab
-  module GitoriousImport
-    GITORIOUS_HOST = "https://gitorious.org"
-  end
-end
diff --git a/lib/gitlab/gitorious_import/client.rb b/lib/gitlab/gitorious_import/client.rb
deleted file mode 100644
index 99fe5bdebfcf1a4cdf26b59373ee9a606bc62c19..0000000000000000000000000000000000000000
--- a/lib/gitlab/gitorious_import/client.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-module Gitlab
-  module GitoriousImport
-    class Client
-      attr_reader :repo_list
-
-      def initialize(repo_list)
-        @repo_list = repo_list
-      end
-
-      def authorize_url(redirect_uri)
-        "#{GITORIOUS_HOST}/gitlab-import?callback_url=#{redirect_uri}"
-      end
-
-      def repos
-        @repos ||= repo_names.map { |full_name| GitoriousImport::Repository.new(full_name) }
-      end
-
-      def repo(id)
-        repos.find { |repo| repo.id == id }
-      end
-
-      private
-
-      def repo_names
-        repo_list.to_s.split(',').map(&:strip).reject(&:blank?)
-      end
-    end
-  end
-end
diff --git a/lib/gitlab/gitorious_import/project_creator.rb b/lib/gitlab/gitorious_import/project_creator.rb
deleted file mode 100644
index 8e22aa9286ddf4d2a332f2daca87a6ab5f2eee9d..0000000000000000000000000000000000000000
--- a/lib/gitlab/gitorious_import/project_creator.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-module Gitlab
-  module GitoriousImport
-    class ProjectCreator
-      attr_reader :repo, :namespace, :current_user
-
-      def initialize(repo, namespace, current_user)
-        @repo = repo
-        @namespace = namespace
-        @current_user = current_user
-      end
-
-      def execute
-        ::Projects::CreateService.new(
-          current_user,
-          name: repo.name,
-          path: repo.path,
-          description: repo.description,
-          namespace_id: namespace.id,
-          visibility_level: Gitlab::VisibilityLevel::PUBLIC,
-          import_type: "gitorious",
-          import_source: repo.full_name,
-          import_url: repo.import_url
-        ).execute
-      end
-    end
-  end
-end
diff --git a/lib/gitlab/gitorious_import/repository.rb b/lib/gitlab/gitorious_import/repository.rb
deleted file mode 100644
index c88f1ae358d1ce61b9ea95c84707577ad1c458ac..0000000000000000000000000000000000000000
--- a/lib/gitlab/gitorious_import/repository.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-module Gitlab
-  module GitoriousImport
-    Repository = Struct.new(:full_name) do
-      def id
-        Digest::SHA1.hexdigest(full_name)
-      end
-
-      def namespace
-        segments.first
-      end
-
-      def path
-        segments.last
-      end
-
-      def name
-        path.titleize
-      end
-
-      def description
-        ""
-      end
-
-      def import_url
-        "#{GITORIOUS_HOST}/#{full_name}.git"
-      end
-
-      private
-
-      def segments
-        full_name.split('/')
-      end
-    end
-  end
-end
diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb
index 59a05411fe9dc36395087ced47fb0ecc3e9bfd59..94261b7eeeded0b6e1760473f647c6e3d899a1bd 100644
--- a/lib/gitlab/import_sources.rb
+++ b/lib/gitlab/import_sources.rb
@@ -14,13 +14,12 @@ module Gitlab
 
       def options
         {
-          'GitHub'          => 'github',
-          'Bitbucket'       => 'bitbucket',
-          'GitLab.com'      => 'gitlab',
-          'Gitorious.org'   => 'gitorious',
-          'Google Code'     => 'google_code',
-          'FogBugz'         => 'fogbugz',
-          'Repo by URL'     => 'git',
+          'GitHub'        => 'github',
+          'Bitbucket'     => 'bitbucket',
+          'GitLab.com'    => 'gitlab',
+          'Google Code'   => 'google_code',
+          'FogBugz'       => 'fogbugz',
+          'Repo by URL'   => 'git',
           'GitLab export' => 'gitlab_project'
         }
       end
diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb
index b4493bf44d28eacde9d5828ab30db6598aa48ed7..01c96a6fe960f223a7fce9b836291a83d39fd328 100644
--- a/lib/gitlab/metrics/rack_middleware.rb
+++ b/lib/gitlab/metrics/rack_middleware.rb
@@ -4,6 +4,17 @@ module Gitlab
     class RackMiddleware
       CONTROLLER_KEY = 'action_controller.instance'
       ENDPOINT_KEY   = 'api.endpoint'
+      CONTENT_TYPES = {
+        'text/html' => :html,
+        'text/plain' => :txt,
+        'application/json' => :json,
+        'text/js' => :js,
+        'application/atom+xml' => :atom,
+        'image/png' => :png,
+        'image/jpeg' => :jpeg,
+        'image/gif' => :gif,
+        'image/svg+xml' => :svg
+      }
 
       def initialize(app)
         @app = app
@@ -46,8 +57,15 @@ module Gitlab
       end
 
       def tag_controller(trans, env)
-        controller   = env[CONTROLLER_KEY]
-        trans.action = "#{controller.class.name}##{controller.action_name}"
+        controller = env[CONTROLLER_KEY]
+        action = "#{controller.class.name}##{controller.action_name}"
+        suffix = CONTENT_TYPES[controller.content_type]
+
+        if suffix && suffix != :html
+          action += ".#{suffix}"
+        end
+
+        trans.action = action
       end
 
       def tag_endpoint(trans, env)
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index fe65c246101e99c4aeac07f576a36f85c6491168..99d0c28e7493911e9c8789b43599a75938b34ca0 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -22,6 +22,8 @@ module Gitlab
         note_url
       when WikiPage
         wiki_page_url
+      when ProjectSnippet
+        project_snippet_url(object)
       else
         raise NotImplementedError.new("No URL builder defined for #{object.class}")
       end
diff --git a/spec/controllers/import/gitorious_controller_spec.rb b/spec/controllers/import/gitorious_controller_spec.rb
deleted file mode 100644
index 4ae2b78e11cb1e6befedba1f0b908dd49b835f29..0000000000000000000000000000000000000000
--- a/spec/controllers/import/gitorious_controller_spec.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require 'spec_helper'
-
-describe Import::GitoriousController do
-  include ImportSpecHelper
-
-  let(:user) { create(:user) }
-
-  before do
-    sign_in(user)
-  end
-
-  describe "GET new" do
-    it "redirects to import endpoint on gitorious.org" do
-      get :new
-
-      expect(controller).to redirect_to("https://gitorious.org/gitlab-import?callback_url=http://test.host/import/gitorious/callback")
-    end
-  end
-
-  describe "GET callback" do
-    it "stores repo list in session" do
-      get :callback, repos: 'foo/bar,baz/qux'
-
-      expect(session[:gitorious_repos]).to eq('foo/bar,baz/qux')
-    end
-  end
-
-  describe "GET status" do
-    before do
-      @repo = OpenStruct.new(full_name: 'asd/vim')
-    end
-
-    it "assigns variables" do
-      @project = create(:project, import_type: 'gitorious', creator_id: user.id)
-      stub_client(repos: [@repo])
-
-      get :status
-
-      expect(assigns(:already_added_projects)).to eq([@project])
-      expect(assigns(:repos)).to eq([@repo])
-    end
-
-    it "does not show already added project" do
-      @project = create(:project, import_type: 'gitorious', creator_id: user.id, import_source: 'asd/vim')
-      stub_client(repos: [@repo])
-
-      get :status
-
-      expect(assigns(:already_added_projects)).to eq([@project])
-      expect(assigns(:repos)).to eq([])
-    end
-  end
-
-  describe "POST create" do
-    before do
-      @repo = Gitlab::GitoriousImport::Repository.new('asd/vim')
-    end
-
-    it "takes already existing namespace" do
-      namespace = create(:namespace, name: "asd", owner: user)
-      expect(Gitlab::GitoriousImport::ProjectCreator).
-        to receive(:new).with(@repo, namespace, user).
-        and_return(double(execute: true))
-      stub_client(repo: @repo)
-
-      post :create, format: :js
-    end
-  end
-end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 0836b71056c7a7d0e44266b3dbb61ba991e494f0..16929767ddf7250f6f70e79d6ef4edd187357d38 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -8,13 +8,13 @@ describe Projects::IssuesController do
   describe "GET #index" do
     context 'external issue tracker' do
       it 'redirects to the external issue tracker' do
-        external = double(issues_url: 'https://example.com/issues')
+        external = double(project_path: 'https://example.com/project')
         allow(project).to receive(:external_issue_tracker).and_return(external)
         controller.instance_variable_set(:@project, project)
 
         get :index, namespace_id: project.namespace.path, project_id: project
 
-        expect(response).to redirect_to('https://example.com/issues')
+        expect(response).to redirect_to('https://example.com/project')
       end
     end
 
diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb
index 4fd51a2349060aa4ccc53f96720dbc66deba525e..424ecc65759c563bf8562470c9f18e617167fcb4 100644
--- a/spec/factories/project_hooks.rb
+++ b/spec/factories/project_hooks.rb
@@ -14,6 +14,7 @@ FactoryGirl.define do
       note_events true
       build_events true
       pipeline_events true
+      wiki_page_events true
     end
   end
 end
diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb
index f4e5c26b51918579b76041fd35ae40d7f8d973e6..1df972843e2e9c3e678b943b48ec1f006d2bc98c 100644
--- a/spec/features/admin/admin_system_info_spec.rb
+++ b/spec/features/admin/admin_system_info_spec.rb
@@ -6,12 +6,49 @@ describe 'Admin System Info' do
   end
 
   describe 'GET /admin/system_info' do
-    it 'shows system info page' do
-      visit admin_system_info_path
+    let(:cpu) { double(:cpu, length: 2) }
+    let(:memory) { double(:memory, active_bytes: 4294967296, total_bytes: 17179869184) }
 
-      expect(page).to have_content 'CPU'
-      expect(page).to have_content 'Memory'
-      expect(page).to have_content 'Disks'
+    context 'when all info is available' do
+      before do
+        allow(Vmstat).to receive(:cpu).and_return(cpu)
+        allow(Vmstat).to receive(:memory).and_return(memory)
+        visit admin_system_info_path
+      end
+
+      it 'shows system info page' do
+        expect(page).to have_content 'CPU 2 cores'
+        expect(page).to have_content 'Memory 4 GB / 16 GB'
+        expect(page).to have_content 'Disks'
+      end
+    end
+
+    context 'when CPU info is not available' do
+      before do
+        allow(Vmstat).to receive(:cpu).and_raise(Errno::ENOENT)
+        allow(Vmstat).to receive(:memory).and_return(memory)
+        visit admin_system_info_path
+      end
+
+      it 'shows system info page with no CPU info' do
+        expect(page).to have_content 'CPU Unable to collect CPU info'
+        expect(page).to have_content 'Memory 4 GB / 16 GB'
+        expect(page).to have_content 'Disks'
+      end
+    end
+
+    context 'when memory info is not available' do
+      before do
+        allow(Vmstat).to receive(:cpu).and_return(cpu)
+        allow(Vmstat).to receive(:memory).and_raise(Errno::ENOENT)
+        visit admin_system_info_path
+      end
+
+      it 'shows system info page with no CPU info' do
+        expect(page).to have_content 'CPU 2 cores'
+        expect(page).to have_content 'Memory Unable to collect memory info'
+        expect(page).to have_content 'Disks'
+      end
     end
   end
 end
diff --git a/spec/features/issues/new_branch_button_spec.rb b/spec/features/issues/new_branch_button_spec.rb
index e528aff4d41454920daab187a0c44d1bdf8e98b5..fb0c47042857b1184fb362b7ed3ae01fd3f470c0 100644
--- a/spec/features/issues/new_branch_button_spec.rb
+++ b/spec/features/issues/new_branch_button_spec.rb
@@ -20,7 +20,7 @@ feature 'Start new branch from an issue', feature: true do
     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}")
+                                          note: "Mentioned in !#{referenced_mr.iid}")
       end
       let(:referenced_mr) do
         create(:merge_request, :simple, source_project: project, target_project: project,
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index 930c36ade2bf48ef77e589545c477a70f24be605..759edf8ec80c5bb968604701df27ce9e3a987504 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -43,7 +43,8 @@ feature 'Merge request conflict resolution', js: true, feature: true do
     'conflict-too-large' => 'when the conflicts contain a large file',
     'conflict-binary-file' => 'when the conflicts contain a binary file',
     'conflict-contains-conflict-markers' => 'when the conflicts contain a file with ambiguous conflict markers',
-    'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another'
+    'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another',
+    'conflict-non-utf8' => 'when the conflicts contain a non-UTF-8 file',
   }
 
   UNRESOLVABLE_CONFLICTS.each do |source_branch, description|
diff --git a/spec/features/merge_requests/merge_request_versions_spec.rb b/spec/features/merge_requests/merge_request_versions_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..577c910f11b1fd186074b6f0fe6b8282163c98f8
--- /dev/null
+++ b/spec/features/merge_requests/merge_request_versions_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+feature 'Merge Request versions', js: true, feature: true do
+  before do
+    login_as :admin
+    merge_request = create(:merge_request, importing: true)
+    merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
+    merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e')
+    project = merge_request.source_project
+    visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+  end
+
+  it 'show the latest version of the diff' do
+    page.within '.mr-version-switch' do
+      expect(page).to have_content 'Version: latest'
+    end
+
+    expect(page).to have_content '8 changed files'
+  end
+
+  describe 'switch between versions' do
+    before do
+      page.within '.mr-version-switch' do
+        find('.btn-link').click
+        click_link '6f6d7e7e'
+      end
+    end
+
+    it 'should show older version' do
+      page.within '.mr-version-switch' do
+        expect(page).to have_content 'Version: 6f6d7e7e'
+      end
+
+      expect(page).to have_content '5 changed files'
+    end
+  end
+end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 7a9edbbe33968fda188cd4f9772f80b9013181c2..f1c522155d36d254ee98af97c12d94fad53866c4 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -141,7 +141,7 @@ describe 'Comments', feature: true do
     let(:project2) { create(:project, :private) }
     let(:issue) { create(:issue, project: project2) }
     let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'markdown') }
-    let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: project, note: "mentioned in #{issue.to_reference(project)}") }
+    let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: project, note: "Mentioned in #{issue.to_reference(project)}") }
 
     it 'shows the system note' do
       login_as :admin
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index 0342f4f1d97e31b9dcde976092e1af23354cf940..32544f3f53802b7dbd769a241ea2e19530981257 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -41,6 +41,27 @@ describe 'Dashboard Todos', feature: true do
           expect(page).to have_content("You're all done!")
         end
       end
+
+      context 'todo is stale on the page' do
+        before do
+          todos = TodosFinder.new(user, state: :pending).execute
+          TodoService.new.mark_todos_as_done(todos, user)
+        end
+
+        describe 'deleting the todo' do
+          before do
+            first('.done-todo').click
+          end
+
+          it 'is removed from the list' do
+            expect(page).not_to have_selector('.todos-list .todo')
+          end
+
+          it 'shows "All done" message' do
+            expect(page).to have_content("You're all done!")
+          end
+        end
+      end
     end
 
     context 'User has Todos with labels spanning multiple projects' do
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 604204cca0a4c3a6ce760694bd4101d50990fde0..284b58d8d5cad0ee1ecc1c919ba022c7e6071659 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -136,4 +136,42 @@ describe ProjectsHelper do
       expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git')
     end
   end
+
+  describe '#last_push_event' do
+    let(:user) { double(:user, fork_of: nil) }
+    let(:project) { double(:project, id: 1) }
+
+    before do
+      allow(helper).to receive(:current_user).and_return(user)
+      helper.instance_variable_set(:@project, project)
+    end
+
+    context 'when there is no current_user' do
+      let(:user) { nil }
+
+      it 'returns nil' do
+        expect(helper.last_push_event).to eq(nil)
+      end
+    end
+
+    it 'returns recent push on the current project' do
+      event = double(:event)
+      expect(user).to receive(:recent_push).with([project.id]).and_return(event)
+
+      expect(helper.last_push_event).to eq(event)
+    end
+
+    context 'when current user has a fork of the current project' do
+      let(:fork) { double(:fork, id: 2) }
+
+      it 'returns recent push considering fork events' do
+        expect(user).to receive(:fork_of).with(project).and_return(fork)
+
+        event_on_fork = double(:event)
+        expect(user).to receive(:recent_push).with([project.id, fork.id]).and_return(event_on_fork)
+
+        expect(helper.last_push_event).to eq(event_on_fork)
+      end
+    end
+  end
 end
diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js
index fa32d0d7da5760f284e27bce7c2e334729102fcb..c1c12b57b532bbc91f3865ab002bcbbe6aa3e6a1 100644
--- a/spec/javascripts/awards_handler_spec.js
+++ b/spec/javascripts/awards_handler_spec.js
@@ -11,7 +11,7 @@
 /*= require ./fixtures/emoji_menu */
 
 (function() {
-  var awardsHandler, lazyAssert;
+  var awardsHandler, lazyAssert, urlRoot;
 
   awardsHandler = null;
 
@@ -27,6 +27,7 @@
   };
 
   gon.award_menu_url = '/emojis';
+  urlRoot = gon.relative_url_root;
 
   lazyAssert = function(done, assertFn) {
     return setTimeout(function() {
@@ -45,9 +46,14 @@
           return cb();
         };
       })(this));
-      return spyOn(jQuery, 'get').and.callFake(function(req, cb) {
+      spyOn(jQuery, 'get').and.callFake(function(req, cb) {
         return cb(window.emojiMenu);
       });
+      spyOn(jQuery, 'cookie');
+    });
+    afterEach(function() {
+      // restore original url root value
+      gon.relative_url_root = urlRoot;
     });
     describe('::showEmojiMenu', function() {
       it('should show emoji menu when Add emoji button clicked', function(done) {
@@ -189,6 +195,28 @@
         return expect($thumbsUpEmoji.data("original-title")).toBe('sam');
       });
     });
+    describe('::addEmojiToFrequentlyUsedList', function() {
+      it('should set a cookie with the correct default path', function() {
+        gon.relative_url_root = '';
+        awardsHandler.addEmojiToFrequentlyUsedList('sunglasses');
+        expect(jQuery.cookie)
+          .toHaveBeenCalledWith('frequently_used_emojis', 'sunglasses', {
+            path: '/',
+            expires: 365
+          })
+        ;
+      });
+      it('should set a cookie with the correct custom root path', function() {
+        gon.relative_url_root = '/gitlab/subdir';
+        awardsHandler.addEmojiToFrequentlyUsedList('alien');
+        expect(jQuery.cookie)
+          .toHaveBeenCalledWith('frequently_used_emojis', 'alien', {
+            path: '/gitlab/subdir',
+            expires: 365
+          })
+        ;
+      });
+    });
     describe('search', function() {
       return it('should filter the emoji', function() {
         $('.js-add-award').eq(0).click();
diff --git a/spec/javascripts/datetime_utility_spec.js.coffee b/spec/javascripts/datetime_utility_spec.js.coffee
index 6b9617341fe7b34dc86fe374ebfa2ccb9bea4ee6..8bd113e7d860ff679d7deeaa6b4527779ab6e001 100644
--- a/spec/javascripts/datetime_utility_spec.js.coffee
+++ b/spec/javascripts/datetime_utility_spec.js.coffee
@@ -29,3 +29,22 @@ describe 'Date time utils', ->
     it 'should return Saturday', ->
       day = gl.utils.getDayName(new Date('07/23/2016'))
       expect(day).toBe('Saturday')
+
+  describe 'get day difference', ->
+    it 'should return 7', ->
+      firstDay = new Date('07/01/2016')
+      secondDay = new Date('07/08/2016')
+      difference = gl.utils.getDayDifference(firstDay, secondDay)
+      expect(difference).toBe(7)
+
+    it 'should return 31', ->
+      firstDay = new Date('07/01/2016')
+      secondDay = new Date('08/01/2016')
+      difference = gl.utils.getDayDifference(firstDay, secondDay)
+      expect(difference).toBe(31)
+
+    it 'should return 365', ->
+      firstDay = new Date('07/02/2015')
+      secondDay = new Date('07/01/2016')
+      difference = gl.utils.getDayDifference(firstDay, secondDay)
+      expect(difference).toBe(365)
\ No newline at end of file
diff --git a/spec/javascripts/fixtures/awards_handler.html.haml b/spec/javascripts/fixtures/awards_handler.html.haml
index d55936ee4f9e61f737c735b8e4212a92288e519e..1ef2e8f862496436a5a60d1cfabd73fd7535093d 100644
--- a/spec/javascripts/fixtures/awards_handler.html.haml
+++ b/spec/javascripts/fixtures/awards_handler.html.haml
@@ -39,7 +39,7 @@
                     %span.note-role Reporter
                     %a.note-action-button.note-emoji-button.js-add-award.js-note-emoji{"data-position" => "right", :href => "#", :title => "Award Emoji"}
                       %i.fa.fa-spinner.fa-spin
-                      %i.fa.fa-smile-o
+                      %i.fa.fa-smile-o.link-highlight
                 .js-task-list-container.note-body.is-task-list-enabled
                   .note-text
                     %p Suscipit sunt quia quisquam sed eveniet ipsam.
diff --git a/spec/javascripts/fixtures/projects.json b/spec/javascripts/fixtures/projects.json
index 84e8d0ba1e4b3d87e825375c6dd32ffd67222a29..4919d77e5a46fa1a2b90b0753777694f8fe4cb65 100644
--- a/spec/javascripts/fixtures/projects.json
+++ b/spec/javascripts/fixtures/projects.json
@@ -1 +1 @@
-[{"id":9,"description":"","default_branch":null,"tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:root/test.git","http_url_to_repo":"http://localhost:3000/root/test.git","web_url":"http://localhost:3000/root/test","owner":{"name":"Administrator","username":"root","id":1,"state":"active","avatar_url":"http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon","web_url":"http://localhost:3000/u/root"},"name":"test","name_with_namespace":"Administrator / test","path":"test","path_with_namespace":"root/test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-14T19:08:05.364Z","last_activity_at":"2016-01-14T19:08:07.418Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":1,"name":"root","path":"root","owner_id":1,"created_at":"2016-01-13T20:19:44.439Z","updated_at":"2016-01-13T20:19:44.439Z","description":"","avatar":null},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":0,"permissions":{"project_access":null,"group_access":null}},{"id":8,"description":"Voluptatem quae nulla eius numquam ullam voluptatibus quia modi.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:h5bp/html5-boilerplate.git","http_url_to_repo":"http://localhost:3000/h5bp/html5-boilerplate.git","web_url":"http://localhost:3000/h5bp/html5-boilerplate","name":"Html5 Boilerplate","name_with_namespace":"H5bp / Html5 Boilerplate","path":"html5-boilerplate","path_with_namespace":"h5bp/html5-boilerplate","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:57.525Z","last_activity_at":"2016-01-13T20:27:57.280Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":5,"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2016-01-13T20:19:57.239Z","updated_at":"2016-01-13T20:19:57.239Z","description":"Tempore accusantium possimus aut libero.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":10,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":7,"description":"Modi odio mollitia dolorem qui.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:twitter/typeahead-js.git","http_url_to_repo":"http://localhost:3000/twitter/typeahead-js.git","web_url":"http://localhost:3000/twitter/typeahead-js","name":"Typeahead.Js","name_with_namespace":"Twitter / Typeahead.Js","path":"typeahead-js","path_with_namespace":"twitter/typeahead-js","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:56.212Z","last_activity_at":"2016-01-13T20:27:51.496Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":6,"description":"Omnis asperiores ipsa et beatae quidem necessitatibus quia.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:twitter/flight.git","http_url_to_repo":"http://localhost:3000/twitter/flight.git","web_url":"http://localhost:3000/twitter/flight","name":"Flight","name_with_namespace":"Twitter / Flight","path":"flight","path_with_namespace":"twitter/flight","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:54.754Z","last_activity_at":"2016-01-13T20:27:50.502Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":5,"description":"Voluptatem commodi voluptate placeat architecto beatae illum dolores fugiat.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-test.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-test.git","web_url":"http://localhost:3000/gitlab-org/gitlab-test","name":"Gitlab Test","name_with_namespace":"Gitlab Org / Gitlab Test","path":"gitlab-test","path_with_namespace":"gitlab-org/gitlab-test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:53.202Z","last_activity_at":"2016-01-13T20:27:41.626Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":4,"description":"Aut molestias quas est ut aperiam officia quod libero.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-shell.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-shell.git","web_url":"http://localhost:3000/gitlab-org/gitlab-shell","name":"Gitlab Shell","name_with_namespace":"Gitlab Org / Gitlab Shell","path":"gitlab-shell","path_with_namespace":"gitlab-org/gitlab-shell","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:51.882Z","last_activity_at":"2016-01-13T20:27:35.678Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":20,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":3,"description":"Excepturi molestiae quia repellendus omnis est illo illum eligendi.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ci.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ci.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ci","name":"Gitlab Ci","name_with_namespace":"Gitlab Org / Gitlab Ci","path":"gitlab-ci","path_with_namespace":"gitlab-org/gitlab-ci","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:50.346Z","last_activity_at":"2016-01-13T20:27:30.115Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":3,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":2,"description":"Adipisci quaerat dignissimos enim sed ipsam dolorem quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":10,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ce.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ce.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ce","name":"Gitlab Ce","name_with_namespace":"Gitlab Org / Gitlab Ce","path":"gitlab-ce","path_with_namespace":"gitlab-org/gitlab-ce","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:49.065Z","last_activity_at":"2016-01-13T20:26:58.454Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":30,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":1,"description":"Vel voluptatem maxime saepe ex quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:documentcloud/underscore.git","http_url_to_repo":"http://localhost:3000/documentcloud/underscore.git","web_url":"http://localhost:3000/documentcloud/underscore","name":"Underscore","name_with_namespace":"Documentcloud / Underscore","path":"underscore","path_with_namespace":"documentcloud/underscore","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:45.862Z","last_activity_at":"2016-01-13T20:25:03.106Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":2,"name":"Documentcloud","path":"documentcloud","owner_id":null,"created_at":"2016-01-13T20:19:44.464Z","updated_at":"2016-01-13T20:19:44.464Z","description":"Aut impedit perferendis fuga et ipsa repellat cupiditate et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}}]
+[{"id":9,"description":"","default_branch":null,"tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:root/test.git","http_url_to_repo":"http://localhost:3000/root/test.git","web_url":"http://localhost:3000/root/test","owner":{"name":"Administrator","username":"root","id":1,"state":"active","avatar_url":"http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon","web_url":"http://localhost:3000/u/root"},"name":"test","name_with_namespace":"Administrator / test","path":"test","path_with_namespace":"root/test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-14T19:08:05.364Z","last_activity_at":"2016-01-14T19:08:07.418Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":1,"name":"root","path":"root","owner_id":1,"created_at":"2016-01-13T20:19:44.439Z","updated_at":"2016-01-13T20:19:44.439Z","description":"","avatar":null},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":0,"permissions":{"project_access":null,"group_access":null}},{"id":8,"description":"Voluptatem quae nulla eius numquam ullam voluptatibus quia modi.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:h5bp/html5-boilerplate.git","http_url_to_repo":"http://localhost:3000/h5bp/html5-boilerplate.git","web_url":"http://localhost:3000/h5bp/html5-boilerplate","name":"Html5 Boilerplate","name_with_namespace":"H5bp / Html5 Boilerplate","path":"html5-boilerplate","path_with_namespace":"h5bp/html5-boilerplate","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:57.525Z","last_activity_at":"2016-01-13T20:27:57.280Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":5,"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2016-01-13T20:19:57.239Z","updated_at":"2016-01-13T20:19:57.239Z","description":"Tempore accusantium possimus aut libero.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":{"access_level":10,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":7,"description":"Modi odio mollitia dolorem qui.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:twitter/typeahead-js.git","http_url_to_repo":"http://localhost:3000/twitter/typeahead-js.git","web_url":"http://localhost:3000/twitter/typeahead-js","name":"Typeahead.Js","name_with_namespace":"Twitter / Typeahead.Js","path":"typeahead-js","path_with_namespace":"twitter/typeahead-js","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:56.212Z","last_activity_at":"2016-01-13T20:27:51.496Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":true,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":6,"description":"Omnis asperiores ipsa et beatae quidem necessitatibus quia.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:twitter/flight.git","http_url_to_repo":"http://localhost:3000/twitter/flight.git","web_url":"http://localhost:3000/twitter/flight","name":"Flight","name_with_namespace":"Twitter / Flight","path":"flight","path_with_namespace":"twitter/flight","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:54.754Z","last_activity_at":"2016-01-13T20:27:50.502Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":true,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":5,"description":"Voluptatem commodi voluptate placeat architecto beatae illum dolores fugiat.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-test.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-test.git","web_url":"http://localhost:3000/gitlab-org/gitlab-test","name":"Gitlab Test","name_with_namespace":"Gitlab Org / Gitlab Test","path":"gitlab-test","path_with_namespace":"gitlab-org/gitlab-test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:53.202Z","last_activity_at":"2016-01-13T20:27:41.626Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":4,"description":"Aut molestias quas est ut aperiam officia quod libero.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-shell.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-shell.git","web_url":"http://localhost:3000/gitlab-org/gitlab-shell","name":"Gitlab Shell","name_with_namespace":"Gitlab Org / Gitlab Shell","path":"gitlab-shell","path_with_namespace":"gitlab-org/gitlab-shell","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:51.882Z","last_activity_at":"2016-01-13T20:27:35.678Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":{"access_level":20,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":3,"description":"Excepturi molestiae quia repellendus omnis est illo illum eligendi.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ci.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ci.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ci","name":"Gitlab Ci","name_with_namespace":"Gitlab Org / Gitlab Ci","path":"gitlab-ci","path_with_namespace":"gitlab-org/gitlab-ci","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:50.346Z","last_activity_at":"2016-01-13T20:27:30.115Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":3,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":2,"description":"Adipisci quaerat dignissimos enim sed ipsam dolorem quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":10,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ce.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ce.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ce","name":"Gitlab Ce","name_with_namespace":"Gitlab Org / Gitlab Ce","path":"gitlab-ce","path_with_namespace":"gitlab-org/gitlab-ce","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:49.065Z","last_activity_at":"2016-01-13T20:26:58.454Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":{"access_level":30,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":1,"description":"Vel voluptatem maxime saepe ex quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:documentcloud/underscore.git","http_url_to_repo":"http://localhost:3000/documentcloud/underscore.git","web_url":"http://localhost:3000/documentcloud/underscore","name":"Underscore","name_with_namespace":"Documentcloud / Underscore","path":"underscore","path_with_namespace":"documentcloud/underscore","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:45.862Z","last_activity_at":"2016-01-13T20:25:03.106Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":2,"name":"Documentcloud","path":"documentcloud","owner_id":null,"created_at":"2016-01-13T20:19:44.464Z","updated_at":"2016-01-13T20:19:44.464Z","description":"Aut impedit perferendis fuga et ipsa repellat cupiditate et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}}]
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 86d04ecfa36b0777b2ec5da99ecabdf53ba7381e..e10c1f5c5474451543b93a5d0b671cbfaf4f854c 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -51,6 +51,16 @@ describe ExtractsPath, lib: true do
         expect(@path).to eq(params[:path])
       end
     end
+
+    context 'subclass overrides get_id' do
+      it 'uses ref returned by get_id' do
+        allow_any_instance_of(self.class).to receive(:get_id){ '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' }
+
+        assign_ref_vars
+
+        expect(@id).to eq(get_id)
+      end
+    end
   end
 
   describe '#extract_ref' do
diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb
index 65a828accdec47c9d32567c9a2a1dcab8a8ad4d1..a1d2ca1e27263080b4c883818e36447e1993c191 100644
--- a/spec/lib/gitlab/conflict/parser_spec.rb
+++ b/spec/lib/gitlab/conflict/parser_spec.rb
@@ -183,6 +183,11 @@ CONFLICT
         expect { parse_text('a' * 102401) }.
           to raise_error(Gitlab::Conflict::Parser::UnmergeableFile)
       end
+
+      it 'raises UnsupportedEncoding when the file contains non-UTF-8 characters' do
+        expect { parse_text("a\xC4\xFC".force_encoding(Encoding::ASCII_8BIT)) }.
+          to raise_error(Gitlab::Conflict::Parser::UnsupportedEncoding)
+      end
     end
   end
 end
diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b7c3bc4e1a74983c75c024262d4659597d61d1cf
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer_spec.rb
@@ -0,0 +1,132 @@
+require 'spec_helper'
+
+describe Gitlab::GithubImport::Importer, lib: true do
+  describe '#execute' do
+    context 'when an error occurs' do
+      let(:project) { create(:project, import_url: 'https://github.com/octocat/Hello-World.git', wiki_enabled: false) }
+      let(:octocat) { double(id: 123456, login: 'octocat') }
+      let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
+      let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
+      let(:repository) { double(id: 1, fork: false) }
+      let(:source_sha) { create(:commit, project: project).id }
+      let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) }
+      let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
+      let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) }
+
+      let(:label) do
+        double(
+          name: 'Bug',
+          color: 'ff0000',
+          url: 'https://api.github.com/repos/octocat/Hello-World/labels/bug'
+        )
+      end
+
+      let(:milestone) do
+        double(
+          number: 1347,
+          state: 'open',
+          title: '1.0',
+          description: 'Version 1.0',
+          due_on: nil,
+          created_at: created_at,
+          updated_at: updated_at,
+          closed_at: nil,
+          url: 'https://api.github.com/repos/octocat/Hello-World/milestones/1'
+        )
+      end
+
+      let(:issue1) do
+        double(
+          number: 1347,
+          milestone: nil,
+          state: 'open',
+          title: 'Found a bug',
+          body: "I'm having a problem with this.",
+          assignee: nil,
+          user: octocat,
+          comments: 0,
+          pull_request: nil,
+          created_at: created_at,
+          updated_at: updated_at,
+          closed_at: nil,
+          url: 'https://api.github.com/repos/octocat/Hello-World/issues/1347'
+        )
+      end
+
+      let(:issue2) do
+        double(
+          number: 1348,
+          milestone: nil,
+          state: 'open',
+          title: nil,
+          body: "I'm having a problem with this.",
+          assignee: nil,
+          user: octocat,
+          comments: 0,
+          pull_request: nil,
+          created_at: created_at,
+          updated_at: updated_at,
+          closed_at: nil,
+          url: 'https://api.github.com/repos/octocat/Hello-World/issues/1348'
+        )
+      end
+
+      let(:pull_request) do
+        double(
+          number: 1347,
+          milestone: nil,
+          state: 'open',
+          title: 'New feature',
+          body: 'Please pull these awesome changes',
+          head: source_branch,
+          base: target_branch,
+          assignee: nil,
+          user: octocat,
+          created_at: created_at,
+          updated_at: updated_at,
+          closed_at: nil,
+          merged_at: nil,
+          url: 'https://api.github.com/repos/octocat/Hello-World/pulls/1347'
+        )
+      end
+
+      before do
+        allow(project).to receive(:import_data).and_return(double.as_null_object)
+        allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound)
+        allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label, label])
+        allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone])
+        allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2])
+        allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request])
+        allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil }))
+        allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error)
+      end
+
+      it 'returns true' do
+        expect(described_class.new(project).execute).to eq true
+      end
+
+      it 'does not raise an error' do
+        expect { described_class.new(project).execute }.not_to raise_error
+      end
+
+      it 'stores error messages' do
+        error = {
+          message: 'The remote data could not be fully imported.',
+          errors: [
+            { type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title has already been taken" },
+            { type: :milestone, url: "https://api.github.com/repos/octocat/Hello-World/milestones/1", errors: "Validation failed: Title has already been taken" },
+            { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1347", errors: "Invalid Repository. Use user/repo format." },
+            { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" },
+            { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." },
+            { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" },
+            { type: :wiki, errors: "Gitlab::Shell::Error" }
+          ]
+        }
+
+        described_class.new(project).execute
+
+        expect(project.import_error).to eq error.to_json
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index aa28e360993434ba264a3362a65a4d5f5ac07e75..b667abf063d65e088307602081637dd8a7c13878 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -27,7 +27,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
       created_at: created_at,
       updated_at: updated_at,
       closed_at: nil,
-      merged_at: nil
+      merged_at: nil,
+      url: 'https://api.github.com/repos/octocat/Hello-World/pulls/1347'
     }
   end
 
@@ -229,4 +230,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
       end
     end
   end
+
+  describe '#url' do
+    let(:raw_data) { double(base_data) }
+
+    it 'return raw url' do
+      expect(pull_request.url).to eq 'https://api.github.com/repos/octocat/Hello-World/pulls/1347'
+    end
+  end
 end
diff --git a/spec/lib/gitlab/gitorious_import/project_creator_spec.rb b/spec/lib/gitlab/gitorious_import/project_creator_spec.rb
deleted file mode 100644
index 946712ca38eb9dfdcacfc3f1382f8e63afe3a751..0000000000000000000000000000000000000000
--- a/spec/lib/gitlab/gitorious_import/project_creator_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::GitoriousImport::ProjectCreator, lib: true do
-  let(:user) { create(:user) }
-  let(:repo) { Gitlab::GitoriousImport::Repository.new('foo/bar-baz-qux') }
-  let(:namespace){ create(:group, owner: user) }
-
-  before do
-    namespace.add_owner(user)
-  end
-
-  it 'creates project' do
-    allow_any_instance_of(Project).to receive(:add_import_job)
-
-    project_creator = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, user)
-    project = project_creator.execute
-
-    expect(project.name).to eq("Bar Baz Qux")
-    expect(project.path).to eq("bar-baz-qux")
-    expect(project.namespace).to eq(namespace)
-    expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
-    expect(project.import_type).to eq("gitorious")
-    expect(project.import_source).to eq("foo/bar-baz-qux")
-    expect(project.import_url).to eq("https://gitorious.org/foo/bar-baz-qux.git")
-  end
-end
diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb
index a30cb2a5e38220c41e8683062781542507cd15de..bcaffd279090309ca3a141327e3f5bade87af6ce 100644
--- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb
+++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb
@@ -19,7 +19,7 @@ describe Gitlab::Metrics::RackMiddleware do
     end
 
     it 'tags a transaction with the name and action of a controller' do
-      klass      = double(:klass, name: 'TestController')
+      klass      = double(:klass, name: 'TestController', content_type: 'text/html')
       controller = double(:controller, class: klass, action_name: 'show')
 
       env['action_controller.instance'] = controller
@@ -32,7 +32,7 @@ describe Gitlab::Metrics::RackMiddleware do
       middleware.call(env)
     end
 
-    it 'tags a transaction with the method andpath of the route in the grape endpoint' do
+    it 'tags a transaction with the method and path of the route in the grape endpoint' do
       route    = double(:route, route_method: "GET", route_path: "/:version/projects/:id/archive(.:format)")
       endpoint = double(:endpoint, route: route)
 
@@ -87,17 +87,30 @@ describe Gitlab::Metrics::RackMiddleware do
 
   describe '#tag_controller' do
     let(:transaction) { middleware.transaction_from_env(env) }
+    let(:content_type) { 'text/html' }
 
-    it 'tags a transaction with the name and action of a controller' do
+    before do
       klass      = double(:klass, name: 'TestController')
-      controller = double(:controller, class: klass, action_name: 'show')
+      controller = double(:controller, class: klass, action_name: 'show', content_type: content_type)
 
       env['action_controller.instance'] = controller
+    end
 
+    it 'tags a transaction with the name and action of a controller' do
       middleware.tag_controller(transaction, env)
 
       expect(transaction.action).to eq('TestController#show')
     end
+
+    context 'when the response content type is not :html' do
+      let(:content_type) { 'application/json' }
+
+      it 'appends the mime type to the transaction action' do
+        middleware.tag_controller(transaction, env)
+
+        expect(transaction.action).to eq('TestController#show.json')
+      end
+    end
   end
 
   describe '#tag_endpoint' do
diff --git a/spec/models/concerns/statuseable_spec.rb b/spec/models/concerns/has_status_spec.rb
similarity index 97%
rename from spec/models/concerns/statuseable_spec.rb
rename to spec/models/concerns/has_status_spec.rb
index 8e0a2a2cbdea9ab38280e8e439d64ce8661f7c2b..e118432d0987835800a87ccf6a3ea1d720ae6638 100644
--- a/spec/models/concerns/statuseable_spec.rb
+++ b/spec/models/concerns/has_status_spec.rb
@@ -1,9 +1,9 @@
 require 'spec_helper'
 
-describe Statuseable do
+describe HasStatus do
   before do
     @object = Object.new
-    @object.extend(Statuseable::ClassMethods)
+    @object.extend(HasStatus::ClassMethods)
   end
 
   describe '.status' do
@@ -12,7 +12,7 @@ describe Statuseable do
     end
 
     subject { @object.status }
-    
+
     shared_examples 'build status summary' do
       context 'all successful' do
         let(:statuses) { Array.new(2) { create(type, status: :success) } }
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index 29f7396f862822fcbaf7647353e8be12aacc9e5b..e5b185dc3f642a0a11a95e75e7ddb6a8cc7a1b74 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -1,6 +1,27 @@
 require 'spec_helper'
 
 describe MergeRequestDiff, models: true do
+  describe 'create new record' do
+    subject { create(:merge_request).merge_request_diff }
+
+    it { expect(subject).to be_valid }
+    it { expect(subject).to be_persisted }
+    it { expect(subject.commits.count).to eq(5) }
+    it { expect(subject.diffs.count).to eq(8) }
+    it { expect(subject.head_commit_sha).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+    it { expect(subject.base_commit_sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') }
+    it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') }
+  end
+
+  describe '#latest' do
+    let!(:mr) { create(:merge_request, :with_diffs) }
+    let!(:first_diff) { mr.merge_request_diff }
+    let!(:last_diff) { mr.create_merge_request_diff }
+
+    it { expect(last_diff.latest?).to be_truthy }
+    it { expect(first_diff.latest?).to be_falsey }
+  end
+
   describe '#diffs' do
     let(:mr) { create(:merge_request, :with_diffs) }
     let(:mr_diff) { mr.merge_request_diff }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 64c56d922fff11468bffa82acbd06920041b107e..d67f71bbb9c2dc6320311eabae482d8b3ef6cd67 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -9,7 +9,7 @@ describe MergeRequest, models: true do
     it { is_expected.to belong_to(:target_project).with_foreign_key(:target_project_id).class_name('Project') }
     it { is_expected.to belong_to(:source_project).with_foreign_key(:source_project_id).class_name('Project') }
     it { is_expected.to belong_to(:merge_user).class_name("User") }
-    it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) }
+    it { is_expected.to have_many(:merge_request_diffs).dependent(:destroy) }
   end
 
   describe 'modules' do
@@ -159,7 +159,7 @@ describe MergeRequest, models: true do
 
     context 'when there are MR diffs' do
       it 'delegates to the MR diffs' do
-        merge_request.merge_request_diff = MergeRequestDiff.new
+        merge_request.save
 
         expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(hash_including(options))
 
@@ -316,7 +316,7 @@ describe MergeRequest, models: true do
     end
 
     it "can be removed if the last commit is the head of the source branch" do
-      allow(subject.source_project).to receive(:commit).and_return(subject.diff_head_commit)
+      allow(subject).to receive(:source_branch_head).and_return(subject.diff_head_commit)
 
       expect(subject.can_remove_source_branch?(user)).to be_truthy
     end
@@ -721,12 +721,15 @@ describe MergeRequest, models: true do
 
     let(:commit) { subject.project.commit(sample_commit.id) }
 
-    it "reloads the diff content" do
-      expect(subject.merge_request_diff).to receive(:reload_content)
-
+    it "does not change existing merge request diff" do
+      expect(subject.merge_request_diff).not_to receive(:save_git_content)
       subject.reload_diff
     end
 
+    it "creates new merge request diff" do
+      expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1)
+    end
+
     it "executs diff cache service" do
       expect_any_instance_of(MergeRequests::MergeRequestDiffCacheService).to receive(:execute).with(subject)
 
@@ -736,13 +739,15 @@ describe MergeRequest, models: true do
     it "updates diff note positions" do
       old_diff_refs = subject.diff_refs
 
-      merge_request_diff = subject.merge_request_diff
-
       # Update merge_request_diff so that #diff_refs will return commit.diff_refs
-      allow(merge_request_diff).to receive(:reload_content) do
-        merge_request_diff.base_commit_sha = commit.parent_id
-        merge_request_diff.start_commit_sha = commit.parent_id
-        merge_request_diff.head_commit_sha = commit.sha
+      allow(subject).to receive(:create_merge_request_diff) do
+        subject.merge_request_diffs.create(
+          base_commit_sha: commit.parent_id,
+          start_commit_sha: commit.parent_id,
+          head_commit_sha: commit.sha
+        )
+
+        subject.merge_request_diff(true)
       end
 
       expect(Notes::DiffPositionUpdateService).to receive(:new).with(
@@ -752,14 +757,31 @@ describe MergeRequest, models: true do
         new_diff_refs: commit.diff_refs,
         paths: note.position.paths
       ).and_call_original
-      expect_any_instance_of(Notes::DiffPositionUpdateService).to receive(:execute).with(note)
 
+      expect_any_instance_of(Notes::DiffPositionUpdateService).to receive(:execute).with(note)
       expect_any_instance_of(DiffNote).to receive(:save).once
 
       subject.reload_diff
     end
   end
 
+  describe '#branch_merge_base_commit' do
+    context 'source and target branch exist' do
+      it { expect(subject.branch_merge_base_commit.sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') }
+      it { expect(subject.branch_merge_base_commit).to be_a(Commit) }
+    end
+
+    context 'when the target branch does not exist' do
+      before do
+        subject.project.repository.raw_repository.delete_branch(subject.target_branch)
+      end
+
+      it 'returns nil' do
+        expect(subject.branch_merge_base_commit).to be_nil
+      end
+    end
+  end
+
   describe "#diff_sha_refs" do
     context "with diffs" do
       subject { create(:merge_request, :with_diffs) }
@@ -890,6 +912,19 @@ describe MergeRequest, models: true do
       expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
     end
 
+    it 'returns a falsey value when the MR is marked as having conflicts, but has none' do
+      merge_request = create_merge_request('master')
+
+      expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
+    end
+
+    it 'returns a falsey value when the MR has a missing ref after a force push' do
+      merge_request = create_merge_request('conflict-resolvable')
+      allow(merge_request.conflicts).to receive(:merge_index).and_raise(Rugged::OdbError)
+
+      expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
+    end
+
     it 'returns a falsey value when the MR does not support new diff notes' do
       merge_request = create_merge_request('conflict-resolvable')
       merge_request.merge_request_diff.update_attributes(start_commit_sha: nil)
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index ef2747046b96131c35e9f8fd9d402f5417cd70b0..9e8ae07e0b2e108a923b19f08558973bb9997442 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -225,7 +225,7 @@ describe Note, models: true do
     let(:note) do
       create :note,
         noteable: ext_issue, project: ext_proj,
-        note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+        note: "Mentioned in issue #{private_issue.to_reference(ext_proj)}",
         system: true
     end
 
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 9a3660012f995320f35f3ff3f657d7cbcf20786d..b2baeeb31bbfce9d109accf5c78f409b1d65f033 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1442,4 +1442,35 @@ describe Project, models: true do
       expect(shared_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
     end
   end
+
+  describe 'change_head' do
+    let(:project) { create(:project) }
+
+    it 'calls the before_change_head method' do
+      expect(project.repository).to receive(:before_change_head)
+      project.change_head(project.default_branch)
+    end
+
+    it 'creates the new reference with rugged' do
+      expect(project.repository.rugged.references).to receive(:create).with('HEAD',
+                                                                            "refs/heads/#{project.default_branch}",
+                                                                            force: true)
+      project.change_head(project.default_branch)
+    end
+
+    it 'copies the gitattributes' do
+      expect(project.repository).to receive(:copy_gitattributes).with(project.default_branch)
+      project.change_head(project.default_branch)
+    end
+
+    it 'expires the avatar cache' do
+      expect(project.repository).to receive(:expire_avatar_cache).with(project.default_branch)
+      project.change_head(project.default_branch)
+    end
+
+    it 'reloads the default branch' do
+      expect(project).to receive(:reload_default_branch)
+      project.change_head(project.default_branch)
+    end
+  end
 end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 51e4780e2b1035b1bd96fee6ddb941a178885bf5..8eb0c5033c977a08f78fec0c178708a15d6b7541 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -920,6 +920,16 @@ describe User, models: true do
 
       expect(subject.recent_push).to eq(nil)
     end
+
+    it "includes push events on any of the provided projects" do
+      expect(subject.recent_push(project1)).to eq(nil)
+      expect(subject.recent_push(project2)).to eq(push_event)
+
+      push_data1 = Gitlab::DataBuilder::Push.build_sample(project1, subject)
+      push_event1 = create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject, data: push_data1)
+
+      expect(subject.recent_push([project1, project2])).to eq(push_event1) # Newest
+    end
   end
 
   describe '#authorized_groups' do
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb
index c65510fadecf0dc1aafabb76ac52ce064c58f4f7..bbdf8f03c2bc3578aec1c547d57853677ca2ed55 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/api_helpers_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
 describe API::Helpers, api: true do
   include API::Helpers
   include ApiHelpers
+  include SentryHelper
 
   let(:user) { create(:user) }
   let(:admin) { create(:admin) }
@@ -234,4 +235,30 @@ describe API::Helpers, api: true do
       expect(to_boolean(nil)).to be_nil
     end
   end
+
+  describe '.handle_api_exception' do
+    before do
+      allow_any_instance_of(self.class).to receive(:sentry_enabled?).and_return(true)
+      allow_any_instance_of(self.class).to receive(:rack_response)
+    end
+
+    it 'does not report a MethodNotAllowed exception to Sentry' do
+      exception = Grape::Exceptions::MethodNotAllowed.new({ 'X-GitLab-Test' => '1' })
+      allow(exception).to receive(:backtrace).and_return(caller)
+
+      expect(Raven).not_to receive(:capture_exception).with(exception)
+
+      handle_api_exception(exception)
+    end
+
+    it 'does report RuntimeError to Sentry' do
+      exception = RuntimeError.new('test error')
+      allow(exception).to receive(:backtrace).and_return(caller)
+
+      expect_any_instance_of(self.class).to receive(:sentry_context)
+      expect(Raven).to receive(:capture_exception).with(exception)
+
+      handle_api_exception(exception)
+    end
+  end
 end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index be52f88831f7078b468495bba8038632e4602349..5d06abcfeb37e00db424e7c63948643d21b0ca2b 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -38,6 +38,68 @@ describe API::API, api: true  do
     end
   end
 
+  describe 'GET /internal/two_factor_recovery_codes' do
+    it 'returns an error message when the key does not exist' do
+      post api('/internal/two_factor_recovery_codes'),
+           secret_token: secret_token,
+           key_id: 12345
+
+      expect(response).to have_http_status(404)
+      expect(json_response['message']).to eq('404 Not found')
+    end
+
+    it 'returns an error message when the key is a deploy key' do
+      deploy_key = create(:deploy_key)
+
+      post api('/internal/two_factor_recovery_codes'),
+           secret_token: secret_token,
+           key_id: deploy_key.id
+
+      expect(json_response['success']).to be_falsey
+      expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes')
+    end
+
+    it 'returns an error message when the user does not exist' do
+      key_without_user = create(:key, user: nil)
+
+      post api('/internal/two_factor_recovery_codes'),
+           secret_token: secret_token,
+           key_id: key_without_user.id
+
+      expect(json_response['success']).to be_falsey
+      expect(json_response['message']).to eq('Could not find a user for the given key')
+      expect(json_response['recovery_codes']).to be_nil
+    end
+
+    context 'when two-factor is enabled' do
+      it 'returns new recovery codes when the user exists' do
+        allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true)
+        allow_any_instance_of(User)
+          .to receive(:generate_otp_backup_codes!).and_return(%w(119135e5a3ebce8e 34bd7b74adbc8861))
+
+        post api('/internal/two_factor_recovery_codes'),
+             secret_token: secret_token,
+             key_id: key.id
+
+        expect(json_response['success']).to be_truthy
+        expect(json_response['recovery_codes']).to match_array(%w(119135e5a3ebce8e 34bd7b74adbc8861))
+      end
+    end
+
+    context 'when two-factor is not enabled' do
+      it 'returns an error message' do
+        allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false)
+
+        post api('/internal/two_factor_recovery_codes'),
+             secret_token: secret_token,
+             key_id: key.id
+
+        expect(json_response['success']).to be_falsey
+        expect(json_response['recovery_codes']).to be_nil
+      end
+    end
+  end
+
   describe "GET /internal/discover" do
     it do
       get(api("/internal/discover"), key_id: key.id, secret_token: secret_token)
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index a40e1a93b715abf29ec2d04c85dbee6af0b25ae0..b8038fc85a19774feb57e5ae0bd7db5de60d5383 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -61,6 +61,7 @@ describe API::API, api: true  do
         expect(response).to have_http_status(200)
         expect(json_response).to be_an Array
         expect(json_response.first['title']).to eq(issue.title)
+        expect(json_response.last).to have_key('web_url')
       end
 
       it "adds pagination headers and keep query params" do
diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8f1e5ac98917a5b630113c4ae3cafe1bb332d0fc
--- /dev/null
+++ b/spec/requests/api/merge_request_diffs_spec.rb
@@ -0,0 +1,49 @@
+require "spec_helper"
+
+describe API::API, 'MergeRequestDiffs', api: true  do
+  include ApiHelpers
+
+  let!(:user)          { create(:user) }
+  let!(:merge_request) { create(:merge_request, importing: true) }
+  let!(:project)       { merge_request.target_project }
+
+  before do
+    merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
+    merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e')
+    project.team << [user, :master]
+  end
+
+  describe 'GET /projects/:id/merge_requests/:merge_request_id/versions' do
+    context 'valid merge request' do
+      before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user) }
+      let(:merge_request_diff) { merge_request.merge_request_diffs.first }
+
+      it { expect(response.status).to eq 200 }
+      it { expect(json_response.size).to eq(merge_request.merge_request_diffs.size) }
+      it { expect(json_response.first['id']).to eq(merge_request_diff.id) }
+      it { expect(json_response.first['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) }
+    end
+
+    it 'returns a 404 when merge_request_id not found' do
+      get api("/projects/#{project.id}/merge_requests/999/versions", user)
+      expect(response).to have_http_status(404)
+    end
+  end
+
+  describe 'GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id' do
+    context 'valid merge request' do
+      before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user) }
+      let(:merge_request_diff) { merge_request.merge_request_diffs.first }
+
+      it { expect(response.status).to eq 200 }
+      it { expect(json_response['id']).to eq(merge_request_diff.id) }
+      it { expect(json_response['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) }
+      it { expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size) }
+    end
+
+    it 'returns a 404 when merge_request_id not found' do
+      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/999", user)
+      expect(response).to have_http_status(404)
+    end
+  end
+end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 617600d617344f2922e54c2fd393ec43010bef75..baff872e28e01be4583ebc6a820d52bc0e13a8a2 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -33,6 +33,7 @@ describe API::API, api: true  do
         expect(json_response).to be_an Array
         expect(json_response.length).to eq(3)
         expect(json_response.last['title']).to eq(merge_request.title)
+        expect(json_response.last).to have_key('web_url')
       end
 
       it "returns an array of all merge_requests" do
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 737fa14cbb0c366a1ee1ad8b6fb5bc04f33fc2c1..223444ea39fc62cd519f152401bd0ba3a07de4a6 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -25,7 +25,7 @@ describe API::API, api: true  do
   let!(:cross_reference_note) do
     create :note,
     noteable: ext_issue, project: ext_proj,
-    note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+    note: "Mentioned in issue #{private_issue.to_reference(ext_proj)}",
     system: true
   end
 
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 914e88c94878d0cfa3b55b52f1496a51f2501a4b..765dc8a8f666d5d1ffdeb3db60abc65458dcd1ce 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -34,6 +34,7 @@ describe API::API, 'ProjectHooks', api: true do
         expect(json_response.first['note_events']).to eq(true)
         expect(json_response.first['build_events']).to eq(true)
         expect(json_response.first['pipeline_events']).to eq(true)
+        expect(json_response.first['wiki_page_events']).to eq(true)
         expect(json_response.first['enable_ssl_verification']).to eq(true)
       end
     end
@@ -57,6 +58,9 @@ describe API::API, 'ProjectHooks', api: true do
         expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
         expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
         expect(json_response['note_events']).to eq(hook.note_events)
+        expect(json_response['build_events']).to eq(hook.build_events)
+        expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
+        expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
         expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification)
       end
 
@@ -93,6 +97,7 @@ describe API::API, 'ProjectHooks', api: true do
       expect(json_response['note_events']).to eq(false)
       expect(json_response['build_events']).to eq(false)
       expect(json_response['pipeline_events']).to eq(false)
+      expect(json_response['wiki_page_events']).to eq(false)
       expect(json_response['enable_ssl_verification']).to eq(true)
     end
 
@@ -118,6 +123,9 @@ describe API::API, 'ProjectHooks', api: true do
       expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
       expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
       expect(json_response['note_events']).to eq(hook.note_events)
+      expect(json_response['build_events']).to eq(hook.build_events)
+      expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
+      expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
       expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification)
     end
 
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 42757ff21b081d984dc0486fff3c32cb8dad32b0..01148f0a05ea427dfca7d71a09bd0baeb5af2204 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -30,6 +30,7 @@ describe API::API, api: true do
       expect(response).to have_http_status(200)
       expect(json_response.size).to eq(3)
       expect(json_response.map{ |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id)
+      expect(json_response.last).to have_key('web_url')
     end
 
     it 'hides private snippets from regular user' do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 4742b3d0e374e69e609318fbc0f7a80783073b88..63f2467be63e52e05e00374d5b113d6d2b2913d4 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -224,7 +224,8 @@ describe API::API, api: true  do
         description: FFaker::Lorem.sentence,
         issues_enabled: false,
         merge_requests_enabled: false,
-        wiki_enabled: false
+        wiki_enabled: false,
+        only_allow_merge_if_build_succeeds: false
       })
 
       post api('/projects', user), project
@@ -276,6 +277,18 @@ describe API::API, api: true  do
       expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
     end
 
+    it 'sets a project as allowing merge even if build fails' do
+      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false })
+      post api('/projects', user), project
+      expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey
+    end
+
+    it 'sets a project as allowing merge only if build succeeds' do
+      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true })
+      post api('/projects', user), project
+      expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy
+    end
+
     context 'when a visibility level is restricted' do
       before do
         @project = attributes_for(:project, { public: true })
@@ -384,6 +397,18 @@ describe API::API, api: true  do
       expect(json_response['public']).to be_falsey
       expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
     end
+
+    it 'sets a project as allowing merge even if build fails' do
+      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false })
+      post api("/projects/user/#{user.id}", admin), project
+      expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey
+    end
+
+    it 'sets a project as allowing merge only if build succeeds' do
+      project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true })
+      post api("/projects/user/#{user.id}", admin), project
+      expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy
+    end
   end
 
   describe "POST /projects/:id/uploads" do
@@ -444,6 +469,7 @@ describe API::API, api: true  do
       expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id)
       expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name)
       expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access)
+      expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds)
     end
 
     it 'returns a project by path name' do
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index f7f45983d26e6a4490fde59d8aedfcb637f01d63..cf4c5f13635aa810e0e4972865656147e4190bff 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -30,7 +30,7 @@ describe Boards::Issues::ListService, services: true do
     let!(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
     let!(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3]) }
     let!(:closed_issue3) { create(:issue, :closed, project: project) }
-    let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1]) }
+    let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1, development]) }
 
     before do
       project.team << [user, :developer]
@@ -58,15 +58,15 @@ describe Boards::Issues::ListService, services: true do
 
         issues = described_class.new(project, user, params).execute
 
-        expect(issues).to eq [closed_issue4, closed_issue2, closed_issue3, closed_issue1]
+        expect(issues).to eq [closed_issue2, closed_issue3, closed_issue1]
       end
 
-      it 'returns opened issues that have label list applied when listing issues from a label list' do
+      it 'returns opened/closed issues that have label list applied when listing issues from a label list' do
         params = { id: list1.id }
 
         issues = described_class.new(project, user, params).execute
 
-        expect(issues).to eq [list1_issue3, list1_issue1, list1_issue2]
+        expect(issues).to eq [closed_issue4, list1_issue3, list1_issue1, list1_issue2]
       end
     end
   end
diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
index c4b874682751c550ab3ce83e6d90b25ce9f15046..807f89e80b76736270ceda59138d48f47164bd11 100644
--- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
+++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
@@ -6,7 +6,7 @@ describe MergeRequests::MergeRequestDiffCacheService do
   describe '#execute' do
     it 'retrieves the diff files to cache the highlighted result' do
       merge_request = create(:merge_request)
-      cache_key = [merge_request.merge_request_diff, 'highlighted-diff-files', Gitlab::Diff::FileCollection::MergeRequest.default_options]
+      cache_key = [merge_request.merge_request_diff, 'highlighted-diff-files', Gitlab::Diff::FileCollection::MergeRequestDiff.default_options]
 
       expect(Rails.cache).to receive(:read).with(cache_key).and_return({})
       expect(Rails.cache).to receive(:write).with(cache_key, anything)
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 00427d6db2a6c29dd1d7313df647940daf0e555c..3d854a959f309cad1010695e8b9e8850154b19a9 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -330,13 +330,13 @@ describe SystemNoteService, services: true do
             let(:mentioner) { project2.repository.commit }
 
             it 'references the mentioning commit' do
-              expect(subject.note).to eq "mentioned in commit #{mentioner.to_reference(project)}"
+              expect(subject.note).to eq "Mentioned in commit #{mentioner.to_reference(project)}"
             end
           end
 
           context 'from non-Commit' do
             it 'references the mentioning object' do
-              expect(subject.note).to eq "mentioned in issue #{mentioner.to_reference(project)}"
+              expect(subject.note).to eq "Mentioned in issue #{mentioner.to_reference(project)}"
             end
           end
         end
@@ -346,13 +346,13 @@ describe SystemNoteService, services: true do
             let(:mentioner) { project.repository.commit }
 
             it 'references the mentioning commit' do
-              expect(subject.note).to eq "mentioned in commit #{mentioner.to_reference}"
+              expect(subject.note).to eq "Mentioned in commit #{mentioner.to_reference}"
             end
           end
 
           context 'from non-Commit' do
             it 'references the mentioning object' do
-              expect(subject.note).to eq "mentioned in issue #{mentioner.to_reference}"
+              expect(subject.note).to eq "Mentioned in issue #{mentioner.to_reference}"
             end
           end
         end
@@ -362,7 +362,7 @@ describe SystemNoteService, services: true do
 
   describe '.cross_reference?' do
     it 'is truthy when text begins with expected text' do
-      expect(described_class.cross_reference?('mentioned in something')).to be_truthy
+      expect(described_class.cross_reference?('Mentioned in something')).to be_truthy
     end
 
     it 'is falsey when text does not begin with expected text' do
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 296fd1bd5a4339b3d72511011d38dd39a5df8a6a..cafcad3e3c04a46aae0d189cd775a2f55c6e9ae2 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -496,6 +496,7 @@ describe TodoService, services: true do
 
   describe '#mark_todos_as_done' do
     let(:issue) { create(:issue, project: project, author: author, assignee: john_doe) }
+    let(:another_issue) { create(:issue, project: project, author: author, assignee: john_doe) }
 
     it 'marks a relation of todos as done' do
       create(:todo, :mentioned, user: john_doe, target: issue, project: project)
@@ -518,6 +519,26 @@ describe TodoService, services: true do
       expect(TodoService.new.mark_todos_as_done([todo], john_doe)).to eq(1)
     end
 
+    context 'when some of the todos are done already' do
+      before do
+        create(:todo, :mentioned, user: john_doe, target: issue, project: project)
+        create(:todo, :mentioned, user: john_doe, target: another_issue, project: project)
+      end
+
+      it 'returns the number of those still pending' do
+        TodoService.new.mark_pending_todos_as_done(issue, john_doe)
+
+        expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq(1)
+      end
+
+      it 'returns 0 if all are done' do
+        TodoService.new.mark_pending_todos_as_done(issue, john_doe)
+        TodoService.new.mark_pending_todos_as_done(another_issue, john_doe)
+
+        expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq(0)
+      end
+    end
+
     it 'caches the number of todos of a user', :caching do
       create(:todo, :mentioned, user: john_doe, target: issue, project: project)
       todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index edbbfc3c9e5729674525103443a8a382c5262f9c..c7a45fc4ff9a62681bd9b548e5bfc70f3f9fafcf 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -24,11 +24,12 @@ module TestEnv
     'expand-collapse-lines'              => '238e82d',
     'video'                              => '8879059',
     'crlf-diff'                          => '5938907',
-    'conflict-start'                     => '14fa46b',
+    'conflict-start'                     => '75284c7',
     'conflict-resolvable'                => '1450cd6',
     'conflict-binary-file'               => '259a6fb',
     'conflict-contains-conflict-markers' => '5e0964c',
     'conflict-missing-side'              => 'eb227b3',
+    'conflict-non-utf8'                  => 'd0a293c',
     'conflict-too-large'                 => '39fa04f',
   }