Skip to content

Commit 6e189da

Browse files
authored
Git - add extension API to get the repository root (microsoft#250044)
* Git - add extension API to get the repository root * Pull request feedback
1 parent 2b6a59a commit 6e189da

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

extensions/git/src/api/api1.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import { Model } from '../model';
99
import { Repository as BaseRepository, Resource } from '../repository';
10-
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery, BranchProtectionProvider, InitOptions, SourceControlHistoryItemDetailsProvider } from './git';
10+
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery, BranchProtectionProvider, InitOptions, SourceControlHistoryItemDetailsProvider, GitErrorCodes } from './git';
1111
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands, CancellationToken } from 'vscode';
1212
import { combinedDisposable, filterEvent, mapEvent } from '../util';
1313
import { toGitUri } from '../uri';
@@ -371,6 +371,27 @@ export class ApiImpl implements API {
371371
return result ? new ApiRepository(result) : null;
372372
}
373373

374+
async getRepositoryRoot(uri: Uri): Promise<Uri | null> {
375+
const repository = this.getRepository(uri);
376+
if (repository) {
377+
return repository.rootUri;
378+
}
379+
380+
try {
381+
const root = await this.#model.git.getRepositoryRoot(uri.fsPath);
382+
return Uri.file(root);
383+
} catch (err) {
384+
if (
385+
err.gitErrorCode === GitErrorCodes.NotAGitRepository ||
386+
err.gitErrorCode === GitErrorCodes.NotASafeGitRepository
387+
) {
388+
return null;
389+
}
390+
391+
throw err;
392+
}
393+
}
394+
374395
async init(root: Uri, options?: InitOptions): Promise<Repository | null> {
375396
const path = root.fsPath;
376397
await this.#model.git.init(path, options);

extensions/git/src/api/git.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ export interface API {
364364

365365
toGitUri(uri: Uri, ref: string): Uri;
366366
getRepository(uri: Uri): Repository | null;
367+
getRepositoryRoot(uri: Uri): Promise<Uri | null>;
367368
init(root: Uri, options?: InitOptions): Promise<Repository | null>;
368369
openRepository(root: Uri): Promise<Repository | null>
369370

@@ -402,6 +403,7 @@ export const enum GitErrorCodes {
402403
NoUserEmailConfigured = 'NoUserEmailConfigured',
403404
NoRemoteRepositorySpecified = 'NoRemoteRepositorySpecified',
404405
NotAGitRepository = 'NotAGitRepository',
406+
NotASafeGitRepository = 'NotASafeGitRepository',
405407
NotAtRepositoryRoot = 'NotAtRepositoryRoot',
406408
Conflict = 'Conflict',
407409
StashConflict = 'StashConflict',

extensions/git/src/git.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ function getGitErrorCode(stderr: string): string | undefined {
342342
return GitErrorCodes.InvalidBranchName;
343343
} else if (/Please,? commit your changes or stash them/.test(stderr)) {
344344
return GitErrorCodes.DirtyWorkTree;
345+
} else if (/detected dubious ownership in repository at/.test(stderr)) {
346+
return GitErrorCodes.NotASafeGitRepository;
345347
}
346348

347349
return undefined;

0 commit comments

Comments
 (0)