refactor: saving time about repo's shared settings (#2108)

- Save repo's settings only when user changed it from `Repository Configuration` dialog and is closing this dialog
- Never unload repo's settings (it is very small in memory)
This commit is contained in:
leo
2026-02-07 10:11:48 +08:00
parent ef177437e4
commit 3b3fac6ef3
3 changed files with 36 additions and 26 deletions

View File

@@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Avalonia.Collections;
@@ -68,15 +72,12 @@ namespace SourceGit.Models
set;
} = [];
public static RepositorySettings Get(string repo, string gitCommonDir)
public static RepositorySettings Get(string gitCommonDir)
{
var fileInfo = new FileInfo(Path.Combine(gitCommonDir, "sourcegit.settings"));
var fullpath = fileInfo.FullName;
if (_cache.TryGetValue(fullpath, out var setting))
{
setting._usedBy.Add(repo);
return setting;
}
if (!File.Exists(fullpath))
{
@@ -96,28 +97,26 @@ namespace SourceGit.Models
}
setting._file = fullpath;
setting._usedBy.Add(repo);
setting._orgHash = HashContent(JsonSerializer.Serialize(setting, JsonCodeGen.Default.RepositorySettings));
_cache.Add(fullpath, setting);
return setting;
}
public void TryUnload(string repo)
public async Task SaveAsync()
{
_usedBy.Remove(repo);
if (_usedBy.Count == 0)
try
{
try
string content = JsonSerializer.Serialize(this, JsonCodeGen.Default.RepositorySettings);
string hash = HashContent(content);
if (!hash.Equals(_orgHash, StringComparison.Ordinal))
{
using var stream = File.Create(_file);
JsonSerializer.Serialize(stream, this, JsonCodeGen.Default.RepositorySettings);
await File.WriteAllTextAsync(_file, content);
_orgHash = hash;
}
catch
{
// Ignore save errors
}
_cache.Remove(_file);
}
catch
{
// Ignore save errors
}
}
@@ -167,8 +166,17 @@ namespace SourceGit.Models
CustomActions.Move(idx + 1, idx);
}
private static string HashContent(string source)
{
var hash = MD5.HashData(Encoding.Default.GetBytes(source));
var builder = new StringBuilder(hash.Length * 2);
foreach (var c in hash)
builder.Append(c.ToString("x2"));
return builder.ToString();
}
private static Dictionary<string, RepositorySettings> _cache = new();
private string _file = string.Empty;
private HashSet<string> _usedBy = new();
private string _orgHash = string.Empty;
}
}

View File

@@ -426,10 +426,10 @@ namespace SourceGit.ViewModels
GitDir = gitDir.Replace('\\', '/').TrimEnd('/');
var commonDirFile = Path.Combine(GitDir, "commondir");
_isWorktree = GitDir.IndexOf("/worktrees/", StringComparison.Ordinal) > 0 &&
var isWorktree = GitDir.IndexOf("/worktrees/", StringComparison.Ordinal) > 0 &&
File.Exists(commonDirFile);
if (_isWorktree)
if (isWorktree)
{
var commonDir = File.ReadAllText(commonDirFile).Trim();
if (!Path.IsPathRooted(commonDir))
@@ -445,7 +445,7 @@ namespace SourceGit.ViewModels
public void Open()
{
_settings = Models.RepositorySettings.Get(FullPath, _gitCommonDir);
_settings = Models.RepositorySettings.Get(_gitCommonDir);
_uiStates = Models.RepositoryUIStates.Load(GitDir);
try
@@ -484,7 +484,6 @@ namespace SourceGit.ViewModels
SelectedView = null; // Do NOT modify. Used to remove exists widgets for GC.Collect
Logs.Clear();
_settings.TryUnload(FullPath);
_uiStates.Unload(_workingCopy.CommitMessage);
if (_cancellationRefreshBranches is { IsCancellationRequested: false })
@@ -1775,6 +1774,9 @@ namespace SourceGit.ViewModels
private async Task AutoFetchOnUIThread()
{
if (_uiStates == null)
return;
CommandLog log = null;
try
@@ -1829,7 +1831,6 @@ namespace SourceGit.ViewModels
log?.Complete();
}
private readonly bool _isWorktree = false;
private readonly string _gitCommonDir = null;
private Models.RepositorySettings _settings = null;
private Models.RepositoryUIStates _uiStates = null;

View File

@@ -295,6 +295,7 @@ namespace SourceGit.ViewModels
await SetIfChangedAsync("fetch.prune", EnablePruneOnFetch ? "true" : "false", "false");
await ApplyIssueTrackerChangesAsync();
await _repo.Settings.SaveAsync();
}
private async Task SetIfChangedAsync(string key, string value, string defValue)
@@ -359,8 +360,8 @@ namespace SourceGit.ViewModels
}
}
private readonly Repository _repo = null;
private readonly Dictionary<string, string> _cached = null;
private readonly Repository _repo;
private readonly Dictionary<string, string> _cached;
private string _httpProxy;
private Models.CommitTemplate _selectedCommitTemplate = null;
private Models.IssueTracker _selectedIssueTracker = null;