diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index fa3999e2a82208282bf6ea5d03d12385b494903c..77f935d82a7ef3553e620ab1d92d75f6ecd09561 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-818f3d85a2c8e6596376f1d2276aa22660203a6c
+d513d220b183d83ae7219ec52f49aa3b4f7fc551
diff --git a/Gemfile b/Gemfile
index 2e2227d98753c48df07aad0ca42cf770daadf09f..e4e68837111fbca78e07e9d887e18c4b0c7d82d7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -472,7 +472,7 @@ end
 gem 'spamcheck', '~> 0.1.0'
 
 # Gitaly GRPC protocol definitions
-gem 'gitaly', '~> 14.1.0.pre.rc4'
+gem 'gitaly', '~> 14.2.0.pre.rc2'
 
 # KAS GRPC protocol definitions
 gem 'kas-grpc', '~> 0.0.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index 7cd04312b948e9873b0886d76467230cf605003e..ea5cc5c26508e1331cc9fa00c56a2999f235e226 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -452,7 +452,7 @@ GEM
       rails (>= 3.2.0)
     git (1.7.0)
       rchardet (~> 1.8)
-    gitaly (14.1.0.pre.rc4)
+    gitaly (14.2.0.pre.rc2)
       grpc (~> 1.0)
     github-markup (1.7.0)
     gitlab (4.16.1)
@@ -1464,7 +1464,7 @@ DEPENDENCIES
   gettext (~> 3.3)
   gettext_i18n_rails (~> 1.8.0)
   gettext_i18n_rails_js (~> 1.3)
-  gitaly (~> 14.1.0.pre.rc4)
+  gitaly (~> 14.2.0.pre.rc2)
   github-markup (~> 1.7.0)
   gitlab-chronic (~> 0.10.5)
   gitlab-dangerfiles (~> 2.3.0)
diff --git a/config/feature_flags/development/set_full_path.yml b/config/feature_flags/development/set_full_path.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a2f249b60fd4abaad7f8b314dfef00e89fe7d3f3
--- /dev/null
+++ b/config/feature_flags/development/set_full_path.yml
@@ -0,0 +1,8 @@
+---
+name: set_full_path
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66929
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337002
+milestone: '14.2'
+type: development
+group: group::gitaly
+default_enabled: false
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 757f14402adeaf46213850cc4209d97a99959eb9..f88c32d9e27ac050bb2b8a36e4e17ee59d7ef9b8 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -911,7 +911,11 @@ def set_full_path(full_path:)
         # This guard avoids Gitaly log/error spam
         raise NoRepository, 'repository does not exist' unless exists?
 
-        set_config('gitlab.fullpath' => full_path)
+        if Feature.enabled?(:set_full_path)
+          gitaly_repository_client.set_full_path(full_path)
+        else
+          set_config('gitlab.fullpath' => full_path)
+        end
       end
 
       def set_config(entries)
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index 009aeaf868a73d1518a988393888256195be0e69..1efce802d22182668524de4a6f71d25467e61d66 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -263,6 +263,21 @@ def write_ref(ref_path, ref, old_ref)
         GitalyClient.call(@storage, :repository_service, :write_ref, request, timeout: GitalyClient.fast_timeout)
       end
 
+      def set_full_path(path)
+        GitalyClient.call(
+          @storage,
+          :repository_service,
+          :set_full_path,
+          Gitaly::SetFullPathRequest.new(
+            repository: @gitaly_repo,
+            path: path
+          ),
+          timeout: GitalyClient.fast_timeout
+        )
+
+        nil
+      end
+
       def set_config(entries)
         return if entries.empty?
 
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 99cb43109c9fe289ad3efea124325361bcf0d00d..e1198349b5c1bc8d6da7902f8e420be7e7cc83d6 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1730,42 +1730,60 @@ def commit_files(commit)
   end
 
   describe '#set_full_path' do
-    before do
-      repository_rugged.config["gitlab.fullpath"] = repository_path
-    end
+    shared_examples '#set_full_path' do
+      before do
+        repository_rugged.config["gitlab.fullpath"] = repository_path
+      end
 
-    context 'is given a path' do
-      it 'writes it to disk' do
-        repository.set_full_path(full_path: "not-the/real-path.git")
+      context 'is given a path' do
+        it 'writes it to disk' do
+          repository.set_full_path(full_path: "not-the/real-path.git")
 
-        config = File.read(File.join(repository_path, "config"))
+          config = File.read(File.join(repository_path, "config"))
 
-        expect(config).to include("[gitlab]")
-        expect(config).to include("fullpath = not-the/real-path.git")
+          expect(config).to include("[gitlab]")
+          expect(config).to include("fullpath = not-the/real-path.git")
+        end
       end
-    end
 
-    context 'it is given an empty path' do
-      it 'does not write it to disk' do
-        repository.set_full_path(full_path: "")
+      context 'it is given an empty path' do
+        it 'does not write it to disk' do
+          repository.set_full_path(full_path: "")
 
-        config = File.read(File.join(repository_path, "config"))
+          config = File.read(File.join(repository_path, "config"))
 
-        expect(config).to include("[gitlab]")
-        expect(config).to include("fullpath = #{repository_path}")
+          expect(config).to include("[gitlab]")
+          expect(config).to include("fullpath = #{repository_path}")
+        end
+      end
+
+      context 'repository does not exist' do
+        it 'raises NoRepository and does not call Gitaly WriteConfig' do
+          repository = Gitlab::Git::Repository.new('default', 'does/not/exist.git', '', 'group/project')
+
+          expect(repository.gitaly_repository_client).not_to receive(:set_full_path)
+
+          expect do
+            repository.set_full_path(full_path: 'foo/bar.git')
+          end.to raise_error(Gitlab::Git::Repository::NoRepository)
+        end
       end
     end
 
-    context 'repository does not exist' do
-      it 'raises NoRepository and does not call Gitaly WriteConfig' do
-        repository = Gitlab::Git::Repository.new('default', 'does/not/exist.git', '', 'group/project')
+    context 'with :set_full_path enabled' do
+      before do
+        stub_feature_flags(set_full_path: true)
+      end
 
-        expect(repository.gitaly_repository_client).not_to receive(:set_full_path)
+      it_behaves_like '#set_full_path'
+    end
 
-        expect do
-          repository.set_full_path(full_path: 'foo/bar.git')
-        end.to raise_error(Gitlab::Git::Repository::NoRepository)
+    context 'with :set_full_path disabled' do
+      before do
+        stub_feature_flags(set_full_path: false)
       end
+
+      it_behaves_like '#set_full_path'
     end
   end
 
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index 53805d67f9f21a3204ef27213505773ed2233b81..95063861b77c720a37ec7e80ec70d5b7e6d40eb1 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -333,4 +333,17 @@
       client.replicate(source_repository)
     end
   end
+
+  describe '#set_full_path' do
+    let(:path) { 'repo/path' }
+
+    it 'sends a set_full_path message' do
+      expect_any_instance_of(Gitaly::RepositoryService::Stub)
+        .to receive(:set_full_path)
+        .with(gitaly_request_with_params(path: path), kind_of(Hash))
+        .and_return(double)
+
+      client.set_full_path(path)
+    end
+  end
 end