Skip to content

Copilot plugin will inflate .git folders #257583

@st0rm23

Description

@st0rm23
  • Copilot Chat Extension Version:1.346.0
  • VS Code Version: 1.102.1
  • OS Version: ubuntu 20.04
  • Feature (e.g. agent/edit/ask mode): agent
  • Selected model (e.g. GPT 4.1, Claude 3.7 Sonnet): N.A
  • Logs:

Problem:
We have a large codebase contributed by 1k+ engineer. Most of time, I just track the master branch. However, when I use vscode with copilot, it will inflate .git folder into a huge size. It is because vscode copilot will trigger git fetch --dry-run which is not neccessary. This fetch will download all objects of all refs into .git.

Steps to Reproduce:

  1. Clone a repo like https://github.com/git/git
  2. use du .git to get git/.git folder size
  3. Start vscode with copilot enabled on git folder
  4. use ps -aux | grep git you would see a command git -c credential.interactive=never fetch --dry-run is executing.
  5. wait 2~3 minutes, use du .git to get git/.git folder size again, you would see the .git folder size increased.

Root cause:
git fetch --dry-run is not trivial but fetching objects into .git folder. This will inflate .git folder. The code piece lies in https://github.com/microsoft/vscode-copilot-chat/blob/main/src/platform/remoteCodeSearch/node/codeSearchRepoTracker.ts#L590, which is using git fetch to get ssh config. This is not the right way, please fix this bug and change to another simple way to get ssh config.

	private async getGithubRemoteFromSshConfig(repo: RepoContext): Promise<ResolvedRepoRemoteInfo | undefined> {
		if (repo.rootUri.scheme !== Schemas.file) {
			return;
		}

		try {
			const execAsync = promisify(exec);
			const { stdout, stderr } = await execAsync('git -c credential.interactive=never fetch --dry-run', {
				cwd: repo.rootUri.fsPath,
				env: {
					GIT_SSH_COMMAND: 'ssh -v -o BatchMode=yes'
				}
			});

			const output = stdout + '\n' + stderr;

			const authMatch = output.match(/^Authenticated to ([^\s]+)\s/m);
			const fromMatch = output.match(/^From ([^:]+):([^/]+)\/([^\s]+)$/m);

			if (authMatch && fromMatch) {
				const authenticatedTo = authMatch[1];
				const owner = fromMatch[2];
				const repo = fromMatch[3].replace(/\.git$/, '');
				const remoteUrl = `ssh://${authenticatedTo}/${owner}/${repo}`;

				const githubRepoId = getGithubRepoIdFromFetchUrl(remoteUrl);
				if (githubRepoId) {
					return {
						repoId: githubRepoId,
						fetchUrl: remoteUrl
					};
				}
			}
			return undefined;
		} catch (e) {
			return undefined;
		}
	}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions