Skip to content

Commit d9eb887

Browse files
committed
Improves default branch lookup
1 parent 3e5eda4 commit d9eb887

File tree

3 files changed

+65
-37
lines changed

3 files changed

+65
-37
lines changed

src/env/node/git/git.ts

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,32 +1266,15 @@ export class Git {
12661266
return [ex.stdout, undefined];
12671267
}
12681268

1269+
let data;
12691270
try {
1270-
const data = await this.exec({ cwd: repoPath }, 'symbolic-ref', '--short', 'HEAD');
1271+
data = await this.exec({ cwd: repoPath }, 'symbolic-ref', '--short', 'HEAD');
12711272
if (data != null) return [data.trim(), undefined];
12721273
} catch {}
12731274

1274-
try {
1275-
const data = await this.exec(
1276-
{ cwd: repoPath },
1277-
'symbolic-ref',
1278-
'--short',
1279-
'refs/remotes/origin/HEAD',
1280-
);
1281-
if (data != null) return [data.trim().substring('origin/'.length), undefined];
1282-
} catch (ex) {
1283-
if (/is not a symbolic ref/.test(ex.stderr)) {
1284-
try {
1285-
const data = await this.exec({ cwd: repoPath }, 'ls-remote', '--symref', 'origin', 'HEAD');
1286-
if (data != null) {
1287-
const match = /ref:\s(\S+)\s+HEAD/m.exec(data);
1288-
if (match != null) {
1289-
const [, branch] = match;
1290-
return [branch.substring('refs/heads/'.length), undefined];
1291-
}
1292-
}
1293-
} catch {}
1294-
}
1275+
data = await this.symbolic_ref__HEAD(repoPath, 'origin');
1276+
if (data != null) {
1277+
return [data.startsWith('origin/') ? data.substring('origin/'.length) : data, undefined];
12951278
}
12961279

12971280
const defaultBranch = (await this.config__get('init.defaultBranch', repoPath)) ?? 'main';
@@ -1337,6 +1320,42 @@ export class Git {
13371320
}
13381321
}
13391322

1323+
async symbolic_ref__HEAD(repoPath: string, remote: string): Promise<string | undefined> {
1324+
let retried = false;
1325+
while (true) {
1326+
try {
1327+
const data = await this.exec(
1328+
{ cwd: repoPath },
1329+
'symbolic-ref',
1330+
'--short',
1331+
`refs/remotes/${remote}/HEAD`,
1332+
);
1333+
return data?.trim() || undefined;
1334+
} catch (ex) {
1335+
if (/is not a symbolic ref/.test(ex.stderr)) {
1336+
try {
1337+
if (!retried) {
1338+
retried = true;
1339+
await this.exec({ cwd: repoPath }, 'remote', 'set-head', '-a', remote);
1340+
continue;
1341+
}
1342+
1343+
const data = await this.exec({ cwd: repoPath }, 'ls-remote', '--symref', remote, 'HEAD');
1344+
if (data != null) {
1345+
const match = /ref:\s(\S+)\s+HEAD/m.exec(data);
1346+
if (match != null) {
1347+
const [, branch] = match;
1348+
return `${remote}/${branch.substring('refs/heads/'.length).trim()}`;
1349+
}
1350+
}
1351+
} catch {}
1352+
}
1353+
1354+
return undefined;
1355+
}
1356+
}
1357+
}
1358+
13401359
async rev_parse__git_dir(cwd: string): Promise<{ path: string; commonPath?: string } | undefined> {
13411360
const data = await this.exec(
13421361
{ cwd: cwd, errors: GitErrorHandling.Ignore },

src/env/node/git/sub-providers/branches.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -375,25 +375,25 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
375375
async getDefaultBranchName(repoPath: string | undefined, remote?: string): Promise<string | undefined> {
376376
if (repoPath == null) return undefined;
377377

378-
if (remote) {
379-
try {
380-
const data = await this.git.exec({ cwd: repoPath }, 'ls-remote', '--symref', remote, 'HEAD');
381-
if (data == null) return undefined;
378+
remote ??= 'origin';
382379

383-
const match = /ref:\s(\S+)\s+HEAD/m.exec(data);
384-
if (match == null) return undefined;
380+
const cacheByRemote = this.cache.defaultBranchName?.get(repoPath);
381+
let promise = cacheByRemote?.get(remote);
382+
if (promise == null) {
383+
async function load(this: BranchesGitSubProvider): Promise<string | undefined> {
384+
return this.git.symbolic_ref__HEAD(repoPath!, remote!);
385+
}
385386

386-
const [, branch] = match;
387-
return `${remote}/${branch.substring('refs/heads/'.length)}`;
388-
} catch {}
389-
}
387+
promise = load.call(this);
390388

391-
try {
392-
const data = await this.git.exec({ cwd: repoPath }, 'symbolic-ref', '--short', 'refs/remotes/origin/HEAD');
393-
return data?.trim() || undefined;
394-
} catch {}
389+
if (cacheByRemote == null) {
390+
this.cache.defaultBranchName?.set(repoPath, new Map([[remote, promise]]));
391+
} else {
392+
cacheByRemote.set(remote, promise);
393+
}
394+
}
395395

396-
return undefined;
396+
return promise;
397397
}
398398

399399
@log()

src/git/cache.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ export class GitCache implements Disposable {
8484
: undefined;
8585
}
8686

87+
private _defaultBranchNameCache: Map<RepoPath, Map<string, Promise<string | undefined>>> | undefined;
88+
get defaultBranchName(): Map<RepoPath, Map<string, Promise<string | undefined>>> | undefined {
89+
return this.useCaching
90+
? (this._defaultBranchNameCache ??= new Map<RepoPath, Map<string, Promise<string | undefined>>>())
91+
: undefined;
92+
}
93+
8794
private _pausedOperationStatusCache: Map<RepoPath, Promise<GitPausedOperationStatus | undefined>> | undefined;
8895
get pausedOperationStatus(): Map<RepoPath, Promise<GitPausedOperationStatus | undefined>> | undefined {
8996
return this.useCaching
@@ -128,6 +135,7 @@ export class GitCache implements Disposable {
128135
if (!types.length || types.includes('branches')) {
129136
cachesToClear.add(this._branchCache);
130137
cachesToClear.add(this._branchesCache);
138+
cachesToClear.add(this._defaultBranchNameCache);
131139
}
132140

133141
if (!types.length || types.includes('contributors')) {
@@ -137,6 +145,7 @@ export class GitCache implements Disposable {
137145
if (!types.length || types.includes('remotes')) {
138146
cachesToClear.add(this._remotesCache);
139147
cachesToClear.add(this._bestRemotesCache);
148+
cachesToClear.add(this._defaultBranchNameCache);
140149
}
141150

142151
if (!types.length || types.includes('providers')) {

0 commit comments

Comments
 (0)