enhance: use ArgumentList instead of manual escaping

This commit is contained in:
Aikawa Yataro 2024-09-14 06:10:42 +00:00
parent 7f87ce3431
commit 77fa7169df
No known key found for this signature in database
GPG key ID: 1C5D95FB10179404
77 changed files with 325 additions and 326 deletions

View file

@ -12,19 +12,14 @@ namespace SourceGit.Commands
if (changes == null || changes.Count == 0) if (changes == null || changes.Count == 0)
{ {
Args = "add ."; Args = ["add", "."];
} }
else else
{ {
var builder = new StringBuilder(); Args.AddRange(["add", "--"]);
builder.Append("add --");
foreach (var c in changes) foreach (var c in changes)
{ Args.Add(c.Path);
builder.Append(" \"");
builder.Append(c.Path);
builder.Append("\"");
}
Args = builder.ToString();
} }
} }
} }

View file

@ -1,19 +1,20 @@
namespace SourceGit.Commands using System.Collections.Generic;
namespace SourceGit.Commands
{ {
public class Apply : Command public class Apply : Command
{ {
public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceMode, string extra) public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceMode, IEnumerable<string> extra)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "apply "; Args = ["apply"];
if (ignoreWhitespace) if (ignoreWhitespace)
Args += "--ignore-whitespace "; Args.Add("--ignore-whitespace");
else else
Args += $"--whitespace={whitespaceMode} "; Args.Add($"--whitespace={whitespaceMode}");
if (!string.IsNullOrEmpty(extra)) Args.AddRange(extra);
Args += $"{extra} "; Args.Add(file);
Args += $"\"{file}\"";
} }
} }
} }

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"archive --format=zip --verbose --output=\"{saveTo}\" {revision}"; Args = ["archive", "--format=zip", "--verbose", "-o", saveTo, revision];
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
_outputHandler = outputHandler; _outputHandler = outputHandler;
} }

View file

@ -13,7 +13,7 @@ namespace SourceGit.Commands
public ViewCommand(string repo) public ViewCommand(string repo)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Args = "ls-files -v"; Args = ["ls-files", "-v"];
RaiseError = false; RaiseError = false;
} }
@ -46,7 +46,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"update-index {mode} -- \"{file}\""; Args = ["update-index", mode, "--", file];
} }
} }

View file

@ -13,7 +13,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"blame -t {revision} -- \"{file}\""; Args = ["blame", "-t", revision, "--", file];
RaiseError = false; RaiseError = false;
_result.File = file; _result.File = file;

View file

@ -7,7 +7,7 @@
var cmd = new Command(); var cmd = new Command();
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"branch {name} {basedOn}"; cmd.Args = ["branch", name, basedOn];
return cmd.Exec(); return cmd.Exec();
} }
@ -16,7 +16,7 @@
var cmd = new Command(); var cmd = new Command();
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"branch -M {name} {to}"; cmd.Args = ["branch", "-M", name, to];
return cmd.Exec(); return cmd.Exec();
} }
@ -27,9 +27,9 @@
cmd.Context = repo; cmd.Context = repo;
if (string.IsNullOrEmpty(upstream)) if (string.IsNullOrEmpty(upstream))
cmd.Args = $"branch {name} --unset-upstream"; cmd.Args = ["branch", name, "--unset-upstream"];
else else
cmd.Args = $"branch {name} -u {upstream}"; cmd.Args = ["branch", name, "-u", upstream];
return cmd.Exec(); return cmd.Exec();
} }
@ -39,7 +39,7 @@
var cmd = new Command(); var cmd = new Command();
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"branch -D {name}"; cmd.Args = ["branch", "-D", name];
return cmd.Exec(); return cmd.Exec();
} }
@ -49,7 +49,7 @@
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey"); cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
cmd.Args = $"push {remote} --delete {name}"; cmd.Args = ["push", remote, "--delete", name];
return cmd.Exec(); return cmd.Exec();
} }
} }

View file

@ -14,7 +14,7 @@ namespace SourceGit.Commands
public bool Branch(string branch, Action<string> onProgress) public bool Branch(string branch, Action<string> onProgress)
{ {
Args = $"checkout --progress {branch}"; Args = ["checkout", "--progress", branch];
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
_outputHandler = onProgress; _outputHandler = onProgress;
return Exec(); return Exec();
@ -22,7 +22,7 @@ namespace SourceGit.Commands
public bool Branch(string branch, string basedOn, Action<string> onProgress) public bool Branch(string branch, string basedOn, Action<string> onProgress)
{ {
Args = $"checkout --progress -b {branch} {basedOn}"; Args = ["checkout", "--progress", "-b", branch, basedOn];
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
_outputHandler = onProgress; _outputHandler = onProgress;
return Exec(); return Exec();
@ -30,41 +30,25 @@ namespace SourceGit.Commands
public bool UseTheirs(List<string> files) public bool UseTheirs(List<string> files)
{ {
StringBuilder builder = new StringBuilder(); Args = ["checkout", "--theirs", "--", ..files];
builder.Append("checkout --theirs --");
foreach (var f in files)
{
builder.Append(" \"");
builder.Append(f);
builder.Append("\"");
}
Args = builder.ToString();
return Exec(); return Exec();
} }
public bool UseMine(List<string> files) public bool UseMine(List<string> files)
{ {
StringBuilder builder = new StringBuilder(); Args = ["checkout", "--ours", "--", ..files];
builder.Append("checkout --ours --");
foreach (var f in files)
{
builder.Append(" \"");
builder.Append(f);
builder.Append("\"");
}
Args = builder.ToString();
return Exec(); return Exec();
} }
public bool FileWithRevision(string file, string revision) public bool FileWithRevision(string file, string revision)
{ {
Args = $"checkout --no-overlay {revision} -- \"{file}\""; Args = ["checkout", "--no-overlay", revision, "--", file];
return Exec(); return Exec();
} }
public bool Commit(string commitId, Action<string> onProgress) public bool Commit(string commitId, Action<string> onProgress)
{ {
Args = $"checkout --detach --progress {commitId}"; Args = ["checkout", "--detach", "--progress", commitId];
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
_outputHandler = onProgress; _outputHandler = onProgress;
return Exec(); return Exec();
@ -72,15 +56,7 @@ namespace SourceGit.Commands
public bool Files(List<string> files) public bool Files(List<string> files)
{ {
StringBuilder builder = new StringBuilder(); Args = ["checkout", "-f", "-q", "--", ..files];
builder.Append("checkout -f -q --");
foreach (var f in files)
{
builder.Append(" \"");
builder.Append(f);
builder.Append("\"");
}
Args = builder.ToString();
return Exec(); return Exec();
} }

View file

@ -7,7 +7,7 @@
var mode = noCommit ? "-n" : "--ff"; var mode = noCommit ? "-n" : "--ff";
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"cherry-pick {mode} {commits}"; Args = ["cherry-pick", mode, commits];
} }
} }
} }

View file

