diff --git a/packages/cli/src/environments/sourceControl/sourceControlGit.service.ee.ts b/packages/cli/src/environments/sourceControl/sourceControlGit.service.ee.ts index cdaa264c97a98..f811f7fa27ddc 100644 --- a/packages/cli/src/environments/sourceControl/sourceControlGit.service.ee.ts +++ b/packages/cli/src/environments/sourceControl/sourceControlGit.service.ee.ts @@ -176,6 +176,7 @@ export class SourceControlGitService { } try { await this.git.addRemote(SOURCE_CONTROL_ORIGIN, sourceControlPreferences.repositoryUrl); + this.logger.debug(`Git remote added: ${sourceControlPreferences.repositoryUrl}`); } catch (error) { if ((error as Error).message.includes('remote origin already exists')) { this.logger.debug(`Git remote already exists: ${(error as Error).message}`); @@ -189,6 +190,9 @@ export class SourceControlGitService { : SOURCE_CONTROL_DEFAULT_NAME, user.email ?? SOURCE_CONTROL_DEFAULT_EMAIL, ); + + await this.trackRemoteIfReady(sourceControlPreferences.branchName); + if (sourceControlPreferences.initRepo) { try { const branches = await this.getBranches(); @@ -201,6 +205,28 @@ export class SourceControlGitService { } } + /** + * If this is a new local repository being set up after remote is ready, + * then set this local to start tracking remote's target branch. + */ + private async trackRemoteIfReady(targetBranch: string) { + if (!this.git) return; + + await this.fetch(); + + const { currentBranch, branches: remoteBranches } = await this.getBranches(); + + if (!currentBranch && remoteBranches.some((b) => b === targetBranch)) { + await this.git.checkout(targetBranch); + + const upstream = [SOURCE_CONTROL_ORIGIN, targetBranch].join('/'); + + await this.git.branch([`--set-upstream-to=${upstream}`, targetBranch]); + + this.logger.info('Set local git repository to track remote', { upstream }); + } + } + async setGitUserDetails(name: string, email: string): Promise { if (!this.git) { throw new ApplicationError('Git is not initialized (setGitUserDetails)'); diff --git a/packages/cli/test/unit/GitService.test.ts b/packages/cli/test/unit/GitService.test.ts new file mode 100644 index 0000000000000..f4a458ac3583b --- /dev/null +++ b/packages/cli/test/unit/GitService.test.ts @@ -0,0 +1,39 @@ +import { SourceControlGitService } from '@/environments/sourceControl/sourceControlGit.service.ee'; +import { mock } from 'jest-mock-extended'; +import type { SourceControlPreferences } from '@/environments/sourceControl/types/sourceControlPreferences'; +import type { User } from '@/databases/entities/User'; +import type { SimpleGit } from 'simple-git'; + +describe('GitService', () => { + describe('initRepository', () => { + describe('when local repo is set up after remote is ready', () => { + it('should track remote', async () => { + /** + * Arrange + */ + const gitService = new SourceControlGitService(mock(), mock(), mock()); + const prefs = mock({ branchName: 'main' }); + const user = mock(); + const git = mock(); + const checkoutSpy = jest.spyOn(git, 'checkout'); + const branchSpy = jest.spyOn(git, 'branch'); + gitService.git = git; + jest.spyOn(gitService, 'setGitSshCommand').mockResolvedValue(); + jest + .spyOn(gitService, 'getBranches') + .mockResolvedValue({ currentBranch: '', branches: ['main'] }); + + /** + * Act + */ + await gitService.initRepository(prefs, user); + + /** + * Assert + */ + expect(checkoutSpy).toHaveBeenCalledWith('main'); + expect(branchSpy).toHaveBeenCalledWith(['--set-upstream-to=origin/main', 'main']); + }); + }); + }); +});