enhance: only store subject in commits.

It has several advantages:

* reduce the memory costed by histories
* higher performance while parsing commits
* no need to calculate subject every time, which is invoked most frequently to render histories
This commit is contained in:
leo 2024-06-08 12:19:48 +08:00
parent 6426da3289
commit 9e45a8a77d
12 changed files with 67 additions and 65 deletions

View file

@ -0,0 +1,19 @@
namespace SourceGit.Commands
{
public class QueryCommitFullMessage : Command
{
public QueryCommitFullMessage(string repo, string sha)
{
WorkingDirectory = repo;
Context = repo;
Args = $"show --no-show-signature --pretty=format:%B -s {sha}";
}
public string Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess) return rs.StdOut.TrimEnd();
return string.Empty;
}
}
}

View file

@ -7,11 +7,9 @@ namespace SourceGit.Commands
{
public QueryCommits(string repo, string limits, bool needFindHead = true)
{
_endOfBodyToken = $"----- END OF BODY {Guid.NewGuid()} -----";
WorkingDirectory = repo;
Context = repo;
Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_endOfBodyToken}\" " + limits;
Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + limits;
_findFirstMerged = needFindHead;
}
@ -24,7 +22,6 @@ namespace SourceGit.Commands
var nextPartIdx = 0;
var start = 0;
var end = rs.StdOut.IndexOf('\n', start);
var max = rs.StdOut.Length;
while (end > 0)
{
var line = rs.StdOut.Substring(start, end - start);
@ -51,24 +48,17 @@ namespace SourceGit.Commands
break;
case 6:
_current.CommitterTime = ulong.Parse(line);
start = end + 1;
end = rs.StdOut.IndexOf(_endOfBodyToken, start, StringComparison.Ordinal);
if (end > 0)
{
if (end > start)
_current.Body = rs.StdOut.Substring(start, end - start).TrimEnd();
start = end + _endOfBodyToken.Length + 1;
end = start >= max ? -1 : rs.StdOut.IndexOf('\n', start);
}
nextPartIdx = 0;
continue;
break;
case 7:
_current.Subject = line;
break;
default:
break;
}
nextPartIdx++;
if (nextPartIdx == 8) nextPartIdx = 0;
start = end + 1;
end = rs.StdOut.IndexOf('\n', start);
}
@ -157,7 +147,7 @@ namespace SourceGit.Commands
if (l.Type != r.Type)
return (int)l.Type - (int)r.Type;
else
return l.Name.CompareTo(r.Name);
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
});
if (_current.IsMerged && !_isHeadFounded)
@ -187,7 +177,6 @@ namespace SourceGit.Commands
}
}
private string _endOfBodyToken = string.Empty;
private List<Models.Commit> _commits = new List<Models.Commit>();
private Models.Commit _current = null;
private bool _findFirstMerged = false;

View file

@ -10,7 +10,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"show --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B -s {sha}";
Args = $"show --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
}
public Models.Commit Result()
@ -32,11 +32,7 @@ namespace SourceGit.Commands
commit.AuthorTime = ulong.Parse(lines[4]);
commit.Committer = Models.User.FindOrAdd(lines[5]);
commit.CommitterTime = ulong.Parse(lines[6]);
StringBuilder builder = new StringBuilder();
for (int i = 7; i < lines.Length; i++)
builder.AppendLine(lines[i]);
commit.Body = builder.ToString().TrimEnd();
commit.Subject = lines[7];
return commit;
}
@ -105,7 +101,7 @@ namespace SourceGit.Commands
if (l.Type != r.Type)
return (int)l.Type - (int)r.Type;
else
return l.Name.CompareTo(r.Name);
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
});
return isHeadOfCurrent;

View file

@ -12,31 +12,13 @@ namespace SourceGit.Models
public ulong AuthorTime { get; set; } = 0;
public User Committer { get; set; } = User.Invalid;
public ulong CommitterTime { get; set; } = 0;
public string Body { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
public List<string> Parents { get; set; } = new List<string>();
public List<Decorator> Decorators { get; set; } = new List<Decorator>();
public bool HasDecorators => Decorators.Count > 0;
public bool IsMerged { get; set; } = false;
public Thickness Margin { get; set; } = new Thickness(0);
public string Subject
{
get
{
var end = Body.IndexOf("\r\n\r\n", StringComparison.Ordinal);
if (end == -1)
{
end = Body.IndexOf("\n\n", StringComparison.Ordinal);
if (end > 0)
return Body.Substring(0, end).Replace("\n", "", StringComparison.Ordinal);
return Body.Replace("\n", " ", StringComparison.Ordinal);
}
return Body.Substring(0, end).Replace("\r\n", " ", StringComparison.Ordinal);
}
}
public string AuthorTimeStr => _utcStart.AddSeconds(AuthorTime).ToString("yyyy/MM/dd HH:mm:ss");
public string CommitterTimeStr => _utcStart.AddSeconds(CommitterTime).ToString("yyyy/MM/dd HH:mm:ss");
public string AuthorTimeShortStr => _utcStart.AddSeconds(AuthorTime).ToString("yyyy/MM/dd");

View file

@ -36,6 +36,12 @@ namespace SourceGit.ViewModels
}
}
public string FullMessage
{
get => _fullMessage;
private set => SetProperty(ref _fullMessage, value);
}
public List<Models.Change> Changes
{
get => _changes;
@ -376,6 +382,7 @@ namespace SourceGit.ViewModels
private void Refresh()
{
_changes = null;
FullMessage = string.Empty;
VisibleChanges = null;
SelectedChanges = null;
@ -389,6 +396,7 @@ namespace SourceGit.ViewModels
Task.Run(() =>
{
var fullMessage = new Commands.QueryCommitFullMessage(_repo, _commit.SHA).Result();
var parent = _commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : _commit.Parents[0];
var cmdChanges = new Commands.CompareRevisions(_repo, parent, _commit.SHA) { Cancel = _cancelToken };
var changes = cmdChanges.Result();
@ -407,6 +415,7 @@ namespace SourceGit.ViewModels
{
Dispatcher.UIThread.Post(() =>
{
FullMessage = fullMessage;
Changes = changes;
VisibleChanges = visible;
});
@ -444,6 +453,7 @@ namespace SourceGit.ViewModels
private string _repo = string.Empty;
private int _activePageIndex = 0;
private Models.Commit _commit = null;
private string _fullMessage = string.Empty;
private List<Models.Change> _changes = null;
private List<Models.Change> _visibleChanges = null;
private List<Models.Change> _selectedChanges = null;

View file

@ -429,7 +429,7 @@ namespace SourceGit.ViewModels
foreach (var c in _histories.Commits)
{
if (c.SHA.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Body.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Subject.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Author.Name.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Committer.Name.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Author.Email.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
namespace SourceGit.ViewModels
@ -21,14 +22,16 @@ namespace SourceGit.ViewModels
public Reword(Repository repo, Models.Commit head)
{
_repo = repo;
_oldMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, head.SHA).Result();
_message = _oldMessage;
Head = head;
Message = head.Body;
View = new Views.Reword() { DataContext = this };
}
public override Task<bool> Sure()
{
if (_message == Head.Body)
if (string.Compare(_message, _oldMessage, StringComparison.Ordinal) == 0)
return null;
_repo.SetWatcherEnabled(false);
@ -44,5 +47,6 @@ namespace SourceGit.ViewModels
private readonly Repository _repo = null;
private string _message = string.Empty;
private string _oldMessage = string.Empty;
}
}

View file

@ -27,7 +27,8 @@ namespace SourceGit.ViewModels
public Squash(Repository repo, Models.Commit head, Models.Commit parent)
{
_repo = repo;
_message = parent.Body;
_message = new Commands.QueryCommitFullMessage(_repo.FullPath, parent.SHA).Result();
Head = head;
Parent = parent;
View = new Views.Squash() { DataContext = this };

View file

@ -93,16 +93,7 @@ namespace SourceGit.ViewModels
return;
}
var head = new Commands.QuerySingleCommit(_repo.FullPath, currentBranch.Head).Result();
if (head == null)
{
App.RaiseException(_repo.FullPath, "No commits to amend!!!");
_useAmend = false;
OnPropertyChanged();
return;
}
CommitMessage = head.Body;
CommitMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, currentBranch.Head).Result();
}
OnPropertyChanged(nameof(IsCommitWithPushVisible));

View file

@ -7,14 +7,15 @@
xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CommitBaseInfo">
x:Class="SourceGit.Views.CommitBaseInfo"
x:Name="ThisControl">
<UserControl.DataTemplates>
<DataTemplate DataType="m:Commit">
<StackPanel Orientation="Vertical">
<!-- Author & Committer -->
<UniformGrid Rows="1" Margin="0,8">
<!-- Author -->
<Grid Grid.Column="0" ColumnDefinitions="96,*">
<Grid ColumnDefinitions="96,*">
<v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Author}"/>
<StackPanel Grid.Column="1" Margin="16,0,8,0" Orientation="Vertical">
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Author}"/>
@ -30,7 +31,7 @@
</Grid>
<!-- Committer -->
<Grid Grid.Column="1" ColumnDefinitions="96,*" IsVisible="{Binding IsCommitterVisible}">
<Grid ColumnDefinitions="96,*" IsVisible="{Binding IsCommitterVisible}">
<v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Committer}"/>
<StackPanel Grid.Column="1" Margin="16,0,8,0" Orientation="Vertical">
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Committer}"/>
@ -104,7 +105,7 @@
<!-- Messages -->
<TextBlock Grid.Row="3" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Message}" VerticalAlignment="Top" Margin="0,4,0,0" />
<ScrollViewer Grid.Row="3" Grid.Column="1" Margin="12,5,8,0" MaxHeight="64" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<SelectableTextBlock Text="{Binding Body}" FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}" TextWrapping="Wrap"/>
<SelectableTextBlock Text="{Binding #ThisControl.Message}" FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}" TextWrapping="Wrap"/>
</ScrollViewer>
</Grid>
</StackPanel>

View file

@ -15,6 +15,15 @@ namespace SourceGit.Views
set => SetValue(CanNavigateProperty, value);
}
public static readonly StyledProperty<string> MessageProperty =
AvaloniaProperty.Register<CommitBaseInfo, string>(nameof(Message), string.Empty);
public string Message
{
get => GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
public CommitBaseInfo()
{
InitializeComponent();

View file

@ -19,7 +19,7 @@
<Grid RowDefinitions="Auto,1,*">
<!-- Base Information -->
<v:CommitBaseInfo Grid.Row="0" Content="{Binding Commit}"/>
<v:CommitBaseInfo Grid.Row="0" Content="{Binding Commit}" Message="{Binding FullMessage}"/>
<!-- Line -->
<Rectangle Grid.Row="1" Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}" VerticalAlignment="Center"/>