@ -9,23 +9,15 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "clean -qfd"; Args = ["clean", "-qfd"];
} }
public Clean(string repo, List<string> files) public Clean(string repo, List<string> files)
{ {
StringBuilder builder = new StringBuilder(); Args = ["clean", "-qfd", "--", ..files];
builder.Append("clean -qfd --");
foreach (var f in files)
{
builder.Append(" \"");
builder.Append(f);
builder.Append("\"");
}
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = builder.ToString();
} }
} }
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
namespace SourceGit.Commands namespace SourceGit.Commands
{ {
@ -6,21 +7,20 @@ namespace SourceGit.Commands
{ {
private readonly Action<string> _notifyProgress; private readonly Action<string> _notifyProgress;
public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action<string> ouputHandler) public Clone(string ctx, string path, string url, string localName, string sshKey, IEnumerable<string> extraArgs, Action<string> ouputHandler)
{ {
Context = ctx; Context = ctx;
WorkingDirectory = path; WorkingDirectory = path;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
SSHKey = sshKey; SSHKey = sshKey;
Args = "clone --progress --verbose --recurse-submodules "; Args = ["clone", "--progress", "--verbose", "--recurse-submodules"];
if (!string.IsNullOrEmpty(extraArgs)) Args.AddRange(extraArgs);
Args += $"{extraArgs} ";
Args += $"{url} "; Args.Add(url);
if (!string.IsNullOrEmpty(localName)) if (!string.IsNullOrEmpty(localName))
Args += localName; Args.Add(localName);
_notifyProgress = ouputHandler; _notifyProgress = ouputHandler;
} }

View file

@ -34,15 +34,15 @@ namespace SourceGit.Commands
public string WorkingDirectory { get; set; } = null; public string WorkingDirectory { get; set; } = null;
public EditorType Editor { get; set; } = EditorType.CoreEditor; // Only used in Exec() mode public EditorType Editor { get; set; } = EditorType.CoreEditor; // Only used in Exec() mode
public string SSHKey { get; set; } = string.Empty; public string SSHKey { get; set; } = string.Empty;
public string Args { get; set; } = string.Empty; public List<string> Args { get; set; } = [];
public bool RaiseError { get; set; } = true; public bool RaiseError { get; set; } = true;
public bool TraitErrorAsOutput { get; set; } = false; public bool TraitErrorAsOutput { get; set; } = false;
public bool Exec() public bool Exec()
{ {
var start = new ProcessStartInfo(); List<string> gitArgs = ["--no-pager", "-c", "core.quotepath=off"];
start.FileName = Native.OS.GitExecutable;
start.Arguments = "--no-pager -c core.quotepath=off "; var start = new ProcessStartInfo(Native.OS.GitExecutable);
start.UseShellExecute = false; start.UseShellExecute = false;
start.CreateNoWindow = true; start.CreateNoWindow = true;
start.RedirectStandardOutput = true; start.RedirectStandardOutput = true;
@ -61,7 +61,7 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(SSHKey)) if (!string.IsNullOrEmpty(SSHKey))
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'"); start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'");
else else
start.Arguments += "-c credential.helper=manager "; gitArgs.AddRange(["-c", "credential.helper=manager"]);
// Force using en_US.UTF-8 locale to avoid GCM crash // Force using en_US.UTF-8 locale to avoid GCM crash
if (OperatingSystem.IsLinux()) if (OperatingSystem.IsLinux())
@ -71,18 +71,28 @@ namespace SourceGit.Commands
switch (Editor) switch (Editor)
{ {
case EditorType.CoreEditor: case EditorType.CoreEditor:
start.Arguments += $"-c core.editor=\"\\\"{selfExecFile}\\\" --core-editor\" "; gitArgs.AddRange(["-c", $"core.editor=\"{selfExecFile}\" --core-editor"]);
break; break;
case EditorType.RebaseEditor: case EditorType.RebaseEditor:
start.Arguments += $"-c core.editor=\"\\\"{selfExecFile}\\\" --rebase-message-editor\" -c sequence.editor=\"\\\"{selfExecFile}\\\" --rebase-todo-editor\" -c rebase.abbreviateCommands=true "; gitArgs.AddRange([
"-c", $"core.editor=\"{selfExecFile}\" --rebase-message-editor",
"-c", $"sequence.editor=\"{selfExecFile}\" --rebase-todo-editor",
"-c", "rebase.abbreviateCommands=true"
]);
break; break;
default: default:
start.Arguments += "-c core.editor=true "; gitArgs.AddRange(["-c", "core.editor=true"]);
break; break;
} }
// Append command args // Append command args
start.Arguments += Args; gitArgs.AddRange(Args);
// Append git args
foreach (var arg in gitArgs)
{
start.ArgumentList.Add(arg);
}
// Working directory // Working directory
if (!string.IsNullOrEmpty(WorkingDirectory)) if (!string.IsNullOrEmpty(WorkingDirectory))
@ -181,9 +191,8 @@ namespace SourceGit.Commands
public ReadToEndResult ReadToEnd() public ReadToEndResult ReadToEnd()
{ {
var start = new ProcessStartInfo(); List<string> gitArgs = ["--no-pager", "-c", "core.quotepath=off", ..Args];
start.FileName = Native.OS.GitExecutable; var start = new ProcessStartInfo(Native.OS.GitExecutable, gitArgs);
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
start.UseShellExecute = false; start.UseShellExecute = false;
start.CreateNoWindow = true; start.CreateNoWindow = true;
start.RedirectStandardOutput = true; start.RedirectStandardOutput = true;

View file

@ -12,11 +12,11 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
Args = $"commit --file=\"{file}\""; Args = ["commit", $"--file={file}"];
if (amend) if (amend)
Args += " --amend --no-edit"; Args.AddRange(["--amend", "--no-edit"]);
if (allowEmpty) if (allowEmpty)
Args += " --allow-empty"; Args.Add("--allow-empty");
} }
} }
} }

View file

@ -15,7 +15,7 @@ namespace SourceGit.Commands
Context = repo; Context = repo;
var based = string.IsNullOrEmpty(start) ? "-R" : start; var based = string.IsNullOrEmpty(start) ? "-R" : start;
Args = $"diff --name-status {based} {end}"; Args = ["diff", "--name-status", based, end];
} }
public List<Models.Change> Result() public List<Models.Change> Result()

View file

@ -15,9 +15,9 @@ namespace SourceGit.Commands
public Dictionary<string, string> ListAll() public Dictionary<string, string> ListAll()
{ {
if (string.IsNullOrEmpty(WorkingDirectory)) if (string.IsNullOrEmpty(WorkingDirectory))
Args = "config --global -l"; Args = ["config", "--global", "-l"];
else else
Args = "config -l"; Args = ["config", "-l"];
var output = ReadToEnd(); var output = ReadToEnd();
var rs = new Dictionary<string, string>(); var rs = new Dictionary<string, string>();
@ -41,7 +41,7 @@ namespace SourceGit.Commands
public string Get(string key) public string Get(string key)
{ {
Args = $"config {key}"; Args = ["config", key];
return ReadToEnd().StdOut.Trim(); return ReadToEnd().StdOut.Trim();
} }
@ -50,16 +50,16 @@ namespace SourceGit.Commands
if (!allowEmpty && string.IsNullOrWhiteSpace(value)) if (!allowEmpty && string.IsNullOrWhiteSpace(value))
{ {
if (string.IsNullOrEmpty(WorkingDirectory)) if (string.IsNullOrEmpty(WorkingDirectory))
Args = $"config --global --unset {key}"; Args = ["config", "--global", "--unset", key];
else else
Args = $"config --unset {key}"; Args = ["config", "--unset", key];
} }
else else
{ {
if (string.IsNullOrWhiteSpace(WorkingDirectory)) if (string.IsNullOrWhiteSpace(WorkingDirectory))
Args = $"config --global {key} \"{value}\""; Args = ["config", "--global", key, value];
else else
Args = $"config {key} \"{value}\""; Args = ["config", key, value];
} }
return Exec(); return Exec();

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "status -uno --ignore-submodules=dirty --porcelain"; Args = ["status", "-uno", "--ignore-submodules=dirty", "--porcelain"];
} }
public int Result() public int Result()

View file

@ -22,7 +22,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"diff --ignore-cr-at-eol --unified={unified} {opt}"; Args = ["diff", "--ignore-cr-at-eol", $"--unified={unified}", ..opt.ToArgs()];
} }
public Models.DiffResult Result() public Models.DiffResult Result()

View file

@ -33,7 +33,7 @@ namespace SourceGit.Commands
for (int i = 0; i < needCheckout.Count; i += 10) for (int i = 0; i < needCheckout.Count; i += 10)
{ {
var count = Math.Min(10, needCheckout.Count - i); var count = Math.Min(10, needCheckout.Count - i);
new Restore(repo, needCheckout.GetRange(i, count), "--worktree --recurse-submodules").Exec(); new Restore(repo, needCheckout.GetRange(i, count), ["--worktree", "--recurse-submodules"]).Exec();
} }
} }
} }

View file

@ -11,17 +11,17 @@ namespace SourceGit.Commands
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey"); SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "fetch --progress --verbose "; Args = ["fetch", "--progress", "--verbose"];
if (prune) if (prune)
Args += "--prune "; Args.Add("--prune");
if (noTags) if (noTags)
Args += "--no-tags "; Args.Add("--no-tags");
else else
Args += "--force "; Args.Add("--force");
Args += remote; Args.Add(remote);
Models.AutoFetchManager.Instance.MarkFetched(repo); Models.AutoFetchManager.Instance.MarkFetched(repo);
} }
@ -33,7 +33,7 @@ namespace SourceGit.Commands
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey"); SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = $"fetch --progress --verbose {remote} {remoteBranch}:{localBranch}"; Args = ["fetch", "--progress", "--verbose", remote, $"{remoteBranch}:{localBranch}"];
} }
protected override void OnReadline(string line) protected override void OnReadline(string line)

