From 13d0dad699bfc4e4529ece16dd577be98945fce1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 6 Jun 2019 15:57:21 +0200 Subject: [PATCH] fix #41085 --- extensions/git/src/git.ts | 12 ++++++++--- extensions/git/src/model.ts | 5 +++-- extensions/git/src/repository.ts | 37 ++++++++++++++++---------------- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index ea3e22eec82..17bd42125ce 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -329,8 +329,8 @@ export class Git { this.env = options.env || {}; } - open(repository: string): Repository { - return new Repository(this, repository); + open(repository: string, dotGit: string): Repository { + return new Repository(this, repository, dotGit); } async init(repository: string): Promise { @@ -370,6 +370,11 @@ export class Git { return path.normalize(result.stdout.trim()); } + async getRepositoryDotGit(repositoryPath: string): Promise { + const result = await this.exec(repositoryPath, ['rev-parse', '--absolute-git-dir']); + return path.normalize(result.stdout.trim()); + } + async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise> { options = assign({ cwd }, options || {}); return await this._exec(args, options); @@ -649,7 +654,8 @@ export class Repository { constructor( private _git: Git, - private repositoryRoot: string + private repositoryRoot: string, + readonly dotGit: string ) { } get git(): Git { diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 22c690a5dfd..2c9085b6820 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -78,7 +78,7 @@ export class Model { this.disposables.push(fsWatcher); const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete); - const onGitRepositoryChange = filterEvent(onWorkspaceChange, uri => /\/\.git\//.test(uri.path)); + const onGitRepositoryChange = filterEvent(onWorkspaceChange, uri => /\/\.git/.test(uri.path)); const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri)); onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables); @@ -232,7 +232,8 @@ export class Model { return; } - const repository = new Repository(this.git.open(repositoryRoot), this.globalState); + const dotGit = await this.git.getRepositoryDotGit(repositoryRoot); + const repository = new Repository(this.git.open(repositoryRoot, dotGit), this.globalState); this.open(repository); } catch (err) { diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 33106400301..d0536c607f8 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -5,7 +5,7 @@ import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType } from 'vscode'; import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git'; -import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util'; +import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, toDisposable } from './util'; import { memoize, throttle, debounce } from './decorators'; import { toGitUri } from './uri'; import { AutoFetcher } from './autofetch'; @@ -553,27 +553,28 @@ export class Repository implements Disposable { private readonly repository: BaseRepository, globalState: Memento ) { - const fsWatcher = workspace.createFileSystemWatcher('**'); - this.disposables.push(fsWatcher); + const workspaceWatcher = workspace.createFileSystemWatcher('**'); + this.disposables.push(workspaceWatcher); - const workspaceFilter = (uri: Uri) => isDescendant(repository.root, uri.fsPath); - const onWorkspaceDelete = filterEvent(fsWatcher.onDidDelete, workspaceFilter); - const onWorkspaceChange = filterEvent(anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate), workspaceFilter); - const onRepositoryDotGitDelete = filterEvent(onWorkspaceDelete, uri => /\/\.git$/.test(uri.path)); - const onRepositoryChange = anyEvent(onWorkspaceDelete, onWorkspaceChange); + const onWorkspaceFileChanges = anyEvent(workspaceWatcher.onDidChange, workspaceWatcher.onDidCreate, workspaceWatcher.onDidDelete); + const onWorkspaceRepositoryFileChanges = filterEvent(onWorkspaceFileChanges, uri => isDescendant(repository.root, uri.fsPath)); + const onWorkspaceWorkingTreeFileChanges = filterEvent(onWorkspaceRepositoryFileChanges, uri => !/\/\.git($|\/)/.test(uri.path)); - // relevant repository changes are: - // - DELETE .git folder - // - ANY CHANGE within .git folder except .git itself and .git/index.lock - const onRelevantRepositoryChange = anyEvent( - onRepositoryDotGitDelete, - filterEvent(onRepositoryChange, uri => !/\/\.git(\/index\.lock)?$/.test(uri.path)) - ); + const dotGitWatcher = fs.watch(repository.dotGit); + const onRepositoryFileEmitter = new EventEmitter(); + dotGitWatcher.on('change', (_, e) => onRepositoryFileEmitter.fire(Uri.file(path.join(repository.dotGit, e as string)))); + dotGitWatcher.on('error', err => console.error(err)); + this.disposables.push(toDisposable(() => dotGitWatcher.close())); + const onRelevantRepositoryChanges = filterEvent(onRepositoryFileEmitter.event, uri => !/\/\.git(\/index\.lock)?$/.test(uri.path)); - onRelevantRepositoryChange(this.onFSChange, this, this.disposables); + // FS changes should trigger `git status`: + // - any change inside the repository working tree + // - any change whithin the first level of the `.git` folder, except the folder itself and `index.lock` + const onFSChange = anyEvent(onWorkspaceWorkingTreeFileChanges, onRelevantRepositoryChanges); + onFSChange(this.onFSChange, this, this.disposables); - const onRelevantGitChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.git\//.test(uri.path)); - onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); + // Relevate repository changes should trigger virtual document change events + onRelevantRepositoryChanges(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); const root = Uri.file(repository.root); this._sourceControl = scm.createSourceControl('git', 'Git', root);