fix index.lock sticking: drop .git/ and index watches, use document-save events
The QFileSystemWatcher on .git/ directory and .git/index file caused a feedback loop: every git operation touching the index fired watch events that triggered git-status, creating lock contention and stale index.lock files. Now only concrete events trigger a refresh: - .git/HEAD file change (branch switch) - refs/heads/ directory change (branch create/delete) - KTextEditor document save (documentSavedOrUploaded signal) No periodic timers. The 500ms debounce remains as the single gate.
This commit is contained in:
parent
7098d70b40
commit
460247e8a0
|
|
@ -483,11 +483,28 @@ GitPlusPlusView::GitPlusPlusView(GitPlusPlusPlugin *plugin, KTextEditor::MainWin
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Debounce timer for filesystem changes (avoid spamming refreshes)
|
// Debounce timer for filesystem/document changes (avoid spamming refreshes)
|
||||||
m_fsDebounce.setSingleShot(true);
|
m_fsDebounce.setSingleShot(true);
|
||||||
m_fsDebounce.setInterval(500);
|
m_fsDebounce.setInterval(500);
|
||||||
connect(&m_fsDebounce, &QTimer::timeout, this, &GitPlusPlusView::updateStatus);
|
connect(&m_fsDebounce, &QTimer::timeout, this, &GitPlusPlusView::updateStatus);
|
||||||
|
|
||||||
|
// Refresh status when any document is saved — this is a concrete event
|
||||||
|
// that likely changes the working tree state.
|
||||||
|
auto connectDocSave = [this](KTextEditor::Document *doc) {
|
||||||
|
connect(doc, &KTextEditor::Document::documentSavedOrUploaded, this, [this]() {
|
||||||
|
m_fsDebounce.start();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
connect(KTextEditor::Editor::instance(), &KTextEditor::Editor::documentCreated,
|
||||||
|
this, [this, connectDocSave](KTextEditor::Editor *, KTextEditor::Document *doc) {
|
||||||
|
connectDocSave(doc);
|
||||||
|
});
|
||||||
|
// Connect already-open documents
|
||||||
|
const auto docs = KTextEditor::Editor::instance()->documents();
|
||||||
|
for (auto *doc : docs) {
|
||||||
|
connectDocSave(doc);
|
||||||
|
}
|
||||||
|
|
||||||
// Initial refresh
|
// Initial refresh
|
||||||
QMetaObject::invokeMethod(this, &GitPlusPlusView::updateStatus, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &GitPlusPlusView::updateStatus, Qt::QueuedConnection);
|
||||||
QMetaObject::invokeMethod(this, &GitPlusPlusView::refreshBranches, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &GitPlusPlusView::refreshBranches, Qt::QueuedConnection);
|
||||||
|
|
@ -686,28 +703,22 @@ void GitPlusPlusView::setupFileWatcher()
|
||||||
|
|
||||||
if (gitDir.isEmpty()) return;
|
if (gitDir.isEmpty()) return;
|
||||||
|
|
||||||
// Watch the git directory itself — picks up renames of index, HEAD, refs, etc.
|
// Only watch refs/heads for branch creation/deletion — a concrete event.
|
||||||
// This is more robust than watching individual files which get replaced atomically.
|
// Do NOT watch the .git directory itself or the index file:
|
||||||
QStringList watchPaths;
|
// those fire on every git operation (index.lock create/delete) and cause
|
||||||
watchPaths << gitDir;
|
// cascading git-status calls that leave index.lock files behind.
|
||||||
|
|
||||||
// Also watch refs/heads for branch changes
|
|
||||||
QString refsHeads = gitDir + QStringLiteral("/refs/heads");
|
QString refsHeads = gitDir + QStringLiteral("/refs/heads");
|
||||||
if (QFileInfo::exists(refsHeads))
|
if (QFileInfo::exists(refsHeads))
|
||||||
watchPaths << refsHeads;
|
m_watcher->addPath(refsHeads);
|
||||||
|
|
||||||
m_watcher->addPaths(watchPaths);
|
|
||||||
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &) {
|
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &) {
|
||||||
m_fsDebounce.start();
|
m_fsDebounce.start();
|
||||||
});
|
});
|
||||||
// Watch HEAD file specifically — changes indicate branch switch
|
|
||||||
QString indexFile = gitDir + QStringLiteral("/index");
|
// Watch HEAD file only — changes indicate a branch switch (concrete event).
|
||||||
QString headFile = gitDir + QStringLiteral("/HEAD");
|
QString headFile = gitDir + QStringLiteral("/HEAD");
|
||||||
QStringList filePaths;
|
if (QFileInfo::exists(headFile)) {
|
||||||
if (QFileInfo::exists(indexFile)) filePaths << indexFile;
|
m_watcher->addPath(headFile);
|
||||||
if (QFileInfo::exists(headFile)) filePaths << headFile;
|
|
||||||
if (!filePaths.isEmpty()) {
|
|
||||||
m_watcher->addPaths(filePaths);
|
|
||||||
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this, headFile](const QString &path) {
|
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this, headFile](const QString &path) {
|
||||||
// Re-add: atomic renames remove the watch
|
// Re-add: atomic renames remove the watch
|
||||||
if (!m_watcher->files().contains(path)) {
|
if (!m_watcher->files().contains(path)) {
|
||||||
|
|
@ -716,9 +727,9 @@ void GitPlusPlusView::setupFileWatcher()
|
||||||
m_watcher->addPath(path);
|
m_watcher->addPath(path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
m_fsDebounce.start();
|
|
||||||
// HEAD change means branch switch — refresh branches
|
|
||||||
if (path == headFile) {
|
if (path == headFile) {
|
||||||
|
// Branch switch — refresh branches and status after a short delay
|
||||||
|
m_fsDebounce.start();
|
||||||
QTimer::singleShot(600, this, [this]() { refreshBranches(); });
|
QTimer::singleShot(600, this, [this]() { refreshBranches(); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue