mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-06-22 10:55:00 +00:00
Merge
This commit is contained in:
commit
75b15c455e
284 changed files with 10116 additions and 5764 deletions
|
@ -12,7 +12,7 @@ namespace SourceGit.Commands
|
|||
Args = includeUntracked ? "add ." : "add -u .";
|
||||
}
|
||||
|
||||
public Add(string repo, List<Models.Change> changes)
|
||||
public Add(string repo, List<string> changes)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
@ -22,7 +22,7 @@ namespace SourceGit.Commands
|
|||
foreach (var c in changes)
|
||||
{
|
||||
builder.Append(" \"");
|
||||
builder.Append(c.Path);
|
||||
builder.Append(c);
|
||||
builder.Append("\"");
|
||||
}
|
||||
Args = builder.ToString();
|
||||
|
|
|
@ -54,21 +54,14 @@
|
|||
|
||||
public static bool DeleteRemote(string repo, string remote, string name)
|
||||
{
|
||||
bool exists = new Remote(repo).HasBranch(remote, name);
|
||||
if (exists)
|
||||
return new Push(repo, remote, $"refs/heads/{name}", true).Exec();
|
||||
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
|
||||
bool exists = new Remote(repo).HasBranch(remote, name);
|
||||
if (exists)
|
||||
{
|
||||
cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
cmd.Args = $"push {remote} --delete {name}";
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Args = $"branch -D -r {remote}/{name}";
|
||||
}
|
||||
|
||||
cmd.Args = $"branch -D -r {remote}/{name}";
|
||||
return cmd.Exec();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace SourceGit.Commands
|
|||
WorkingDirectory = path;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = sshKey;
|
||||
Args = "clone --progress --verbose --recurse-submodules ";
|
||||
Args = "clone --progress --verbose ";
|
||||
|
||||
if (!string.IsNullOrEmpty(extraArgs))
|
||||
Args += $"{extraArgs} ";
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
using Avalonia.Threading;
|
||||
|
||||
|
@ -10,11 +11,6 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public partial class Command
|
||||
{
|
||||
public class CancelToken
|
||||
{
|
||||
public bool Requested { get; set; } = false;
|
||||
}
|
||||
|
||||
public class ReadToEndResult
|
||||
{
|
||||
public bool IsSuccess { get; set; } = false;
|
||||
|
@ -30,7 +26,7 @@ namespace SourceGit.Commands
|
|||
}
|
||||
|
||||
public string Context { get; set; } = string.Empty;
|
||||
public CancelToken Cancel { get; set; } = null;
|
||||
public CancellationToken CancellationToken { get; set; } = CancellationToken.None;
|
||||
public string WorkingDirectory { get; set; } = null;
|
||||
public EditorType Editor { get; set; } = EditorType.CoreEditor; // Only used in Exec() mode
|
||||
public string SSHKey { get; set; } = string.Empty;
|
||||
|
@ -43,36 +39,15 @@ namespace SourceGit.Commands
|
|||
var start = CreateGitStartInfo();
|
||||
var errs = new List<string>();
|
||||
var proc = new Process() { StartInfo = start };
|
||||
var isCancelled = false;
|
||||
|
||||
proc.OutputDataReceived += (_, e) =>
|
||||
{
|
||||
if (Cancel != null && Cancel.Requested)
|
||||
{
|
||||
isCancelled = true;
|
||||
proc.CancelErrorRead();
|
||||
proc.CancelOutputRead();
|
||||
if (!proc.HasExited)
|
||||
proc.Kill(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Data != null)
|
||||
OnReadline(e.Data);
|
||||
};
|
||||
|
||||
proc.ErrorDataReceived += (_, e) =>
|
||||
{
|
||||
if (Cancel != null && Cancel.Requested)
|
||||
{
|
||||
isCancelled = true;
|
||||
proc.CancelErrorRead();
|
||||
proc.CancelOutputRead();
|
||||
if (!proc.HasExited)
|
||||
proc.Kill(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
errs.Add(string.Empty);
|
||||
|
@ -97,9 +72,25 @@ namespace SourceGit.Commands
|
|||
errs.Add(e.Data);
|
||||
};
|
||||
|
||||
var dummy = null as Process;
|
||||
var dummyProcLock = new object();
|
||||
try
|
||||
{
|
||||
proc.Start();
|
||||
|
||||
// It not safe, please only use `CancellationToken` in readonly commands.
|
||||
if (CancellationToken.CanBeCanceled)
|
||||
{
|
||||
dummy = proc;
|
||||
CancellationToken.Register(() =>
|
||||
{
|
||||
lock (dummyProcLock)
|
||||
{
|
||||
if (dummy is { HasExited: false })
|
||||
dummy.Kill();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -113,10 +104,18 @@ namespace SourceGit.Commands
|
|||
proc.BeginErrorReadLine();
|
||||
proc.WaitForExit();
|
||||
|
||||
if (dummy != null)
|
||||
{
|
||||
lock (dummyProcLock)
|
||||
{
|
||||
dummy = null;
|
||||
}
|
||||
}
|
||||
|
||||
int exitCode = proc.ExitCode;
|
||||
proc.Close();
|
||||
|
||||
if (!isCancelled && exitCode != 0)
|
||||
if (!CancellationToken.IsCancellationRequested && exitCode != 0)
|
||||
{
|
||||
if (RaiseError)
|
||||
{
|
||||
|
@ -192,13 +191,12 @@ namespace SourceGit.Commands
|
|||
if (!start.Environment.ContainsKey("GIT_SSH_COMMAND") && !string.IsNullOrEmpty(SSHKey))
|
||||
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}'");
|
||||
|
||||
// Force using en_US.UTF-8 locale to avoid GCM crash
|
||||
// Force using en_US.UTF-8 locale
|
||||
if (OperatingSystem.IsLinux())
|
||||
start.Environment.Add("LANG", "en_US.UTF-8");
|
||||
|
||||
// Fix macOS `PATH` env
|
||||
if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
|
||||
start.Environment.Add("PATH", Native.OS.CustomPathEnv);
|
||||
{
|
||||
start.Environment.Add("LANG", "C");
|
||||
start.Environment.Add("LC_ALL", "C");
|
||||
}
|
||||
|
||||
// Force using this app as git editor.
|
||||
switch (Editor)
|
||||
|
|
|
@ -6,8 +6,10 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public partial class CompareRevisions : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
|
||||
[GeneratedRegex(@"^([MADC])\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
|
||||
private static partial Regex REG_RENAME_FORMAT();
|
||||
|
||||
public CompareRevisions(string repo, string start, string end)
|
||||
{
|
||||
|
@ -18,6 +20,15 @@ namespace SourceGit.Commands
|
|||
Args = $"diff --name-status {based} {end}";
|
||||
}
|
||||
|
||||
public CompareRevisions(string repo, string start, string end, string path)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
var based = string.IsNullOrEmpty(start) ? "-R" : start;
|
||||
Args = $"diff --name-status {based} {end} -- \"{path}\"";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
|
@ -29,7 +40,17 @@ namespace SourceGit.Commands
|
|||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
{
|
||||
match = REG_RENAME_FORMAT().Match(line);
|
||||
if (match.Success)
|
||||
{
|
||||
var renamed = new Models.Change() { Path = match.Groups[1].Value };
|
||||
renamed.Set(Models.ChangeState.Renamed);
|
||||
_changes.Add(renamed);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
@ -48,10 +69,6 @@ namespace SourceGit.Commands
|
|||
change.Set(Models.ChangeState.Deleted);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
case 'R':
|
||||
change.Set(Models.ChangeState.Renamed);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
case 'C':
|
||||
change.Set(Models.ChangeState.Copied);
|
||||
_changes.Add(change);
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace SourceGit.Commands
|
|||
var rs = new Dictionary<string, string>();
|
||||
if (output.IsSuccess)
|
||||
{
|
||||
var lines = output.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var idx = line.IndexOf('=', StringComparison.Ordinal);
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "status -uno --ignore-submodules=dirty --porcelain";
|
||||
Args = "--no-optional-locks status -uno --ignore-submodules=dirty --porcelain";
|
||||
}
|
||||
|
||||
public int Result()
|
||||
|
@ -16,7 +16,7 @@ namespace SourceGit.Commands
|
|||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
return lines.Length;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,18 @@ namespace SourceGit.Commands
|
|||
return;
|
||||
}
|
||||
|
||||
if (line.StartsWith("deleted file mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.OldMode = line.Substring(18);
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.StartsWith("new file mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.NewMode = line.Substring(14);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_result.IsBinary)
|
||||
return;
|
||||
|
||||
|
|
|
@ -8,7 +8,26 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public static class ExecuteCustomAction
|
||||
{
|
||||
public static void Run(string repo, string file, string args, Action<string> outputHandler)
|
||||
public static void Run(string repo, string file, string args)
|
||||
{
|
||||
var start = new ProcessStartInfo();
|
||||
start.FileName = file;
|
||||
start.Arguments = args;
|
||||
start.UseShellExecute = false;
|
||||
start.CreateNoWindow = true;
|
||||
start.WorkingDirectory = repo;
|
||||
|
||||
try
|
||||
{
|
||||
Process.Start(start);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message));
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunAndWait(string repo, string file, string args, Action<string> outputHandler)
|
||||
{
|
||||
var start = new ProcessStartInfo();
|
||||
start.FileName = file;
|
||||
|
@ -21,14 +40,6 @@ namespace SourceGit.Commands
|
|||
start.StandardErrorEncoding = Encoding.UTF8;
|
||||
start.WorkingDirectory = repo;
|
||||
|
||||
// Force using en_US.UTF-8 locale to avoid GCM crash
|
||||
if (OperatingSystem.IsLinux())
|
||||
start.Environment.Add("LANG", "en_US.UTF-8");
|
||||
|
||||
// Fix macOS `PATH` env
|
||||
if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
|
||||
start.Environment.Add("PATH", Native.OS.CustomPathEnv);
|
||||
|
||||
var proc = new Process() { StartInfo = start };
|
||||
var builder = new StringBuilder();
|
||||
|
||||
|
@ -57,19 +68,14 @@ namespace SourceGit.Commands
|
|||
var exitCode = proc.ExitCode;
|
||||
if (exitCode != 0)
|
||||
{
|
||||
var errMsg = builder.ToString();
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, errMsg);
|
||||
});
|
||||
var errMsg = builder.ToString().Trim();
|
||||
if (!string.IsNullOrEmpty(errMsg))
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, errMsg));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, e.Message);
|
||||
});
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message));
|
||||
}
|
||||
|
||||
proc.Close();
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public class Fetch : Command
|
||||
{
|
||||
public Fetch(string repo, string remote, bool noTags, bool prune, bool force, Action<string> outputHandler)
|
||||
public Fetch(string repo, string remote, bool noTags, bool force, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
|
@ -21,9 +21,6 @@ namespace SourceGit.Commands
|
|||
if (force)
|
||||
Args += "--force ";
|
||||
|
||||
if (prune)
|
||||
Args += "--prune ";
|
||||
|
||||
Args += remote;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -20,82 +22,78 @@ namespace SourceGit.Commands
|
|||
}
|
||||
}
|
||||
|
||||
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onProgress)
|
||||
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onResponse)
|
||||
{
|
||||
_service = service;
|
||||
_repo = repo;
|
||||
_changes = changes;
|
||||
_cancelToken = cancelToken;
|
||||
_onProgress = onProgress;
|
||||
_onResponse = onResponse;
|
||||
}
|
||||
|
||||
public string Result()
|
||||
public void Exec()
|
||||
{
|
||||
try
|
||||
{
|
||||
var summarybuilder = new StringBuilder();
|
||||
var bodyBuilder = new StringBuilder();
|
||||
_onResponse?.Invoke("Waiting for pre-file analyzing to completed...\n\n");
|
||||
|
||||
var responseBuilder = new StringBuilder();
|
||||
var summaryBuilder = new StringBuilder();
|
||||
foreach (var change in _changes)
|
||||
{
|
||||
if (_cancelToken.IsCancellationRequested)
|
||||
return "";
|
||||
return;
|
||||
|
||||
_onProgress?.Invoke($"Analyzing {change.Path}...");
|
||||
responseBuilder.Append("- ");
|
||||
summaryBuilder.Append("- ");
|
||||
|
||||
var summary = GenerateChangeSummary(change);
|
||||
summarybuilder.Append("- ");
|
||||
summarybuilder.Append(summary);
|
||||
summarybuilder.Append("(file: ");
|
||||
summarybuilder.Append(change.Path);
|
||||
summarybuilder.Append(")");
|
||||
summarybuilder.AppendLine();
|
||||
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
_service.Chat(
|
||||
_service.AnalyzeDiffPrompt,
|
||||
$"Here is the `git diff` output: {rs.StdOut}",
|
||||
_cancelToken,
|
||||
update =>
|
||||
{
|
||||
responseBuilder.Append(update);
|
||||
summaryBuilder.Append(update);
|
||||
|
||||
bodyBuilder.Append("- ");
|
||||
bodyBuilder.Append(summary);
|
||||
bodyBuilder.AppendLine();
|
||||
_onResponse?.Invoke($"Waiting for pre-file analyzing to completed...\n\n{responseBuilder}");
|
||||
});
|
||||
}
|
||||
|
||||
responseBuilder.Append("\n");
|
||||
summaryBuilder.Append("(file: ");
|
||||
summaryBuilder.Append(change.Path);
|
||||
summaryBuilder.Append(")\n");
|
||||
}
|
||||
|
||||
if (_cancelToken.IsCancellationRequested)
|
||||
return "";
|
||||
return;
|
||||
|
||||
_onProgress?.Invoke($"Generating commit message...");
|
||||
|
||||
var body = bodyBuilder.ToString();
|
||||
var subject = GenerateSubject(summarybuilder.ToString());
|
||||
return string.Format("{0}\n\n{1}", subject, body);
|
||||
var responseBody = responseBuilder.ToString();
|
||||
var subjectBuilder = new StringBuilder();
|
||||
_service.Chat(
|
||||
_service.GenerateSubjectPrompt,
|
||||
$"Here are the summaries changes:\n{summaryBuilder}",
|
||||
_cancelToken,
|
||||
update =>
|
||||
{
|
||||
subjectBuilder.Append(update);
|
||||
_onResponse?.Invoke($"{subjectBuilder}\n\n{responseBody}");
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.RaiseException(_repo, $"Failed to generate commit message: {e}");
|
||||
return "";
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(_repo, $"Failed to generate commit message: {e}"));
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateChangeSummary(Models.Change change)
|
||||
{
|
||||
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
|
||||
var diff = rs.IsSuccess ? rs.StdOut : "unknown change";
|
||||
|
||||
var rsp = _service.Chat(_service.AnalyzeDiffPrompt, $"Here is the `git diff` output: {diff}", _cancelToken);
|
||||
if (rsp != null && rsp.Choices.Count > 0)
|
||||
return rsp.Choices[0].Message.Content;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string GenerateSubject(string summary)
|
||||
{
|
||||
var rsp = _service.Chat(_service.GenerateSubjectPrompt, $"Here are the summaries changes:\n{summary}", _cancelToken);
|
||||
if (rsp != null && rsp.Choices.Count > 0)
|
||||
return rsp.Choices[0].Message.Content;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private Models.OpenAIService _service;
|
||||
private string _repo;
|
||||
private List<Models.Change> _changes;
|
||||
private CancellationToken _cancelToken;
|
||||
private Action<string> _onProgress;
|
||||
private Action<string> _onResponse;
|
||||
}
|
||||
}
|
||||
|
|
24
src/Commands/IsBareRepository.cs
Normal file
24
src/Commands/IsBareRepository.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class IsBareRepository : Command
|
||||
{
|
||||
public IsBareRepository(string path)
|
||||
{
|
||||
WorkingDirectory = path;
|
||||
Args = "rev-parse --is-bare-repository";
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
{
|
||||
if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||
|
||||
!Directory.Exists(Path.Combine(WorkingDirectory, "objects")) ||
|
||||
!File.Exists(Path.Combine(WorkingDirectory, "HEAD")))
|
||||
return false;
|
||||
|
||||
var rs = ReadToEnd();
|
||||
return rs.IsSuccess && rs.StdOut.Trim() == "true";
|
||||
}
|
||||
}
|
||||
}
|
17
src/Commands/IsCommitSHA.cs
Normal file
17
src/Commands/IsCommitSHA.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace SourceGit.Commands
|
||||
{
|
||||
public class IsCommitSHA : Command
|
||||
{
|
||||
public IsCommitSHA(string repo, string hash)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Args = $"cat-file -t {hash}";
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
return rs.IsSuccess && rs.StdOut.Trim().Equals("commit");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public partial class LFS
|
||||
{
|
||||
[GeneratedRegex(@"^(.+)\s+(\w+)\s+\w+:(\d+)$")]
|
||||
[GeneratedRegex(@"^(.+)\s+([\w.]+)\s+\w+:(\d+)$")]
|
||||
private static partial Regex REG_LOCK();
|
||||
|
||||
class SubCmd : Command
|
||||
|
@ -82,7 +82,7 @@ namespace SourceGit.Commands
|
|||
var rs = cmd.ReadToEnd();
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_LOCK().Match(line);
|
||||
|
|
|
@ -13,9 +13,12 @@ namespace SourceGit.Commands
|
|||
cmd.Context = repo;
|
||||
cmd.RaiseError = true;
|
||||
|
||||
// NOTE: If no <file> names are specified, 'git mergetool' will run the merge tool program on every file with merge conflicts.
|
||||
var fileArg = string.IsNullOrEmpty(file) ? "" : $"\"{file}\"";
|
||||
|
||||
if (toolType == 0)
|
||||
{
|
||||
cmd.Args = $"mergetool \"{file}\"";
|
||||
cmd.Args = $"mergetool {fileArg}";
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
|
@ -32,7 +35,7 @@ namespace SourceGit.Commands
|
|||
return false;
|
||||
}
|
||||
|
||||
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit \"{file}\"";
|
||||
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit {fileArg}";
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,21 +4,20 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public class Pull : Command
|
||||
{
|
||||
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, bool prune, Action<string> outputHandler)
|
||||
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "pull --verbose --progress --tags ";
|
||||
Args = "pull --verbose --progress ";
|
||||
|
||||
if (useRebase)
|
||||
Args += "--rebase ";
|
||||
Args += "--rebase=true ";
|
||||
|
||||
if (noTags)
|
||||
Args += "--no-tags ";
|
||||
if (prune)
|
||||
Args += "--prune ";
|
||||
|
||||
Args += $"{remote} {branch}";
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace SourceGit.Commands
|
|||
Args += $"{remote} {local}:{remoteBranch}";
|
||||
}
|
||||
|
||||
public Push(string repo, string remote, string tag, bool isDelete)
|
||||
public Push(string repo, string remote, string refname, bool isDelete)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
@ -36,7 +36,7 @@ namespace SourceGit.Commands
|
|||
if (isDelete)
|
||||
Args += "--delete ";
|
||||
|
||||
Args += $"{remote} refs/tags/{tag}";
|
||||
Args += $"{remote} {refname}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
|
|
|
@ -24,12 +24,23 @@ namespace SourceGit.Commands
|
|||
if (!rs.IsSuccess)
|
||||
return branches;
|
||||
|
||||
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
var remoteBranches = new HashSet<string>();
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var b = ParseLine(line);
|
||||
if (b != null)
|
||||
{
|
||||
branches.Add(b);
|
||||
if (!b.IsLocal)
|
||||
remoteBranches.Add(b.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var b in branches)
|
||||
{
|
||||
if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
|
||||
b.IsUpsteamGone = !remoteBranches.Contains(b.Upstream);
|
||||
}
|
||||
|
||||
return branches;
|
||||
|
@ -75,6 +86,7 @@ namespace SourceGit.Commands
|
|||
branch.Head = parts[1];
|
||||
branch.IsCurrent = parts[2] == "*";
|
||||
branch.Upstream = parts[3];
|
||||
branch.IsUpsteamGone = false;
|
||||
|
||||
if (branch.IsLocal && !string.IsNullOrEmpty(parts[4]) && !parts[4].Equals("=", StringComparison.Ordinal))
|
||||
branch.TrackStatus = new QueryTrackStatus(WorkingDirectory, branch.Name, branch.Upstream).Result();
|
||||
|
|
|
@ -9,10 +9,10 @@ namespace SourceGit.Commands
|
|||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
_commit = commit;
|
||||
Args = $"rev-list -{max} --parents --branches --remotes ^{commit}";
|
||||
Args = $"rev-list -{max} --parents --branches --remotes --ancestry-path ^{commit}";
|
||||
}
|
||||
|
||||
public IEnumerable<string> Result()
|
||||
public List<string> Result()
|
||||
{
|
||||
Exec();
|
||||
return _lines;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"show --no-show-signature --pretty=format:%B -s {sha}";
|
||||
Args = $"show --no-show-signature --format=%B -s {sha}";
|
||||
}
|
||||
|
||||
public string Result()
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
const string baseArgs = "show --no-show-signature --pretty=format:\"%G?%n%GS%n%GK\" -s";
|
||||
const string baseArgs = "show --no-show-signature --format=%G?%n%GS%n%GK -s";
|
||||
const string fakeSignersFileArg = "-c gpg.ssh.allowedSignersFile=/dev/null";
|
||||
Args = $"{(useFakeSignersFile ? fakeSignersFileArg : string.Empty)} {baseArgs} {sha}";
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
if (!rs.IsSuccess)
|
||||
return null;
|
||||
|
||||
var raw = rs.StdOut.Trim();
|
||||
var raw = rs.StdOut.Trim().ReplaceLineEndings("\n");
|
||||
if (raw.Length <= 1)
|
||||
return null;
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
|||
Signer = lines[1],
|
||||
Key = lines[2]
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"log --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}";
|
||||
Args = $"log --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {limits}";
|
||||
_findFirstMerged = needFindHead;
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,13 @@ namespace SourceGit.Commands
|
|||
{
|
||||
string search = onlyCurrentBranch ? string.Empty : "--branches --remotes ";
|
||||
|
||||
if (method == Models.CommitSearchMethod.ByUser)
|
||||
if (method == Models.CommitSearchMethod.ByAuthor)
|
||||
{
|
||||
search += $"-i --author=\"{filter}\" --committer=\"{filter}\"";
|
||||
search += $"-i --author=\"{filter}\"";
|
||||
}
|
||||
else if (method == Models.CommitSearchMethod.ByCommitter)
|
||||
{
|
||||
search += $"-i --committer=\"{filter}\"";
|
||||
}
|
||||
else if (method == Models.CommitSearchMethod.ByFile)
|
||||
{
|
||||
|
@ -31,7 +35,7 @@ namespace SourceGit.Commands
|
|||
var argsBuilder = new StringBuilder();
|
||||
argsBuilder.Append(search);
|
||||
|
||||
var words = filter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var words = filter.Split([' ', '\t', '\r'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var word in words)
|
||||
{
|
||||
var escaped = word.Trim().Replace("\"", "\\\"", StringComparison.Ordinal);
|
||||
|
@ -44,7 +48,7 @@ namespace SourceGit.Commands
|
|||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"log -1000 --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 " + search;
|
||||
Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + search;
|
||||
_findFirstMerged = false;
|
||||
}
|
||||
|
||||
|
@ -120,7 +124,7 @@ namespace SourceGit.Commands
|
|||
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var shas = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
if (shas.Length == 0)
|
||||
return;
|
||||
|
||||
|
|
|
@ -3,18 +3,18 @@ using System.Collections.Generic;
|
|||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryCommitsWithFullMessage : Command
|
||||
public class QueryCommitsForInteractiveRebase : Command
|
||||
{
|
||||
public QueryCommitsWithFullMessage(string repo, string args)
|
||||
public QueryCommitsForInteractiveRebase(string repo, string on)
|
||||
{
|
||||
_boundary = $"----- BOUNDARY OF COMMIT {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{_boundary}\" {args}";
|
||||
Args = $"log --date-order --no-show-signature --decorate=full --format=\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {on}..HEAD";
|
||||
}
|
||||
|
||||
public List<Models.CommitWithMessage> Result()
|
||||
public List<Models.InteractiveCommit> Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
|
@ -29,7 +29,7 @@ namespace SourceGit.Commands
|
|||
switch (nextPartIdx)
|
||||
{
|
||||
case 0:
|
||||
_current = new Models.CommitWithMessage();
|
||||
_current = new Models.InteractiveCommit();
|
||||
_current.Commit.SHA = line;
|
||||
_commits.Add(_current);
|
||||
break;
|
||||
|
@ -52,7 +52,7 @@ namespace SourceGit.Commands
|
|||
_current.Commit.CommitterTime = ulong.Parse(line);
|
||||
break;
|
||||
default:
|
||||
var boundary = rs.StdOut.IndexOf(_boundary, end + 1);
|
||||
var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
|
||||
if (boundary > end)
|
||||
{
|
||||
_current.Message = rs.StdOut.Substring(start, boundary - start - 1);
|
||||
|
@ -88,8 +88,8 @@ namespace SourceGit.Commands
|
|||
_current.Commit.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
private List<Models.CommitWithMessage> _commits = new List<Models.CommitWithMessage>();
|
||||
private Models.CommitWithMessage _current = null;
|
||||
private List<Models.InteractiveCommit> _commits = [];
|
||||
private Models.InteractiveCommit _current = null;
|
||||
private string _boundary = "";
|
||||
}
|
||||
}
|
26
src/Commands/QueryGitCommonDir.cs
Normal file
26
src/Commands/QueryGitCommonDir.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryGitCommonDir : Command
|
||||
{
|
||||
public QueryGitCommonDir(string workDir)
|
||||
{
|
||||
WorkingDirectory = workDir;
|
||||
Args = "rev-parse --git-common-dir";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public string Result()
|
||||
{
|
||||
var rs = ReadToEnd().StdOut;
|
||||
if (string.IsNullOrEmpty(rs))
|
||||
return null;
|
||||
|
||||
rs = rs.Trim();
|
||||
if (Path.IsPathRooted(rs))
|
||||
return rs;
|
||||
return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
|
||||
Args = $"--no-optional-locks status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result()
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace SourceGit.Commands
|
|||
if (!output.IsSuccess)
|
||||
return rs;
|
||||
|
||||
var lines = output.StdOut.Split('\n');
|
||||
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.EndsWith("/HEAD", StringComparison.Ordinal))
|
||||
|
|
21
src/Commands/QueryRevisionByRefName.cs
Normal file
21
src/Commands/QueryRevisionByRefName.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryRevisionByRefName : Command
|
||||
{
|
||||
public QueryRevisionByRefName(string repo, string refname)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"rev-parse {refname}";
|
||||
}
|
||||
|
||||
public string Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
|
||||
return rs.StdOut.Trim();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace SourceGit.Commands
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryRevisionFileNames : Command
|
||||
{
|
||||
|
@ -9,13 +11,17 @@
|
|||
Args = $"ls-tree -r -z --name-only {revision}";
|
||||
}
|
||||
|
||||
public string[] Result()
|
||||
public List<string> Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess)
|
||||
return rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
|
||||
if (!rs.IsSuccess)
|
||||
return [];
|
||||
|
||||
return [];
|
||||
var lines = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
|
||||
var outs = new List<string>();
|
||||
foreach (var line in lines)
|
||||
outs.Add(line);
|
||||
return outs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,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%s -s {sha}";
|
||||
Args = $"show --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
|
||||
}
|
||||
|
||||
public Models.Commit Result()
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace SourceGit.Commands
|
|||
if (rs.IsSuccess)
|
||||
{
|
||||
var changes = new List<Models.Change>();
|
||||
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_FORMAT2().Match(line);
|
||||
|
|
|
@ -1,60 +1,76 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Query stash changes. Requires git >= 2.32.0
|
||||
/// </summary>
|
||||
public partial class QueryStashChanges : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
|
||||
[GeneratedRegex(@"^([MADC])\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
|
||||
private static partial Regex REG_RENAME_FORMAT();
|
||||
|
||||
public QueryStashChanges(string repo, string sha)
|
||||
public QueryStashChanges(string repo, string stash)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"diff --name-status --pretty=format: {sha}^ {sha}";
|
||||
Args = $"stash show -u --name-status \"{stash}\"";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
return _changes;
|
||||
}
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return [];
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
return;
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status[0])
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
var outs = new List<Models.Change>();
|
||||
foreach (var line in lines)
|
||||
{
|
||||
case 'M':
|
||||
change.Set(Models.ChangeState.Modified);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
case 'A':
|
||||
change.Set(Models.ChangeState.Added);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
case 'D':
|
||||
change.Set(Models.ChangeState.Deleted);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
case 'R':
|
||||
change.Set(Models.ChangeState.Renamed);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
case 'C':
|
||||
change.Set(Models.ChangeState.Copied);
|
||||
_changes.Add(change);
|
||||
break;
|
||||
}
|
||||
}
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
{
|
||||
match = REG_RENAME_FORMAT().Match(line);
|
||||
if (match.Success)
|
||||
{
|
||||
var renamed = new Models.Change() { Path = match.Groups[1].Value };
|
||||
renamed.Set(Models.ChangeState.Renamed);
|
||||
outs.Add(renamed);
|
||||
}
|
||||
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
continue;
|
||||
}
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status[0])
|
||||
{
|
||||
case 'M':
|
||||
change.Set(Models.ChangeState.Modified);
|
||||
outs.Add(change);
|
||||
break;
|
||||
case 'A':
|
||||
change.Set(Models.ChangeState.Added);
|
||||
outs.Add(change);
|
||||
break;
|
||||
case 'D':
|
||||
change.Set(Models.ChangeState.Deleted);
|
||||
outs.Add(change);
|
||||
break;
|
||||
case 'C':
|
||||
change.Set(Models.ChangeState.Copied);
|
||||
outs.Add(change);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outs.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
|
||||
return outs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
|
@ -8,7 +9,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "stash list --pretty=format:%H%n%ct%n%gd%n%s";
|
||||
Args = "stash list --format=%H%n%P%n%ct%n%gd%n%s";
|
||||
}
|
||||
|
||||
public List<Models.Stash> Result()
|
||||
|
@ -26,21 +27,32 @@ namespace SourceGit.Commands
|
|||
_stashes.Add(_current);
|
||||
break;
|
||||
case 1:
|
||||
_current.Time = ulong.Parse(line);
|
||||
ParseParent(line);
|
||||
break;
|
||||
case 2:
|
||||
_current.Name = line;
|
||||
_current.Time = ulong.Parse(line);
|
||||
break;
|
||||
case 3:
|
||||
_current.Name = line;
|
||||
break;
|
||||
case 4:
|
||||
_current.Message = line;
|
||||
break;
|
||||
}
|
||||
|
||||
_nextLineIdx++;
|
||||
if (_nextLineIdx > 3)
|
||||
if (_nextLineIdx > 4)
|
||||
_nextLineIdx = 0;
|
||||
}
|
||||
|
||||
private void ParseParent(string data)
|
||||
{
|
||||
if (data.Length < 8)
|
||||
return;
|
||||
|
||||
_current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
private readonly List<Models.Stash> _stashes = new List<Models.Stash>();
|
||||
private Models.Stash _current = null;
|
||||
private int _nextLineIdx = 0;
|
||||
|
|
|
@ -24,11 +24,9 @@ namespace SourceGit.Commands
|
|||
{
|
||||
var submodules = new List<Models.Submodule>();
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return submodules;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], System.StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_FORMAT1().Match(line);
|
||||
|
@ -51,13 +49,13 @@ namespace SourceGit.Commands
|
|||
|
||||
if (submodules.Count > 0)
|
||||
{
|
||||
Args = $"status -uno --porcelain -- {builder}";
|
||||
Args = $"--no-optional-locks status -uno --porcelain -- {builder}";
|
||||
rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return submodules;
|
||||
|
||||
var dirty = new HashSet<string>();
|
||||
lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
|
||||
lines = rs.StdOut.Split(['\r', '\n'], System.StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_FORMAT_STATUS().Match(line);
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace SourceGit.Commands
|
|||
if (!rs.IsSuccess)
|
||||
return status;
|
||||
|
||||
var lines = rs.StdOut.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line[0] == '>')
|
||||
|
|
|
@ -37,6 +37,19 @@ namespace SourceGit.Commands
|
|||
return true;
|
||||
}
|
||||
|
||||
public static bool ProcessStashChanges(string repo, List<Models.DiffOption> opts, string saveTo)
|
||||
{
|
||||
using (var sw = File.Create(saveTo))
|
||||
{
|
||||
foreach (var opt in opts)
|
||||
{
|
||||
if (!ProcessSingleChange(repo, opt, sw))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
|
|
|
@ -11,16 +11,26 @@ namespace SourceGit.Commands
|
|||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Push(string message)
|
||||
public bool Push(string message, bool includeUntracked = true, bool keepIndex = false)
|
||||
{
|
||||
Args = $"stash push -m \"{message}\"";
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push ");
|
||||
if (includeUntracked)
|
||||
builder.Append("--include-untracked ");
|
||||
if (keepIndex)
|
||||
builder.Append("--keep-index ");
|
||||
builder.Append("-m \"");
|
||||
builder.Append(message);
|
||||
builder.Append("\"");
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Push(string message, List<Models.Change> changes, bool keepIndex)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push ");
|
||||
builder.Append("stash push --include-untracked ");
|
||||
if (keepIndex)
|
||||
builder.Append("--keep-index ");
|
||||
builder.Append("-m \"");
|
||||
|
@ -37,7 +47,7 @@ namespace SourceGit.Commands
|
|||
public bool Push(string message, string pathspecFromFile, bool keepIndex)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push --pathspec-from-file=\"");
|
||||
builder.Append("stash push --include-untracked --pathspec-from-file=\"");
|
||||
builder.Append(pathspecFromFile);
|
||||
builder.Append("\" ");
|
||||
if (keepIndex)
|
||||
|
@ -63,21 +73,22 @@ namespace SourceGit.Commands
|
|||
return Exec();
|
||||
}
|
||||
|
||||
public bool Apply(string name)
|
||||
public bool Apply(string name, bool restoreIndex)
|
||||
{
|
||||
Args = $"stash apply -q {name}";
|
||||
var opts = restoreIndex ? "--index" : string.Empty;
|
||||
Args = $"stash apply -q {opts} \"{name}\"";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Pop(string name)
|
||||
{
|
||||
Args = $"stash pop -q {name}";
|
||||
Args = $"stash pop -q --index \"{name}\"";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Drop(string name)
|
||||
{
|
||||
Args = $"stash drop -q {name}";
|
||||
Args = $"stash drop -q \"{name}\"";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace SourceGit.Commands
|
|||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"log --date-order --branches --remotes -{max} --pretty=format:\"%ct$%aN\"";
|
||||
Args = $"log --date-order --branches --remotes -{max} --format=%ct$%aN±%aE";
|
||||
}
|
||||
|
||||
public Models.Statistics Result()
|
||||
|
|
|
@ -48,9 +48,7 @@ namespace SourceGit.Commands
|
|||
if (remotes != null)
|
||||
{
|
||||
foreach (var r in remotes)
|
||||
{
|
||||
new Push(repo, r.Name, name, true).Exec();
|
||||
}
|
||||
new Push(repo, r.Name, $"refs/tags/{name}", true).Exec();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
|
@ -20,12 +21,13 @@ namespace SourceGit.Commands
|
|||
var last = null as Models.Worktree;
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.StartsWith("worktree ", StringComparison.Ordinal))
|
||||
{
|
||||
last = new Models.Worktree() { FullPath = line.Substring(9).Trim() };
|
||||
last.RelativePath = Path.GetRelativePath(WorkingDirectory, last.FullPath);
|
||||
worktrees.Add(last);
|
||||
}
|
||||
else if (line.StartsWith("bare", StringComparison.Ordinal))
|
||||
|
@ -73,6 +75,8 @@ namespace SourceGit.Commands
|
|||
|
||||
if (!string.IsNullOrEmpty(tracking))
|
||||
Args += tracking;
|
||||
else if (!string.IsNullOrEmpty(name) && !createNew)
|
||||
Args += name;
|
||||
|
||||
_outputHandler = outputHandler;
|
||||
return Exec();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue