diff --git a/lib/modules/manager/gradle/artifacts.spec.ts b/lib/modules/manager/gradle/artifacts.spec.ts
index d42d22dc55c691d057c27a24a6762beab4cc1783..087952f444900b1989199bff6c923deb185a5d10 100644
--- a/lib/modules/manager/gradle/artifacts.spec.ts
+++ b/lib/modules/manager/gradle/artifacts.spec.ts
@@ -12,6 +12,7 @@ import {
   logger,
   mockedFunction,
   partial,
+  scm,
 } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
@@ -61,7 +62,7 @@ describe('modules/manager/gradle/artifacts', () => {
     });
 
     fs.findUpLocal.mockResolvedValue('gradlew');
-    git.getFileList.mockResolvedValue([
+    scm.getFileList.mockResolvedValue([
       'gradlew',
       'build.gradle',
       'gradle.lockfile',
@@ -92,7 +93,7 @@ describe('modules/manager/gradle/artifacts', () => {
 
   it('aborts if no lockfile is found', async () => {
     const execSnapshots = mockExecAll();
-    git.getFileList.mockResolvedValue(['build.gradle', 'settings.gradle']);
+    scm.getFileList.mockResolvedValue(['build.gradle', 'settings.gradle']);
 
     expect(
       await updateArtifacts({
diff --git a/lib/modules/manager/gradle/artifacts.ts b/lib/modules/manager/gradle/artifacts.ts
index 671aa24a628fc725a308def3568348d9e27e7952..68efbcb4206c867493edae4cd56ce509b5bc6dd7 100644
--- a/lib/modules/manager/gradle/artifacts.ts
+++ b/lib/modules/manager/gradle/artifacts.ts
@@ -6,8 +6,9 @@ import { logger } from '../../../logger';
 import { exec } from '../../../util/exec';
 import type { ExecOptions } from '../../../util/exec/types';
 import { findUpLocal, readLocalFile, writeLocalFile } from '../../../util/fs';
-import { getFileList, getFiles, getRepoStatus } from '../../../util/git';
+import { getFiles, getRepoStatus } from '../../../util/git';
 import { regEx } from '../../../util/regex';
+import { scm } from '../../platform/scm';
 import {
   extraEnv,
   extractGradleVersion,
@@ -94,7 +95,7 @@ export async function updateArtifacts({
 }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
   logger.debug(`gradle.updateArtifacts(${packageFileName})`);
 
-  const fileList = await getFileList();
+  const fileList = await scm.getFileList();
   const lockFiles = fileList.filter((file) => isLockFile(file));
   if (!lockFiles.length) {
     logger.debug('No Gradle dependency lockfiles found - skipping update');
diff --git a/lib/modules/manager/nuget/artifacts.spec.ts b/lib/modules/manager/nuget/artifacts.spec.ts
index b6ae31d6cc5749d744ad65900ccd132e09f4272a..5520b23a89ea87cc64a09b813d72bb363edf48e1 100644
--- a/lib/modules/manager/nuget/artifacts.spec.ts
+++ b/lib/modules/manager/nuget/artifacts.spec.ts
@@ -1,6 +1,6 @@
 import { join } from 'upath';
 import { envMock, mockExecAll } from '../../../../test/exec-util';
-import { env, fs, git, mocked } from '../../../../test/util';
+import { env, fs, git, mocked, scm } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
 import * as docker from '../../../util/exec/docker';
@@ -40,7 +40,7 @@ describe('modules/manager/nuget/artifacts', () => {
     getDefaultRegistries.mockReturnValue([]);
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
     fs.privateCacheDir.mockImplementation(realFs.privateCacheDir);
-    git.getFileList.mockResolvedValueOnce([]);
+    scm.getFileList.mockResolvedValueOnce([]);
     GlobalConfig.set(adminConfig);
     docker.resetPrefetchedImages();
   });
diff --git a/lib/modules/manager/nuget/package-tree.spec.ts b/lib/modules/manager/nuget/package-tree.spec.ts
index a55418292934794ab5615797ef263e0b3241849b..3b9e99e04c860e370a29a728bfd04237c8d58276 100644
--- a/lib/modules/manager/nuget/package-tree.spec.ts
+++ b/lib/modules/manager/nuget/package-tree.spec.ts
@@ -1,7 +1,7 @@
 import { fs as memfs } from 'memfs';
 import upath from 'upath';
 import { Fixtures } from '../../../../test/fixtures';
-import { git } from '../../../../test/util';
+import { scm } from '../../../../test/util';
 import { GlobalConfig } from '../../../config/global';
 import type { RepoGlobalConfig } from '../../../config/types';
 import { getDependentPackageFiles } from './package-tree';
@@ -27,7 +27,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('returns self for single project', async () => {
-      git.getFileList.mockResolvedValue(['single.csproj']);
+      scm.getFileList.mockResolvedValue(['single.csproj']);
       Fixtures.mock({
         '/tmp/repo/single.csproj': Fixtures.get(
           'single-project-file/single.csproj'
@@ -40,7 +40,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('returns self for two projects with no references', async () => {
-      git.getFileList.mockResolvedValue(['one.csproj', 'two.csproj']);
+      scm.getFileList.mockResolvedValue(['one.csproj', 'two.csproj']);
       Fixtures.mock({
         '/tmp/repo/one.csproj': Fixtures.get('two-no-reference/one.csproj'),
         '/tmp/repo/two.csproj': Fixtures.get('two-no-reference/two.csproj'),
@@ -55,7 +55,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('returns projects for two projects with one reference', async () => {
-      git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
+      scm.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
       Fixtures.mock({
         '/tmp/repo/one/one.csproj': Fixtures.get(
           'two-one-reference/one/one.csproj'
@@ -72,7 +72,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('returns project for two projects with one reference and central versions', async () => {
-      git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
+      scm.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
       Fixtures.mock({
         '/tmp/repo/one/one.csproj': Fixtures.get(
           'two-one-reference-with-central-versions/one/one.csproj'
@@ -94,7 +94,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('returns projects for three projects with two linear references', async () => {
-      git.getFileList.mockResolvedValue([
+      scm.getFileList.mockResolvedValue([
         'one/one.csproj',
         'two/two.csproj',
         'three/three.csproj',
@@ -128,7 +128,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('returns projects for three projects with two tree-like references', async () => {
-      git.getFileList.mockResolvedValue([
+      scm.getFileList.mockResolvedValue([
         'one/one.csproj',
         'two/two.csproj',
         'three/three.csproj',
@@ -160,7 +160,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('throws error on circular reference', async () => {
-      git.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
+      scm.getFileList.mockResolvedValue(['one/one.csproj', 'two/two.csproj']);
       Fixtures.mock({
         '/tmp/repo/one/one.csproj': Fixtures.get(
           'circular-reference/one/one.csproj'
@@ -176,7 +176,7 @@ describe('modules/manager/nuget/package-tree', () => {
     });
 
     it('skips on invalid xml file', async () => {
-      git.getFileList.mockResolvedValue(['foo/bar.csproj']);
+      scm.getFileList.mockResolvedValue(['foo/bar.csproj']);
       Fixtures.mock({ '/tmp/repo/foo/bar.csproj': '<invalid' });
       expect(await getDependentPackageFiles('foo/bar.csproj')).toEqual([
         { isLeaf: true, name: 'foo/bar.csproj' },
diff --git a/lib/modules/manager/nuget/package-tree.ts b/lib/modules/manager/nuget/package-tree.ts
index 0da8c32a6929b8d6725ad6572720a164b9b54f04..ca277baf52c53f0426e06460da7ec3fe221d175f 100644
--- a/lib/modules/manager/nuget/package-tree.ts
+++ b/lib/modules/manager/nuget/package-tree.ts
@@ -3,7 +3,7 @@ import { Graph } from 'graph-data-structure';
 import { minimatch } from 'minimatch';
 import upath from 'upath';
 import { logger } from '../../../logger';
-import { getFileList } from '../../../util/git';
+import { scm } from '../../platform/scm';
 import type { ProjectFile } from './types';
 import { readFileAsXmlDocument } from './util';
 
@@ -129,7 +129,7 @@ function reframeRelativePathToRootOfRepo(
  * Get a list of package files in localDir
  */
 async function getAllPackageFiles(): Promise<string[]> {
-  const allFiles = await getFileList();
+  const allFiles = await scm.getFileList();
   const filteredPackageFiles = allFiles.filter(
     minimatch.filter('*.{cs,vb,fs}proj', { matchBase: true, nocase: true })
   );
diff --git a/lib/modules/platform/default-scm.spec.ts b/lib/modules/platform/default-scm.spec.ts
index 023948fa3dacaec6f2e22f0474dd94533029ba16..7c9f7128d8de3ab5aae05bc92ecf06b428f62ba9 100644
--- a/lib/modules/platform/default-scm.spec.ts
+++ b/lib/modules/platform/default-scm.spec.ts
@@ -48,4 +48,16 @@ describe('modules/platform/default-scm', () => {
     await defaultGitScm.isBranchModified('branchName');
     expect(git.isBranchModified).toHaveBeenCalledTimes(1);
   });
+
+  it('delegate getFileList to util/git', async () => {
+    git.getFileList.mockResolvedValueOnce([]);
+    await defaultGitScm.getFileList();
+    expect(git.getFileList).toHaveBeenCalledTimes(1);
+  });
+
+  it('delegate checkoutBranch to util/git', async () => {
+    git.checkoutBranch.mockResolvedValueOnce('');
+    await defaultGitScm.checkoutBranch('branchName');
+    expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+  });
 });
diff --git a/lib/modules/platform/default-scm.ts b/lib/modules/platform/default-scm.ts
index d21f3cff0b832eb826322c473558475dc2309f1a..f210500a9a0d42b9a85c786a9e20e68d4c437312 100644
--- a/lib/modules/platform/default-scm.ts
+++ b/lib/modules/platform/default-scm.ts
@@ -30,4 +30,12 @@ export class DefaultGitScm implements PlatformScm {
   isBranchModified(branchName: string): Promise<boolean> {
     return git.isBranchModified(branchName);
   }
+
+  getFileList(): Promise<string[]> {
+    return git.getFileList();
+  }
+
+  checkoutBranch(branchName: string): Promise<CommitSha> {
+    return git.checkoutBranch(branchName);
+  }
 }
diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts
index 57917c8ca690e36983a35ce12019e37120e7488f..12205f74099bb25d943b66215863c5f5d72824e5 100644
--- a/lib/modules/platform/types.ts
+++ b/lib/modules/platform/types.ts
@@ -225,4 +225,6 @@ export interface PlatformScm {
   getBranchCommit(branchName: string): Promise<CommitSha | null>;
   deleteBranch(branchName: string): Promise<void>;
   commitAndPush(commitConfig: CommitFilesConfig): Promise<CommitSha | null>;
+  getFileList(): Promise<string[]>;
+  checkoutBranch(branchName: string): Promise<CommitSha>;
 }
diff --git a/lib/workers/repository/config-migration/branch/create.spec.ts b/lib/workers/repository/config-migration/branch/create.spec.ts
index d1e450be9d8598d17fdaf14d6025582ebc55db47..6f854ccc3c0075c8baba8a47c1e84a5b6cc9bab0 100644
--- a/lib/workers/repository/config-migration/branch/create.spec.ts
+++ b/lib/workers/repository/config-migration/branch/create.spec.ts
@@ -2,7 +2,6 @@ import type { Indent } from 'detect-indent';
 import { Fixtures } from '../../../../../test/fixtures';
 import { RenovateConfig, getConfig, partial } from '../../../../../test/util';
 import { scm } from '../../../../modules/platform/scm';
-import { checkoutBranch } from '../../../../util/git';
 import { createConfigMigrationBranch } from './create';
 import { MigratedDataFactory } from './migrated-data';
 import type { MigratedData } from './migrated-data';
@@ -37,7 +36,7 @@ describe('workers/repository/config-migration/branch/create', () => {
   describe('createConfigMigrationBranch', () => {
     it('applies the default commit message', async () => {
       await createConfigMigrationBranch(config, migratedConfigData);
-      expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+      expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
       expect(scm.commitAndPush).toHaveBeenCalledWith({
         branchName: 'renovate/migrate-config',
         baseBranch: 'dev',
@@ -60,7 +59,7 @@ describe('workers/repository/config-migration/branch/create', () => {
 
       await createConfigMigrationBranch(config, migratedConfigData);
 
-      expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+      expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
       expect(scm.commitAndPush).toHaveBeenCalledWith({
         branchName: 'renovate/migrate-config',
         baseBranch: 'dev',
@@ -84,7 +83,7 @@ describe('workers/repository/config-migration/branch/create', () => {
         const message = `PREFIX: migrate config renovate.json`;
         await createConfigMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+        expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
         expect(scm.commitAndPush).toHaveBeenCalledWith({
           branchName: 'renovate/migrate-config',
           baseBranch: 'dev',
@@ -109,7 +108,7 @@ describe('workers/repository/config-migration/branch/create', () => {
         const message = `Migrate config renovate.json ${suffix}`;
         await createConfigMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+        expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
         expect(scm.commitAndPush).toHaveBeenCalledWith({
           branchName: 'renovate/migrate-config',
           baseBranch: 'dev',
@@ -135,7 +134,7 @@ describe('workers/repository/config-migration/branch/create', () => {
 
         await createConfigMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+        expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
         expect(scm.commitAndPush).toHaveBeenCalledWith({
           branchName: 'renovate/migrate-config',
           baseBranch: 'dev',
@@ -160,7 +159,7 @@ describe('workers/repository/config-migration/branch/create', () => {
 
         await createConfigMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+        expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
         expect(scm.commitAndPush).toHaveBeenCalledWith({
           branchName: 'renovate/migrate-config',
           baseBranch: 'dev',
diff --git a/lib/workers/repository/config-migration/branch/create.ts b/lib/workers/repository/config-migration/branch/create.ts
index e29fa0724957207db760f8d232e723a21de7d36c..e188e212f5a82e0a4308dad50e2e353b609e6138 100644
--- a/lib/workers/repository/config-migration/branch/create.ts
+++ b/lib/workers/repository/config-migration/branch/create.ts
@@ -2,7 +2,6 @@ import { GlobalConfig } from '../../../../config/global';
 import type { RenovateConfig } from '../../../../config/types';
 import { logger } from '../../../../logger';
 import { scm } from '../../../../modules/platform/scm';
-import { checkoutBranch } from '../../../../util/git';
 import { getMigrationBranchName } from '../common';
 import { ConfigMigrationCommitMessageFactory } from './commit-message';
 import { MigratedDataFactory } from './migrated-data';
@@ -29,7 +28,7 @@ export async function createConfigMigrationBranch(
     return Promise.resolve(null);
   }
 
-  await checkoutBranch(config.defaultBranch!);
+  await scm.checkoutBranch(config.defaultBranch!);
   const contents = await MigratedDataFactory.applyPrettierFormatting(
     migratedConfigData
   );
diff --git a/lib/workers/repository/config-migration/branch/index.spec.ts b/lib/workers/repository/config-migration/branch/index.spec.ts
index a9f89c60599ebbfa61adcb26efd092f5974b06f8..34edd71ef7c3b70c29bf100edcca112c5e823cdf 100644
--- a/lib/workers/repository/config-migration/branch/index.spec.ts
+++ b/lib/workers/repository/config-migration/branch/index.spec.ts
@@ -56,7 +56,7 @@ describe('workers/repository/config-migration/branch/index', () => {
       const res = await checkConfigMigrationBranch(config, migratedData);
       // TODO: types (#7154)
       expect(res).toBe(`${config.branchPrefix!}migrate-config`);
-      expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+      expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
       expect(git.commitFiles).toHaveBeenCalledTimes(0);
       expect(logger.debug).toHaveBeenCalledWith(
         'Config Migration PR already exists'
@@ -72,7 +72,7 @@ describe('workers/repository/config-migration/branch/index', () => {
       const res = await checkConfigMigrationBranch(config, migratedData);
       // TODO: types (#7154)
       expect(res).toBe(`${config.branchPrefix!}migrate-config`);
-      expect(git.checkoutBranch).toHaveBeenCalledTimes(0);
+      expect(scm.checkoutBranch).toHaveBeenCalledTimes(0);
       expect(git.commitFiles).toHaveBeenCalledTimes(0);
     });
 
@@ -83,7 +83,7 @@ describe('workers/repository/config-migration/branch/index', () => {
       const res = await checkConfigMigrationBranch(config, migratedData);
       // TODO: types (#7154)
       expect(res).toBe(`${config.branchPrefix!}migrate-config`);
-      expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+      expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
       expect(git.commitFiles).toHaveBeenCalledTimes(0);
       expect(logger.debug).toHaveBeenCalledWith('Need to create migration PR');
     });
@@ -98,7 +98,7 @@ describe('workers/repository/config-migration/branch/index', () => {
       const res = await checkConfigMigrationBranch(config, migratedData);
       // TODO: types (#7154)
       expect(res).toBe(`${config.branchPrefix!}migrate-config`);
-      expect(git.checkoutBranch).toHaveBeenCalledTimes(0);
+      expect(scm.checkoutBranch).toHaveBeenCalledTimes(0);
       expect(git.commitFiles).toHaveBeenCalledTimes(0);
     });
 
@@ -112,7 +112,7 @@ describe('workers/repository/config-migration/branch/index', () => {
         scm.branchExists.mockResolvedValueOnce(true);
         const res = await checkConfigMigrationBranch(config, migratedData);
         expect(res).toBeNull();
-        expect(git.checkoutBranch).toHaveBeenCalledTimes(0);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(0);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
         expect(scm.deleteBranch).toHaveBeenCalledTimes(1);
         expect(logger.debug).toHaveBeenCalledWith(
diff --git a/lib/workers/repository/config-migration/branch/index.ts b/lib/workers/repository/config-migration/branch/index.ts
index 25ee7ea7bc960b850773691854aa202d0a731f30..3142269212c71e4aa860b8623ef52a66c4a00cae 100644
--- a/lib/workers/repository/config-migration/branch/index.ts
+++ b/lib/workers/repository/config-migration/branch/index.ts
@@ -4,7 +4,6 @@ import { logger } from '../../../../logger';
 import { FindPRConfig, Pr, platform } from '../../../../modules/platform';
 import { ensureComment } from '../../../../modules/platform/comment';
 import { scm } from '../../../../modules/platform/scm';
-import { checkoutBranch } from '../../../../util/git';
 import { getMigrationBranchName } from '../common';
 import { ConfigMigrationCommitMessageFactory } from './commit-message';
 import { createConfigMigrationBranch } from './create';
@@ -67,7 +66,7 @@ export async function checkConfigMigrationBranch(
     await createConfigMigrationBranch(config, migratedConfigData);
   }
   if (!GlobalConfig.get('dryRun')) {
-    await checkoutBranch(configMigrationBranch);
+    await scm.checkoutBranch(configMigrationBranch);
   }
   return configMigrationBranch;
 }
diff --git a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts
index 09f7bcecc13af8344a8a618a53a806e6bc08b82b..3f1b32301a0d611ed079ee242b7c206f90aa0532 100644
--- a/lib/workers/repository/config-migration/branch/migrated-data.spec.ts
+++ b/lib/workers/repository/config-migration/branch/migrated-data.spec.ts
@@ -1,11 +1,10 @@
 import detectIndent from 'detect-indent';
 import { Fixtures } from '../../../../../test/fixtures';
-import { mockedFunction } from '../../../../../test/util';
+import { mockedFunction, scm } from '../../../../../test/util';
 
 import { migrateConfig } from '../../../../config/migration';
 import { logger } from '../../../../logger';
 import { readLocalFile } from '../../../../util/fs';
-import { getFileList } from '../../../../util/git';
 import { detectRepoFileConfig } from '../../init/merge';
 import { MigratedDataFactory } from './migrated-data';
 
@@ -141,7 +140,7 @@ describe('workers/repository/config-migration/branch/migrated-data', () => {
     });
 
     beforeEach(() => {
-      mockedFunction(getFileList).mockResolvedValue([]);
+      mockedFunction(scm.getFileList).mockResolvedValue([]);
     });
 
     it('does not format when no prettier config is present', async () => {
@@ -173,7 +172,7 @@ describe('workers/repository/config-migration/branch/migrated-data', () => {
 
     it('formats when prettier config file is found', async () => {
       const formatted = formattedMigratedData.content;
-      mockedFunction(getFileList).mockResolvedValue(['.prettierrc']);
+      mockedFunction(scm.getFileList).mockResolvedValue(['.prettierrc']);
       await MigratedDataFactory.getAsync();
       await expect(
         MigratedDataFactory.applyPrettierFormatting(migratedData)
diff --git a/lib/workers/repository/config-migration/branch/migrated-data.ts b/lib/workers/repository/config-migration/branch/migrated-data.ts
index e0f1ec79832ed553b07f1b2d62ab37d75f74eed5..1961a817ad96d5a8a4e0b92019474c0490324a37 100644
--- a/lib/workers/repository/config-migration/branch/migrated-data.ts
+++ b/lib/workers/repository/config-migration/branch/migrated-data.ts
@@ -5,8 +5,8 @@ import upath from 'upath';
 import { migrateConfig } from '../../../../config/migration';
 import { prettier } from '../../../../expose.cjs';
 import { logger } from '../../../../logger';
+import { scm } from '../../../../modules/platform/scm';
 import { readLocalFile } from '../../../../util/fs';
-import { getFileList } from '../../../../util/git';
 import { detectRepoFileConfig } from '../../init/merge';
 
 export interface MigratedData {
@@ -43,7 +43,7 @@ export async function applyPrettierFormatting(
 ): Promise<string> {
   try {
     logger.trace('applyPrettierFormatting - START');
-    const fileList = await getFileList();
+    const fileList = await scm.getFileList();
     let prettierExists = fileList.some((file) =>
       prettierConfigFilenames.has(file)
     );
diff --git a/lib/workers/repository/config-migration/branch/rebase.spec.ts b/lib/workers/repository/config-migration/branch/rebase.spec.ts
index 1ac78e49ad33228d84eb7f5d1509f2b051ef548f..4f7ebdb6884e06c966e13c18795e9316ca2fb42a 100644
--- a/lib/workers/repository/config-migration/branch/rebase.spec.ts
+++ b/lib/workers/repository/config-migration/branch/rebase.spec.ts
@@ -9,7 +9,6 @@ import {
   scm,
 } from '../../../../../test/util';
 import { GlobalConfig } from '../../../../config/global';
-import { checkoutBranch } from '../../../../util/git';
 import { MigratedDataFactory } from './migrated-data';
 import type { MigratedData } from './migrated-data';
 import { jsonStripWhitespaces, rebaseMigrationBranch } from './rebase';
@@ -60,7 +59,7 @@ describe('workers/repository/config-migration/branch/rebase', () => {
 
       await rebaseMigrationBranch(config, migratedConfigData);
 
-      expect(checkoutBranch).toHaveBeenCalledTimes(0);
+      expect(scm.checkoutBranch).toHaveBeenCalledTimes(0);
       expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
     });
 
@@ -76,7 +75,7 @@ describe('workers/repository/config-migration/branch/rebase', () => {
 
         await rebaseMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledTimes(0);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(0);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
         expect(git.getFile).toHaveBeenCalledTimes(1);
       }
@@ -93,7 +92,7 @@ describe('workers/repository/config-migration/branch/rebase', () => {
 
       await rebaseMigrationBranch(config, migratedConfigData);
 
-      expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+      expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
       expect(scm.commitAndPush).toHaveBeenCalledTimes(1);
     });
 
@@ -111,7 +110,7 @@ describe('workers/repository/config-migration/branch/rebase', () => {
 
         await rebaseMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
+        expect(scm.checkoutBranch).toHaveBeenCalledWith(config.defaultBranch);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(1);
         expect(scm.commitAndPush).toHaveBeenCalledWith({
           branchName: 'renovate/migrate-config',
@@ -144,7 +143,7 @@ describe('workers/repository/config-migration/branch/rebase', () => {
 
         await rebaseMigrationBranch(config, migratedConfigData);
 
-        expect(checkoutBranch).toHaveBeenCalledTimes(0);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(0);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
       }
     );
diff --git a/lib/workers/repository/config-migration/branch/rebase.ts b/lib/workers/repository/config-migration/branch/rebase.ts
index cb932c114842442c1e3e5b3738723e06a0851387..a638401972ea06f563d672090b7ba3f8809a075d 100644
--- a/lib/workers/repository/config-migration/branch/rebase.ts
+++ b/lib/workers/repository/config-migration/branch/rebase.ts
@@ -3,7 +3,7 @@ import { GlobalConfig } from '../../../../config/global';
 import type { RenovateConfig } from '../../../../config/types';
 import { logger } from '../../../../logger';
 import { scm } from '../../../../modules/platform/scm';
-import { checkoutBranch, getFile } from '../../../../util/git';
+import { getFile } from '../../../../util/git';
 import { quickStringify } from '../../../../util/stringify';
 import { getMigrationBranchName } from '../common';
 import { ConfigMigrationCommitMessageFactory } from './commit-message';
@@ -42,7 +42,7 @@ export async function rebaseMigrationBranch(
   );
   const commitMessage = commitMessageFactory.getCommitMessage();
 
-  await checkoutBranch(config.defaultBranch!);
+  await scm.checkoutBranch(config.defaultBranch!);
   contents = await MigratedDataFactory.applyPrettierFormatting(
     migratedConfigData
   );
diff --git a/lib/workers/repository/extract/index.spec.ts b/lib/workers/repository/extract/index.spec.ts
index 4b39cf0be52636debc4fc9df048eda1f521d9bfc..ca553db29719518ca7b586e6148e98bdb541c08e 100644
--- a/lib/workers/repository/extract/index.spec.ts
+++ b/lib/workers/repository/extract/index.spec.ts
@@ -1,4 +1,4 @@
-import { getConfig, git, mocked } from '../../../../test/util';
+import { getConfig, mocked, scm } from '../../../../test/util';
 import type { RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
 import * as _managerFiles from './manager-files';
@@ -16,7 +16,7 @@ describe('workers/repository/extract/index', () => {
 
     beforeEach(() => {
       jest.resetAllMocks();
-      git.getFileList.mockResolvedValue(fileList);
+      scm.getFileList.mockResolvedValue(fileList);
       config = getConfig();
     });
 
diff --git a/lib/workers/repository/extract/index.ts b/lib/workers/repository/extract/index.ts
index a2337de4a45d263ad7287bbf9f1d9535b85aff47..9f4f45cc9bcb39f308391b40cd66f1fc09c03041 100644
--- a/lib/workers/repository/extract/index.ts
+++ b/lib/workers/repository/extract/index.ts
@@ -3,7 +3,7 @@ import { getManagerConfig, mergeChildConfig } from '../../../config';
 import type { ManagerConfig, RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
 import { getManagerList, hashMap } from '../../../modules/manager';
-import { getFileList } from '../../../util/git';
+import { scm } from '../../../modules/platform/scm';
 import type { ExtractResult, WorkerExtractConfig } from '../../types';
 import { getMatchingFiles } from './file-match';
 import { getManagerPackageFiles } from './manager-files';
@@ -20,7 +20,7 @@ export async function extractAllDependencies(
     );
   }
   const extractList: WorkerExtractConfig[] = [];
-  const fileList = await getFileList();
+  const fileList = await scm.getFileList();
 
   const tryConfig = (managerConfig: ManagerConfig): void => {
     const matchingFileList = getMatchingFiles(managerConfig, fileList);
diff --git a/lib/workers/repository/init/merge.spec.ts b/lib/workers/repository/init/merge.spec.ts
index 5a03b80b845cede58bddd859aa99787a14f2190b..595275293d4223ff4d9001dfbdcd2e5683b9400a 100644
--- a/lib/workers/repository/init/merge.spec.ts
+++ b/lib/workers/repository/init/merge.spec.ts
@@ -2,11 +2,11 @@ import {
   RenovateConfig,
   fs,
   getConfig,
-  git,
   logger,
   mocked,
   partial,
   platform,
+  scm,
 } from '../../../../test/util';
 import * as _migrateAndValidate from '../../../config/migrate-validate';
 import * as _migrate from '../../../config/migration';
@@ -44,7 +44,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('returns config if not found', async () => {
-      git.getFileList.mockResolvedValue(['package.json']);
+      scm.getFileList.mockResolvedValue(['package.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       expect(await detectRepoFileConfig()).toEqual({});
     });
@@ -56,7 +56,7 @@ describe('workers/repository/init/merge', () => {
           partial<RepoCacheData>({ configFileName: 'renovate.json' })
         );
       platform.getRawFile.mockRejectedValueOnce(new Error());
-      git.getFileList.mockResolvedValue(['package.json']);
+      scm.getFileList.mockResolvedValue(['package.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       expect(await detectRepoFileConfig()).toEqual({});
       expect(logger.logger.debug).toHaveBeenCalledWith(
@@ -65,7 +65,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('uses package.json config if found', async () => {
-      git.getFileList.mockResolvedValue(['package.json']);
+      scm.getFileList.mockResolvedValue(['package.json']);
       const pJson = JSON.stringify({
         name: 'something',
         renovate: {
@@ -86,7 +86,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('massages package.json renovate string', async () => {
-      git.getFileList.mockResolvedValue(['package.json']);
+      scm.getFileList.mockResolvedValue(['package.json']);
       const pJson = JSON.stringify({
         name: 'something',
         renovate: 'github>renovatebot/renovate',
@@ -100,7 +100,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('returns error if cannot parse', async () => {
-      git.getFileList.mockResolvedValue(['package.json', 'renovate.json']);
+      scm.getFileList.mockResolvedValue(['package.json', 'renovate.json']);
       fs.readLocalFile.mockResolvedValue('cannot parse');
       expect(await detectRepoFileConfig()).toEqual({
         configFileName: 'renovate.json',
@@ -112,7 +112,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('throws error if duplicate keys', async () => {
-      git.getFileList.mockResolvedValue(['package.json', '.renovaterc']);
+      scm.getFileList.mockResolvedValue(['package.json', '.renovaterc']);
       fs.readLocalFile.mockResolvedValue(
         '{ "enabled": true, "enabled": false }'
       );
@@ -130,7 +130,7 @@ describe('workers/repository/init/merge', () => {
       const configFileRaw = `{
         // this is json5 format
       }`;
-      git.getFileList.mockResolvedValue(['package.json', 'renovate.json5']);
+      scm.getFileList.mockResolvedValue(['package.json', 'renovate.json5']);
       fs.readLocalFile.mockResolvedValue(configFileRaw);
       expect(await detectRepoFileConfig()).toEqual({
         configFileName: 'renovate.json5',
@@ -140,7 +140,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('finds .github/renovate.json', async () => {
-      git.getFileList.mockResolvedValue([
+      scm.getFileList.mockResolvedValue([
         'package.json',
         '.github/renovate.json',
       ]);
@@ -153,7 +153,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('finds .gitlab/renovate.json', async () => {
-      git.getFileList.mockResolvedValue([
+      scm.getFileList.mockResolvedValue([
         'package.json',
         '.gitlab/renovate.json',
       ]);
@@ -166,7 +166,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('finds .renovaterc.json', async () => {
-      git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
+      scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       platform.getRawFile.mockResolvedValueOnce('{"something":"new"}');
       expect(await detectRepoFileConfig()).toEqual({
@@ -184,7 +184,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('finds .renovaterc.json5', async () => {
-      git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json5']);
+      scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json5']);
       fs.readLocalFile.mockResolvedValue('{}');
       platform.getRawFile.mockResolvedValueOnce('{"something":"new"}');
       expect(await detectRepoFileConfig()).toEqual({
@@ -225,7 +225,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('throws error if misconfigured', async () => {
-      git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
+      scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       migrateAndValidate.migrateAndValidate.mockResolvedValueOnce({
         errors: [{ topic: 'dep', message: 'test error' }],
@@ -241,7 +241,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('migrates nested config', async () => {
-      git.getFileList.mockResolvedValue(['renovate.json']);
+      scm.getFileList.mockResolvedValue(['renovate.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       migrateAndValidate.migrateAndValidate.mockImplementation((_, c) => {
         // We shouldn't see packageRules here (avoids #14827).
@@ -271,7 +271,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('ignores presets', async () => {
-      git.getFileList.mockResolvedValue(['renovate.json']);
+      scm.getFileList.mockResolvedValue(['renovate.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       migrateAndValidate.migrateAndValidate.mockResolvedValue({
         extends: ['config:base'],
@@ -290,7 +290,7 @@ describe('workers/repository/init/merge', () => {
     });
 
     it('continues if no errors', async () => {
-      git.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
+      scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       migrateAndValidate.migrateAndValidate.mockResolvedValue({
         warnings: [],
diff --git a/lib/workers/repository/init/merge.ts b/lib/workers/repository/init/merge.ts
index 04c3cba0e61cba46c77369278c05222d4b263e50..38d6a2ba0d6188a9e0443a09e08ce68ff02717cd 100644
--- a/lib/workers/repository/init/merge.ts
+++ b/lib/workers/repository/init/merge.ts
@@ -17,17 +17,17 @@ import {
 import { logger } from '../../../logger';
 import * as npmApi from '../../../modules/datasource/npm';
 import { platform } from '../../../modules/platform';
+import { scm } from '../../../modules/platform/scm';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import { getCache } from '../../../util/cache/repository';
 import { readLocalFile } from '../../../util/fs';
-import { getFileList } from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import * as queue from '../../../util/http/queue';
 import * as throttle from '../../../util/http/throttle';
 import type { RepoFileConfig } from './types';
 
 async function detectConfigFile(): Promise<string | null> {
-  const fileList = await getFileList();
+  const fileList = await scm.getFileList();
   for (const fileName of configFileNames) {
     if (fileName === 'package.json') {
       try {
diff --git a/lib/workers/repository/onboarding/branch/check.spec.ts b/lib/workers/repository/onboarding/branch/check.spec.ts
index e8f03bb6515a06de52b632b37c0629bf9cc58219..74684f8f809352ba438da66e483df6fa499a4cf0 100644
--- a/lib/workers/repository/onboarding/branch/check.spec.ts
+++ b/lib/workers/repository/onboarding/branch/check.spec.ts
@@ -4,6 +4,7 @@ import {
   mocked,
   partial,
   platform,
+  scm,
 } from '../../../../../test/util';
 import { REPOSITORY_CLOSED_ONBOARDING } from '../../../../constants/error-messages';
 import { logger } from '../../../../logger';
@@ -49,7 +50,7 @@ describe('workers/repository/onboarding/branch/check', () => {
         onboardingBranchSha: 'onboarding-sha',
       },
     });
-    git.getFileList.mockResolvedValue([]);
+    scm.getFileList.mockResolvedValue([]);
     await isOnboarded(config);
     expect(logger.debug).not.toHaveBeenCalledWith(
       'Onboarding cache is valid. Repo is not onboarded'
@@ -59,7 +60,7 @@ describe('workers/repository/onboarding/branch/check', () => {
   it('continues with normal logic if closedPr exists', async () => {
     cache.getCache.mockReturnValue({});
     platform.findPr.mockResolvedValue(partial<Pr>());
-    git.getFileList.mockResolvedValue([]);
+    scm.getFileList.mockResolvedValue([]);
     await expect(isOnboarded(config)).rejects.toThrow(
       REPOSITORY_CLOSED_ONBOARDING
     );
diff --git a/lib/workers/repository/onboarding/branch/check.ts b/lib/workers/repository/onboarding/branch/check.ts
index 3a3ec850809eb832d4394ae6e6f26741749e0571..bf3abf09f1fe03207ff80da9004bb4dee7343aa4 100644
--- a/lib/workers/repository/onboarding/branch/check.ts
+++ b/lib/workers/repository/onboarding/branch/check.ts
@@ -7,13 +7,14 @@ import {
 import { logger } from '../../../../logger';
 import { Pr, platform } from '../../../../modules/platform';
 import { ensureComment } from '../../../../modules/platform/comment';
+import { scm } from '../../../../modules/platform/scm';
 import { getCache } from '../../../../util/cache/repository';
 import { readLocalFile } from '../../../../util/fs';
-import { getBranchCommit, getFileList } from '../../../../util/git';
+import { getBranchCommit } from '../../../../util/git';
 
 async function findFile(fileName: string): Promise<boolean> {
   logger.debug(`findFile(${fileName})`);
-  const fileList = await getFileList();
+  const fileList = await scm.getFileList();
   return fileList.includes(fileName);
 }
 
diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts
index 04fc5ed1856d67db72e99746efe2efbf42a473f1..d9821294b5880b92a4185054c74007ddb364c8d0 100644
--- a/lib/workers/repository/onboarding/branch/index.spec.ts
+++ b/lib/workers/repository/onboarding/branch/index.spec.ts
@@ -3,7 +3,6 @@ import {
   RenovateConfig,
   fs,
   getConfig,
-  git,
   mocked,
   platform,
   scm,
@@ -55,7 +54,7 @@ describe('workers/repository/onboarding/branch/index', () => {
       config = getConfig();
       config.repository = 'some/repo';
       OnboardingState.prUpdateRequested = false;
-      git.getFileList.mockResolvedValue([]);
+      scm.getFileList.mockResolvedValue([]);
       cache.getCache.mockReturnValue({});
     });
 
@@ -96,7 +95,7 @@ describe('workers/repository/onboarding/branch/index', () => {
             '  "$schema": "https://docs.renovatebot.com/renovate-schema.json"\n' +
             '}\n'
         );
-        git.getFileList.mockResolvedValue(['package.json']);
+        scm.getFileList.mockResolvedValue(['package.json']);
         fs.readLocalFile.mockResolvedValue('{}');
         await checkOnboardingBranch(config);
         const file = scm.commitAndPush.mock.calls[0][0]
@@ -121,7 +120,7 @@ describe('workers/repository/onboarding/branch/index', () => {
           '  "extends": ["some/renovate-config"]\n' +
           '}\n'
       );
-      git.getFileList.mockResolvedValue(['package.json']);
+      scm.getFileList.mockResolvedValue(['package.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       await checkOnboardingBranch(config);
       const expectConfig = {
@@ -156,7 +155,7 @@ describe('workers/repository/onboarding/branch/index', () => {
     it('handles skipped onboarding, requireConfig=required, and a config file', async () => {
       config.requireConfig = 'required';
       config.onboarding = false;
-      git.getFileList.mockResolvedValueOnce(['renovate.json']);
+      scm.getFileList.mockResolvedValueOnce(['renovate.json']);
       const res = await checkOnboardingBranch(config);
       expect(res.repoIsOnboarded).toBeTrue();
     });
@@ -171,7 +170,7 @@ describe('workers/repository/onboarding/branch/index', () => {
     it('handles skipped onboarding, requireConfig=required, and no config file', async () => {
       config.requireConfig = 'required';
       config.onboarding = false;
-      git.getFileList.mockResolvedValueOnce(['package.json']);
+      scm.getFileList.mockResolvedValueOnce(['package.json']);
       fs.readLocalFile.mockResolvedValueOnce('{}');
       const onboardingResult = checkOnboardingBranch(config);
       await expect(onboardingResult).rejects.toThrow('disabled');
@@ -179,7 +178,7 @@ describe('workers/repository/onboarding/branch/index', () => {
 
     it('detects repo is onboarded via file', async () => {
       cache.getCache.mockReturnValue(dummyCache);
-      git.getFileList.mockResolvedValueOnce(['renovate.json']);
+      scm.getFileList.mockResolvedValueOnce(['renovate.json']);
       const res = await checkOnboardingBranch(config);
       expect(res.repoIsOnboarded).toBeTrue();
       expect(onboardingCache.deleteOnboardingCache).toHaveBeenCalledTimes(1); // removes onboarding cache when repo is onboarded
@@ -187,7 +186,7 @@ describe('workers/repository/onboarding/branch/index', () => {
 
     it('handles removed cached file name', async () => {
       cache.getCache.mockReturnValue({ configFileName: '.renovaterc' });
-      git.getFileList.mockResolvedValueOnce(['renovate.json']);
+      scm.getFileList.mockResolvedValueOnce(['renovate.json']);
       const res = await checkOnboardingBranch(config);
       expect(res.repoIsOnboarded).toBeTrue();
     });
@@ -236,7 +235,7 @@ describe('workers/repository/onboarding/branch/index', () => {
     });
 
     it('detects repo is onboarded via package.json config', async () => {
-      git.getFileList.mockResolvedValueOnce(['package.json']);
+      scm.getFileList.mockResolvedValueOnce(['package.json']);
       fs.readLocalFile.mockResolvedValueOnce('{"renovate":{}}');
       const res = await checkOnboardingBranch(config);
       expect(res.repoIsOnboarded).toBeTrue();
@@ -264,14 +263,14 @@ describe('workers/repository/onboarding/branch/index', () => {
 
     it('updates onboarding branch', async () => {
       cache.getCache.mockReturnValue(dummyCache);
-      git.getFileList.mockResolvedValue(['package.json']);
+      scm.getFileList.mockResolvedValue(['package.json']);
       platform.findPr.mockResolvedValue(null);
       platform.getBranchPr.mockResolvedValueOnce(mock<Pr>());
       rebase.rebaseOnboardingBranch.mockResolvedValueOnce('123test');
       const res = await checkOnboardingBranch(config);
       expect(res.repoIsOnboarded).toBeFalse();
       expect(res.branchList).toEqual(['renovate/configure']);
-      expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+      expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
       expect(onboardingCache.setOnboardingCache).toHaveBeenCalledTimes(1); // update onboarding cache
       expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
     });
@@ -281,7 +280,7 @@ describe('workers/repository/onboarding/branch/index', () => {
         GlobalConfig.set({ platform: 'github' });
         config.onboardingRebaseCheckbox = true;
         OnboardingState.prUpdateRequested = false;
-        git.getFileList.mockResolvedValueOnce(['package.json']);
+        scm.getFileList.mockResolvedValueOnce(['package.json']);
         platform.findPr.mockResolvedValueOnce(null);
         rebase.rebaseOnboardingBranch.mockResolvedValueOnce(null);
       });
@@ -297,7 +296,7 @@ describe('workers/repository/onboarding/branch/index', () => {
           `Platform '${pl}' does not support extended markdown`
         );
         expect(OnboardingState.prUpdateRequested).toBeTrue();
-        expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
       });
 
@@ -311,7 +310,7 @@ describe('workers/repository/onboarding/branch/index', () => {
           `No rebase checkbox was found in the onboarding PR`
         );
         expect(OnboardingState.prUpdateRequested).toBeTrue();
-        expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
       });
 
@@ -326,7 +325,7 @@ describe('workers/repository/onboarding/branch/index', () => {
         );
         expect(OnboardingState.prUpdateRequested).toBeTrue();
         ``;
-        expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
       });
 
@@ -337,7 +336,7 @@ describe('workers/repository/onboarding/branch/index', () => {
         await checkOnboardingBranch(config);
 
         expect(OnboardingState.prUpdateRequested).toBeFalse();
-        expect(git.checkoutBranch).toHaveBeenCalledTimes(1);
+        expect(scm.checkoutBranch).toHaveBeenCalledTimes(1);
         expect(scm.commitAndPush).toHaveBeenCalledTimes(0);
       });
     });
diff --git a/lib/workers/repository/onboarding/branch/index.ts b/lib/workers/repository/onboarding/branch/index.ts
index c8f50ecefa8575b9bb71f235039901293d7fff9a..e131f8069a4a66672f2a364a6d2a4a2be7316bc0 100644
--- a/lib/workers/repository/onboarding/branch/index.ts
+++ b/lib/workers/repository/onboarding/branch/index.ts
@@ -8,11 +8,8 @@ import {
 } from '../../../../constants/error-messages';
 import { logger } from '../../../../logger';
 import { Pr, platform } from '../../../../modules/platform';
-import {
-  checkoutBranch,
-  getBranchCommit,
-  setGitAuthor,
-} from '../../../../util/git';
+import { scm } from '../../../../modules/platform/scm';
+import { getBranchCommit, setGitAuthor } from '../../../../util/git';
 import { extractAllDependencies } from '../../extract';
 import { mergeRenovateConfig } from '../../init/merge';
 import { OnboardingState } from '../common';
@@ -108,7 +105,7 @@ export async function checkOnboardingBranch(
   if (!GlobalConfig.get('dryRun')) {
     logger.debug('Checkout onboarding branch.');
     // TODO #7154
-    await checkoutBranch(onboardingBranch!);
+    await scm.checkoutBranch(onboardingBranch!);
   }
   // TODO #7154
   const branchList = [onboardingBranch!];
diff --git a/lib/workers/repository/process/extract-update.spec.ts b/lib/workers/repository/process/extract-update.spec.ts
index 47b8e67e3a232f92f6731a0617e507a7de50ebcd..2dc09dccfd6def9f805a442c991c4522f71f3dc6 100644
--- a/lib/workers/repository/process/extract-update.spec.ts
+++ b/lib/workers/repository/process/extract-update.spec.ts
@@ -1,4 +1,4 @@
-import { git, logger, mocked, scm } from '../../../../test/util';
+import { logger, mocked, scm } from '../../../../test/util';
 import type { PackageFile } from '../../../modules/manager/types';
 import * as _repositoryCache from '../../../util/cache/repository';
 import type { BaseBranchCache } from '../../../util/cache/repository/types';
@@ -50,7 +50,7 @@ describe('workers/repository/process/extract-update', () => {
         suppressNotifications: ['deprecationWarningIssues'],
       };
       repositoryCache.getCache.mockReturnValueOnce({ scan: {} });
-      git.checkoutBranch.mockResolvedValueOnce('123test');
+      scm.checkoutBranch.mockResolvedValueOnce('123test');
       const packageFiles = await extract(config);
       const res = await lookup(config, packageFiles);
       expect(res).toEqual({
@@ -81,7 +81,7 @@ describe('workers/repository/process/extract-update', () => {
           addLabels: 'npm',
         },
       };
-      git.checkoutBranch.mockResolvedValueOnce('123test');
+      scm.checkoutBranch.mockResolvedValueOnce('123test');
       repositoryCache.getCache.mockReturnValueOnce({ scan: {} });
       const packageFiles = await extract(config);
       expect(packageFiles).toBeUndefined();
@@ -105,7 +105,7 @@ describe('workers/repository/process/extract-update', () => {
         },
       });
       scm.getBranchCommit.mockResolvedValueOnce('123test');
-      git.checkoutBranch.mockResolvedValueOnce('123test');
+      scm.checkoutBranch.mockResolvedValueOnce('123test');
       const res = await extract(config);
       expect(res).toEqual(packageFiles);
     });
@@ -121,7 +121,7 @@ describe('workers/repository/process/extract-update', () => {
         appendVulnerabilityPackageRules: appendVulnerabilityPackageRulesMock,
       });
       repositoryCache.getCache.mockReturnValueOnce({ scan: {} });
-      git.checkoutBranch.mockResolvedValueOnce('123test');
+      scm.checkoutBranch.mockResolvedValueOnce('123test');
 
       const packageFiles = await extract(config);
       await lookup(config, packageFiles);
@@ -138,7 +138,7 @@ describe('workers/repository/process/extract-update', () => {
       };
       createVulnerabilitiesMock.mockRejectedValueOnce(new Error());
       repositoryCache.getCache.mockReturnValueOnce({ scan: {} });
-      git.checkoutBranch.mockResolvedValueOnce('123test');
+      scm.checkoutBranch.mockResolvedValueOnce('123test');
 
       const packageFiles = await extract(config);
       await lookup(config, packageFiles);
diff --git a/lib/workers/repository/process/extract-update.ts b/lib/workers/repository/process/extract-update.ts
index d10df7303bbaee75786a7f8a59ab24139e0ca2c2..66e0c14bdf36dbf33767970c1dc09fcbd0ab6317 100644
--- a/lib/workers/repository/process/extract-update.ts
+++ b/lib/workers/repository/process/extract-update.ts
@@ -8,7 +8,6 @@ import { getCache } from '../../../util/cache/repository';
 import type { BaseBranchCache } from '../../../util/cache/repository/types';
 import { checkGithubToken as ensureGithubToken } from '../../../util/check-token';
 import { fingerprint } from '../../../util/fingerprint';
-import { checkoutBranch } from '../../../util/git';
 import type { BranchConfig } from '../../types';
 import { extractAllDependencies } from '../extract';
 import { generateFingerprintConfig } from '../extract/extract-fingerprint-config';
@@ -137,7 +136,7 @@ export async function extract(
       logger.info({ err }, 'Error deleting cached dep updates');
     }
   } else {
-    await checkoutBranch(baseBranch!);
+    await scm.checkoutBranch(baseBranch!);
     const extractResult = (await extractAllDependencies(config)) || {};
     packageFiles = extractResult.packageFiles;
     const { extractionFingerprints } = extractResult;
diff --git a/lib/workers/repository/update/branch/automerge.spec.ts b/lib/workers/repository/update/branch/automerge.spec.ts
index 81bafafe388f26a67221cf9acefb694021c72074..87bb468913a999e6a4fb14635d7cbc7e0b996129 100644
--- a/lib/workers/repository/update/branch/automerge.spec.ts
+++ b/lib/workers/repository/update/branch/automerge.spec.ts
@@ -1,4 +1,4 @@
-import { getConfig, git, platform } from '../../../../../test/util';
+import { getConfig, git, platform, scm } from '../../../../../test/util';
 import { GlobalConfig } from '../../../../config/global';
 import type { RenovateConfig } from '../../../../config/types';
 import * as schedule from '../branch/schedule';
@@ -70,7 +70,7 @@ describe('workers/repository/update/branch/automerge', () => {
       const res = await tryBranchAutomerge(config);
 
       expect(res).toBe('failed');
-      expect(git.checkoutBranch).toHaveBeenCalled();
+      expect(scm.checkoutBranch).toHaveBeenCalled();
     });
 
     it('returns true if automerge succeeds', async () => {
@@ -82,7 +82,7 @@ describe('workers/repository/update/branch/automerge', () => {
       const res = await tryBranchAutomerge(config);
 
       expect(res).toBe('automerged');
-      expect(git.checkoutBranch).toHaveBeenCalledWith('test-branch');
+      expect(scm.checkoutBranch).toHaveBeenCalledWith('test-branch');
     });
 
     it('returns true if automerge succeeds (dry-run)', async () => {
diff --git a/lib/workers/repository/update/branch/automerge.ts b/lib/workers/repository/update/branch/automerge.ts
index 8db027b4cc24f16707b69ea1cbf7b7334c71d138..b6595e2ec118e98b10ae7dda565624221cc8f876 100644
--- a/lib/workers/repository/update/branch/automerge.ts
+++ b/lib/workers/repository/update/branch/automerge.ts
@@ -2,7 +2,8 @@ import { GlobalConfig } from '../../../../config/global';
 import type { RenovateConfig } from '../../../../config/types';
 import { logger } from '../../../../logger';
 import { platform } from '../../../../modules/platform';
-import { checkoutBranch, mergeBranch } from '../../../../util/git';
+import { scm } from '../../../../modules/platform/scm';
+import { mergeBranch } from '../../../../util/git';
 import { isScheduledNow } from './schedule';
 import { resolveBranchStatus } from './status-checks';
 
@@ -42,7 +43,7 @@ export async function tryBranchAutomerge(
         // TODO: types (#7154)
         logger.info(`DRY-RUN: Would automerge branch ${config.branchName!}`);
       } else {
-        await checkoutBranch(config.baseBranch!);
+        await scm.checkoutBranch(config.baseBranch!);
         await mergeBranch(config.branchName!);
       }
       logger.info({ branch: config.branchName }, 'Branch automerged');
diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts
index 636803ec391f9ddfde124f9bf168cae83d460478..aaec7534c8499cbe952b657abfa13663c0c98afd 100644
--- a/lib/workers/repository/update/branch/index.spec.ts
+++ b/lib/workers/repository/update/branch/index.spec.ts
@@ -2253,13 +2253,13 @@ describe('workers/repository/update/branch/index', () => {
       });
       config.baseBranch = 'main';
       await branchWorker.processBranch(config);
-      expect(git.checkoutBranch).toHaveBeenLastCalledWith('main');
+      expect(scm.checkoutBranch).toHaveBeenLastCalledWith('main');
       // Check that the last checkoutBranch call is after the only commitFilesToBranch call
-      const checkoutBranchCalledTimes = git.checkoutBranch.mock.calls.length;
+      const checkoutBranchCalledTimes = scm.checkoutBranch.mock.calls.length;
       expect(
         commit.commitFilesToBranch.mock.invocationCallOrder[0]
       ).toBeLessThan(
-        git.checkoutBranch.mock.invocationCallOrder[
+        scm.checkoutBranch.mock.invocationCallOrder[
           checkoutBranchCalledTimes - 1
         ]
       );
diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts
index ba93eee78e8414ec19b3c60b00bde6b0d2def482..7b61df3f669645c30e0c040b7b299b5ee91646f5 100644
--- a/lib/workers/repository/update/branch/index.ts
+++ b/lib/workers/repository/update/branch/index.ts
@@ -25,7 +25,6 @@ import { scm } from '../../../../modules/platform/scm';
 import { ExternalHostError } from '../../../../types/errors/external-host-error';
 import { getElapsedMs } from '../../../../util/date';
 import { emojify } from '../../../../util/emoji';
-import { checkoutBranch } from '../../../../util/git';
 import {
   getMergeConfidenceLevel,
   isActiveConfidenceLevel,
@@ -406,7 +405,7 @@ export async function processBranch(
     // TODO: types (#7154)
     logger.debug(`Using reuseExistingBranch: ${config.reuseExistingBranch!}`);
     if (!(config.reuseExistingBranch && config.skipBranchUpdate)) {
-      await checkoutBranch(config.baseBranch);
+      await scm.checkoutBranch(config.baseBranch);
       const res = await getUpdatedPackageFiles(config);
       // istanbul ignore if
       if (res.artifactErrors && config.artifactErrors) {
@@ -524,7 +523,7 @@ export async function processBranch(
       commitSha = await commitFilesToBranch(config);
       // Checkout to base branch to ensure that the next branch processing always starts with git being on the baseBranch
       // baseBranch is not checked out at the start of processBranch() due to pull/16246
-      await checkoutBranch(config.baseBranch);
+      await scm.checkoutBranch(config.baseBranch);
       updatesVerified = true;
     }
     // istanbul ignore if