Инкрементальный индекс, пресеты автосейва, упрощение git-слоя

- VaultIndex: updateFile/removeFile/syncIncremental по mtime+size, полный рескан только на старте/смене/внешних правках; relink висячих ссылок; FileStore.externalChanged
- QML: точечные обновления индекса вместо rebuild на каждый сейв
- Настройки: пресеты safe/balanced/eco/manual + диалог с +/- и шкалами; коммит после паузы, в manual — по Ctrl+S
- GitManager: кэш истории, пагинация, diff в потоке, точечный commitFile, fileExistedAt, топологический порядок истории
- Удалены highlightedCode, словный merge, fileDiffText/Html, 2-arg fileHistory
This commit is contained in:
2026-09-07 01:06:21 +03:00
parent 417d0273b7
commit 0a46471cc6
3 changed files with 24 additions and 6 deletions
+10 -5
View File
@@ -407,14 +407,19 @@ QVariantList GitManager::fileHistory(const QString &vaultPath, const QString &fi
git_repository_free(repo);
return out;
}
git_revwalk_sorting(walk, GIT_SORT_TIME);
// TIME|TOPOLOGICAL: время + гарантия «потомки раньше родителей».
// Один TIME при коммитах в одну секунду тасует порядок (баг: «новой» могла
// оказаться старая версия); история хранилища линейная, топология даёт точный порядок.
git_revwalk_sorting(walk, GIT_SORT_TIME | GIT_SORT_TOPOLOGICAL);
git_revwalk_push_head(walk);
// Собираем до limit КАСАНИЙ файла (а не коммитов): иначе на активной истории
// «Показать ещё» врало бы при разреженных касаниях. Перебор коммитов ограничен.
git_oid oid;
int iter = 0;
const int maxIter = limit; // ограничение для скорости
while (git_revwalk_next(&oid, walk) == 0 && iter < maxIter) {
++iter;
int scanned = 0;
const int scanCap = 2000;
while (git_revwalk_next(&oid, walk) == 0 && (int)out.size() < limit && scanned < scanCap) {
++scanned;
git_commit *commit = nullptr;
if (git_commit_lookup(&commit, repo, &oid) < 0)
continue;
+1 -1
View File
@@ -37,7 +37,7 @@ public:
// История файла: список коммитов где файл менялся. Сортировка новые сверху.
// Каждый элемент: {hash, shortHash, message, author, time (QDateTime), timeStr, timeAgo}.
// Не больше limit свежих (limit<=0 — до 500).
// Не больше limit КАСАНИЙ (limit<=0 — до 500); перебор коммитов ограничен изнутри.
// Для кнопки «Показать ещё»: запросить limit+1, hasMore = (размер > limit).
Q_INVOKABLE QVariantList fileHistory(const QString &vaultPath, const QString &filePath,
int limit) const;
+13
View File
@@ -167,6 +167,19 @@ int main(int argc, char *argv[])
return fail("paged cache");
// limit<=0 — как раньше (всё)
if(git.fileHistory(vault, file, 0).size() != full.size()) return fail("limit 0");
// разреженная история: 30 чужих коммитов — касания файла всё равно находятся,
// hasMore-логика (limit+1) при этом не врёт
for (int i = 0; i < 30; ++i) {
QFile fn(vault+"/noise.md");
if(!fn.open(QIODevice::WriteOnly | QIODevice::Append)) return fail("noise open");
fn.write(QString("n%1\n").arg(i).toUtf8());
fn.close();
if(!git.commitAll(vault, QString("noise %1").arg(i))) return fail("noise commit", git.lastError());
}
QVariantList sparse = git.fileHistory(vault, file, 3);
if(sparse.size() != 3) return fail("sparse size", QString::number(sparse.size()));
if(sparse.first().toMap().value("hash") != full.first().toMap().value("hash"))
return fail("sparse order");
}
// fileExistedAt: отличает «пустой файл» от «файла не было»