From b7395e97f3586fc14f94d2868148e992508b2d76 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Nov 2019 13:29:48 +0100 Subject: [PATCH] Git: Speed up the unmanagedFiles() function Given a list of files, we should not call git for every single one of them to figure out which ones are part of the repository, because this job can be done with a single call. As a test case, I added my whole ~/dev directory with ca 600,000 source files to a generic project. With this patch, the time spent on retrieving the list of unmanaged files went down from nine hours to seven seconds. Task-number: QTCREATORBUG-20652 Change-Id: Ic04a2b973e14eff549a2642bde7bc269df069fd1 Reviewed-by: Orgad Shaneh --- src/plugins/git/gitclient.cpp | 18 ++++++++++++++++++ src/plugins/git/gitclient.h | 1 + src/plugins/git/gitversioncontrol.cpp | 6 ++++++ src/plugins/git/gitversioncontrol.h | 1 + 4 files changed, 26 insertions(+) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index a6bf59df630..d06ac0e03b2 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -823,6 +823,24 @@ bool GitClient::managesFile(const QString &workingDirectory, const QString &file == SynchronousProcessResponse::Finished; } +QStringList GitClient::unmanagedFiles(const QString &workingDirectory, + const QStringList &filePaths) const +{ + QStringList args({"ls-files", "-z"}); + QDir wd(workingDirectory); + args << transform(filePaths, [&wd](const QString &fp) { return wd.relativeFilePath(fp); }); + const SynchronousProcessResponse response + = vcsFullySynchronousExec(workingDirectory, args, Core::ShellCommand::NoOutput); + if (response.result != SynchronousProcessResponse::Finished) + return filePaths; + const QStringList managedFilePaths + = transform(response.stdOut().split('\0', QString::SkipEmptyParts), + [&wd](const QString &fp) { return wd.absoluteFilePath(fp); }); + return filtered(filePaths, [&managedFilePaths](const QString &fp) { + return !managedFilePaths.contains(fp); + }); +} + QTextCodec *GitClient::codecFor(GitClient::CodecType codecType, const QString &source) const { if (codecType == CodecSource) { diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 32f7ac0e25e..f23ac7dd652 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -133,6 +133,7 @@ public: QString findRepositoryForDirectory(const QString &directory) const; QString findGitDirForRepository(const QString &repositoryDir) const; bool managesFile(const QString &workingDirectory, const QString &fileName) const; + QStringList unmanagedFiles(const QString &workingDirectory, const QStringList &filePaths) const; void diffFile(const QString &workingDirectory, const QString &fileName) const; void diffFiles(const QString &workingDirectory, diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp index 123cf6753c7..822f7373937 100644 --- a/src/plugins/git/gitversioncontrol.cpp +++ b/src/plugins/git/gitversioncontrol.cpp @@ -190,6 +190,12 @@ bool GitVersionControl::managesFile(const QString &workingDirectory, const QStri return m_client->managesFile(workingDirectory, fileName); } +QStringList GitVersionControl::unmanagedFiles(const QString &workingDir, + const QStringList &filePaths) const +{ + return m_client->unmanagedFiles(workingDir, filePaths); +} + bool GitVersionControl::vcsAnnotate(const QString &file, int line) { const QFileInfo fi(file); diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h index 7985040f8e4..fd8fd8c0697 100644 --- a/src/plugins/git/gitversioncontrol.h +++ b/src/plugins/git/gitversioncontrol.h @@ -46,6 +46,7 @@ public: bool managesDirectory(const QString &directory, QString *topLevel) const final; bool managesFile(const QString &workingDirectory, const QString &fileName) const final; + QStringList unmanagedFiles(const QString &workingDir, const QStringList &filePaths) const final; bool isConfigured() const final; bool supportsOperation(Operation operation) const final;