diff --git a/extensions/git/src/contentProvider.ts b/extensions/git/src/contentProvider.ts index d7bd26dffc2..9ab283dcd1e 100644 --- a/extensions/git/src/contentProvider.ts +++ b/extensions/git/src/contentProvider.ts @@ -9,7 +9,7 @@ import { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode' import { debounce, throttle } from './decorators'; import { fromGitUri, toGitUri } from './uri'; import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model'; -import { filterEvent, eventToPromise } from './util'; +import { filterEvent, eventToPromise, isDescendant } from './util'; interface CacheRow { uri: Uri; @@ -72,7 +72,7 @@ export class GitContentProvider { const fsPath = uri.fsPath; for (const root of this.changedRepositoryRoots) { - if (fsPath.startsWith(root)) { + if (isDescendant(root, fsPath)) { this._onDidChange.fire(uri); return; } diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 00be3fd3556..a28d386c38b 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -8,7 +8,7 @@ import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, ConfigurationChangeEvent } from 'vscode'; import { Repository, RepositoryState } from './repository'; import { memoize, sequentialize, debounce } from './decorators'; -import { dispose, anyEvent, filterEvent, IDisposable } from './util'; +import { dispose, anyEvent, filterEvent, IDisposable, isDescendant } from './util'; import { Git, GitErrorCodes } from './git'; import * as path from 'path'; import * as fs from 'fs'; @@ -44,14 +44,6 @@ interface OpenRepository extends Disposable { repository: Repository; } -function isParent(parent: string, child: string): boolean { - if (parent.charAt(parent.length - 1) !== path.sep) { - parent += path.sep; - } - - return child.startsWith(parent); -} - export class Model { private _onDidOpenRepository = new EventEmitter(); @@ -136,7 +128,7 @@ export class Model { .map(folder => this.getOpenRepository(folder.uri)) .filter(r => !!r) .filter(r => !activeRepositories.has(r!.repository)) - .filter(r => !(workspace.workspaceFolders || []).some(f => isParent(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; + .filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath)); openRepositoriesToDispose.forEach(r => r.dispose()); @@ -285,7 +277,7 @@ export class Model { for (const liveRepository of this.openRepositories) { const relativePath = path.relative(liveRepository.repository.root, resourcePath); - if (!/^\.\./.test(relativePath)) { + if (isDescendant(liveRepository.repository.root, resourcePath)) { return liveRepository; } } diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 73242e60c0f..c400a818d9d 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -7,7 +7,7 @@ import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode'; import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git'; -import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util'; +import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant } from './util'; import { memoize, throttle, debounce } from './decorators'; import { toGitUri } from './uri'; import { AutoFetcher } from './autofetch'; @@ -473,7 +473,7 @@ export class Repository implements Disposable { this.disposables.push(fsWatcher); const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete); - const onRepositoryChange = filterEvent(onWorkspaceChange, uri => !/^\.\./.test(path.relative(repository.root, uri.fsPath))); + const onRepositoryChange = filterEvent(onWorkspaceChange, uri => isDescendant(repository.root, uri.fsPath)); const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git\/index\.lock$/.test(uri.path)); onRelevantRepositoryChange(this.onFSChange, this, this.disposables); @@ -760,7 +760,8 @@ export class Repository implements Disposable { return this.run(Operation.CheckIgnore, () => { return new Promise>((resolve, reject) => { - filePaths = filePaths.filter(filePath => !path.relative(this.root, filePath).startsWith('..')); + filePaths = filePaths + .filter(filePath => isDescendant(this.root, filePath)); if (filePaths.length === 0) { // nothing left diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index ef13e9de13c..6831fea9428 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -6,7 +6,7 @@ 'use strict'; import { Event } from 'vscode'; -import { dirname } from 'path'; +import { dirname, sep } from 'path'; import { Readable } from 'stream'; import * as fs from 'fs'; import * as byline from 'byline'; @@ -273,4 +273,16 @@ export function detectUnicodeEncoding(buffer: Buffer): Encoding | null { } return null; -} \ No newline at end of file +} + +export function isDescendant(parent: string, descendant: string): boolean { + if (parent === descendant) { + return true; + } + + if (parent.charAt(parent.length - 1) !== sep) { + parent += sep; + } + + return descendant.startsWith(parent); +}