Skip to content

Commit

Permalink
Rebase: improve perfs when displaying list of commits
Browse files Browse the repository at this point in the history
by retrieving all the commits data with only one `git log` call
instead of one by commit.
It is possible as when rebasing, all the commits belong to the same branch.

Kept a fall back to previous way to retrieve commit data for 1 commit
if commit is not in the one loaded.

Results with 7448 commits rebased: 2s instead of 4m50 previously

Fixes #10698 and #11196
  • Loading branch information
pmiossec committed Sep 7, 2023
1 parent 6a64d95 commit 0c40e6d
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 30 deletions.
65 changes: 35 additions & 30 deletions GitCommands/Git/GitModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2143,42 +2143,47 @@ public IReadOnlyList<PatchFile> GetInteractiveRebasePatchFiles()

List<PatchFile> patchFiles = new();

if (todoCommits is not null)
if (todoCommits is null)
{
string commentChar = EffectiveConfigFile.GetString("core.commentChar", "#");
return patchFiles;
}

string? currentCommitShortHash = File.Exists(CurrentFilePath) ? File.ReadAllText(CurrentFilePath).Trim() : null;
var isCurrentFound = false;
foreach (string todoCommit in todoCommits)
{
if (todoCommit.StartsWith(commentChar))
{
continue;
}
string commentChar = EffectiveConfigFile.GetString("core.commentChar", "#");

string[] parts = todoCommit.Split(Delimiters.Space);
string[][] todoCommitsInfos = todoCommits.Where(l => !l.StartsWith(commentChar))
.Select(l => l.Split(Delimiters.Space))
.Where(p => p.Length >= 3)
.ToArray();

if (parts.Length < 3)
{
continue;
}
string? currentCommitShortHash = File.Exists(CurrentFilePath) ? File.ReadAllText(CurrentFilePath).Trim() : null;
var isCurrentFound = false;

string commitHash = parts[1];
CommitData? data = _commitDataManager.GetCommitData(commitHash, out var error);
var isApplying = currentCommitShortHash is not null && commitHash.StartsWith(currentCommitShortHash);
isCurrentFound |= isApplying;
RevisionReader reader = new(this, hasReflogSelector: false);
CancellationTokenSource cts = new(2 * 60_000);
Dictionary<string, GitRevision> rebasedCommitsRevisions =
reader.GetRevisionsFromRange(todoCommitsInfos[0][1], todoCommitsInfos[^1][1], cts.Token)
.ToDictionary(r => r.Guid, r => r);

patchFiles.Add(new PatchFile
{
Author = error ?? data?.Author,
ObjectId = data?.ObjectId,
Subject = error ?? data?.Body,
Action = parts[0],
Date = error ?? data?.CommitDate.LocalDateTime.ToString(),
IsNext = isApplying,
IsApplied = !isCurrentFound,
});
}
foreach (string[] parts in todoCommitsInfos)
{
string commitHash = parts[1];
CommitData? data = rebasedCommitsRevisions.TryGetValue(commitHash, out GitRevision commitRevision)
? _commitDataManager.CreateFromRevision(commitRevision, null)
: _commitDataManager.GetCommitData(commitHash, out var _);

var isApplying = currentCommitShortHash is not null && commitHash.StartsWith(currentCommitShortHash);
isCurrentFound |= isApplying;

patchFiles.Add(new PatchFile
{
Author = data?.Author,
ObjectId = data?.ObjectId,
Subject = data?.Body,
Action = parts[0],
Date = data?.CommitDate.LocalDateTime.ToString(),
IsNext = isApplying,
IsApplied = !isCurrentFound,
});
}

return patchFiles;
Expand Down
24 changes: 24 additions & 0 deletions GitCommands/RevisionReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,30 @@ public IReadOnlyCollection<GitRevision> GetRevisionsFromList(IList<ObjectId> unt
return GetRevisionsFromArguments(arguments, cancellationToken);
}

/// <summary>
/// Get the GitRevisions for all commits between 2 commits (boundaries included).
/// </summary>
/// <param name="olderCommitId">older commit Id.</param>
/// <param name="newerCommitId">newer commit Id.</param>
/// <param name="cancellationToken">Cancellation cancellationToken.</param>
/// <returns>List with GitRevisions.</returns>
public IReadOnlyCollection<GitRevision> GetRevisionsFromRange(string olderCommitId, string newerCommitId, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(olderCommitId) || string.IsNullOrWhiteSpace(newerCommitId))
{
return Array.Empty<GitRevision>();
}

GitArgumentBuilder arguments = new("log")
{
"-z",
$"--pretty=format:\"{FullFormat}\"",
$"{olderCommitId}~..{newerCommitId}"
};

return GetRevisionsFromArguments(arguments, cancellationToken);
}

/// <summary>
/// Get the GitRevisions for Git argument.
/// </summary>
Expand Down

0 comments on commit 0c40e6d

Please sign in to comment.