View file

@ -6,7 +6,7 @@
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"format-patch {commit} -1 -o \"{saveTo}\""; Args = ["format-patch", commit, "-1", "-o", saveTo];
} }
} }
} }

View file

@ -10,7 +10,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
Args = "gc --prune"; Args = ["gc", "--prune"];
} }
protected override void OnReadline(string line) protected override void OnReadline(string line)

View file

@ -16,7 +16,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"diff --diff-algorithm=minimal {opt}"; Args = ["diff", "--diff-algorithm=minimal", ..opt.ToArgs()];
} }
} }

View file

@ -60,7 +60,7 @@ namespace SourceGit.Commands
var init = new Command(); var init = new Command();
init.WorkingDirectory = repo; init.WorkingDirectory = repo;
init.Context = repo; init.Context = repo;
init.Args = "flow init -d"; init.Args = ["flow", "init", "-d"];
return init.Exec(); return init.Exec();
} }
@ -128,7 +128,7 @@ namespace SourceGit.Commands
var start = new Command(); var start = new Command();
start.WorkingDirectory = repo; start.WorkingDirectory = repo;
start.Context = repo; start.Context = repo;
start.Args = $"flow {type} start {name}"; start.Args = ["flow", type, "start", name];
return start.Exec(); return start.Exec();
} }
@ -148,7 +148,7 @@ namespace SourceGit.Commands
var finish = new Command(); var finish = new Command();
finish.WorkingDirectory = repo; finish.WorkingDirectory = repo;
finish.Context = repo; finish.Context = repo;
finish.Args = $"flow {type} finish {option} {name}"; finish.Args = ["flow", type, "finish", option, name];
return finish.Exec(); return finish.Exec();
} }

View file

@ -6,7 +6,7 @@
{ {
Context = ctx; Context = ctx;
WorkingDirectory = dir; WorkingDirectory = dir;
Args = "init -q"; Args = ["init", "-q"];
} }
} }
} }

View file

@ -11,7 +11,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {commit} --numstat -- \"{path}\""; Args = ["diff", "4b825dc642cb6eb9a060e54bf8d69288fbee4904", commit, "--numstat", "--", path];
RaiseError = false; RaiseError = false;
} }

View file

@ -8,7 +8,7 @@
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"diff -a --ignore-cr-at-eol --check {opt}"; Args = ["diff", "-a", "--ignore-cr-at-eol", "--check", ..opt.ToArgs()];
} }
} }
} }

View file

@ -6,7 +6,7 @@
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"check-attr -z filter \"{path}\""; Args = ["check-attr", "-z", "filter", path];
RaiseError = false; RaiseError = false;
} }
@ -14,7 +14,7 @@
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"check-attr --source {sha} -z filter \"{path}\""; Args = ["check-attr", "--source", sha, "-z", "filter", path];
RaiseError = false; RaiseError = false;
} }

View file

@ -12,11 +12,11 @@ namespace SourceGit.Commands
class SubCmd : Command class SubCmd : Command
{ {
public SubCmd(string repo, string args, Action<string> onProgress) public SubCmd(string repo, IEnumerable<string> args, Action<string> onProgress)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = args; Args = new List<string>(args);
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
_outputHandler = onProgress; _outputHandler = onProgress;
} }
@ -46,39 +46,43 @@ namespace SourceGit.Commands
public bool Install() public bool Install()
{ {
return new SubCmd(_repo, "lfs install --local", null).Exec(); return new SubCmd(_repo, ["lfs", "install", "--local"], null).Exec();
} }
public bool Track(string pattern, bool isFilenameMode = false) public bool Track(string pattern, bool isFilenameMode = false)
{ {
var opt = isFilenameMode ? "--filename" : ""; var opt = isFilenameMode ? "--filename" : "";
return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", null).Exec(); List<string> args = ["lfs", "track"];
if (isFilenameMode)
args.Add("--filename");
args.Add(pattern);
return new SubCmd(_repo, args, null).Exec();
} }
public void Fetch(string remote, Action<string> outputHandler) public void Fetch(string remote, Action<string> outputHandler)
{ {
new SubCmd(_repo, $"lfs fetch {remote}", outputHandler).Exec(); new SubCmd(_repo, ["lfs", "fetch", remote], outputHandler).Exec();
} }
public void Pull(string remote, Action<string> outputHandler) public void Pull(string remote, Action<string> outputHandler)
{ {
new SubCmd(_repo, $"lfs pull {remote}", outputHandler).Exec(); new SubCmd(_repo, ["lfs", "pull", remote], outputHandler).Exec();
} }
public void Push(string remote, Action<string> outputHandler) public void Push(string remote, Action<string> outputHandler)
{ {
new SubCmd(_repo, $"lfs push {remote}", outputHandler).Exec(); new SubCmd(_repo, ["lfs", "push", remote], outputHandler).Exec();
} }
public void Prune(Action<string> outputHandler) public void Prune(Action<string> outputHandler)
{ {
new SubCmd(_repo, "lfs prune", outputHandler).Exec(); new SubCmd(_repo, ["lfs", "prune"], outputHandler).Exec();
} }
public List<Models.LFSLock> Locks(string remote) public List<Models.LFSLock> Locks(string remote)
{ {
var locks = new List<Models.LFSLock>(); var locks = new List<Models.LFSLock>();
var cmd = new SubCmd(_repo, $"lfs locks --remote={remote}", null); var cmd = new SubCmd(_repo, ["lfs", "locks", $"--remote={remote}"], null);
var rs = cmd.ReadToEnd(); var rs = cmd.ReadToEnd();
if (rs.IsSuccess) if (rs.IsSuccess)
{ {
@ -103,19 +107,25 @@ namespace SourceGit.Commands
public bool Lock(string remote, string file) public bool Lock(string remote, string file)
{ {
return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", null).Exec(); return new SubCmd(_repo, ["lfs", "lock", $"--remote={remote}", file], null).Exec();
} }
public bool Unlock(string remote, string file, bool force) public bool Unlock(string remote, string file, bool force)
{ {
var opt = force ? "-f" : ""; List<string> args = ["lfs", "unlock", $"--remote={remote}"];
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", null).Exec(); if (force)
args.Add("-f");
args.Add(file);
return new SubCmd(_repo, args, null).Exec();
} }
public bool Unlock(string remote, long id, bool force) public bool Unlock(string remote, long id, bool force)
{ {
var opt = force ? "-f" : ""; List<string> args = ["lfs", "unlock", $"--remote={remote}"];
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", null).Exec(); if (force)
args.Add("-f");
args.Add($"--id={id}");
return new SubCmd(_repo, args, null).Exec();
} }
private readonly string _repo; private readonly string _repo;

View file

@ -10,7 +10,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
Args = $"merge --progress {source} {mode}"; Args = ["merge", "--progress", source, mode];
} }
protected override void OnReadline(string line) protected override void OnReadline(string line)

View file

@ -15,7 +15,7 @@ namespace SourceGit.Commands
if (toolType == 0) if (toolType == 0)
{ {
cmd.Args = $"mergetool \"{file}\""; cmd.Args = ["mergetool", file];
return cmd.Exec(); return cmd.Exec();
} }
@ -32,7 +32,13 @@ namespace SourceGit.Commands
return false; 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", file
];
return cmd.Exec(); return cmd.Exec();
} }
@ -45,7 +51,7 @@ namespace SourceGit.Commands
if (toolType == 0) if (toolType == 0)
{ {
cmd.Args = $"difftool -g --no-prompt {option}"; cmd.Args = ["difftool", "-g", "--no-prompt", ..option.ToArgs()];
return cmd.Exec(); return cmd.Exec();
} }
@ -62,7 +68,11 @@ namespace SourceGit.Commands
return false; return false;
} }
cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.DiffCmd}\" difftool --tool=sourcegit --no-prompt {option}"; cmd.Args = [
"-c", $"difftool.sourcegit.cmd=\"{toolPath}\" {supported.DiffCmd}",
"difftool", "--tool=sourcegit", "--no-prompt"
];
cmd.Args.AddRange(option.ToArgs());
return cmd.Exec(); return cmd.Exec();
} }
} }

View file

