diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index eb223c1101db27c0d914a552cc4f5ed0fc880249..e8975eb57e0f05e98d2b611cd118fd9c1732802f 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -52,6 +52,14 @@ module API
           :push_code
         ]
       end
+
+      def parse_allowed_environment_variables
+        return if params[:env].blank?
+
+        JSON.parse(params[:env])
+
+      rescue JSON::ParserError
+      end
     end
   end
 end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 7087ce114014f325dfa23c66897fa096c80942d7..db2d18f935d0423282aa7233622b89cefdfef3ea 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -32,7 +32,11 @@ module API
           if wiki?
             Gitlab::GitAccessWiki.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
           else
-            Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
+            Gitlab::GitAccess.new(actor,
+                                  project,
+                                  protocol,
+                                  authentication_abilities: ssh_authentication_abilities,
+                                  env: parse_allowed_environment_variables)
           end
 
         access_status = access.check(params[:action], params[:changes])
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index cb1065223d4d65b9de3602a5dbc8df63a977137f..3d203017d9f4a1311c600fd7d0a5e3a726e45c59 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -3,11 +3,12 @@ module Gitlab
     class ChangeAccess
       attr_reader :user_access, :project
 
-      def initialize(change, user_access:, project:)
+      def initialize(change, user_access:, project:, env: {})
         @oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref)
         @branch_name = Gitlab::Git.branch_name(@ref)
         @user_access = user_access
         @project = project
+        @env = env
       end
 
       def exec
@@ -68,7 +69,7 @@ module Gitlab
       end
 
       def forced_push?
-        Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev)
+        Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev, env: @env)
       end
 
       def matching_merge_request?
diff --git a/lib/gitlab/checks/force_push.rb b/lib/gitlab/checks/force_push.rb
index 5fe86553bd014486944dc6fa936457e490e93628..589525e40ade1d26f68c96c39e59493a98eea542 100644
--- a/lib/gitlab/checks/force_push.rb
+++ b/lib/gitlab/checks/force_push.rb
@@ -1,14 +1,14 @@
 module Gitlab
   module Checks
     class ForcePush
-      def self.force_push?(project, oldrev, newrev)
+      def self.force_push?(project, oldrev, newrev, env: {})
         return false if project.empty_repo?
 
         # Created or deleted branch
         if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
           false
         else
-          missed_ref, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list --max-count=1 #{oldrev} ^#{newrev}))
+          missed_ref, _ = Gitlab::Git::RevList.new(oldrev, newrev, project: project, env: env).execute
           missed_ref.present?
         end
       end
diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ecdb7f07744fb553028cbf50ef8da1e66cb71ee2
--- /dev/null
+++ b/lib/gitlab/git/rev_list.rb
@@ -0,0 +1,28 @@
+# Call out to the `git rev-list` command
+
+module Gitlab
+  module Git
+    class RevList
+      def initialize(oldrev, newrev, project:, env: nil)
+        @args = [Gitlab.config.git.bin_path,
+                 "--git-dir=#{project.repository.path_to_repo}",
+                 "rev-list",
+                 "--max-count=1",
+                 oldrev,
+                 "^#{newrev}"]
+
+        @env = env.slice(*allowed_environment_variables)
+      end
+
+      def execute
+        Gitlab::Popen.popen(@args, nil, @env.slice(*allowed_environment_variables))
+      end
+
+      private
+
+      def allowed_environment_variables
+        %w(GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_OBJECT_DIRECTORY)
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index db07b7c5fcc5756dd160e44f7b3cee02c41a96ab..c6b6efda360cb9a752e8128e2a6cb6c942977050 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -17,12 +17,13 @@ module Gitlab
 
     attr_reader :actor, :project, :protocol, :user_access, :authentication_abilities
 
-    def initialize(actor, project, protocol, authentication_abilities:)
+    def initialize(actor, project, protocol, authentication_abilities:, env: {})
       @actor    = actor
       @project  = project
       @protocol = protocol
       @authentication_abilities = authentication_abilities
       @user_access = UserAccess.new(user, project: project)
+      @env = env
     end
 
     def check(cmd, changes)
@@ -103,7 +104,7 @@ module Gitlab
     end
 
     def change_access_check(change)
-      Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec
+      Checks::ChangeAccess.new(change, user_access: user_access, project: project, env: @env).exec
     end
 
     def protocol_allowed?
diff --git a/lib/gitlab/popen.rb b/lib/gitlab/popen.rb
index cc74bb29087c7fd56cc0d7d07b3f57131fd5af53..4bc5cda8cb587ee32ab9f3fd1e88a66ef5925367 100644
--- a/lib/gitlab/popen.rb
+++ b/lib/gitlab/popen.rb
@@ -5,13 +5,13 @@ module Gitlab
   module Popen
     extend self
 
-    def popen(cmd, path = nil)
+    def popen(cmd, path = nil, vars = {})
       unless cmd.is_a?(Array)
         raise "System commands must be given as an array of strings"
       end
 
       path ||= Dir.pwd
-      vars = { "PWD" => path }
+      vars['PWD'] = path
       options = { chdir: path }
 
       unless File.directory?(path)