Git - Attempt to parse HEAD file before invoking git.exe (#162572)

* Attempt to parse HEAD file before invoking git.exe

* Pull request feedback

* Pull request feedback

* More pull request feedback
This commit is contained in:
Ladislau Szomoru
2022-10-12 15:56:36 +02:00
committed by GitHub
parent bbc1c35e4c
commit b43c281df2
2 changed files with 44 additions and 12 deletions

View File

@@ -18,6 +18,7 @@ import { detectEncoding } from './encoding';
import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git';
import * as byline from 'byline';
import { StringDecoder } from 'string_decoder';
import { OutputChannelLogger } from './log';
import TelemetryReporter from '@vscode/extension-telemetry';
// https://github.com/microsoft/vscode/issues/65693
@@ -400,8 +401,8 @@ export class Git {
return Versions.compare(Versions.fromString(this.version), Versions.fromString(version));
}
open(repository: string, dotGit: { path: string; commonPath?: string }): Repository {
return new Repository(this, repository, dotGit);
open(repository: string, dotGit: { path: string; commonPath?: string }, outputChannelLogger: OutputChannelLogger): Repository {
return new Repository(this, repository, dotGit, outputChannelLogger);
}
async init(repository: string): Promise<void> {
@@ -913,7 +914,8 @@ export class Repository {
constructor(
private _git: Git,
private repositoryRoot: string,
readonly dotGit: { path: string; commonPath?: string }
readonly dotGit: { path: string; commonPath?: string },
private outputChannelLogger: OutputChannelLogger
) { }
get git(): Git {
@@ -1996,6 +1998,16 @@ export class Repository {
async getHEAD(): Promise<Ref> {
try {
// Attempt to parse the HEAD file
const result = await this.getHEADFS();
return result;
}
catch (err) {
this.outputChannelLogger.logWarning(err.message);
}
try {
// Fallback to using git to determine HEAD
const result = await this.exec(['symbolic-ref', '--short', 'HEAD']);
if (!result.stdout) {
@@ -2003,15 +2015,35 @@ export class Repository {
}
return { name: result.stdout.trim(), commit: undefined, type: RefType.Head };
} catch (err) {
const result = await this.exec(['rev-parse', 'HEAD']);
if (!result.stdout) {
throw new Error('Error parsing HEAD');
}
return { name: undefined, commit: result.stdout.trim(), type: RefType.Head };
}
catch (err) { }
// Detached HEAD
const result = await this.exec(['rev-parse', 'HEAD']);
if (!result.stdout) {
throw new Error('Error parsing HEAD');
}
return { name: undefined, commit: result.stdout.trim(), type: RefType.Head };
}
async getHEADFS(): Promise<Ref> {
const raw = await fs.readFile(path.join(this.dotGit.commonPath ?? this.dotGit.path, 'HEAD'), 'utf8');
// Branch
const branchMatch = raw.match(/^ref: refs\/heads\/(?<name>.*)$/m);
if (branchMatch?.groups?.name) {
return { name: branchMatch.groups.name, commit: undefined, type: RefType.Head };
}
// Detached
const commitMatch = raw.match(/^(?<commit>[0-9a-f]{40})$/m);
if (commitMatch?.groups?.commit) {
return { name: undefined, commit: commitMatch.groups.commit, type: RefType.Head };
}
throw new Error(`Unable to parse HEAD file. HEAD file contents: ${raw}.`);
}
async findTrackingBranches(upstreamBranch: string): Promise<Branch[]> {