@ -11,14 +11,14 @@ namespace SourceGit.Commands
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey"); SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "pull --verbose --progress --tags "; Args = ["pull", "--verbose", "--progress", "--tags"];
if (useRebase) if (useRebase)
Args += "--rebase "; Args.Add("--rebase");
if (noTags) if (noTags)
Args += "--no-tags "; Args.Add("--no-tags");
Args += $"{remote} {branch}"; Args.AddRange([remote, branch]);
} }
protected override void OnReadline(string line) protected override void OnReadline(string line)

View file

@ -12,18 +12,18 @@ namespace SourceGit.Commands
Context = repo; Context = repo;
TraitErrorAsOutput = true; TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey"); SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "push --progress --verbose "; Args = ["push", "--progress", "--verbose"];
if (withTags) if (withTags)
Args += "--tags "; Args.Add("--tags");
if (checkSubmodules) if (checkSubmodules)
Args += "--recurse-submodules=check "; Args.Add("--recurse-submodules=check");
if (track) if (track)
Args += "-u "; Args.Add("-u");
if (force) if (force)
Args += "--force-with-lease "; Args.Add("--force-with-lease");
Args += $"{remote} {local}:{remoteBranch}"; Args.AddRange([remote, $"{local}:{remoteBranch}"]);
} }
public Push(string repo, string remote, string tag, bool isDelete) public Push(string repo, string remote, string tag, bool isDelete)
@ -31,12 +31,12 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey"); SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "push "; Args = ["push"];
if (isDelete) if (isDelete)
Args += "--delete "; Args.Add("--delete");
Args += $"{remote} refs/tags/{tag}"; Args.AddRange([remote, $"refs/tags/{tag}"]);
} }
protected override void OnReadline(string line) protected override void OnReadline(string line)

View file

@ -14,7 +14,10 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "branch -l --all -v --format=\"%(refname)$%(objectname)$%(HEAD)$%(upstream)$%(upstream:trackshort)\""; Args = [
"branch", "-l", "--all", "-v",
"--format=%(refname)$%(objectname)$%(HEAD)$%(upstream)$%(upstream:trackshort)"
];
} }
public List<Models.Branch> Result() public List<Models.Branch> Result()

View file

@ -6,7 +6,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"show --no-show-signature --pretty=format:%B -s {sha}"; Args = ["show", "--no-show-signature", "--pretty=format:%B", "-s", sha];
} }
public string Result() public string Result()

View file

@ -1,47 +1,51 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands namespace SourceGit.Commands
{ {
public class QueryCommits : Command public class QueryCommits : Command
{ {
public QueryCommits(string repo, string limits, bool needFindHead = true) public QueryCommits(string repo, IEnumerable<string> limits, bool needFindHead = true)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = 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%s " + 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; _findFirstMerged = needFindHead;
} }
public QueryCommits(string repo, string filter, Models.CommitSearchMethod method) public QueryCommits(string repo, string filter, Models.CommitSearchMethod method)
{ {
string search; var search = new List<string>();
if (method == Models.CommitSearchMethod.ByUser) if (method == Models.CommitSearchMethod.ByUser)
{ {
search = $"-i --author=\"{filter}\" --committer=\"{filter}\""; search = ["-i", $"--author={filter}", $"--commiter={filter}"];
} }
else if (method == Models.CommitSearchMethod.ByFile) else if (method == Models.CommitSearchMethod.ByFile)
{ {
search = $"-- \"{filter}\""; search = ["--", filter];
} }
else else
{ {
var argsBuilder = new StringBuilder();
var words = filter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries); var words = filter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var word in words) foreach (var word in words)
{ {
var escaped = word.Trim().Replace("\"", "\\\"", StringComparison.Ordinal); search.Add($"--grep={word.Trim()}");
argsBuilder.Append($"--grep=\"{escaped}\" ");
} }
argsBuilder.Append("--all-match -i"); search.AddRange(["--all-match", "-i"]);
search = argsBuilder.ToString();
} }
WorkingDirectory = repo; WorkingDirectory = repo;
Context = 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 --branches --remotes " + search; 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",
"--branches", "--remotes", ..search
];
_findFirstMerged = false; _findFirstMerged = false;
} }
@ -122,7 +126,7 @@ namespace SourceGit.Commands
private void MarkFirstMerged() private void MarkFirstMerged()
{ {
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\""; Args = ["log", $"--since={_commits[^1].CommitterTimeStr}", "--format=%H"];
var rs = ReadToEnd(); var rs = ReadToEnd();
var shas = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries); var shas = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);

View file

@ -5,13 +5,17 @@ namespace SourceGit.Commands
{ {
public class QueryCommitsWithFullMessage : Command public class QueryCommitsWithFullMessage : Command
{ {
public QueryCommitsWithFullMessage(string repo, string args) public QueryCommitsWithFullMessage(string repo, IEnumerable<string> args)
{ {
_boundary = $"----- BOUNDARY OF COMMIT {Guid.NewGuid()} -----"; _boundary = $"----- BOUNDARY OF COMMIT {Guid.NewGuid()} -----";
WorkingDirectory = repo; WorkingDirectory = repo;
Context = 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",
$"--pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}",
..args
];
} }
public List<Models.CommitWithMessage> Result() public List<Models.CommitWithMessage> Result()

View file

@ -6,7 +6,7 @@
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "ls-tree -r --name-only HEAD"; Args = ["ls-tree", "-r", "--name-only", "HEAD"];
} }
public string[] Result() public string[] Result()

View file

@ -8,10 +8,8 @@ namespace SourceGit.Commands
{ {
public static Stream Run(string repo, string revision, string file) public static Stream Run(string repo, string revision, string file)
{ {
var starter = new ProcessStartInfo(); var starter = new ProcessStartInfo(Native.OS.GitExecutable, ["show", $"{revision}:{file}"]);
starter.WorkingDirectory = repo; starter.WorkingDirectory = repo;
starter.FileName = Native.OS.GitExecutable;
starter.Arguments = $"show {revision}:\"{file}\"";
starter.UseShellExecute = false; starter.UseShellExecute = false;
starter.CreateNoWindow = true; starter.CreateNoWindow = true;
starter.WindowStyle = ProcessWindowStyle.Hidden; starter.WindowStyle = ProcessWindowStyle.Hidden;

View file

@ -11,7 +11,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"ls-tree {revision} -l -- {file}"; Args = ["ls-tree", revision, "-l", "--", file];
} }
public long Result() public long Result()

View file

@ -7,7 +7,7 @@ namespace SourceGit.Commands
public QueryGitDir(string workDir) public QueryGitDir(string workDir)
{ {
WorkingDirectory = workDir; WorkingDirectory = workDir;
Args = "rev-parse --git-dir"; Args = ["rev-parse", "--git-dir"];
RaiseError = false; RaiseError = false;
} }

View file

@ -14,7 +14,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain"; Args = ["status", $"-u{UNTRACKED[includeUntracked ? 1 : 0]}", "--ignore-submodules=dirty", "--porcelain"];
} }
public List<Models.Change> Result() public List<Models.Change> Result()

View file

@ -9,7 +9,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
RaiseError = false; RaiseError = false;
Args = $"for-each-ref --format=\"%(refname)\" --contains {commit}"; Args = ["for-each-ref", "--format=%(refname)", "--contains", commit];
} }
public List<Models.Decorator> Result() public List<Models.Decorator> Result()

View file

@ -12,7 +12,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "remote -v"; Args = ["remote", "-v"];
} }
public List<Models.Remote> Result() public List<Models.Remote> Result()

View file

@ -5,7 +5,7 @@
public QueryRepositoryRootPath(string path) public QueryRepositoryRootPath(string path)
{ {
WorkingDirectory = path; WorkingDirectory = path;
Args = "rev-parse --show-toplevel"; Args = ["rev-parse", "--show-toplevel"];
} }
} }
} }

View file

@ -12,10 +12,10 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"ls-tree {sha}"; Args = ["ls-tree", sha];
if (!string.IsNullOrEmpty(parentFolder)) if (!string.IsNullOrEmpty(parentFolder))
Args += $" -- \"{parentFolder}\""; Args.AddRange(["--", parentFolder]);
} }
public List<Models.Object> Result() public List<Models.Object> Result()

View file

@ -8,7 +8,11 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = 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",
"--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() public Models.Commit Result()

View file

@ -15,7 +15,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "diff-index --cached -M HEAD^"; Args = ["diff-index", "--cached", "-M", "HEAD^"];
} }
public List<Models.Change> Result() public List<Models.Change> Result()

View file

@ -11,7 +11,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"ls-files -s -- \"{file}\""; Args = ["ls-files", "-s", "--", file];
} }
public string Result() public string Result()

View file

@ -12,7 +12,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"diff --name-status --pretty=format: {sha}^ {sha}"; Args = ["diff", "--name-status", "--pretty=format:", $"{sha}^", sha];
} }
public List<Models.Change> Result() public List<Models.Change> Result()

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "stash list --pretty=format:%H%n%ct%n%gd%n%s"; Args = ["stash", "list", "--pretty=format:%H%n%ct%n%gd%n%s"];
} }
public List<Models.Stash> Result() public List<Models.Stash> Result()

View file

@ -17,7 +17,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "submodule status"; Args = ["submodule", "status"];
} }
public List<Models.Submodule> Result() public List<Models.Submodule> Result()
@ -27,7 +27,7 @@ namespace SourceGit.Commands
if (!rs.IsSuccess) if (!rs.IsSuccess)
return submodules; return submodules;
var builder = new StringBuilder(); var extra = new List<string>();
var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries); var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines) foreach (var line in lines)
{ {
@ -35,7 +35,7 @@ namespace SourceGit.Commands
if (match.Success) if (match.Success)
{ {
var path = match.Groups[1].Value; var path = match.Groups[1].Value;
builder.Append($"\"{path}\" "); extra.Add(path);
submodules.Add(new Models.Submodule() { Path = path }); submodules.Add(new Models.Submodule() { Path = path });
continue; continue;
} }
@ -44,14 +44,14 @@ namespace SourceGit.Commands
if (match.Success) if (match.Success)
{ {
var path = match.Groups[1].Value; var path = match.Groups[1].Value;
builder.Append($"\"{path}\" "); extra.Add(path);
submodules.Add(new Models.Submodule() { Path = path }); submodules.Add(new Models.Submodule() { Path = path });
} }
} }
if (submodules.Count > 0) if (submodules.Count > 0)
{ {
Args = $"status -uno --porcelain -- {builder}"; Args = ["status", "-uno", "--porcelain", "--", ..extra];
rs = ReadToEnd(); rs = ReadToEnd();
if (!rs.IsSuccess) if (!rs.IsSuccess)
return submodules; return submodules;

View file

@ -9,7 +9,7 @@ namespace SourceGit.Commands
{ {
Context = repo; Context = repo;
WorkingDirectory = repo; WorkingDirectory = repo;
Args = "tag -l --sort=-creatordate --format=\"$%(refname)$%(objectname)$%(*objectname)\""; Args = ["tag", "-l", "--sort=-creatordate", "--format=$%(refname)$%(objectname)$%(*objectname)"];
} }
public List<Models.Tag> Result() public List<Models.Tag> Result()

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"rev-list --left-right {local}...{upstream}"; Args = ["rev-list", "--left-right", $"{local}...{upstream}"];
} }
public Models.BranchTrackStatus Result() public Models.BranchTrackStatus Result()

View file

@ -6,10 +6,10 @@
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "rebase "; Args = ["rebase"];
if (autoStash) if (autoStash)
Args += "--autostash "; Args.Add("--autostash");
Args += basedOn; Args.Add(basedOn);
} }
} }
@ -20,7 +20,7 @@
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Editor = EditorType.RebaseEditor; Editor = EditorType.RebaseEditor;
Args = $"rebase -i --autosquash {basedOn}"; Args = ["rebase", "-i", "--autosquash", basedOn];
} }
} }
} }

View file

@ -10,31 +10,31 @@
public bool Add(string name, string url) public bool Add(string name, string url)
{ {
Args = $"remote add {name} {url}"; Args = ["remote", "add", name, url];
return Exec(); return Exec();
} }
public bool Delete(string name) public bool Delete(string name)
{ {
Args = $"remote remove {name}"; Args = ["remote", "remove", name];
return Exec(); return Exec();
} }
public bool Rename(string name, string to) public bool Rename(string name, string to)
{ {
Args = $"remote rename {name} {to}"; Args = ["remote", "rename", name, to];
return Exec(); return Exec();
} }
public bool Prune(string name) public bool Prune(string name)
{ {
Args = $"remote prune {name}"; Args = ["remote", "prune", name];
return Exec(); return Exec();
} }
public bool SetURL(string name, string url) public bool SetURL(string name, string url)
{ {
Args = $"remote set-url {name} {url}"; Args = ["remote", "set-url", name, url];
return Exec(); return Exec();
} }
} }

View file

@ -9,7 +9,7 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "reset"; Args = ["reset"];
} }
public Reset(string repo, List<Models.Change> changes) public Reset(string repo, List<Models.Change> changes)
@ -17,22 +17,18 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
var builder = new StringBuilder(); Args = ["reset", "--"];
builder.Append("reset --");
foreach (var c in changes) foreach (var c in changes)
{ {
builder.Append(" \""); Args.Add(c.Path);
builder.Append(c.Path);
builder.Append("\"");
} }
Args = builder.ToString();
} }
public Reset(string repo, string revision, string mode) public Reset(string repo, string revision, string mode)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"reset {mode} {revision}"; Args = ["reset", mode, revision];
} }
} }
} }

View file

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands namespace SourceGit.Commands
{ {
@ -9,22 +8,15 @@ namespace SourceGit.Commands
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "restore . --source=HEAD --staged --worktree --recurse-submodules"; Args = ["restore", ".", "--source=HEAD", "--staged", "--worktree", "--recurse-submodules"];
} }
public Restore(string repo, List<string> files, string extra) public Restore(string repo, IEnumerable<string> files, IEnumerable<string> extra)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
StringBuilder builder = new StringBuilder(); Args = ["restore", ..extra, "--", ..files];
builder.Append("restore ");
if (!string.IsNullOrEmpty(extra))
builder.Append(extra).Append(" ");
builder.Append("--");
foreach (var f in files)
builder.Append(' ').Append('"').Append(f).Append('"');
Args = builder.ToString();
} }
} }
} }

View file

@ -6,9 +6,9 @@
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"revert -m 1 {commit} --no-edit"; Args = ["revert", "-m", "1", commit, "--no-edit"];
if (!autoCommit) if (!autoCommit)
Args += " --no-commit"; Args.Add("--no-commit");
} }
} }
} }

