mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-06-21 18:35:00 +00:00
enhance: file rename detection and path resolution in file history
This commit is contained in:
parent
46231a759c
commit
a86a9cfd2b
4 changed files with 199 additions and 24 deletions
|
@ -8,7 +8,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
[GeneratedRegex(@"^([MADC])\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
|
||||
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)\s+(.+)$")]
|
||||
private static partial Regex REG_RENAME_FORMAT();
|
||||
|
||||
public CompareRevisions(string repo, string start, string end)
|
||||
|
@ -51,7 +51,11 @@ namespace SourceGit.Commands
|
|||
match = REG_RENAME_FORMAT().Match(line);
|
||||
if (match.Success)
|
||||
{
|
||||
var renamed = new Models.Change() { Path = match.Groups[1].Value };
|
||||
var renamed = new Models.Change()
|
||||
{
|
||||
OriginalPath = match.Groups[1].Value,
|
||||
Path = match.Groups[2].Value
|
||||
};
|
||||
renamed.Set(Models.ChangeState.Renamed);
|
||||
_changes.Add(renamed);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace SourceGit.Commands
|
|||
}
|
||||
else if (method == Models.CommitSearchMethod.ByFile)
|
||||
{
|
||||
search += $"-- \"{filter}\"";
|
||||
search += $"--follow -- \"{filter}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
124
src/Commands/QueryFilePathInRevision.cs
Normal file
124
src/Commands/QueryFilePathInRevision.cs
Normal file
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryFilePathInRevision : Command
|
||||
{
|
||||
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)\s+(.+)$")]
|
||||
private static partial Regex REG_RENAME_FORMAT();
|
||||
|
||||
public QueryFilePathInRevision(string repo, string revision, string currentPath)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
_revision = revision;
|
||||
_currentPath = currentPath;
|
||||
}
|
||||
|
||||
public string Result()
|
||||
{
|
||||
if (CheckPathExistsInRevision(_currentPath))
|
||||
return _currentPath;
|
||||
|
||||
string mappedPath = FindRenameHistory();
|
||||
return mappedPath ?? _currentPath;
|
||||
}
|
||||
|
||||
private bool CheckPathExistsInRevision(string path)
|
||||
{
|
||||
Args = $"ls-tree -r {_revision} -- \"{path}\"";
|
||||
var rs = ReadToEnd();
|
||||
return rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut);
|
||||
}
|
||||
|
||||
private string FindRenameHistory()
|
||||
{
|
||||
var fileHistory = BuildFileHistory();
|
||||
if (fileHistory == null || fileHistory.Count == 0)
|
||||
return null;
|
||||
|
||||
foreach (var entry in fileHistory)
|
||||
{
|
||||
if (!IsTargetRevisionBefore(entry.CommitSHA))
|
||||
continue;
|
||||
|
||||
if (CheckPathExistsInRevision(entry.OldPath))
|
||||
return entry.OldPath;
|
||||
}
|
||||
|
||||
if (fileHistory.Count > 0)
|
||||
{
|
||||
var oldestPath = fileHistory[^1].OldPath;
|
||||
if (CheckPathExistsInRevision(oldestPath))
|
||||
return oldestPath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsTargetRevisionBefore(string commitSHA)
|
||||
{
|
||||
Args = $"merge-base --is-ancestor {_revision} {commitSHA}";
|
||||
var rs = ReadToEnd();
|
||||
return rs.IsSuccess;
|
||||
}
|
||||
|
||||
private List<RenameHistoryEntry> BuildFileHistory()
|
||||
{
|
||||
Args = $"log --follow --name-status --pretty=format:\"commit %H\" -M -- \"{_currentPath}\"";
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return null;
|
||||
|
||||
var result = new List<RenameHistoryEntry>();
|
||||
var lines = rs.StdOut.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
string currentCommit = null;
|
||||
string currentPath = _currentPath;
|
||||
|
||||
foreach (var t in lines)
|
||||
{
|
||||
var line = t.Trim();
|
||||
|
||||
if (line.StartsWith("commit ", StringComparison.Ordinal))
|
||||
{
|
||||
currentCommit = line.Substring("commit ".Length);
|
||||
continue;
|
||||
}
|
||||
|
||||
var match = REG_RENAME_FORMAT().Match(line);
|
||||
if (match.Success && currentCommit != null)
|
||||
{
|
||||
var oldPath = match.Groups[1].Value;
|
||||
var newPath = match.Groups[2].Value;
|
||||
|
||||
if (newPath == currentPath)
|
||||
{
|
||||
result.Add(new RenameHistoryEntry
|
||||
{
|
||||
CommitSHA = currentCommit,
|
||||
OldPath = oldPath,
|
||||
NewPath = newPath
|
||||
});
|
||||
|
||||
currentPath = oldPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class RenameHistoryEntry
|
||||
{
|
||||
public string CommitSHA { get; set; }
|
||||
public string OldPath { get; set; }
|
||||
public string NewPath { get; set; }
|
||||
}
|
||||
|
||||
private readonly string _revision;
|
||||
private readonly string _currentPath;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue