diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 92e97dfea36255bdd40542eefff702f3af9041ac..d9a16052f1a6c3a49b4d8ada870c22a65529498d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -550,6 +550,7 @@ setup-test-env:
   script:
     - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
     - scripts/gitaly-test-build # Do not use 'bundle exec' here
+    - BUNDLE_GEMFILE=Gemfile.rails5 bundle install $BUNDLE_INSTALL_FLAGS
   artifacts:
     expire_in: 7d
     paths:
@@ -743,6 +744,12 @@ downtime_check:
     - /(^docs[\/-].*|.*-docs$)/
     - /(^qa[\/-].*|.*-qa$)/
 
+rails5_gemfile_lock_check:
+  <<: *dedicated-no-docs-no-db-pull-cache-job
+  <<: *except-docs-and-qa
+  script:
+    - scripts/rails5-gemfile-lock-check
+
 ee_compat_check:
   <<: *rake-exec
   except:
diff --git a/Gemfile.lock b/Gemfile.lock
index 7ee9c9d20c9521e7af746f7591abdead230012f2..43850d1f999c3c8722143e1127ec18b92b29a223 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -320,7 +320,7 @@ GEM
       flowdock (~> 0.7)
       gitlab-grit (>= 2.4.1)
       multi_json
-    gitlab-gollum-lib (4.2.7.2)
+    gitlab-gollum-lib (4.2.7.4)
       gemojione (~> 3.2)
       github-markup (~> 1.6)
       gollum-grit_adapter (~> 1.0)
@@ -328,7 +328,7 @@ GEM
       rouge (~> 3.1)
       sanitize (~> 2.1)
       stringex (~> 2.6)
-    gitlab-gollum-rugged_adapter (0.4.4)
+    gitlab-gollum-rugged_adapter (0.4.4.1)
       mime-types (>= 1.15)
       rugged (~> 0.25)
     gitlab-grit (2.8.2)
diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock
index 4f1155eff06584fdde3377369c6c9545156c7ba1..8e5f305ffcf2239dc091ca9cc3339d5c68e3db22 100644
--- a/Gemfile.rails5.lock
+++ b/Gemfile.rails5.lock
@@ -340,7 +340,7 @@ GEM
       mime-types (>= 1.16)
       posix-spawn (~> 0.3)
     gitlab-license (1.0.0)
-    gitlab-markup (1.6.3)
+    gitlab-markup (1.6.4)
     gitlab-styles (2.3.2)
       rubocop (~> 0.51)
       rubocop-gitlab-security (~> 0.1.0)
@@ -780,36 +780,36 @@ GEM
       chunky_png
     rqrcode-rails3 (0.1.7)
       rqrcode (>= 0.4.2)
-    rspec (3.6.0)
-      rspec-core (~> 3.6.0)
-      rspec-expectations (~> 3.6.0)
-      rspec-mocks (~> 3.6.0)
-    rspec-core (3.6.0)
-      rspec-support (~> 3.6.0)
-    rspec-expectations (3.6.0)
+    rspec (3.7.0)
+      rspec-core (~> 3.7.0)
+      rspec-expectations (~> 3.7.0)
+      rspec-mocks (~> 3.7.0)
+    rspec-core (3.7.1)
+      rspec-support (~> 3.7.0)
+    rspec-expectations (3.7.0)
       diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.6.0)
-    rspec-mocks (3.6.0)
+      rspec-support (~> 3.7.0)
+    rspec-mocks (3.7.0)
       diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.6.0)
+      rspec-support (~> 3.7.0)
     rspec-parameterized (0.4.0)
       binding_of_caller
       parser
       proc_to_ast
       rspec (>= 2.13, < 4)
       unparser
-    rspec-rails (3.6.0)
+    rspec-rails (3.7.2)
       actionpack (>= 3.0)
       activesupport (>= 3.0)
       railties (>= 3.0)
-      rspec-core (~> 3.6.0)
-      rspec-expectations (~> 3.6.0)
-      rspec-mocks (~> 3.6.0)
-      rspec-support (~> 3.6.0)
+      rspec-core (~> 3.7.0)
+      rspec-expectations (~> 3.7.0)
+      rspec-mocks (~> 3.7.0)
+      rspec-support (~> 3.7.0)
     rspec-retry (0.4.5)
       rspec-core
     rspec-set (0.1.3)
-    rspec-support (3.6.0)
+    rspec-support (3.7.1)
     rspec_profiling (0.0.5)
       activerecord
       pg
@@ -1089,7 +1089,7 @@ DEPENDENCIES
   gitlab-gollum-lib (~> 4.2)
   gitlab-gollum-rugged_adapter (~> 0.4.4)
   gitlab-license (~> 1.0)
-  gitlab-markup (~> 1.6.2)
+  gitlab-markup (~> 1.6.4)
   gitlab-styles (~> 2.3)
   gitlab_omniauth-ldap (~> 2.0.4)
   gon (~> 6.2)
@@ -1189,7 +1189,7 @@ DEPENDENCIES
   rouge (~> 3.1)
   rqrcode-rails3 (~> 0.1.7)
   rspec-parameterized
-  rspec-rails (~> 3.6.0)
+  rspec-rails (~> 3.7.0)
   rspec-retry (~> 0.4.5)
   rspec-set (~> 0.1.3)
   rspec_profiling (~> 0.0.5)
diff --git a/PROCESS.md b/PROCESS.md
index 4ddc104ae25d4b25a57f9a6bf1ffc6ae30d154dd..bef80a134e1f9391b2f72478d62aec2e70862444 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -193,11 +193,7 @@ next patch release.
 
 If a merge request is to be picked into more than one release it will need one
 `Pick into X.Y` label per release where the merge request should be back-ported
-to.
-
-For example, if the current patch release is `10.1.1` and a regression fix needs
-to be backported down to the `9.5` release, you will need to assign it the
-`10.1` milestone and the following labels:
+to. For example:
 
 - `Pick into 10.1`
 - `Pick into 10.0`
diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue
index 4d234a36fe5ca5968363a942cf3c77d3b34130e4..6713b54efae89782f9769726aaa736730ec37b8f 100644
--- a/app/assets/javascripts/ide/components/jobs/detail.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail.vue
@@ -122,6 +122,7 @@ export default {
       @scroll="scrollBuildLog"
     >
       <code
+        v-show="!detailJob.isLoading"
         class="bash"
         v-html="jobOutput"
       >
diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue
index d9fa2764d65a4b17f06304be57a8b490b80edb05..33110d27050b068359d23a1cc2b2edf6662132b5 100644
--- a/app/assets/javascripts/issue_show/components/fields/description.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description.vue
@@ -58,7 +58,7 @@
         v-model="formState.description"
         ref="textarea"
         slot="textarea"
-        placeholder="Write a comment or drag your files here..."
+        placeholder="Write a comment or drag your files here鈥�"
         @keydown.meta.enter="updateIssuable"
         @keydown.ctrl.enter="updateIssuable">
       </textarea>
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 72d7e22fba0257266b116de7cf5b1f5926f238bd..17943d7abfbdfb44681dd8871e2f1cd984e7e3ea 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -361,7 +361,7 @@ js-gfm-input js-autosize markdown-area js-vue-textarea"
                   ref="textarea"
                   slot="textarea"
                   :disabled="isSubmitting"
-                  placeholder="Write a comment or drag your files here..."
+                  placeholder="Write a comment or drag your files here鈥�"
                   @keydown.up="editCurrentUserLastNote()"
                   @keydown.meta.enter="handleSave()"
                   @keydown.ctrl.enter="handleSave()">
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index c59a2e7a40627c122c1c77929e1ecd6d0e768fcc..93b669869584f3ff279384912fc3409aed375314 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -173,7 +173,7 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea"
           v-model="updatedNoteBody"
           ref="textarea"
           slot="textarea"
-          placeholder="Write a comment or drag your files here..."
+          placeholder="Write a comment or drag your files here鈥�"
           @keydown.meta.enter="handleUpdate()"
           @keydown.ctrl.enter="handleUpdate()"
           @keydown.up="editMyLastNote()"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
index 05fecd4de358a126fabd878effc8792404570ddc..df866ed570648dc95512e53496b65ca50694212d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
@@ -1,5 +1,6 @@
 <script>
 import { n__ } from '~/locale';
+import { stripHtml } from '~/lib/utils/text_utility';
 import statusIcon from '../mr_widget_status_icon.vue';
 import eventHub from '../../event_hub';
 
@@ -27,6 +28,9 @@ export default {
   },
 
   computed: {
+    mergeError() {
+      return this.mr.mergeError ? stripHtml(this.mr.mergeError, ' ').trim() : '';
+    },
     timerText() {
       return n__(
         'Refreshing in a second to show the updated status...',
@@ -83,9 +87,9 @@ export default {
         <span class="bold">
           <span
             class="has-error-message"
-            v-if="mr.mergeError"
+            v-if="mergeError"
           >
-            {{ mr.mergeError }}.
+            {{ mergeError }}.
           </span>
           <span v-else>
             {{ s__("mrWidget|Merge failed.") }}
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 3c7edb0d4bbc986ecc4faf40c59bf20dfc289af3..6e7fc50c63d916d268362d1ac3b399064ddeb4f3 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -1129,7 +1129,7 @@
 
 .ide-context-header {
   .avatar {
-    flex: 0 0 40px;
+    flex: 0 0 38px;
   }
 
   .ide-merge-requests-dropdown.dropdown-menu {
diff --git a/app/models/project.rb b/app/models/project.rb
index 894df788b0726e2ca2c28df0af9b2ed7530a7196..45cbd174788a06f050bd7258919cffea3ed63e9e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2154,10 +2154,14 @@ class Project < ActiveRecord::Base
     check_access = -> do
       next false if empty_repo?
 
-      merge_request = source_of_merge_requests.opened
-                        .where(allow_collaboration: true)
-                        .find_by(source_branch: branch_name)
-      merge_request&.can_be_merged_by?(user)
+      merge_requests = source_of_merge_requests.opened
+                         .where(allow_collaboration: true)
+
+      if branch_name
+        merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user)
+      else
+        merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) }
+      end
     end
 
     if RequestStore.active?
diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml
index b47870329662b49ee1079fee247f954cc1dd28e1..d6f758608a0f070f5cc64a0287b6205037a8201e 100644
--- a/app/views/projects/releases/edit.html.haml
+++ b/app/views/projects/releases/edit.html.haml
@@ -13,7 +13,7 @@
 
   = form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name), html: { class: 'common-note-form release-form js-quick-submit' }) do |f|
     = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
-      = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here..."
+      = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here鈥�"
       = render 'shared/notes/hints'
     .error-alert
     .prepend-top-default
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index b596748ca5f9f979feebbe8bf51ee6e721296122..da822ac5675aa4761060e4fbc5ed2ff12741bd0a 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -36,7 +36,7 @@
     = label_tag :release_description, s_('TagsPage|Release notes'), class: 'col-form-label col-sm-2'
     .col-sm-10
       = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
-        = render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here...'), current_text: @release_description
+        = render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here鈥�'), current_text: @release_description
         = render 'shared/notes/hints'
       .form-text.text-muted
         = s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.')
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index bcceb69954a53f375ef6b7f12e1971de800e6076..26fe1de31fe01f069b3e29911eecb264020e2d48 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -25,7 +25,7 @@
     .col-sm-12= f.label :content, class: 'control-label-full-width'
     .col-sm-12
       = render layout: 'projects/md_preview', locals: { url: project_wiki_preview_markdown_path(@project, @page.slug) } do
-        = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here...")
+        = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here鈥�")
         = render 'shared/notes/hints'
 
       .clearfix
diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml
index e5dfa7dbf71b8ec4e9e0d6df7d4d93c2cdb10109..25df2fe5cd6c57644a1181f99fd6a3cee8b002a2 100644
--- a/app/views/shared/form_elements/_description.html.haml
+++ b/app/views/shared/form_elements/_description.html.haml
@@ -16,7 +16,7 @@
     = render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do
       = render 'projects/zen', f: form, attr: :description,
                                classes: 'note-textarea qa-issuable-form-description',
-                               placeholder: "Write a comment or drag your files here...",
+                               placeholder: "Write a comment or drag your files here鈥�",
                                supports_quick_actions: supports_quick_actions
       = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
       .clearfix
diff --git a/app/views/shared/notes/_edit_form.html.haml b/app/views/shared/notes/_edit_form.html.haml
index 8923e5602a41f51ec182d8d18d1d7a82994a4872..71a5b94e958b0f4101ae76c860b336759d0b1763 100644
--- a/app/views/shared/notes/_edit_form.html.haml
+++ b/app/views/shared/notes/_edit_form.html.haml
@@ -3,7 +3,7 @@
     = hidden_field_tag :target_id, '', class: 'js-form-target-id'
     = hidden_field_tag :target_type, '', class: 'js-form-target-type'
     = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(project), referenced_users: true } do
-      = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here..."
+      = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here鈥�"
       = render 'shared/notes/hints'
 
     .note-form-actions.clearfix
diff --git a/app/views/shared/notes/_form.html.haml b/app/views/shared/notes/_form.html.haml
index 71c0d740bc802ab2e7526cc01fc953997c481725..c360f1ffe2a2ad229359503b33494044c55d1539 100644
--- a/app/views/shared/notes/_form.html.haml
+++ b/app/views/shared/notes/_form.html.haml
@@ -29,7 +29,7 @@
       = render 'projects/zen', f: f,
         attr: :note,
         classes: 'note-textarea js-note-text',
-        placeholder: "Write a comment or drag your files here...",
+        placeholder: "Write a comment or drag your files here鈥�",
         supports_quick_actions: supports_quick_actions,
         supports_autocomplete: supports_autocomplete
       = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb
index 08b1c3a7d7af7fb5f2c5760c8bf9db3afee5f4cc..db48bb7e8b81592601880684d3010702162efc5a 100644
--- a/app/workers/repository_fork_worker.rb
+++ b/app/workers/repository_fork_worker.rb
@@ -23,10 +23,11 @@ class RepositoryForkWorker
 
       source_repository_storage_path, source_disk_path = *args
 
-      source_repository_storage_name = Gitlab.config.repositories.storages.find do |_, info|
-        info.legacy_disk_path == source_repository_storage_path
-      end&.first || raise("no shard found for path '#{source_repository_storage_path}'")
-
+      source_repository_storage_name = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.find do |_, info|
+          info.legacy_disk_path == source_repository_storage_path
+        end&.first || raise("no shard found for path '#{source_repository_storage_path}'")
+      end
       fork_repository(target_project, source_repository_storage_name, source_disk_path)
     end
   end
diff --git a/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml b/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml
new file mode 100644
index 0000000000000000000000000000000000000000..69d49f3e3e0da5f414e433d49e2960ee30260511
--- /dev/null
+++ b/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml
@@ -0,0 +1,5 @@
+---
+title: Add CI job to check Gemfile.rails5.lock
+merge_request: 19605
+author: "@blackst0ne"
+type: other
diff --git a/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml b/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml
new file mode 100644
index 0000000000000000000000000000000000000000..54154ad2449efe3e6e5c40aecd1e64da696d2795
--- /dev/null
+++ b/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml
@@ -0,0 +1,6 @@
+---
+title: Fix bug where maintainer would not be allowed to push to forks with merge requests
+  that have `Allow maintainer edits` enabled.
+merge_request: 18968
+author:
+type: fixed
diff --git a/changelogs/unreleased/da-port-cte-to-ce.yml b/changelogs/unreleased/da-port-cte-to-ce.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6fa759fcf7dc2af82abd8865ae59fc9c9a458619
--- /dev/null
+++ b/changelogs/unreleased/da-port-cte-to-ce.yml
@@ -0,0 +1,5 @@
+---
+title: Add Gitlab::SQL:CTE for easily building CTE statements
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/fix-br-decode.yml b/changelogs/unreleased/fix-br-decode.yml
new file mode 100644
index 0000000000000000000000000000000000000000..66ecc3deb3595ee76c583754955a258e522a4b8d
--- /dev/null
+++ b/changelogs/unreleased/fix-br-decode.yml
@@ -0,0 +1,5 @@
+---
+title: mergeError message has been binded using v-html directive
+merge_request: 19058
+author: Murat Dogan
+type: fixed
diff --git a/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml b/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3b4d429707fa49bedade83f1f24c2929d5b9cad3
--- /dev/null
+++ b/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed bug that allowed to remove other wiki pages if the title had wildcard characters
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/gitaly-opt-out-branch-tag.yml b/changelogs/unreleased/gitaly-opt-out-branch-tag.yml
new file mode 100644
index 0000000000000000000000000000000000000000..750fc863eed1a17d9999e5d54a80fdda4bdf546c
--- /dev/null
+++ b/changelogs/unreleased/gitaly-opt-out-branch-tag.yml
@@ -0,0 +1,5 @@
+---
+title: Move Gitaly branch/tag/ref RPC's to opt-out
+merge_request: 19644
+author:
+type: other
diff --git a/changelogs/unreleased/pr-importer-io-extra-error-handling.yml b/changelogs/unreleased/pr-importer-io-extra-error-handling.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2f7121b2840fb00cd548990a0b2a46d8b24c8ec8
--- /dev/null
+++ b/changelogs/unreleased/pr-importer-io-extra-error-handling.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure MR diffs always exist in the PR importer
+merge_request:
+author:
+type: fixed
diff --git a/config/routes/wiki.rb b/config/routes/wiki.rb
index c2da84ff6f2324701b3895049200698a14be12d4..cd3828b743c99bc9cba3d84e0d9fb5136db0a9f5 100644
--- a/config/routes/wiki.rb
+++ b/config/routes/wiki.rb
@@ -6,7 +6,7 @@ scope(controller: :wikis) do
     post '/', to: 'wikis#create'
   end
 
-  scope(path: 'wikis/*id', as: :wiki, format: false) do
+  scope(path: 'wikis/*id', as: :wiki, format: false, defaults: { format: :html }) do
     get :edit
     get :history
     post :preview_markdown
diff --git a/doc/administration/integration/koding.md b/doc/administration/integration/koding.md
index 67f9f01efb8944e4c54346eb2c93283af0027775..6c1ec3028cc54faaa46a6f037f5af3668126ddd4 100644
--- a/doc/administration/integration/koding.md
+++ b/doc/administration/integration/koding.md
@@ -100,14 +100,14 @@ As it's pointed out before, you will need public access to this machine that
 you've installed Koding and GitLab on. Better to use a domain but a static IP
 is also fine.
 
-For IP based installation you can use [xip.io](https://xip.io) service which is
+For IP based installation you can use [nip.io](https://nip.io) service which is
 free and provides DNS resolution to IP based requests like following;
 
-  - 127.0.0.1.xip.io              -> resolves to 127.0.0.1
-  - foo.bar.baz.127.0.0.1.xip.io  -> resolves to 127.0.0.1
+  - 127.0.0.1.nip.io              -> resolves to 127.0.0.1
+  - foo.bar.baz.127.0.0.1.nip.io  -> resolves to 127.0.0.1
   - and so on...
 
-As Koding needs subdomains for team names; `foo.127.0.0.1.xip.io` requests for
+As Koding needs subdomains for team names; `foo.127.0.0.1.nip.io` requests for
 a running koding instance on `127.0.0.1` server will be handled as `foo` team
 requests.
 
@@ -127,8 +127,8 @@ your Koding installation. Team called `gitlab` has integration on Koding out
 of the box, so if you didn't change anything your team on Koding should be
 `gitlab`.
 
-So, if your Koding is running on `http://1.2.3.4.xip.io:8090` your URL needs
-to be `http://gitlab.1.2.3.4.xip.io:8090`. You need to provide the same host
+So, if your Koding is running on `http://1.2.3.4.nip.io:8090` your URL needs
+to be `http://gitlab.1.2.3.4.nip.io:8090`. You need to provide the same host
 with your Koding installation here.
 
 
@@ -192,7 +192,7 @@ cd koding
 docker-compose run                              \
   --service-ports backend                       \
   /opt/koding/scripts/bootstrap-container build \
-  --host=**YOUR_IP**.xip.io                     \
+  --host=**YOUR_IP**.nip.io                     \
   --gitlabHost=**GITLAB_IP**                    \
   --gitlabPort=**GITLAB_PORT**                  \
   --gitlabToken=**SECRET_TOKEN**                \
@@ -224,7 +224,7 @@ cd koding
 docker-compose run                              \
   --service-ports backend                       \
   /opt/koding/scripts/bootstrap-container build \
-  --host=**YOUR_IP**.xip.io                     \
+  --host=**YOUR_IP**.nip.io                     \
 ```
 
 #### Enable Single Sign On
@@ -233,7 +233,7 @@ Once you restarted your Koding and logged in with your username and password
 you need to activate oauth authentication for your user. To do that
 
  - Navigate to Dashboard on Koding from;
-   `http://gitlab.**YOUR_IP**.xip.io:8090/Home/my-account`
+   `http://gitlab.**YOUR_IP**.nip.io:8090/Home/my-account`
  - Scroll down to Integrations section
  - Click on toggle to turn On integration in GitLab integration section
 
diff --git a/doc/development/README.md b/doc/development/README.md
index bdb2c68dc4297018a2f318a4d4914b699c3b8d97..1f23677691906db1d737d8b4257458adf82b409f 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -32,7 +32,7 @@ description: 'Learn how to contribute to GitLab.'
 - [GitLab utilities](utilities.md)
 - [API styleguide](api_styleguide.md) Use this styleguide if you are
   contributing to the API.
-- [GrapQL API styleguide](api_graphql_styleguide.md) Use this
+- [GraphQL API styleguide](api_graphql_styleguide.md) Use this
   styleguide if you are contribution to the [GraphQL API](../api/graphql/index.md)
 - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
 - [Working with Gitaly](gitaly.md)
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index 0edcb23c7c5ea1b485dd0cfdaefd4c3f5d95c862..4ba9958e2c6230a73a8cf51dd3da32e7431884ca 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -233,7 +233,7 @@ This makes use of [`Intl.DateTimeFormat`].
 Please never split a sentence as that would assume the sentence grammar and
 structure is the same in all languages.
 
-For instance, the following
+For instance, the following:
 
 ```js
 {{ s__("mrWidget|Set by") }}
@@ -247,6 +247,27 @@ should be externalized as follows:
 {{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }}
 ```
 
+#### Avoid splitting sentences when adding links
+
+This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages.
+
+Instead of:
+
+```haml
+- zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
+= s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
+```
+
+Set the link starting and ending HTML fragments as variables like so:
+
+```haml
+- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
+- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
+= s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
+```
+
+The reasoning behind this is that in some languages words change depending on context. For example in Japanese 銇� is added to the subject of a sentence and 銈� to the object. This is impossible to translate correctly if we extract individual words from the sentence.
+
 When in doubt, try to follow the best practices described in this [Mozilla
 Developer documentation][mdn].
 
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
index c9766040234dc6aa26e68316be71359f7c67d832..4666511d747f331f4b98e183aa275b5996d89874 100644
--- a/doc/gitlab-basics/command-line-commands.md
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -7,17 +7,19 @@ In Git, when you copy a project you say you "clone" it. To work on a git project
 When you are on your Dashboard, click on the project that you'd like to clone.
 To work in the project, you can copy a link to the Git repository through a SSH
 or a HTTPS protocol. SSH is easier to use after it's been
-[setup](create-your-ssh-keys.md). While you are at the **Project** tab, select
-HTTPS or SSH from the dropdown menu and copy the link using the 'Copy to clipboard'
+[set up](create-your-ssh-keys.md). While you are at the **Project** tab, select
+HTTPS or SSH from the dropdown menu and copy the link using the _Copy URL to clipboard_
 button (you'll have to paste it on your shell in the next step).
 
 ![Copy the HTTPS or SSH](img/project_clone_url.png)
 
 ## On the command line
 
+This section has examples of some basic shell commands that you might find useful. For more information, search the web for _bash commands_.
+
 ### Clone your project
 
-Go to your computer's shell and type the following command:
+Go to your computer's shell and type the following command with your SSH or HTTPS URL:
 
 ```
 git clone PASTE HTTPS OR SSH HERE
@@ -25,33 +27,45 @@ git clone PASTE HTTPS OR SSH HERE
 
 A clone of the project will be created in your computer.
 
->**Note:** If you clone your project via an URL that contains special characters, make sure that they are URL-encoded.
+>**Note:** If you clone your project via a URL that contains special characters, make sure that characters are URL-encoded.
 
-### Go into a project, directory or file to work in it
+### Go into a project directory to work in it
 
 ```
-cd NAME-OF-PROJECT-OR-FILE
+cd NAME-OF-PROJECT
 ```
 
-### Go back one directory or file
+### Go back one directory
 
 ```
-cd ../
+cd ..
 ```
 
-### View what鈥檚 in the directory that you are in
+### List what鈥檚 in the current directory
 
 ```
 ls
 ```
 
-### Create a directory
+### List what鈥檚 in the current directory that starts with `a`
+
+```
+ls a*
+```
+
+### List what鈥檚 in the current directory that ends with `.md`
+
+```
+ls *.md
+```
+
+### Create a new directory
 
 ```
 mkdir NAME-OF-YOUR-DIRECTORY
 ```
 
-### Create a README.md or file in directory
+### Create a README.md file in the current directory
 
 ```
 touch README.md
@@ -62,6 +76,12 @@ nano README.md
 #### Press: enter
 ```
 
+### Show the contents of the README.md file
+
+```
+cat README.md
+```
+
 ### Remove a file
 
 ```
@@ -74,12 +94,18 @@ rm NAME-OF-FILE
 rm -r NAME-OF-DIRECTORY
 ```
 
-### View history in the command line
+### View command history
 
 ```
 history
 ```
 
+### Execute command 123 from history
+
+```
+!123
+```
+
 ### Carry out commands for which the account you are using lacks authority
 
 You will be asked for an administrator鈥檚 password.
@@ -88,8 +114,14 @@ You will be asked for an administrator鈥檚 password.
 sudo
 ```
 
-### Tell where you are
+### Show which directory I am in
 
 ```
 pwd
 ```
+
+### Clear the shell window
+
+```
+clear
+```
diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md
index e1d1969651e0fa06c13e8ecc5c85357f8f925c4a..852a58a9afc220b75292852a764e6b2597544b84 100644
--- a/doc/install/kubernetes/gitlab_omnibus.md
+++ b/doc/install/kubernetes/gitlab_omnibus.md
@@ -120,7 +120,7 @@ gitlabConfigStorageSize: 1Gi
 Ingress routing and SSL are automatically configured within this Chart. An NGINX ingress is provisioned and configured, and will route traffic to any service. SSL certificates are automatically created and configured by [kube-lego](https://github.com/kubernetes/charts/tree/master/stable/kube-lego).
 
 > **Note:**
-Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [xip.io](http://xip.io) and [nip.io](http://nip.io) are unlikely to work.
+Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [nip.io](http://nip.io) and [nip.io](http://nip.io) are unlikely to work.
 
 ## Installing GitLab using the Helm Chart
 > **Note:**
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index 1ced1fb513d6e930da5950778b5f2be41e7ec1ee..60e1e2b5f8aef1db5e55777dfd9ccf0ce604f867 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -307,10 +307,10 @@ hostname** and use greater values for the volume sizes. If you don't provide a
 password for PostgreSQL, it will be created automatically.
 
 >**Note:**
-The `gitlab.apps.10.2.2.2.xip.io` hostname that is used by default will
+The `gitlab.apps.10.2.2.2.nip.io` hostname that is used by default will
 resolve to the host with IP `10.2.2.2` which is the IP our VM uses. It is a
 trick to have distinct FQDNs pointing to services that are on our local network.
-Read more on how this works in <http://xip.io>.
+Read more on how this works in <http://nip.io>.
 
 Now that we configured this, let's see how to manage and scale GitLab.
 
@@ -347,7 +347,7 @@ Navigate back to the **Overview** and hopefully all pods will be up and running.
 ![GitLab running](img/gitlab-running.png)
 
 Congratulations! You can now navigate to your new shinny GitLab instance by
-visiting <http://gitlab.apps.10.2.2.2.xip.io> where you will be asked to
+visiting <http://gitlab.apps.10.2.2.2.nip.io> where you will be asked to
 change the root user password. Login using `root` as username and providing the
 password you just set, and start using GitLab!
 
@@ -521,4 +521,4 @@ PaaS and managing your applications with the ease of containers.
 [autoscaling]: https://docs.openshift.org/latest/dev_guide/pod_autoscaling.html "Documentation - Autoscale"
 [basic-cli]: https://docs.openshift.org/latest/cli_reference/basic_cli_operations.html "Documentation - Basic CLI operations"
 [openshift-docs]: https://docs.openshift.org "OpenShift documentation"
-[scc]: https://docs.openshift.org/latest/admin_guide/manage_scc.html "Documentation - Managing Security Context Constraints"
\ No newline at end of file
+[scc]: https://docs.openshift.org/latest/admin_guide/manage_scc.html "Documentation - Managing Security Context Constraints"
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 4fa82d53725dbf12448694cfd56ff80aee41977b..7df8a4341eb98c3e6d0f3c0e5bd836639b074025 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -135,9 +135,9 @@ and `1.2.3.4` is the IP address of your load balancer; generally NGINX
 ([see requirements](#requirements)). How to set up the DNS record is beyond
 the scope of this document; you should check with your DNS provider.
 
-Alternatively you can use free public services like [xip.io](http://xip.io) or
+Alternatively you can use free public services like [nip.io](http://nip.io) or
 [nip.io](http://nip.io) which provide automatic wildcard DNS without any
-configuration. Just set the Auto DevOps base domain to `1.2.3.4.xip.io` or
+configuration. Just set the Auto DevOps base domain to `1.2.3.4.nip.io` or
 `1.2.3.4.nip.io`.
 
 Once set up, all requests will hit the load balancer, which in turn will route
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 4193c4906d95baca017b64d500366b87f437c201..ea288460dfa290f0bea8a0335324be04f957809c 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -41,20 +41,20 @@ new Kubernetes cluster that will be hosted on GKE to your project:
 
 1. Navigate to your project's **Operations > Kubernetes** page.
 1. Click on **Add Kubernetes cluster**.
-1. Click on **Create with GKE**.
+1. Click on **Create with Google Kubernetes Engine**.
 1. Connect your Google account if you haven't done already by clicking the
    **Sign in with Google** button.
 1. Fill in the requested values:
-  - **Cluster name** (required) - The name you wish to give the cluster.
-  - **GCP project ID** (required) - The ID of the project you created in your GCP
+  - **Kubernetes cluster name** - The name you wish to give the cluster.
+  - **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster.
+  - **Google Cloud Platform project** - The project you created in your GCP
     console that will host the Kubernetes cluster. This must **not** be confused
-    with the project name. Learn more about [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
+    with the project ID. Learn more about [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
   - **Zone** - The [zone](https://cloud.google.com/compute/docs/regions-zones/)
     under which the cluster will be created.
   - **Number of nodes** - The number of nodes you wish the cluster to have.
   - **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types)
     of the Virtual Machine instance that the cluster will be based on.
-  - **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster.
 1. Finally, click the **Create Kubernetes cluster** button.
 
 After a few moments, your cluster should be created. If something goes wrong,
diff --git a/doc/user/project/import/img/import_projects_from_repo_url.png b/doc/user/project/import/img/import_projects_from_repo_url.png
index ec867da1087f7aedaa0529528b4c71c7a2160d61..c453c7e558a8d8e7e4f8529ec2a5f3e0a4e9921a 100644
Binary files a/doc/user/project/import/img/import_projects_from_repo_url.png and b/doc/user/project/import/img/import_projects_from_repo_url.png differ
diff --git a/lib/gitlab/git/gitlab_projects.rb b/lib/gitlab/git/gitlab_projects.rb
index 4631b4caf7cdd8598416c15d7894ba08962bc333..5ff15a787f0678b55e6dfecb8cbf37be417559a3 100644
--- a/lib/gitlab/git/gitlab_projects.rb
+++ b/lib/gitlab/git/gitlab_projects.rb
@@ -53,24 +53,11 @@ module Gitlab
       # Import project via git clone --bare
       # URL must be publicly cloneable
       def import_project(source, timeout)
-        Gitlab::GitalyClient.migrate(:import_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
-          if is_enabled
-            gitaly_import_repository(source)
-          else
-            git_import_repository(source, timeout)
-          end
-        end
+        git_import_repository(source, timeout)
       end
 
       def fork_repository(new_shard_name, new_repository_relative_path)
-        Gitlab::GitalyClient.migrate(:fork_repository,
-                                     status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
-          if is_enabled
-            gitaly_fork_repository(new_shard_name, new_repository_relative_path)
-          else
-            git_fork_repository(new_shard_name, new_repository_relative_path)
-          end
-        end
+        git_fork_repository(new_shard_name, new_repository_relative_path)
       end
 
       def fetch_remote(name, timeout, force:, tags:, ssh_key: nil, known_hosts: nil, prune: true)
@@ -242,16 +229,6 @@ module Gitlab
         true
       end
 
-      def gitaly_import_repository(source)
-        raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
-
-        Gitlab::GitalyClient::RepositoryService.new(raw_repository).import_repository(source)
-        true
-      rescue GRPC::BadStatus => e
-        @output << e.message
-        false
-      end
-
       def git_fork_repository(new_shard_name, new_repository_relative_path)
         from_path = repository_absolute_path
         new_shard_path = Gitlab.config.repositories.storages.fetch(new_shard_name).legacy_disk_path
@@ -271,16 +248,6 @@ module Gitlab
 
         run(cmd, nil) && Gitlab::Git::Repository.create_hooks(to_path, global_hooks_path)
       end
-
-      def gitaly_fork_repository(new_shard_name, new_repository_relative_path)
-        target_repository = Gitlab::Git::Repository.new(new_shard_name, new_repository_relative_path, nil)
-        raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
-
-        Gitlab::GitalyClient::RepositoryService.new(target_repository).fork_repository(raw_repository)
-      rescue GRPC::BadStatus => e
-        logger.error "fork-repository failed: #{e.message}"
-        false
-      end
     end
   end
 end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index a34caaf2cfdf2df99dc0c0f243646aecce80456d..28ac00e672f8d1929acb37d97f8c8b83f1cdfc80 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -120,7 +120,7 @@ module Gitlab
 
       # Default branch in the repository
       def root_ref
-        @root_ref ||= gitaly_migrate(:root_ref) do |is_enabled|
+        @root_ref ||= gitaly_migrate(:root_ref, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_client.default_branch_name
           else
@@ -152,7 +152,7 @@ module Gitlab
       # Returns an Array of branch names
       # sorted by name ASC
       def branch_names
-        gitaly_migrate(:branch_names) do |is_enabled|
+        gitaly_migrate(:branch_names, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_client.branch_names
           else
@@ -163,7 +163,7 @@ module Gitlab
 
       # Returns an Array of Branches
       def branches
-        gitaly_migrate(:branches) do |is_enabled|
+        gitaly_migrate(:branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_client.branches
           else
@@ -200,7 +200,7 @@ module Gitlab
       end
 
       def local_branches(sort_by: nil)
-        gitaly_migrate(:local_branches) do |is_enabled|
+        gitaly_migrate(:local_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_client.local_branches(sort_by: sort_by)
           else
@@ -270,7 +270,7 @@ module Gitlab
 
       # Returns an Array of tag names
       def tag_names
-        gitaly_migrate(:tag_names) do |is_enabled|
+        gitaly_migrate(:tag_names, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_client.tag_names
           else
@@ -283,7 +283,7 @@ module Gitlab
       #
       # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/390
       def tags
-        gitaly_migrate(:tags) do |is_enabled|
+        gitaly_migrate(:tags, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             tags_from_gitaly
           else
@@ -310,7 +310,7 @@ module Gitlab
       #
       # name - The name of the tag as a String.
       def tag_exists?(name)
-        gitaly_migrate(:ref_exists_tags) do |is_enabled|
+        gitaly_migrate(:ref_exists_tags, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_exists?("refs/tags/#{name}")
           else
@@ -323,7 +323,7 @@ module Gitlab
       #
       # name - The name of the branch as a String.
       def branch_exists?(name)
-        gitaly_migrate(:ref_exists_branches) do |is_enabled|
+        gitaly_migrate(:ref_exists_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
           if is_enabled
             gitaly_ref_exists?("refs/heads/#{name}")
           else
diff --git a/lib/gitlab/github_import/importer/pull_request_importer.rb b/lib/gitlab/github_import/importer/pull_request_importer.rb
index b2f6cb7ad19a97cabf146d0dc8f259fe0647f5e5..6b3688c43813a4788b57851f82a57acbaabb7cd0 100644
--- a/lib/gitlab/github_import/importer/pull_request_importer.rb
+++ b/lib/gitlab/github_import/importer/pull_request_importer.rb
@@ -104,7 +104,8 @@ module Gitlab
           # first save the diff, then populate it.
           diff =
             if already_exists
-              merge_request.merge_request_diffs.take
+              merge_request.merge_request_diffs.take ||
+                merge_request.merge_request_diffs.build
             else
               merge_request.merge_request_diffs.build
             end
diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb
index e5c02dd8ecc9c5f05ce2d41ad5986fc1f83970f7..4a87f43597e02107eaf93f1358f1e31f0ffef6a6 100644
--- a/lib/gitlab/setup_helper.rb
+++ b/lib/gitlab/setup_helper.rb
@@ -24,7 +24,9 @@ module Gitlab
             address = val['gitaly_address']
           end
 
-          storages << { name: key, path: val.legacy_disk_path }
+          Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            storages << { name: key, path: val.legacy_disk_path }
+          end
         end
 
         if Rails.env.test?
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 4a691d640b3db780b6c47cdc7a541867707f382d..4b8aae4f5a2593db524a4410043e0c5d52b2a947 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -106,10 +106,17 @@ module Gitlab
         raise Error.new("don't use disk paths with import_repository: #{url.inspect}")
       end
 
-      # The timeout ensures the subprocess won't hang forever
-      cmd = gitlab_projects(storage, "#{name}.git")
-      success = cmd.import_project(url, git_timeout)
+      relative_path = "#{name}.git"
+      cmd = gitaly_migrate(:import_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
+        if is_enabled
+          GitalyGitlabProjects.new(storage, relative_path)
+        else
+          # The timeout ensures the subprocess won't hang forever
+          gitlab_projects(storage, relative_path)
+        end
+      end
 
+      success = cmd.import_project(url, git_timeout)
       raise Error, cmd.output unless success
 
       success
@@ -165,8 +172,16 @@ module Gitlab
     #
     # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/817
     def fork_repository(forked_from_storage, forked_from_disk_path, forked_to_storage, forked_to_disk_path)
-      gitlab_projects(forked_from_storage, "#{forked_from_disk_path}.git")
-        .fork_repository(forked_to_storage, "#{forked_to_disk_path}.git")
+      forked_from_relative_path = "#{forked_from_disk_path}.git"
+      fork_args = [forked_to_storage, "#{forked_to_disk_path}.git"]
+
+      gitaly_migrate(:fork_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
+        if is_enabled
+          GitalyGitlabProjects.new(forked_from_storage, forked_from_relative_path).fork_repository(*fork_args)
+        else
+          gitlab_projects(forked_from_storage, forked_from_relative_path).fork_repository(*fork_args)
+        end
+      end
     end
 
     # Removes a repository from file system, using rm_diretory which is an alias
@@ -452,5 +467,39 @@ module Gitlab
       # need to do the same here...
       raise Error, e
     end
+
+    class GitalyGitlabProjects
+      attr_reader :shard_name, :repository_relative_path, :output
+
+      def initialize(shard_name, repository_relative_path)
+        @shard_name = shard_name
+        @repository_relative_path = repository_relative_path
+        @output = ''
+      end
+
+      def import_project(source, _timeout)
+        raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
+
+        Gitlab::GitalyClient::RepositoryService.new(raw_repository).import_repository(source)
+        true
+      rescue GRPC::BadStatus => e
+        @output = e.message
+        false
+      end
+
+      def fork_repository(new_shard_name, new_repository_relative_path)
+        target_repository = Gitlab::Git::Repository.new(new_shard_name, new_repository_relative_path, nil)
+        raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
+
+        Gitlab::GitalyClient::RepositoryService.new(target_repository).fork_repository(raw_repository)
+      rescue GRPC::BadStatus => e
+        logger.error "fork-repository failed: #{e.message}"
+        false
+      end
+
+      def logger
+        Rails.logger
+      end
+    end
   end
 end
diff --git a/lib/gitlab/sql/cte.rb b/lib/gitlab/sql/cte.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f357829ba3ff3041f998ef3af560d456921188dd
--- /dev/null
+++ b/lib/gitlab/sql/cte.rb
@@ -0,0 +1,50 @@
+module Gitlab
+  module SQL
+    # Class for easily building CTE statements.
+    #
+    # Example:
+    #
+    #     cte = CTE.new(:my_cte_name)
+    #     ns = Arel::Table.new(:namespaces)
+    #
+    #     cte << Namespace.
+    #       where(ns[:parent_id].eq(some_namespace_id))
+    #
+    #     Namespace
+    #       with(cte.to_arel).
+    #       from(cte.alias_to(ns))
+    class CTE
+      attr_reader :table, :query
+
+      # name - The name of the CTE as a String or Symbol.
+      def initialize(name, query)
+        @table = Arel::Table.new(name)
+        @query = query
+      end
+
+      # Returns the Arel relation for this CTE.
+      def to_arel
+        sql = Arel::Nodes::SqlLiteral.new("(#{query.to_sql})")
+
+        Arel::Nodes::As.new(table, sql)
+      end
+
+      # Returns an "AS" statement that aliases the CTE name as the given table
+      # name. This allows one to trick ActiveRecord into thinking it's selecting
+      # from an actual table, when in reality it's selecting from a CTE.
+      #
+      # alias_table - The Arel table to use as the alias.
+      def alias_to(alias_table)
+        Arel::Nodes::As.new(table, alias_table)
+      end
+
+      # Applies the CTE to the given relation, returning a new one that will
+      # query from it.
+      def apply_to(relation)
+        relation.except(:where)
+          .with(to_arel)
+          .from(alias_to(relation.model.arel_table))
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/task_helpers.rb b/lib/gitlab/task_helpers.rb
index 723e655c15015bd4931a2942283baa345428897a..922418966e9997a2c3c9e1859926c7409b82d9ef 100644
--- a/lib/gitlab/task_helpers.rb
+++ b/lib/gitlab/task_helpers.rb
@@ -140,7 +140,9 @@ module Gitlab
     end
 
     def repository_storage_paths_args
-      Gitlab.config.repositories.storages.values.map { |rs| rs.legacy_disk_path }
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.values.map { |rs| rs.legacy_disk_path }
+      end
     end
 
     def user_home
diff --git a/lib/system_check/orphans/namespace_check.rb b/lib/system_check/orphans/namespace_check.rb
index b5f443abe06e74a21f626a6f893e478001a899df..09b57c7b408fa2361480099c6374ec78d75946c8 100644
--- a/lib/system_check/orphans/namespace_check.rb
+++ b/lib/system_check/orphans/namespace_check.rb
@@ -4,13 +4,15 @@ module SystemCheck
       set_name 'Orphaned namespaces:'
 
       def multi_check
-        Gitlab.config.repositories.storages.each do |storage_name, repository_storage|
-          $stdout.puts
-          $stdout.puts "* Storage: #{storage_name} (#{repository_storage.legacy_disk_path})".color(:yellow)
-          toplevel_namespace_dirs = disk_namespaces(repository_storage.legacy_disk_path)
-
-          orphans = (toplevel_namespace_dirs - existing_namespaces)
-          print_orphans(orphans, storage_name)
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          Gitlab.config.repositories.storages.each do |storage_name, repository_storage|
+            $stdout.puts
+            $stdout.puts "* Storage: #{storage_name} (#{repository_storage.legacy_disk_path})".color(:yellow)
+            toplevel_namespace_dirs = disk_namespaces(repository_storage.legacy_disk_path)
+
+            orphans = (toplevel_namespace_dirs - existing_namespaces)
+            print_orphans(orphans, storage_name)
+          end
         end
 
         clear_namespaces! # releases memory when check finishes
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index ff86208f85baad8630aec14dd49bc05bccfb8460..1c0ee573147c025f5e8f62fc183396917d03ca5f 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -47,11 +47,13 @@ namespace :gitlab do
       start_checking "GitLab Shell"
 
       check_gitlab_shell
-      check_repo_base_exists
-      check_repo_base_is_not_symlink
-      check_repo_base_user_and_group
-      check_repo_base_permissions
-      check_repos_hooks_directory_is_link
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        check_repo_base_exists
+        check_repo_base_is_not_symlink
+        check_repo_base_user_and_group
+        check_repo_base_permissions
+        check_repos_hooks_directory_is_link
+      end
       check_gitlab_shell_self_test
 
       finished_checking "GitLab Shell"
diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake
index 7d1d73b0fffb553f4ed4e7892886a9d796b5fcab..2d510fe02b2c2a4ddf4f8d19e0d601154a5a3807 100644
--- a/lib/tasks/gitlab/info.rake
+++ b/lib/tasks/gitlab/info.rake
@@ -82,8 +82,10 @@ namespace :gitlab do
       puts "GitLab Shell".color(:yellow)
       puts "Version:\t#{gitlab_shell_version || "unknown".color(:red)}"
       puts "Repository storage paths:"
-      Gitlab.config.repositories.storages.each do |name, repository_storage|
-        puts "- #{name}: \t#{repository_storage.legacy_disk_path}"
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.each do |name, repository_storage|
+          puts "- #{name}: \t#{repository_storage.legacy_disk_path}"
+        end
       end
       puts "Hooks:\t\t#{Gitlab.config.gitlab_shell.hooks_path}"
       puts "Git:\t\t#{Gitlab.config.git.bin_path}"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index c0649bdb2bcb0f90aaef50f59f58a7743b5c938d..7b2388a62f0db00a3e1f684437a656d35d6c1327 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gitlab 1.0.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-06-08 18:27+0200\n"
-"PO-Revision-Date: 2018-06-08 18:27+0200\n"
+"POT-Creation-Date: 2018-06-11 09:18+0200\n"
+"PO-Revision-Date: 2018-06-11 09:18+0200\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: \n"
@@ -5108,7 +5108,7 @@ msgstr ""
 msgid "TagsPage|Use git tag command to add a new one:"
 msgstr ""
 
-msgid "TagsPage|Write your release notes or drag files here..."
+msgid "TagsPage|Write your release notes or drag files here鈥�"
 msgstr ""
 
 msgid "TagsPage|protected"
@@ -5931,7 +5931,7 @@ msgstr ""
 msgid "WikiPage|Page slug"
 msgstr ""
 
-msgid "WikiPage|Write your content or drag files here..."
+msgid "WikiPage|Write your content or drag files here鈥�"
 msgstr ""
 
 msgid "Wiki|Create Page"
diff --git a/qa/qa/factory/repository/push.rb b/qa/qa/factory/repository/push.rb
index 7bb808652da663e948deb38b4cf67e6d60cc509b..7c0d580c5ca884b82d3cefc8b591809d67134416 100644
--- a/qa/qa/factory/repository/push.rb
+++ b/qa/qa/factory/repository/push.rb
@@ -1,3 +1,5 @@
+require 'pathname'
+
 module QA
   module Factory
     module Repository
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index fe432edfa2a3eb8011d67e703152f17bfa4f8063..81d00d45753930a4ebc9ea900dd35078ad465e55 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -46,6 +46,18 @@ module QA
       def sandbox_name
         ENV['GITLAB_SANDBOX_NAME']
       end
+
+      def gcloud_account_key
+        ENV.fetch("GCLOUD_ACCOUNT_KEY")
+      end
+
+      def gcloud_account_email
+        ENV.fetch("GCLOUD_ACCOUNT_EMAIL")
+      end
+
+      def gcloud_zone
+        ENV.fetch('GCLOUD_ZONE')
+      end
     end
   end
 end
diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb
index 604bc522983f0ba9848f6bcaa35577be6ff3ffd3..7627c8c7ad90931de6417d09221be501174af91f 100644
--- a/qa/qa/service/kubernetes_cluster.rb
+++ b/qa/qa/service/kubernetes_cluster.rb
@@ -20,9 +20,11 @@ module QA
           gcloud container clusters
           create #{cluster_name}
           --enable-legacy-authorization
-          --zone us-central1-a
+          --zone #{Runtime::Env.gcloud_zone}
           && gcloud container clusters
-          get-credentials #{cluster_name}
+          get-credentials
+          --zone #{Runtime::Env.gcloud_zone}
+          #{cluster_name}
         CMD
 
         @api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'`
@@ -32,7 +34,12 @@ module QA
       end
 
       def remove!
-        shell("gcloud container clusters delete #{cluster_name} --quiet --async")
+        shell <<~CMD.tr("\n", ' ')
+          gcloud container clusters delete
+          --zone #{Runtime::Env.gcloud_zone}
+	  #{cluster_name}
+	  --quiet --async
+	CMD
       end
 
       private
@@ -54,9 +61,9 @@ module QA
       def attempt_login_with_env_vars
         puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY."
         gcloud_account_key = Tempfile.new('gcloud-account-key')
-        gcloud_account_key.write(ENV.fetch("GCLOUD_ACCOUNT_KEY"))
+        gcloud_account_key.write(Runtime::Env.gcloud_account_key)
         gcloud_account_key.close
-        gcloud_account_email = ENV.fetch("GCLOUD_ACCOUNT_EMAIL")
+        gcloud_account_email = Runtime::Env.gcloud_account_email
         shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}")
       ensure
         gcloud_account_key && gcloud_account_key.unlink
diff --git a/qa/qa/specs/features/project/auto_devops_spec.rb b/qa/qa/specs/features/project/auto_devops_spec.rb
index f3f59d33457d9777236d7dbed6b5b4921ec5455d..202a847d1a542b314c7bd0388308a455aacf060c 100644
--- a/qa/qa/specs/features/project/auto_devops_spec.rb
+++ b/qa/qa/specs/features/project/auto_devops_spec.rb
@@ -1,3 +1,5 @@
+require 'pathname'
+
 module QA
   feature 'Auto Devops', :kubernetes do
     after do
diff --git a/scripts/rails5-gemfile-lock-check b/scripts/rails5-gemfile-lock-check
new file mode 100755
index 0000000000000000000000000000000000000000..da6f1b7145ec4484fe23d5c1b5cba5fd84ee94e4
--- /dev/null
+++ b/scripts/rails5-gemfile-lock-check
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+echo -e "=> Checking if Gemfile.rails5.lock is up-to-date...\\n"
+
+cp Gemfile.rails5.lock Gemfile.rails5.lock.orig
+BUNDLE_GEMFILE=Gemfile.rails5 bundle install "$BUNDLE_INSTALL_FLAGS"
+diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock >/dev/null 2>&1
+
+if [ $? == 1 ]
+then
+  diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock
+
+  echo -e "\\n鉁� ERROR: Gemfile.rails5.lock is not up-to-date!
+         Please run 'BUNDLE_GEMFILE=Gemfile.rails5 bundle install'\\n" >&2
+  exit 1
+fi
+
+echo "鉁� Gemfile.rails5.lock is up-to-date"
+exit 0
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 6890400e671286dffa2f238d17c190c6b66e9037..5c8de6ba25a8254aaec115fc1621cbb4202e3936 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -189,11 +189,6 @@ FactoryBot.define do
     trait :empty_repo do
       after(:create) do |project|
         raise "Failed to create repository!" unless project.create_repository
-
-        # We delete hooks so that gitlab-shell will not try to authenticate with
-        # an API that isn't running
-        project.gitlab_shell.rm_directory(project.repository_storage,
-                                          File.join("#{project.disk_path}.git", 'hooks'))
       end
     end
 
@@ -219,13 +214,6 @@ FactoryBot.define do
     trait :wiki_repo do
       after(:create) do |project|
         raise 'Failed to create wiki repository!' unless project.create_wiki
-
-        # We delete hooks so that gitlab-shell will not try to authenticate with
-        # an API that isn't running
-        project.gitlab_shell.rm_directory(
-          project.repository_storage,
-          File.join("#{project.wiki.repository.disk_path}.git", "hooks")
-        )
       end
     end
 
diff --git a/spec/javascripts/ide/components/jobs/detail_spec.js b/spec/javascripts/ide/components/jobs/detail_spec.js
index 641ba06f6536f552a1ba875ed4fd16f73fba465e..8f8d4b9709ed074720f65a9d787de34ad122ca21 100644
--- a/spec/javascripts/ide/components/jobs/detail_spec.js
+++ b/spec/javascripts/ide/components/jobs/detail_spec.js
@@ -62,6 +62,11 @@ describe('IDE jobs detail view', () => {
     expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('');
   });
 
+  it('hides output when loading', () => {
+    expect(vm.$el.querySelector('.bash')).not.toBe(null);
+    expect(vm.$el.querySelector('.bash').style.display).toBe('none');
+  });
+
   it('hide loading icon when isLoading is false', done => {
     vm.$store.state.pipelines.detailJob.isLoading = false;
 
diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js
index 224debbeff6e8fb22b4cbccd26cd46c48cec1c9b..a7d1e4331eb35875a883bc77cd895542346edd18 100644
--- a/spec/javascripts/notes/components/comment_form_spec.js
+++ b/spec/javascripts/notes/components/comment_form_spec.js
@@ -84,7 +84,7 @@ describe('issue_comment_form component', () => {
       it('should render textarea with placeholder', () => {
         expect(
           vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
-        ).toEqual('Write a comment or drag your files here...');
+        ).toEqual('Write a comment or drag your files here鈥�');
       });
 
       it('should make textarea disabled while requesting', (done) => {
diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js
index 0e792eee5e9aa8aea21cb07b677605b735b2c214..d494c63ff1191493d54aa432b9801ef856360e2b 100644
--- a/spec/javascripts/notes/components/note_app_spec.js
+++ b/spec/javascripts/notes/components/note_app_spec.js
@@ -106,7 +106,7 @@ describe('note_app', () => {
       expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM');
       expect(
         vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
-      ).toEqual('Write a comment or drag your files here...');
+      ).toEqual('Write a comment or drag your files here鈥�');
     });
 
     it('should render form comment button as disabled', () => {
@@ -129,7 +129,7 @@ describe('note_app', () => {
       expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM');
       expect(
         vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
-      ).toEqual('Write a comment or drag your files here...');
+      ).toEqual('Write a comment or drag your files here鈥�');
     });
   });
 
diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js
index f841a408d09fca62385c416b97f057ba9ccf7b89..413d4f694344cba79e5bce63898513351391d650 100644
--- a/spec/javascripts/notes/components/note_form_spec.js
+++ b/spec/javascripts/notes/components/note_form_spec.js
@@ -49,7 +49,7 @@ describe('issue_note_form component', () => {
     it('should render text area with placeholder', () => {
       expect(
         vm.$el.querySelector('textarea').getAttribute('placeholder'),
-      ).toEqual('Write a comment or drag your files here...');
+      ).toEqual('Write a comment or drag your files here鈥�');
     });
 
     it('should link to markdown docs', () => {
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
index a0a74648328ad18a649ea7e51564eb93a2a499d6..8de99fd3c9644d5a070fefe7557f28d3a5c74640 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
@@ -6,6 +6,7 @@ import mountComponent from 'spec/helpers/vue_mount_component_helper';
 describe('MRWidgetFailedToMerge', () => {
   const dummyIntervalId = 1337;
   let Component;
+  let mr;
   let vm;
 
   beforeEach(() => {
@@ -13,10 +14,11 @@ describe('MRWidgetFailedToMerge', () => {
     spyOn(eventHub, '$emit');
     spyOn(window, 'setInterval').and.returnValue(dummyIntervalId);
     spyOn(window, 'clearInterval').and.stub();
+    mr = {
+      mergeError: 'Merge error happened',
+    };
     vm = mountComponent(Component, {
-      mr: {
-        mergeError: 'Merge error happened.',
-      },
+      mr,
     });
   });
 
@@ -44,6 +46,19 @@ describe('MRWidgetFailedToMerge', () => {
         expect(vm.timerText).toEqual('Refreshing in a second to show the updated status...');
       });
     });
+
+    describe('mergeError', () => {
+      it('removes forced line breaks', done => {
+        mr.mergeError = 'contains<br />line breaks<br />';
+
+        Vue.nextTick()
+          .then(() => {
+            expect(vm.mergeError).toBe('contains line breaks');
+          })
+          .then(done)
+          .catch(done.fail);
+      });
+    });
   });
 
   describe('created', () => {
@@ -103,7 +118,7 @@ describe('MRWidgetFailedToMerge', () => {
 
     it('renders given error', () => {
       expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual(
-        'Merge error happened..',
+        'Merge error happened.',
       );
     });
 
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index f0e83ccfc7a09e4e29171a1362e743b5541e4b74..5dfbb8e71f8fb6256855608acd09e276a3093247 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -79,7 +79,9 @@ describe Gitlab::Diff::File do
     let(:diffs) { commit.diffs }
 
     before do
-      info_dir_path = File.join(project.repository.path_to_repo, 'info')
+      info_dir_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        File.join(project.repository.path_to_repo, 'info')
+      end
 
       FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path)
       File.write(File.join(info_dir_path, 'attributes'), "*.md -diff\n")
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 94eaf86ef808a2ff0f84c4d5bdda2dda574994a5..6015086f00229acf47997901e6979d5b1bf4099e 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -149,7 +149,9 @@ describe Gitlab::Git::Blob, seed_helper: true do
       it 'limits the size of a large file' do
         blob_size = Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE + 1
         buffer = Array.new(blob_size, 0)
-        rugged_blob = Rugged::Blob.from_buffer(repository.rugged, buffer.join(''))
+        rugged_blob = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          Rugged::Blob.from_buffer(repository.rugged, buffer.join(''))
+        end
         blob = Gitlab::Git::Blob.raw(repository, rugged_blob)
 
         expect(blob.size).to eq(blob_size)
@@ -164,7 +166,9 @@ describe Gitlab::Git::Blob, seed_helper: true do
 
     context 'when sha references a tree' do
       it 'returns nil' do
-        tree = repository.rugged.rev_parse('master^{tree}')
+        tree = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          repository.rugged.rev_parse('master^{tree}')
+        end
 
         blob = Gitlab::Git::Blob.raw(repository, tree.oid)
 
@@ -278,7 +282,11 @@ describe Gitlab::Git::Blob, seed_helper: true do
   end
 
   describe '.batch_lfs_pointers' do
-    let(:tree_object) { repository.rugged.rev_parse('master^{tree}') }
+    let(:tree_object) do
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        repository.rugged.rev_parse('master^{tree}')
+      end
+    end
 
     let(:non_lfs_blob) do
       Gitlab::Git::Blob.find(
diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb
index a19155ed5b08f20c59f6a82f3815c1a3c0399e09..ec1a684cfbcce8cb42e64d35dc5e292fe614a312 100644
--- a/spec/lib/gitlab/git/branch_spec.rb
+++ b/spec/lib/gitlab/git/branch_spec.rb
@@ -69,7 +69,9 @@ describe Gitlab::Git::Branch, seed_helper: true do
       Gitlab::Git.committer_hash(email: user.email, name: user.name)
     end
     let(:params) do
-      parents = [repository.rugged.head.target]
+      parents = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        [repository.rugged.head.target]
+      end
       tree = parents.first.tree
 
       {
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 89be8a1b7f212feab3c6c912e49e72bb5d396e48..5af982c7a549f7528cb44a7ed8ba5b0b552e8f85 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -4,12 +4,15 @@ describe Gitlab::Git::Commit, seed_helper: true do
   let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
   let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) }
   let(:rugged_commit) do
-    repository.rugged.lookup(SeedRepo::Commit::ID)
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      repository.rugged.lookup(SeedRepo::Commit::ID)
+    end
   end
-
   describe "Commit info" do
     before do
-      repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
+      repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
+      end
 
       @committer = {
         email: 'mike@smith.com',
@@ -58,7 +61,9 @@ describe Gitlab::Git::Commit, seed_helper: true do
 
     after do
       # Erase the new commit so other tests get the original repo
-      repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
+      repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
+      end
       repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
     end
   end
@@ -115,7 +120,9 @@ describe Gitlab::Git::Commit, seed_helper: true do
     describe '.find' do
       it "should return first head commit if without params" do
         expect(described_class.last(repository).id).to eq(
-          repository.rugged.head.target.oid
+          Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            repository.rugged.head.target.oid
+          end
         )
       end
 
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 4a7b06003fc4e0e0d9f57db8c73a58470987bf8a..3bb0b5be15b72913a042737f830b23e54569e7bf 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -27,8 +27,10 @@ EOT
       too_large: false
     }
 
-    @rugged_diff = repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths:
-                                          [".gitmodules"]).patches.first
+    @rugged_diff = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths:
+                                              [".gitmodules"]).patches.first
+    end
   end
 
   describe '.new' do
diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb
index 8b715d717c1e65c3373471fa4931d634494ec18d..f5d8503c30c859a5e1cd1d87ddfed212870580a6 100644
--- a/spec/lib/gitlab/git/gitlab_projects_spec.rb
+++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb
@@ -5,6 +5,13 @@ describe Gitlab::Git::GitlabProjects do
     TestEnv.clean_test_path
   end
 
+  around do |example|
+    # TODO move this spec to gitaly-ruby. GitlabProjects is not used in gitlab-ce
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      example.run
+    end
+  end
+
   let(:project) { create(:project, :repository) }
 
   if $VERBOSE
@@ -190,36 +197,30 @@ describe Gitlab::Git::GitlabProjects do
       end
     end
 
-    context 'when Gitaly import_repository feature is enabled' do
-      it_behaves_like 'importing repository'
-    end
+    describe 'logging' do
+      it 'imports a repo' do
+        message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>."
+        expect(logger).to receive(:info).with(message)
 
-    context 'when Gitaly import_repository feature is disabled', :disable_gitaly do
-      describe 'logging' do
-        it 'imports a repo' do
-          message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>."
-          expect(logger).to receive(:info).with(message)
-
-          subject
-        end
+        subject
       end
+    end
 
-      context 'timeout' do
-        it 'does not import a repo' do
-          stub_spawn_timeout(cmd, timeout, nil)
+    context 'timeout' do
+      it 'does not import a repo' do
+        stub_spawn_timeout(cmd, timeout, nil)
 
-          message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed."
-          expect(logger).to receive(:error).with(message)
+        message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed."
+        expect(logger).to receive(:error).with(message)
 
-          is_expected.to be_falsy
+        is_expected.to be_falsy
 
-          expect(gl_projects.output).to eq("Timed out\n")
-          expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy
-        end
+        expect(gl_projects.output).to eq("Timed out\n")
+        expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy
       end
-
-      it_behaves_like 'importing repository'
     end
+
+    it_behaves_like 'importing repository'
   end
 
   describe '#fork_repository' do
@@ -232,9 +233,6 @@ describe Gitlab::Git::GitlabProjects do
 
     before do
       FileUtils.mkdir_p(dest_repos_path)
-
-      # Undo spec_helper stub that deletes hooks
-      allow_any_instance_of(described_class).to receive(:fork_repository).and_call_original
     end
 
     after do
@@ -258,51 +256,45 @@ describe Gitlab::Git::GitlabProjects do
       end
     end
 
-    context 'when Gitaly fork_repository feature is enabled' do
-      it_behaves_like 'forking a repository'
-    end
-
-    context 'when Gitaly fork_repository feature is disabled', :disable_gitaly do
-      it_behaves_like 'forking a repository'
+    it_behaves_like 'forking a repository'
 
-      # We seem to be stuck to having only one working Gitaly storage in tests, changing
-      # that is not very straight-forward so I'm leaving this test here for now till
-      # https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed.
-      context 'different storages' do
-        let(:dest_repos) { 'alternative' }
-        let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), dest_repos) }
+    # We seem to be stuck to having only one working Gitaly storage in tests, changing
+    # that is not very straight-forward so I'm leaving this test here for now till
+    # https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed.
+    context 'different storages' do
+      let(:dest_repos) { 'alternative' }
+      let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), dest_repos) }
 
-        before do
-          stub_storage_settings(dest_repos => { 'path' => dest_repos_path })
-        end
+      before do
+        stub_storage_settings(dest_repos => { 'path' => dest_repos_path })
+      end
 
-        it 'forks the repo' do
-          is_expected.to be_truthy
+      it 'forks the repo' do
+        is_expected.to be_truthy
 
-          expect(File.exist?(dest_repo)).to be_truthy
-          expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy
-          expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy
-        end
+        expect(File.exist?(dest_repo)).to be_truthy
+        expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy
+        expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy
       end
+    end
 
-      describe 'log messages' do
-        describe 'successful fork' do
-          it do
-            message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>."
-            expect(logger).to receive(:info).with(message)
+    describe 'log messages' do
+      describe 'successful fork' do
+        it do
+          message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>."
+          expect(logger).to receive(:info).with(message)
 
-            subject
-          end
+          subject
         end
+      end
 
-        describe 'failed fork due existing destination' do
-          it do
-            FileUtils.mkdir_p(dest_repo)
-            message = "fork-repository failed: destination repository <#{dest_repo}> already exists."
-            expect(logger).to receive(:error).with(message)
+      describe 'failed fork due existing destination' do
+        it do
+          FileUtils.mkdir_p(dest_repo)
+          message = "fork-repository failed: destination repository <#{dest_repo}> already exists."
+          expect(logger).to receive(:error).with(message)
 
-            subject
-          end
+          subject
         end
       end
     end
diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb
index d9b3d0cf419eaf3007fc3b0ffb47309d976bb1ea..a45c8510b1520e6b7aa2efe54614f438946ef5b9 100644
--- a/spec/lib/gitlab/git/hook_spec.rb
+++ b/spec/lib/gitlab/git/hook_spec.rb
@@ -8,6 +8,13 @@ describe Gitlab::Git::Hook do
     allow_any_instance_of(described_class).to receive(:trigger).and_call_original
   end
 
+  around do |example|
+    # TODO move hook tests to gitaly-ruby. Hook will disappear from gitlab-ce
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      example.run
+    end
+  end
+
   describe "#trigger" do
     set(:project) { create(:project, :repository) }
     let(:repository) { project.repository.raw_repository }
diff --git a/spec/lib/gitlab/git/index_spec.rb b/spec/lib/gitlab/git/index_spec.rb
index 73fbc6a6afa4ab52f59c5913276eb0ccc53535fc..16e6bd35449fc5cbd0ac2225999f17e31dc0569d 100644
--- a/spec/lib/gitlab/git/index_spec.rb
+++ b/spec/lib/gitlab/git/index_spec.rb
@@ -8,6 +8,13 @@ describe Gitlab::Git::Index, seed_helper: true do
     index.read_tree(repository.lookup('master').tree)
   end
 
+  around do |example|
+    # TODO move these specs to gitaly-ruby. The Index class will disappear from gitlab-ce
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      example.run
+    end
+  end
+
   describe '#create' do
     let(:options) do
       {
diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb
index 722d697c28e8cbdaaa43a52a47af5098dab1c65e..35b06b14620203d4d8d7cd7551133acaf5b42aa4 100644
--- a/spec/lib/gitlab/git/wiki_spec.rb
+++ b/spec/lib/gitlab/git/wiki_spec.rb
@@ -25,6 +25,22 @@ describe Gitlab::Git::Wiki do
     end
   end
 
+  describe '#delete_page', :skip_gitaly_mock do
+    after do
+      destroy_page('page1')
+    end
+
+    it 'only removes the page with the same path' do
+      create_page('page1', 'content')
+      create_page('*', 'content')
+
+      subject.delete_page('*', commit_details('whatever'))
+
+      expect(subject.pages.count).to eq 1
+      expect(subject.pages.first.title).to eq 'page1'
+    end
+  end
+
   def create_page(name, content)
     subject.write_page(name, :markdown, content, commit_details(name))
   end
diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
index 6686b7ce0b59136af9828edec5c5d5e7d8bc9326..3422a1e82fc523e7c86c5e3e37dc68e187d538f6 100644
--- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
@@ -276,5 +276,17 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
 
       expect(diff.merge_request_diff_commits.exists?).to eq(true)
     end
+
+    context 'when the merge request exists' do
+      it 'creates the merge request diffs if they do not yet exist' do
+        mr, _ = importer.create_merge_request
+
+        mr.merge_request_diffs.delete_all
+
+        importer.insert_git_data(mr, true)
+
+        expect(mr.merge_request_diffs.exists?).to eq(true)
+      end
+    end
   end
 end
diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
index b793636c4d6a4eb886c655ffb55f8b18b3d94241..68eaa70e6b61c0d3f1a3051788aadc82e47cedf3 100644
--- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
+++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
@@ -19,7 +19,9 @@ describe Gitlab::ImportExport::MergeRequestParser do
   end
 
   after do
-    FileUtils.rm_rf(project.repository.path_to_repo)
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      FileUtils.rm_rf(project.repository.path_to_repo)
+    end
   end
 
   it 'has a source branch' do
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 14eae22a2ec0be4dd9235c7623e1a38bb77916cd..155e166329840aa8afbb397db367224862ca2722 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -498,16 +498,34 @@ describe Gitlab::Shell do
         )
       end
 
-      it 'returns true when the command succeeds' do
-        expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true }
+      context 'with gitaly' do
+        it 'returns true when the command succeeds' do
+          expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
+            .with(repository.raw_repository) { :gitaly_response_object }
+
+          is_expected.to be_truthy
+        end
+
+        it 'return false when the command fails' do
+          expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
+            .with(repository.raw_repository) { raise GRPC::BadStatus, 'bla' }
 
-        is_expected.to be_truthy
+          is_expected.to be_falsy
+        end
       end
 
-      it 'return false when the command fails' do
-        expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false }
+      context 'without gitaly', :disable_gitaly do
+        it 'returns true when the command succeeds' do
+          expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true }
 
-        is_expected.to be_falsy
+          is_expected.to be_truthy
+        end
+
+        it 'return false when the command fails' do
+          expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false }
+
+          is_expected.to be_falsy
+        end
       end
     end
 
@@ -662,21 +680,43 @@ describe Gitlab::Shell do
     describe '#import_repository' do
       let(:import_url) { 'https://gitlab.com/gitlab-org/gitlab-ce.git' }
 
-      it 'returns true when the command succeeds' do
-        expect(gitlab_projects).to receive(:import_project).with(import_url, timeout) { true }
+      context 'with gitaly' do
+        it 'returns true when the command succeeds' do
+          expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository).with(import_url)
 
-        result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url)
+          result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url)
 
-        expect(result).to be_truthy
+          expect(result).to be_truthy
+        end
+
+        it 'raises an exception when the command fails' do
+          expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository)
+            .with(import_url) { raise GRPC::BadStatus, 'bla' }
+          expect_any_instance_of(Gitlab::Shell::GitalyGitlabProjects).to receive(:output) { 'error'}
+
+          expect do
+            gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url)
+          end.to raise_error(Gitlab::Shell::Error, "error")
+        end
       end
 
-      it 'raises an exception when the command fails' do
-        allow(gitlab_projects).to receive(:output) { 'error' }
-        expect(gitlab_projects).to receive(:import_project) { false }
+      context 'without gitaly', :disable_gitaly do
+        it 'returns true when the command succeeds' do
+          expect(gitlab_projects).to receive(:import_project).with(import_url, timeout) { true }
 
-        expect do
-          gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url)
-        end.to raise_error(Gitlab::Shell::Error, "error")
+          result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url)
+
+          expect(result).to be_truthy
+        end
+
+        it 'raises an exception when the command fails' do
+          allow(gitlab_projects).to receive(:output) { 'error' }
+          expect(gitlab_projects).to receive(:import_project) { false }
+
+          expect do
+            gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url)
+          end.to raise_error(Gitlab::Shell::Error, "error")
+        end
       end
     end
   end
diff --git a/spec/lib/gitlab/sql/cte_spec.rb b/spec/lib/gitlab/sql/cte_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d6763c7b2e1d2e7bfc61679c5645d586903b19ce
--- /dev/null
+++ b/spec/lib/gitlab/sql/cte_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe Gitlab::SQL::CTE, :postgresql do
+  describe '#to_arel' do
+    it 'generates an Arel relation for the CTE body' do
+      relation = User.where(id: 1)
+      cte = described_class.new(:cte_name, relation)
+      sql = cte.to_arel.to_sql
+      name = ActiveRecord::Base.connection.quote_table_name(:cte_name)
+
+      sql1 = ActiveRecord::Base.connection.unprepared_statement do
+        relation.except(:order).to_sql
+      end
+
+      expect(sql).to eq("#{name} AS (#{sql1})")
+    end
+  end
+
+  describe '#alias_to' do
+    it 'returns an alias for the CTE' do
+      cte = described_class.new(:cte_name, nil)
+      table = Arel::Table.new(:kittens)
+
+      source_name = ActiveRecord::Base.connection.quote_table_name(:cte_name)
+      alias_name = ActiveRecord::Base.connection.quote_table_name(:kittens)
+
+      expect(cte.alias_to(table).to_sql).to eq("#{source_name} AS #{alias_name}")
+    end
+  end
+
+  describe '#apply_to' do
+    it 'applies a CTE to an ActiveRecord::Relation' do
+      user = create(:user)
+      cte = described_class.new(:cte_name, User.where(id: user.id))
+
+      relation = cte.apply_to(User.all)
+
+      expect(relation.to_sql).to match(/WITH .+cte_name/)
+      expect(relation.to_a).to eq(User.where(id: user.id).to_a)
+    end
+  end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 125bf69824bf97cfc6297d93365dceec0db5fd10..4703b4484c2517bb72c472102119efffd67fed54 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -4049,6 +4049,11 @@ describe Project do
           .to be_truthy
       end
 
+      it 'allows access when there are merge requests open but no branch name is given' do
+        expect(project.branch_allows_collaboration?(user, nil))
+          .to be_truthy
+      end
+
       it 'does not allow guest users access' do
         guest = create(:user)
         target_project.add_guest(guest)
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 99ce136e09245f9111dab33abbf9da9b28a5ff77..e756f79e74b74b2c643446e4d694c335622a2d2f 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -1,6 +1,7 @@
 require "spec_helper"
 
 describe 'Git HTTP requests' do
+  include ProjectForksHelper
   include TermsHelper
   include GitHttpHelpers
   include WorkhorseHelpers
@@ -305,6 +306,22 @@ describe 'Git HTTP requests' do
                 expect(response.body).to eq(change_access_error(:push_code))
               end
             end
+
+            context 'when merge requests are open that allow maintainer access' do
+              let(:canonical_project) { create(:project, :public, :repository) }
+              let(:project) { fork_project(canonical_project, nil, repository: true) }
+
+              before do
+                canonical_project.add_master(user)
+                create(:merge_request,
+                       source_project: project,
+                       target_project:  canonical_project,
+                       source_branch: 'fixes',
+                       allow_collaboration: true)
+              end
+
+              it_behaves_like 'pushes are allowed'
+            end
           end
         end
 
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index a4dd47633f4afe597e78e61d8c0a99cb84778003..5a69a2140801116c86187fcaea5f1c4af319be13 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -36,33 +36,36 @@ describe 'project routing' do
   shared_examples 'RESTful project resources' do
     let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] }
     let(:controller_path) { controller }
+    let(:id) { { id: '1' } }
+    let(:format) { {} } # response format, e.g. { format: :html }
+    let(:params) { { namespace_id: 'gitlab', project_id: 'gitlabhq' } }
 
     it 'to #index' do
-      expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:index)
+      expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", params) if actions.include?(:index)
     end
 
     it 'to #create' do
-      expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:create)
+      expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", params) if actions.include?(:create)
     end
 
     it 'to #new' do
-      expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:new)
+      expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", params) if actions.include?(:new)
     end
 
     it 'to #edit' do
-      expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:edit)
+      expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", params.merge(**id, **format)) if actions.include?(:edit)
     end
 
     it 'to #show' do
-      expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:show)
+      expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", params.merge(**id, **format)) if actions.include?(:show)
     end
 
     it 'to #update' do
-      expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:update)
+      expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", params.merge(id)) if actions.include?(:update)
     end
 
     it 'to #destroy' do
-      expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:destroy)
+      expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", params.merge(**id, **format)) if actions.include?(:destroy)
     end
   end
 
@@ -150,12 +153,13 @@ describe 'project routing' do
     end
 
     it 'to #history' do
-      expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
+      expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: :html)
     end
 
     it_behaves_like 'RESTful project resources' do
       let(:actions)    { [:create, :edit, :show, :destroy] }
       let(:controller) { 'wikis' }
+      let(:format) { { format: :html } }
     end
   end
 
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index 33405d7a7ec69753b1ced3d3cb53a4f17b656a29..92159e1e37219f03e46e5350d2d110b3544304e7 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -118,7 +118,9 @@ describe GitTagPushService do
 
       before do
         # Create the lightweight tag
-        project.repository.raw_repository.rugged.tags.create(tag_name, newrev)
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          project.repository.raw_repository.rugged.tags.create(tag_name, newrev)
+        end
 
         # Clear tag list cache
         project.repository.expire_tags_cache
diff --git a/spec/services/merge_requests/squash_service_spec.rb b/spec/services/merge_requests/squash_service_spec.rb
index bd88478742565b5955e813afaafb43614e0ea697..ded17fa92a41d9f5128af93095463e3abcf0f8bd 100644
--- a/spec/services/merge_requests/squash_service_spec.rb
+++ b/spec/services/merge_requests/squash_service_spec.rb
@@ -63,7 +63,9 @@ describe MergeRequests::SquashService do
       end
 
       it 'has the same diff as the merge request, but a different SHA' do
-        rugged = project.repository.rugged
+        rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          project.repository.rugged
+        end
         mr_diff = rugged.diff(merge_request.diff_base_sha, merge_request.diff_head_sha)
         squash_diff = rugged.diff(merge_request.diff_start_sha, squash_sha)
 
diff --git a/spec/services/projects/after_import_service_spec.rb b/spec/services/projects/after_import_service_spec.rb
index c6678fc1f5cf8ff8058d1df1df9eb10ded439ff3..cd52bc88f4c48bd608a47f753a9ac57d09160b99 100644
--- a/spec/services/projects/after_import_service_spec.rb
+++ b/spec/services/projects/after_import_service_spec.rb
@@ -32,7 +32,7 @@ describe Projects::AfterImportService do
       end
 
       it 'removes refs/pull/**/*' do
-        expect(repository.rugged.references.map(&:name))
+        expect(rugged.references.map(&:name))
           .not_to include(%r{\Arefs/pull/})
       end
     end
@@ -46,10 +46,14 @@ describe Projects::AfterImportService do
         end
 
         it "does not remove refs/#{name}/tmp" do
-          expect(repository.rugged.references.map(&:name))
+          expect(rugged.references.map(&:name))
             .to include("refs/#{name}/tmp")
         end
       end
     end
+
+    def rugged
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.rugged }
+    end
   end
 end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index b63f409579e12296359cc0ed743de773f0f2e074..38660ad7a0133283ef051274d975501cdbda43ce 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -5,7 +5,11 @@ describe Projects::DestroyService do
 
   let!(:user) { create(:user) }
   let!(:project) { create(:project, :repository, namespace: user.namespace) }
-  let!(:path) { project.repository.path_to_repo }
+  let!(:path) do
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.path_to_repo
+    end
+  end
   let!(:remove_path) { path.sub(/\.git\Z/, "+#{project.id}+deleted.git") }
   let!(:async) { false } # execute or async_execute
 
diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
index 7dca81eb59efd78ac9385d06c9b581225036c394..ed4930313c5fb3dd5929c55f16371b5b0c5a17b4 100644
--- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
@@ -37,7 +37,11 @@ describe Projects::HashedStorage::MigrateRepositoryService do
       it 'writes project full path to .git/config' do
         service.execute
 
-        expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
+        rugged_config = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          project.repository.rugged.config['gitlab.fullpath']
+        end
+
+        expect(rugged_config).to eq project.full_path
       end
     end
 
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 8e555bdc528c3e13814fd71375f20496450f00e9..414a8a1251ad2b976e247a3d93ad2f69160771ce 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -126,19 +126,6 @@ RSpec.configure do |config|
   end
 
   config.before(:example) do
-    # Skip pre-receive hook check so we can use the web editor and merge.
-    allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
-
-    allow_any_instance_of(Gitlab::Git::GitlabProjects).to receive(:fork_repository).and_wrap_original do |m, *args|
-      m.call(*args)
-
-      shard_name, repository_relative_path = args
-      # We can't leave the hooks in place after a fork, as those would fail in tests
-      # The "internal" API is not available
-      Gitlab::Shell.new.rm_directory(shard_name,
-                                     File.join(repository_relative_path, 'hooks'))
-    end
-
     # Enable all features by default for testing
     allow(Feature).to receive(:enabled?) { true }
   end
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index 1fef50a52ec612553313a15058eb26178bc4d3aa..05a8e6206ae6a4072ab942994f6f84fe24b4bcf7 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -135,6 +135,16 @@ module TestEnv
       install_dir: Gitlab.config.gitlab_shell.path,
       version: Gitlab::Shell.version_required,
       task: 'gitlab:shell:install')
+
+    create_fake_git_hooks
+  end
+
+  def create_fake_git_hooks
+    # gitlab-shell hooks don't work in our test environment because they try to make internal API calls
+    hooks_dir = File.join(Gitlab.config.gitlab_shell.path, 'hooks')
+    %w[pre-receive post-receive update].each do |hook|
+      File.open(File.join(hooks_dir, hook), 'w', 0755) { |f| f.puts '#!/bin/sh' }
+    end
   end
 
   def setup_gitaly
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index 1e507c0236e53d12f5a8b1348ae8fe90bb113b33..4545226d78c3b8cbe3045c3528b54161ff655d9d 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -134,7 +134,9 @@ describe 'gitlab:gitaly namespace rake task' do
 
       parsed_output = TomlRB.parse(expected_output)
       config.each do |name, params|
-        expect(parsed_output['storage']).to include({ 'name' => name, 'path' => params.legacy_disk_path })
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          expect(parsed_output['storage']).to include({ 'name' => name, 'path' => params.legacy_disk_path })
+        end
       end
     end
   end
diff --git a/spec/tasks/gitlab/shell_rake_spec.rb b/spec/tasks/gitlab/shell_rake_spec.rb
index 4a756c5742d55bb20f8e100b856b2e4f86033bc6..0ed5d3e27b98942eb260a6de097ef732c55283c0 100644
--- a/spec/tasks/gitlab/shell_rake_spec.rb
+++ b/spec/tasks/gitlab/shell_rake_spec.rb
@@ -7,11 +7,17 @@ describe 'gitlab:shell rake tasks' do
     stub_warn_user_is_not_gitlab
   end
 
+  after do
+    TestEnv.create_fake_git_hooks
+  end
+
   describe 'install task' do
     it 'invokes create_hooks task' do
       expect(Rake::Task['gitlab:shell:create_hooks']).to receive(:invoke)
 
-      storages = Gitlab.config.repositories.storages.values.map(&:legacy_disk_path)
+      storages = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.values.map(&:legacy_disk_path)
+      end
       expect(Kernel).to receive(:system).with('bin/install', *storages).and_call_original
       expect(Kernel).to receive(:system).with('bin/compile').and_call_original
 
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index f44b4edc3054022f786c0f9ae79b9a820a02f04d..807d1b8c0844a417aaefbc4b4b700fe61a85b9fa 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -218,7 +218,9 @@ describe GitGarbageCollectWorker do
 
   # Create a new commit on a random new branch
   def create_objects(project)
-    rugged = project.repository.rugged
+    rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.rugged
+    end
     old_commit = rugged.branches.first.target
     new_commit_sha = Rugged::Commit.create(
       rugged,
@@ -237,7 +239,9 @@ describe GitGarbageCollectWorker do
   end
 
   def packs(project)
-    Dir["#{project.repository.path_to_repo}/objects/pack/*.pack"]
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      Dir["#{project.repository.path_to_repo}/objects/pack/*.pack"]
+    end
   end
 
   def packed_refs(project)
diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb
index f19c9dff9410f15e89e137084d4bd3c2196b9d4b..42e1d86e3bb755fc98721b89bbbb437f1e18899c 100644
--- a/spec/workers/project_destroy_worker_spec.rb
+++ b/spec/workers/project_destroy_worker_spec.rb
@@ -2,7 +2,11 @@ require 'spec_helper'
 
 describe ProjectDestroyWorker do
   let(:project) { create(:project, :repository, pending_delete: true) }
-  let(:path) { project.repository.path_to_repo }
+  let(:path) do
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.path_to_repo
+    end
+  end
 
   subject { described_class.new }
 
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index ae4786389c780b11034099d3d6a9a9807df9d9e5..5d83397e8df0d226c29770e8ba98fbaf09dc83b0 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -94,6 +94,9 @@ describe RepositoryForkWorker do
       it_behaves_like 'RepositoryForkWorker performing'
 
       it 'logs a message about forking with old-style arguments' do
+        allow(subject).to receive(:gitlab_shell).and_return(shell)
+        expect(shell).to receive(:fork_repository) { true }
+
         allow(Rails.logger).to receive(:info).with(anything) # To compensate for other logs
         expect(Rails.logger).to receive(:info).with("Project #{fork_project.id} is being forked using old-style arguments.")