View file

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using Avalonia.Threading; using Avalonia.Threading;
namespace SourceGit.Commands namespace SourceGit.Commands
@ -25,10 +24,11 @@ namespace SourceGit.Commands
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer) private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer)
{ {
var starter = new ProcessStartInfo(); var starter = new ProcessStartInfo(
Native.OS.GitExecutable,
["diff", "--ignore-cr-at-eol", "--unified=4", ..opt.ToArgs()]
);
starter.WorkingDirectory = repo; starter.WorkingDirectory = repo;
starter.FileName = Native.OS.GitExecutable;
starter.Arguments = $"diff --ignore-cr-at-eol --unified=4 {opt}";
starter.UseShellExecute = false; starter.UseShellExecute = false;
starter.CreateNoWindow = true; starter.CreateNoWindow = true;
starter.WindowStyle = ProcessWindowStyle.Hidden; starter.WindowStyle = ProcessWindowStyle.Hidden;

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -14,24 +15,22 @@ namespace SourceGit.Commands
if (isLFSFiltered) if (isLFSFiltered)
{ {
var tmpFile = saveTo + ".tmp"; var tmpFile = saveTo + ".tmp";
if (ExecCmd(repo, $"show {revision}:\"{file}\"", tmpFile)) if (ExecCmd(repo, ["show", $"{revision}:{file}"], tmpFile))
{ {
ExecCmd(repo, $"lfs smudge", saveTo, tmpFile); ExecCmd(repo, ["lfs", "smudge"], saveTo, tmpFile);
} }
File.Delete(tmpFile); File.Delete(tmpFile);
} }
else else
{ {
ExecCmd(repo, $"show {revision}:\"{file}\"", saveTo); ExecCmd(repo, ["show", $"{revision}:{file}"], saveTo);
} }
} }
private static bool ExecCmd(string repo, string args, string outputFile, string inputFile = null) private static bool ExecCmd(string repo, IEnumerable<string> args, string outputFile, string inputFile = null)
{ {
var starter = new ProcessStartInfo(); var starter = new ProcessStartInfo(Native.OS.GitExecutable, args);
starter.WorkingDirectory = repo; starter.WorkingDirectory = repo;
starter.FileName = Native.OS.GitExecutable;
starter.Arguments = args;
starter.UseShellExecute = false; starter.UseShellExecute = false;
starter.CreateNoWindow = true; starter.CreateNoWindow = true;
starter.WindowStyle = ProcessWindowStyle.Hidden; starter.WindowStyle = ProcessWindowStyle.Hidden;

View file

@ -13,17 +13,17 @@ namespace SourceGit.Commands
public bool Push(string message) public bool Push(string message)
{ {
Args = $"stash push -m \"{message}\""; Args = ["stash", "push", "-m", message];
return Exec(); return Exec();
} }
public bool Push(List<Models.Change> changes, string message) public bool Push(List<Models.Change> changes, string message)
{ {
var pathsBuilder = new StringBuilder(); Args = ["stash", "push", "-m", message, "--"];
var needAdd = new List<Models.Change>(); var needAdd = new List<Models.Change>();
foreach (var c in changes) foreach (var c in changes)
{ {
pathsBuilder.Append($"\"{c.Path}\" "); Args.Add(c.Path);
if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked) if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked)
{ {
@ -41,32 +41,30 @@ namespace SourceGit.Commands
needAdd.Clear(); needAdd.Clear();
} }
var paths = pathsBuilder.ToString();
Args = $"stash push -m \"{message}\" -- {paths}";
return Exec(); return Exec();
} }
public bool Apply(string name) public bool Apply(string name)
{ {
Args = $"stash apply -q {name}"; Args = ["stash", "apply", "-q", name];
return Exec(); return Exec();
} }
public bool Pop(string name) public bool Pop(string name)
{ {
Args = $"stash pop -q {name}"; Args = ["stash", "pop", "-q", name];
return Exec(); return Exec();
} }
public bool Drop(string name) public bool Drop(string name)
{ {
Args = $"stash drop -q {name}"; Args = ["stash", "drop", "-q", name];
return Exec(); return Exec();
} }
public bool Clear() public bool Clear()
{ {
Args = "stash clear"; Args = ["stash", "clear"];
return Exec(); return Exec();
} }
} }

View file

@ -10,7 +10,10 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"log --date-order --branches --remotes --since=\"{_statistics.Since()}\" --pretty=format:\"%ct$%an\""; Args = [
"log", "--date-order", "--branches", "--remotes",
$"--since={_statistics.Since()}", "--pretty=format:%ct$%an"
];
} }
public Models.Statistics Result() public Models.Statistics Result()

View file

@ -13,34 +13,34 @@ namespace SourceGit.Commands
public bool Add(string url, string relativePath, bool recursive, Action<string> outputHandler) public bool Add(string url, string relativePath, bool recursive, Action<string> outputHandler)
{ {
_outputHandler = outputHandler; _outputHandler = outputHandler;
Args = $"submodule add {url} \"{relativePath}\""; Args = ["submodule", "add", url, relativePath];
if (!Exec()) if (!Exec())
return false; return false;
if (recursive) if (recursive)
{ {
Args = $"submodule update --init --recursive -- \"{relativePath}\""; Args = ["submodule", "update", "--init", "--recursive", "--", relativePath];
return Exec(); return Exec();
} }
else else
{ {
Args = $"submodule update --init -- \"{relativePath}\""; Args = ["submodule", "update", "--init", "--", relativePath];
return true; return true;
} }
} }
public bool Update(string module, bool init, bool recursive, bool useRemote, Action<string> outputHandler) public bool Update(string module, bool init, bool recursive, bool useRemote, Action<string> outputHandler)
{ {
Args = "submodule update"; Args = ["submodule", "update"];
if (init) if (init)
Args += " --init"; Args.Add("--init");
if (recursive) if (recursive)
Args += " --recursive"; Args.Add("--recursive");
if (useRemote) if (useRemote)
Args += " --remote"; Args.Add("--remote");
if (!string.IsNullOrEmpty(module)) if (!string.IsNullOrEmpty(module))
Args += $" -- \"{module}\""; Args.AddRange(["--", module]);
_outputHandler = outputHandler; _outputHandler = outputHandler;
return Exec(); return Exec();
@ -48,11 +48,11 @@ namespace SourceGit.Commands
public bool Delete(string relativePath) public bool Delete(string relativePath)
{ {
Args = $"submodule deinit -f \"{relativePath}\""; Args = ["submodule", "deinit", "-f", relativePath];
if (!Exec()) if (!Exec())
return false; return false;
Args = $"rm -rf \"{relativePath}\""; Args = ["rm", "-rf", relativePath];
return Exec(); return Exec();
} }

View file

@ -10,27 +10,27 @@ namespace SourceGit.Commands
var cmd = new Command(); var cmd = new Command();
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"tag {name} {basedOn}"; cmd.Args = ["tag", name, basedOn];
return cmd.Exec(); return cmd.Exec();
} }
public static bool Add(string repo, string name, string basedOn, string message, bool sign) public static bool Add(string repo, string name, string basedOn, string message, bool sign)
{ {
var param = sign ? "-s -a" : "-a"; IEnumerable<string> param = sign ? ["-s", "-a"] : ["-a"];
var cmd = new Command(); var cmd = new Command();
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"tag {param} {name} {basedOn} "; cmd.Args = ["tag", ..param, name, basedOn];
if (!string.IsNullOrEmpty(message)) if (!string.IsNullOrEmpty(message))
{ {
string tmp = Path.GetTempFileName(); string tmp = Path.GetTempFileName();
File.WriteAllText(tmp, message); File.WriteAllText(tmp, message);
cmd.Args += $"-F \"{tmp}\""; cmd.Args.AddRange(["-F", tmp]);
} }
else else
{ {
cmd.Args += $"-m {name}"; cmd.Args.AddRange(["-m", name]);
} }
return cmd.Exec(); return cmd.Exec();
@ -41,7 +41,7 @@ namespace SourceGit.Commands
var cmd = new Command(); var cmd = new Command();
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"tag --delete {name}"; cmd.Args = ["tag", "--delete", name];
if (!cmd.Exec()) if (!cmd.Exec())
return false; return false;

View file

@ -53,10 +53,11 @@ namespace SourceGit.Commands
public bool Exec() public bool Exec()
{ {
var starter = new ProcessStartInfo(); var starter = new ProcessStartInfo(
Native.OS.GitExecutable,
["-c", "core.editor=true", "update-index", "--index-info"]
);
starter.WorkingDirectory = _repo; starter.WorkingDirectory = _repo;
starter.FileName = Native.OS.GitExecutable;
starter.Arguments = "-c core.editor=true update-index --index-info";
starter.UseShellExecute = false; starter.UseShellExecute = false;
starter.CreateNoWindow = true; starter.CreateNoWindow = true;
starter.WindowStyle = ProcessWindowStyle.Hidden; starter.WindowStyle = ProcessWindowStyle.Hidden;

View file

@ -4,7 +4,7 @@
{ {
public Version() public Version()
{ {
Args = "--version"; Args = ["--version"];
RaiseError = false; RaiseError = false;
} }

View file

@ -13,7 +13,7 @@ namespace SourceGit.Commands
public List<Models.Worktree> List() public List<Models.Worktree> List()
{ {
Args = "worktree list --porcelain"; Args = ["worktree", "list", "--porcelain"];
var rs = ReadToEnd(); var rs = ReadToEnd();
var worktrees = new List<Models.Worktree>(); var worktrees = new List<Models.Worktree>();
@ -56,23 +56,23 @@ namespace SourceGit.Commands
public bool Add(string fullpath, string name, bool createNew, string tracking, Action<string> outputHandler) public bool Add(string fullpath, string name, bool createNew, string tracking, Action<string> outputHandler)
{ {
Args = "worktree add "; Args = ["worktree", "add"];
if (!string.IsNullOrEmpty(tracking)) if (!string.IsNullOrEmpty(tracking))
Args += "--track "; Args.Add("--track");
if (!string.IsNullOrEmpty(name)) if (!string.IsNullOrEmpty(name))
{ {
if (createNew) if (createNew)
Args += $"-b {name} "; Args.AddRange(["-b", name]);
else else
Args += $"-B {name} "; Args.AddRange(["-B", name]);
} }
Args += $"\"{fullpath}\" "; Args.Add(fullpath);
if (!string.IsNullOrEmpty(tracking)) if (!string.IsNullOrEmpty(tracking))
Args += tracking; Args.Add(tracking);
_outputHandler = outputHandler; _outputHandler = outputHandler;
return Exec(); return Exec();
@ -80,29 +80,29 @@ namespace SourceGit.Commands
public bool Prune(Action<string> outputHandler) public bool Prune(Action<string> outputHandler)
{ {
Args = "worktree prune -v"; Args = ["worktree", "prune", "-v"];
_outputHandler = outputHandler; _outputHandler = outputHandler;
return Exec(); return Exec();
} }
public bool Lock(string fullpath) public bool Lock(string fullpath)
{ {
Args = $"worktree lock \"{fullpath}\""; Args = ["worktree", "lock", fullpath];
return Exec(); return Exec();
} }
public bool Unlock(string fullpath) public bool Unlock(string fullpath)
{ {
Args = $"worktree unlock \"{fullpath}\""; Args = ["worktree", "unlock", fullpath];
return Exec(); return Exec();
} }
public bool Remove(string fullpath, bool force, Action<string> outputHandler) public bool Remove(string fullpath, bool force, Action<string> outputHandler)
{ {
if (force) if (force)
Args = $"worktree remove -f \"{fullpath}\""; Args = ["worktree", "remove", "-f", fullpath];
else else
Args = $"worktree remove \"{fullpath}\""; Args = ["worktree", "remove", fullpath];
_outputHandler = outputHandler; _outputHandler = outputHandler;
return Exec(); return Exec();

View file

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace SourceGit.Models namespace SourceGit.Models
{ {
@ -27,7 +26,7 @@ namespace SourceGit.Models
{ {
case ChangeState.Added: case ChangeState.Added:
case ChangeState.Untracked: case ChangeState.Untracked:
_extra = "--no-index"; _extra = ["--no-index"];
_path = change.Path; _path = change.Path;
_orgPath = "/dev/null"; _orgPath = "/dev/null";
break; break;
@ -40,9 +39,9 @@ namespace SourceGit.Models
else else
{ {
if (change.DataForAmend != null) if (change.DataForAmend != null)
_extra = "--cached HEAD^"; _extra = ["--cached", "HEAD^"];
else else
_extra = "--cached"; _extra = ["--cached"];
_path = change.Path; _path = change.Path;
_orgPath = change.OriginalPath; _orgPath = change.OriginalPath;
@ -94,27 +93,25 @@ namespace SourceGit.Models
/// Converts to diff command arguments. /// Converts to diff command arguments.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public override string ToString() public List<string> ToArgs()
{ {
var builder = new StringBuilder(); var args = new List<string>();
if (!string.IsNullOrEmpty(_extra)) args.AddRange(_extra);
builder.Append($"{_extra} "); args.AddRange(_revisions);
foreach (var r in _revisions)
builder.Append($"{r} ");
builder.Append("-- "); args.Add("--");
if (!string.IsNullOrEmpty(_orgPath)) if (!string.IsNullOrEmpty(_orgPath))
builder.Append($"\"{_orgPath}\" "); args.Add(_orgPath);
builder.Append($"\"{_path}\""); args.Add(_path);
return builder.ToString(); return args;
} }
private readonly Change _workingCopyChange = null; private readonly Change _workingCopyChange = null;
private readonly bool _isUnstaged = false; private readonly bool _isUnstaged = false;
private readonly string _path; private readonly string _path;
private readonly string _orgPath = string.Empty; private readonly string _orgPath = string.Empty;
private readonly string _extra = string.Empty; private readonly IEnumerable<string> _extra = [];
private readonly List<string> _revisions = new List<string>(); private readonly List<string> _revisions = new List<string>();
} }
} }

View file

@ -12,12 +12,14 @@ namespace SourceGit.Models
{ {
public class ExternalTool public class ExternalTool
{ {
public const string ARG_PLACEHOLDER = "$ARG";
public string Name { get; private set; } public string Name { get; private set; }
public string Executable { get; private set; } public string Executable { get; private set; }
public string OpenCmdArgs { get; private set; } public IEnumerable<string> OpenCmdArgs { get; private set; }
public Bitmap IconImage { get; private set; } = null; public Bitmap IconImage { get; private set; } = null;
public ExternalTool(string name, string icon, string executable, string openCmdArgs) public ExternalTool(string name, string icon, string executable, IEnumerable<string> openCmdArgs)
{ {
Name = name; Name = name;
Executable = executable; Executable = executable;
@ -37,11 +39,15 @@ namespace SourceGit.Models
public void Open(string repo) public void Open(string repo)
{ {
Process.Start(new ProcessStartInfo() var args = new List<string>(OpenCmdArgs);
int i = args.IndexOf(ARG_PLACEHOLDER);
if (i != -1) {
args[i] = repo;
}
Process.Start(new ProcessStartInfo(Executable, args)
{ {
WorkingDirectory = repo, WorkingDirectory = repo,
FileName = Executable,
Arguments = string.Format(OpenCmdArgs, repo),
UseShellExecute = false, UseShellExecute = false,
}); });
} }
@ -110,7 +116,7 @@ namespace SourceGit.Models
_customPaths = new ExternalToolPaths(); _customPaths = new ExternalToolPaths();
} }
public void TryAdd(string name, string icon, string args, string key, Func<string> finder) public void TryAdd(string name, string icon, IEnumerable<string> args, string key, Func<string> finder)
{ {
if (_customPaths.Tools.TryGetValue(key, out var customPath) && File.Exists(customPath)) if (_customPaths.Tools.TryGetValue(key, out var customPath) && File.Exists(customPath))
{ {
@ -126,27 +132,27 @@ namespace SourceGit.Models
public void VSCode(Func<string> platformFinder) public void VSCode(Func<string> platformFinder)
{ {
TryAdd("Visual Studio Code", "vscode", "\"{0}\"", "VSCODE", platformFinder); TryAdd("Visual Studio Code", "vscode", [ExternalTool.ARG_PLACEHOLDER], "VSCODE", platformFinder);
} }
public void VSCodeInsiders(Func<string> platformFinder) public void VSCodeInsiders(Func<string> platformFinder)
{ {
TryAdd("Visual Studio Code - Insiders", "vscode_insiders", "\"{0}\"", "VSCODE_INSIDERS", platformFinder); TryAdd("Visual Studio Code - Insiders", "vscode_insiders", [ExternalTool.ARG_PLACEHOLDER], "VSCODE_INSIDERS", platformFinder);
} }
public void VSCodium(Func<string> platformFinder) public void VSCodium(Func<string> platformFinder)
{ {
TryAdd("VSCodium", "codium", "\"{0}\"", "VSCODIUM", platformFinder); TryAdd("VSCodium", "codium", [ExternalTool.ARG_PLACEHOLDER], "VSCODIUM", platformFinder);
} }
public void Fleet(Func<string> platformFinder) public void Fleet(Func<string> platformFinder)
{ {
TryAdd("Fleet", "fleet", "\"{0}\"", "FLEET", platformFinder); TryAdd("Fleet", "fleet", [ExternalTool.ARG_PLACEHOLDER], "FLEET", platformFinder);
} }
public void SublimeText(Func<string> platformFinder) public void SublimeText(Func<string> platformFinder)
{ {
TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT", platformFinder); TryAdd("Sublime Text", "sublime_text", [ExternalTool.ARG_PLACEHOLDER], "SUBLIME_TEXT", platformFinder);
} }
public void FindJetBrainsFromToolbox(Func<string> platformFinder) public void FindJetBrainsFromToolbox(Func<string> platformFinder)
@ -166,7 +172,7 @@ namespace SourceGit.Models
$"{tool.DisplayName} {tool.DisplayVersion}", $"{tool.DisplayName} {tool.DisplayVersion}",
supported_icons.Contains(tool.ProductCode) ? $"JetBrains/{tool.ProductCode}" : "JetBrains/JB", supported_icons.Contains(tool.ProductCode) ? $"JetBrains/{tool.ProductCode}" : "JetBrains/JB",
Path.Combine(tool.InstallLocation, tool.LaunchCommand), Path.Combine(tool.InstallLocation, tool.LaunchCommand),
"\"{0}\"")); [ExternalTool.ARG_PLACEHOLDER]));
} }
} }
} }

View file

@ -52,20 +52,20 @@ namespace SourceGit.Native
public void OpenBrowser(string url) public void OpenBrowser(string url)
{ {
Process.Start("xdg-open", $"\"{url}\""); Process.Start("xdg-open", [url]);
} }
public void OpenInFileManager(string path, bool select) public void OpenInFileManager(string path, bool select)
{ {
if (Directory.Exists(path)) if (Directory.Exists(path))
{ {
Process.Start("xdg-open", $"\"{path}\""); Process.Start("xdg-open", [path]);
} }
else else
{ {
var dir = Path.GetDirectoryName(path); var dir = Path.GetDirectoryName(path);
if (Directory.Exists(dir)) if (Directory.Exists(dir))
Process.Start("xdg-open", $"\"{dir}\""); Process.Start("xdg-open", [dir]);
} }
} }
@ -85,7 +85,7 @@ namespace SourceGit.Native
public void OpenWithDefaultEditor(string file) public void OpenWithDefaultEditor(string file)
{ {
var proc = Process.Start("xdg-open", $"\"{file}\""); var proc = Process.Start("xdg-open", [file]);
if (proc != null) if (proc != null)
{ {
proc.WaitForExit(); proc.WaitForExit();

View file

@ -51,27 +51,27 @@ namespace SourceGit.Native
public void OpenBrowser(string url) public void OpenBrowser(string url)
{ {
Process.Start("open", url); Process.Start("open", [url]);
} }
public void OpenInFileManager(string path, bool select) public void OpenInFileManager(string path, bool select)
{ {
if (Directory.Exists(path)) if (Directory.Exists(path))
Process.Start("open", $"\"{path}\""); Process.Start("open", [path]);
else if (File.Exists(path)) else if (File.Exists(path))
Process.Start("open", $"\"{path}\" -R"); Process.Start("open", [path]);
} }
public void OpenTerminal(string workdir) public void OpenTerminal(string workdir)
{ {
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var dir = string.IsNullOrEmpty(workdir) ? home : workdir; var dir = string.IsNullOrEmpty(workdir) ? home : workdir;
Process.Start("open", $"-a {OS.ShellOrTerminal} \"{dir}\""); Process.Start("open", ["-a", OS.ShellOrTerminal, dir]);
} }
public void OpenWithDefaultEditor(string file) public void OpenWithDefaultEditor(string file)
{ {
Process.Start("open", $"\"{file}\""); Process.Start("open", [file]);
} }
} }
} }

View file

@ -151,7 +151,7 @@ namespace SourceGit.Native
public void OpenBrowser(string url) public void OpenBrowser(string url)
{ {
var info = new ProcessStartInfo("cmd", $"/c start {url}"); var info = new ProcessStartInfo("cmd", ["/c", "start", url]);
info.CreateNoWindow = true; info.CreateNoWindow = true;
Process.Start(info); Process.Start(info);
} }
@ -201,7 +201,7 @@ namespace SourceGit.Native
public void OpenWithDefaultEditor(string file) public void OpenWithDefaultEditor(string file)
{ {
var info = new FileInfo(file); var info = new FileInfo(file);
var start = new ProcessStartInfo("cmd", $"/c start \"\" \"{info.FullName}\""); var start = new ProcessStartInfo("cmd", ["/c", "start", "", info.FullName]);
start.CreateNoWindow = true; start.CreateNoWindow = true;
Process.Start(start); Process.Start(start);
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -47,7 +48,7 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _local, value); set => SetProperty(ref _local, value);
} }
public string ExtraArgs public IEnumerable<string> ExtraArgs
{ {
get => _extraArgs; get => _extraArgs;
set => SetProperty(ref _extraArgs, value); set => SetProperty(ref _extraArgs, value);
@ -154,6 +155,6 @@ namespace SourceGit.ViewModels
private string _sshKey = string.Empty; private string _sshKey = string.Empty;
private string _parentFolder = Preference.Instance.GitDefaultCloneDir; private string _parentFolder = Preference.Instance.GitDefaultCloneDir;
private string _local = string.Empty; private string _local = string.Empty;
private string _extraArgs = string.Empty; private IEnumerable<string> _extraArgs = [];
} }
} }

View file

@ -63,7 +63,7 @@ namespace SourceGit.ViewModels
Task.Run(() => Task.Run(() =>
{ {
var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 -- \"{file}\"", false).Result(); var commits = new Commands.QueryCommits(_repo.FullPath, ["-n", "10000", "--", file], false).Result();
Dispatcher.UIThread.Invoke(() => Dispatcher.UIThread.Invoke(() =>
{ {
IsLoading = false; IsLoading = false;

View file

@ -28,7 +28,7 @@ namespace SourceGit.ViewModels
{ {
WorkingDirectory = Repository, WorkingDirectory = Repository,
Context = Repository, Context = Repository,
Args = $"{Cmd} --abort", Args = [Cmd, "--abort"],
}.Exec(); }.Exec();
} }
@ -39,7 +39,7 @@ namespace SourceGit.ViewModels
WorkingDirectory = Repository, WorkingDirectory = Repository,
Context = Repository, Context = Repository,
Editor = Commands.Command.EditorType.None, Editor = Commands.Command.EditorType.None,
Args = $"{Cmd} --continue", Args = [Cmd, "--continue"],
}.Exec(); }.Exec();
} }
} }
@ -63,7 +63,7 @@ namespace SourceGit.ViewModels
WorkingDirectory = Repository, WorkingDirectory = Repository,
Context = Repository, Context = Repository,
Editor = Commands.Command.EditorType.RebaseEditor, Editor = Commands.Command.EditorType.RebaseEditor,
Args = $"rebase --continue", Args = ["rebase", "--continue"],
}.Exec(); }.Exec();
if (succ) if (succ)

View file

@ -118,7 +118,7 @@ namespace SourceGit.ViewModels
Task.Run(() => Task.Run(() =>
{ {
var commits = new Commands.QueryCommitsWithFullMessage(repoPath, $"{on.SHA}...HEAD").Result(); var commits = new Commands.QueryCommitsWithFullMessage(repoPath, [$"{on.SHA}...HEAD"]).Result();
var list = new List<InteractiveRebaseItem>(); var list = new List<InteractiveRebaseItem>();
foreach (var c in commits) foreach (var c in commits)

View file

@ -765,9 +765,9 @@ namespace SourceGit.ViewModels
{ {
Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true); Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true);
var limits = $"-{Preference.Instance.MaxHistoryCommits} "; List<string> limits = [$"-{Preference.Instance.MaxHistoryCommits}"];
if (_enableFirstParentInHistories) if (_enableFirstParentInHistories)
limits += "--first-parent "; limits.Add("--first-parent");
var validFilters = new List<string>(); var validFilters = new List<string>();
foreach (var filter in _settings.Filters) foreach (var filter in _settings.Filters)
@ -786,7 +786,7 @@ namespace SourceGit.ViewModels
if (validFilters.Count > 0) if (validFilters.Count > 0)
{ {
limits += string.Join(" ", validFilters); limits.AddRange(validFilters);
if (_settings.Filters.Count != validFilters.Count) if (_settings.Filters.Count != validFilters.Count)
{ {
@ -799,7 +799,7 @@ namespace SourceGit.ViewModels
} }
else else
{ {
limits += "--exclude=refs/stash --all"; limits.AddRange(["--exclude=refs/stash", "-all"]);
} }
var commits = new Commands.QueryCommits(_fullpath, limits).Result(); var commits = new Commands.QueryCommits(_fullpath, limits).Result();

View file

@ -1211,7 +1211,7 @@ namespace SourceGit.Views
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, chunk.IsOldSide, tmpFile); diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, chunk.IsOldSide, tmpFile);
} }
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").Exec(); new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", ["--cache", "--index"]).Exec();
File.Delete(tmpFile); File.Delete(tmpFile);
} }
@ -1265,7 +1265,7 @@ namespace SourceGit.Views
else else
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile); diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").Exec(); new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", ["--cache", "--index", "--reverse"]).Exec();
File.Delete(tmpFile); File.Delete(tmpFile);
} }
@ -1323,7 +1323,7 @@ namespace SourceGit.Views
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile); diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
} }
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--reverse").Exec(); new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", ["--reverse"]).Exec();
File.Delete(tmpFile); File.Delete(tmpFile);
} }