mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-05-20 11:44:59 +00:00
feature: git command logs
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
parent
928a0ad3c5
commit
8b39df32cc
101 changed files with 1040 additions and 573 deletions
11
src/App.Utils.cs
Normal file
11
src/App.Utils.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace SourceGit
|
||||
{
|
||||
public static class CommandExtensions
|
||||
{
|
||||
public static T Use<T>(this T cmd, Models.ICommandLog log) where T : Commands.Command
|
||||
{
|
||||
cmd.Log = log;
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Archive : Command
|
||||
{
|
||||
public Archive(string repo, string revision, string saveTo, Action<string> outputHandler)
|
||||
public Archive(string repo, string revision, string saveTo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"archive --format=zip --verbose --output=\"{saveTo}\" {revision}";
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = outputHandler;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,75 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class AssumeUnchanged
|
||||
public class AssumeUnchanged : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\w)\s+(.+)$")]
|
||||
private static partial Regex REG_PARSE();
|
||||
|
||||
class ViewCommand : Command
|
||||
public AssumeUnchanged(string repo, string file, bool bAdd)
|
||||
{
|
||||
public ViewCommand(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Args = "ls-files -v";
|
||||
RaiseError = false;
|
||||
}
|
||||
var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
|
||||
|
||||
public List<string> Result()
|
||||
{
|
||||
Exec();
|
||||
return _outs;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_PARSE().Match(line);
|
||||
if (!match.Success)
|
||||
return;
|
||||
|
||||
if (match.Groups[1].Value == "h")
|
||||
{
|
||||
_outs.Add(match.Groups[2].Value);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<string> _outs = new List<string>();
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"update-index {mode} -- \"{file}\"";
|
||||
}
|
||||
|
||||
class ModCommand : Command
|
||||
{
|
||||
public ModCommand(string repo, string file, bool bAdd)
|
||||
{
|
||||
var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"update-index {mode} -- \"{file}\"";
|
||||
}
|
||||
}
|
||||
|
||||
public AssumeUnchanged(string repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public List<string> View()
|
||||
{
|
||||
return new ViewCommand(_repo).Result();
|
||||
}
|
||||
|
||||
public void Add(string file)
|
||||
{
|
||||
new ModCommand(_repo, file, true).Exec();
|
||||
}
|
||||
|
||||
public void Remove(string file)
|
||||
{
|
||||
new ModCommand(_repo, file, false).Exec();
|
||||
}
|
||||
|
||||
private readonly string _repo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,17 @@ namespace SourceGit.Commands
|
|||
|
||||
public Models.BlameData Result()
|
||||
{
|
||||
var succ = Exec();
|
||||
if (!succ)
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return _result;
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
return new Models.BlameData();
|
||||
ParseLine(line);
|
||||
|
||||
if (_result.IsBinary)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_needUnifyCommitSHA)
|
||||
|
@ -42,13 +49,8 @@ namespace SourceGit.Commands
|
|||
return _result;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
private void ParseLine(string line)
|
||||
{
|
||||
if (_result.IsBinary)
|
||||
return;
|
||||
if (string.IsNullOrEmpty(line))
|
||||
return;
|
||||
|
||||
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
_result.IsBinary = true;
|
||||
|
|
|
@ -11,29 +11,32 @@
|
|||
return cmd.ReadToEnd().StdOut.Trim();
|
||||
}
|
||||
|
||||
public static bool Create(string repo, string name, string basedOn)
|
||||
public static bool Create(string repo, string name, string basedOn, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch {name} {basedOn}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool Rename(string repo, string name, string to)
|
||||
public static bool Rename(string repo, string name, string to, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch -M {name} {to}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool SetUpstream(string repo, string name, string upstream)
|
||||
public static bool SetUpstream(string repo, string name, string upstream, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Log = log;
|
||||
|
||||
if (string.IsNullOrEmpty(upstream))
|
||||
cmd.Args = $"branch {name} --unset-upstream";
|
||||
|
@ -43,25 +46,27 @@
|
|||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool DeleteLocal(string repo, string name)
|
||||
public static bool DeleteLocal(string repo, string name, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch -D {name}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool DeleteRemote(string repo, string remote, string name)
|
||||
public static bool DeleteRemote(string repo, string remote, string name, Models.ICommandLog log)
|
||||
{
|
||||
bool exists = new Remote(repo).HasBranch(remote, name);
|
||||
if (exists)
|
||||
return new Push(repo, remote, $"refs/heads/{name}", true).Exec();
|
||||
return new Push(repo, remote, $"refs/heads/{name}", true).Use(log).Exec();
|
||||
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch -D -r {remote}/{name}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
|
@ -12,19 +11,15 @@ namespace SourceGit.Commands
|
|||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Branch(string branch, Action<string> onProgress)
|
||||
public bool Branch(string branch)
|
||||
{
|
||||
Args = $"checkout --recurse-submodules --progress {branch}";
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Branch(string branch, string basedOn, Action<string> onProgress)
|
||||
public bool Branch(string branch, string basedOn)
|
||||
{
|
||||
Args = $"checkout --recurse-submodules --progress -b {branch} {basedOn}";
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
|
@ -62,19 +57,10 @@ namespace SourceGit.Commands
|
|||
return Exec();
|
||||
}
|
||||
|
||||
public bool Commit(string commitId, Action<string> onProgress)
|
||||
public bool Commit(string commitId)
|
||||
{
|
||||
Args = $"checkout --detach --progress {commitId}";
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Clone : Command
|
||||
{
|
||||
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, string extraArgs)
|
||||
{
|
||||
Context = ctx;
|
||||
WorkingDirectory = path;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = sshKey;
|
||||
Args = "clone --progress --verbose ";
|
||||
|
||||
|
@ -21,13 +16,6 @@ namespace SourceGit.Commands
|
|||
|
||||
if (!string.IsNullOrEmpty(localName))
|
||||
Args += localName;
|
||||
|
||||
_notifyProgress = ouputHandler;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_notifyProgress?.Invoke(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace SourceGit.Commands
|
|||
public string SSHKey { get; set; } = string.Empty;
|
||||
public string Args { get; set; } = string.Empty;
|
||||
public bool RaiseError { get; set; } = true;
|
||||
public bool TraitErrorAsOutput { get; set; } = false;
|
||||
public Models.ICommandLog Log { get; set; } = null;
|
||||
|
||||
public bool Exec()
|
||||
{
|
||||
|
@ -40,10 +40,14 @@ namespace SourceGit.Commands
|
|||
var errs = new List<string>();
|
||||
var proc = new Process() { StartInfo = start };
|
||||
|
||||
Log?.AppendLine($"$ git {Args}\n");
|
||||
|
||||
proc.OutputDataReceived += (_, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
OnReadline(e.Data);
|
||||
if (e.Data == null)
|
||||
return;
|
||||
|
||||
Log?.AppendLine(e.Data);
|
||||
};
|
||||
|
||||
proc.ErrorDataReceived += (_, e) =>
|
||||
|
@ -54,8 +58,7 @@ namespace SourceGit.Commands
|
|||
return;
|
||||
}
|
||||
|
||||
if (TraitErrorAsOutput)
|
||||
OnReadline(e.Data);
|
||||
Log?.AppendLine(e.Data);
|
||||
|
||||
// Ignore progress messages
|
||||
if (e.Data.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal))
|
||||
|
@ -97,6 +100,7 @@ namespace SourceGit.Commands
|
|||
if (RaiseError)
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(Context, e.Message));
|
||||
|
||||
Log?.AppendLine(string.Empty);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -114,6 +118,7 @@ namespace SourceGit.Commands
|
|||
|
||||
int exitCode = proc.ExitCode;
|
||||
proc.Close();
|
||||
Log?.AppendLine(string.Empty);
|
||||
|
||||
if (!CancellationToken.IsCancellationRequested && exitCode != 0)
|
||||
{
|
||||
|
@ -162,11 +167,6 @@ namespace SourceGit.Commands
|
|||
return rs;
|
||||
}
|
||||
|
||||
protected virtual void OnReadline(string line)
|
||||
{
|
||||
// Implemented by derived class
|
||||
}
|
||||
|
||||
private ProcessStartInfo CreateGitStartInfo()
|
||||
{
|
||||
var start = new ProcessStartInfo();
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace SourceGit.Commands
|
|||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
Args = $"commit --allow-empty --file=\"{_tmpFile}\"";
|
||||
if (amend)
|
||||
Args += " --amend --no-edit";
|
||||
|
|
|
@ -31,12 +31,19 @@ namespace SourceGit.Commands
|
|||
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return _changes;
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
ParseLine(line);
|
||||
|
||||
_changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
|
||||
return _changes;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
private void ParseLine(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace SourceGit.Commands
|
|||
{
|
||||
public static class Discard
|
||||
{
|
||||
public static void All(string repo, bool includeIgnored)
|
||||
public static void All(string repo, bool includeIgnored, Models.ICommandLog log)
|
||||
{
|
||||
new Restore(repo).Exec();
|
||||
new Clean(repo, includeIgnored).Exec();
|
||||
new Restore(repo).Use(log).Exec();
|
||||
new Clean(repo, includeIgnored).Use(log).Exec();
|
||||
}
|
||||
|
||||
public static void Changes(string repo, List<Models.Change> changes)
|
||||
public static void Changes(string repo, List<Models.Change> changes, Models.ICommandLog log)
|
||||
{
|
||||
var needClean = new List<string>();
|
||||
var needCheckout = new List<string>();
|
||||
|
@ -27,13 +27,13 @@ namespace SourceGit.Commands
|
|||
for (int i = 0; i < needClean.Count; i += 10)
|
||||
{
|
||||
var count = Math.Min(10, needClean.Count - i);
|
||||
new Clean(repo, needClean.GetRange(i, count)).Exec();
|
||||
new Clean(repo, needClean.GetRange(i, count)).Use(log).Exec();
|
||||
}
|
||||
|
||||
for (int i = 0; i < needCheckout.Count; i += 10)
|
||||
{
|
||||
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").Use(log).Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Fetch : Command
|
||||
{
|
||||
public Fetch(string repo, string remote, bool noTags, bool force, Action<string> outputHandler)
|
||||
public Fetch(string repo, string remote, bool noTags, bool force)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "fetch --progress --verbose ";
|
||||
|
||||
|
@ -24,21 +20,12 @@ namespace SourceGit.Commands
|
|||
Args += remote;
|
||||
}
|
||||
|
||||
public Fetch(string repo, Models.Branch local, Models.Branch remote, Action<string> outputHandler)
|
||||
public Fetch(string repo, Models.Branch local, Models.Branch remote)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote.Remote}.sshkey");
|
||||
Args = $"fetch --progress --verbose {remote.Remote} {remote.Name}:{local.Name}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class GC : Command
|
||||
{
|
||||
public GC(string repo, Action<string> outputHandler)
|
||||
public GC(string repo)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
Args = "gc --prune=now";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,17 +35,17 @@ namespace SourceGit.Commands
|
|||
config.ContainsKey("gitflow.prefix.hotfix");
|
||||
}
|
||||
|
||||
public static bool Init(string repo, List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
|
||||
public static bool Init(string repo, List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
|
||||
{
|
||||
var current = branches.Find(x => x.IsCurrent);
|
||||
|
||||
var masterBranch = branches.Find(x => x.Name == master);
|
||||
if (masterBranch == null && current != null)
|
||||
Branch.Create(repo, master, current.Head);
|
||||
Branch.Create(repo, master, current.Head, log);
|
||||
|
||||
var devBranch = branches.Find(x => x.Name == develop);
|
||||
if (devBranch == null && current != null)
|
||||
Branch.Create(repo, develop, current.Head);
|
||||
Branch.Create(repo, develop, current.Head, log);
|
||||
|
||||
var config = new Config(repo);
|
||||
config.Set("gitflow.branch.master", master);
|
||||
|
@ -61,6 +61,7 @@ namespace SourceGit.Commands
|
|||
init.WorkingDirectory = repo;
|
||||
init.Context = repo;
|
||||
init.Args = "flow init -d";
|
||||
init.Log = log;
|
||||
return init.Exec();
|
||||
}
|
||||
|
||||
|
@ -113,7 +114,7 @@ namespace SourceGit.Commands
|
|||
return rs;
|
||||
}
|
||||
|
||||
public static bool Start(string repo, string type, string name)
|
||||
public static bool Start(string repo, string type, string name, Models.ICommandLog log)
|
||||
{
|
||||
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
|
||||
{
|
||||
|
@ -129,10 +130,11 @@ namespace SourceGit.Commands
|
|||
start.WorkingDirectory = repo;
|
||||
start.Context = repo;
|
||||
start.Args = $"flow {type} start {name}";
|
||||
start.Log = log;
|
||||
return start.Exec();
|
||||
}
|
||||
|
||||
public static bool Finish(string repo, string type, string name, bool keepBranch)
|
||||
public static bool Finish(string repo, string type, string name, bool keepBranch, Models.ICommandLog log)
|
||||
{
|
||||
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
|
||||
{
|
||||
|
@ -149,6 +151,7 @@ namespace SourceGit.Commands
|
|||
finish.WorkingDirectory = repo;
|
||||
finish.Context = repo;
|
||||
finish.Args = $"flow {type} finish {option} {name}";
|
||||
finish.Log = log;
|
||||
return finish.Exec();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,10 @@
|
|||
Context = repo;
|
||||
Args = $"diff -a --ignore-cr-at-eol --check {opt}";
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
{
|
||||
return ReadToEnd().IsSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,21 +12,13 @@ namespace SourceGit.Commands
|
|||
|
||||
class SubCmd : Command
|
||||
{
|
||||
public SubCmd(string repo, string args, Action<string> onProgress)
|
||||
public SubCmd(string repo, string args, Models.ICommandLog log)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = args;
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
Log = log;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
|
||||
public LFS(string repo)
|
||||
|
@ -49,30 +41,30 @@ namespace SourceGit.Commands
|
|||
return new SubCmd(_repo, "lfs install --local", null).Exec();
|
||||
}
|
||||
|
||||
public bool Track(string pattern, bool isFilenameMode = false)
|
||||
public bool Track(string pattern, bool isFilenameMode, Models.ICommandLog log)
|
||||
{
|
||||
var opt = isFilenameMode ? "--filename" : "";
|
||||
return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", null).Exec();
|
||||
return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).Exec();
|
||||
}
|
||||
|
||||
public void Fetch(string remote, Action<string> outputHandler)
|
||||
public void Fetch(string remote, Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, $"lfs fetch {remote}", outputHandler).Exec();
|
||||
new SubCmd(_repo, $"lfs fetch {remote}", log).Exec();
|
||||
}
|
||||
|
||||
public void Pull(string remote, Action<string> outputHandler)
|
||||
public void Pull(string remote, Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, $"lfs pull {remote}", outputHandler).Exec();
|
||||
new SubCmd(_repo, $"lfs pull {remote}", log).Exec();
|
||||
}
|
||||
|
||||
public void Push(string remote, Action<string> outputHandler)
|
||||
public void Push(string remote, Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, $"lfs push {remote}", outputHandler).Exec();
|
||||
new SubCmd(_repo, $"lfs push {remote}", log).Exec();
|
||||
}
|
||||
|
||||
public void Prune(Action<string> outputHandler)
|
||||
public void Prune(Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, "lfs prune", outputHandler).Exec();
|
||||
new SubCmd(_repo, "lfs prune", log).Exec();
|
||||
}
|
||||
|
||||
public List<Models.LFSLock> Locks(string remote)
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Merge : Command
|
||||
{
|
||||
public Merge(string repo, string source, string mode, Action<string> outputHandler)
|
||||
public Merge(string repo, string source, string mode)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
Args = $"merge --progress {source} {mode}";
|
||||
}
|
||||
|
||||
public Merge(string repo, List<string> targets, bool autoCommit, string strategy, Action<string> outputHandler)
|
||||
public Merge(string repo, List<string> targets, bool autoCommit, string strategy)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("merge --progress ");
|
||||
|
@ -37,12 +32,5 @@ namespace SourceGit.Commands
|
|||
|
||||
Args = builder.ToString();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Pull : Command
|
||||
{
|
||||
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, Action<string> outputHandler)
|
||||
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "pull --verbose --progress ";
|
||||
|
||||
|
@ -21,12 +17,5 @@ namespace SourceGit.Commands
|
|||
|
||||
Args += $"{remote} {branch}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Push : Command
|
||||
{
|
||||
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force, Action<string> onProgress)
|
||||
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force)
|
||||
{
|
||||
_outputHandler = onProgress;
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "push --progress --verbose ";
|
||||
|
||||
|
@ -38,12 +33,5 @@ namespace SourceGit.Commands
|
|||
|
||||
Args += $"{remote} {refname}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private readonly Action<string> _outputHandler = null;
|
||||
}
|
||||
}
|
||||
|
|
37
src/Commands/QueryAssumeUnchangedFiles.cs
Normal file
37
src/Commands/QueryAssumeUnchangedFiles.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryAssumeUnchangedFiles : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\w)\s+(.+)$")]
|
||||
private static partial Regex REG_PARSE();
|
||||
|
||||
public QueryAssumeUnchangedFiles(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Args = "ls-files -v";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public List<string> Result()
|
||||
{
|
||||
var outs = new List<string>();
|
||||
var rs = ReadToEnd();
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_PARSE().Match(line);
|
||||
if (!match.Success)
|
||||
continue;
|
||||
|
||||
if (match.Groups[1].Value == "h")
|
||||
outs.Add(match.Groups[2].Value);
|
||||
}
|
||||
|
||||
return outs;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
|
@ -14,17 +15,21 @@ namespace SourceGit.Commands
|
|||
|
||||
public List<string> Result()
|
||||
{
|
||||
Exec();
|
||||
return _lines;
|
||||
}
|
||||
var rs = ReadToEnd();
|
||||
var outs = new List<string>();
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.Contains(_commit))
|
||||
outs.Add(line.Substring(0, 40));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
if (line.Contains(_commit))
|
||||
_lines.Add(line.Substring(0, 40));
|
||||
return outs;
|
||||
}
|
||||
|
||||
private string _commit;
|
||||
private List<string> _lines = new List<string>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
|
@ -18,21 +19,23 @@ namespace SourceGit.Commands
|
|||
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
return _changes;
|
||||
}
|
||||
var outs = new List<Models.Change>();
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return outs;
|
||||
|
||||
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)
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
continue;
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case " M":
|
||||
change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
|
||||
break;
|
||||
|
@ -145,12 +148,14 @@ namespace SourceGit.Commands
|
|||
change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None)
|
||||
outs.Add(change);
|
||||
}
|
||||
|
||||
_changes.Add(change);
|
||||
return outs;
|
||||
}
|
||||
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
|
@ -17,27 +18,31 @@ namespace SourceGit.Commands
|
|||
|
||||
public List<Models.Remote> Result()
|
||||
{
|
||||
Exec();
|
||||
return _loaded;
|
||||
}
|
||||
var outs = new List<Models.Remote>();
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return outs;
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_REMOTE().Match(line);
|
||||
if (!match.Success)
|
||||
return;
|
||||
|
||||
var remote = new Models.Remote()
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
Name = match.Groups[1].Value,
|
||||
URL = match.Groups[2].Value,
|
||||
};
|
||||
var match = REG_REMOTE().Match(line);
|
||||
if (!match.Success)
|
||||
continue;
|
||||
|
||||
if (_loaded.Find(x => x.Name == remote.Name) != null)
|
||||
return;
|
||||
_loaded.Add(remote);
|
||||
var remote = new Models.Remote()
|
||||
{
|
||||
Name = match.Groups[1].Value,
|
||||
URL = match.Groups[2].Value,
|
||||
};
|
||||
|
||||
if (outs.Find(x => x.Name == remote.Name) != null)
|
||||
continue;
|
||||
|
||||
outs.Add(remote);
|
||||
}
|
||||
|
||||
return outs;
|
||||
}
|
||||
|
||||
private readonly List<Models.Remote> _loaded = new List<Models.Remote>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,35 +14,50 @@ namespace SourceGit.Commands
|
|||
|
||||
public List<Models.Stash> Result()
|
||||
{
|
||||
Exec();
|
||||
return _stashes;
|
||||
}
|
||||
var outs = new List<Models.Stash>();
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return outs;
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
switch (_nextLineIdx)
|
||||
var nextPartIdx = 0;
|
||||
var start = 0;
|
||||
var end = rs.StdOut.IndexOf('\n', start);
|
||||
while (end > 0)
|
||||
{
|
||||
case 0:
|
||||
_current = new Models.Stash() { SHA = line };
|
||||
_stashes.Add(_current);
|
||||
break;
|
||||
case 1:
|
||||
ParseParent(line);
|
||||
break;
|
||||
case 2:
|
||||
_current.Time = ulong.Parse(line);
|
||||
break;
|
||||
case 3:
|
||||
_current.Name = line;
|
||||
break;
|
||||
case 4:
|
||||
_current.Message = line;
|
||||
break;
|
||||
var line = rs.StdOut.Substring(start, end - start);
|
||||
|
||||
switch (nextPartIdx)
|
||||
{
|
||||
case 0:
|
||||
_current = new Models.Stash() { SHA = line };
|
||||
outs.Add(_current);
|
||||
break;
|
||||
case 1:
|
||||
ParseParent(line);
|
||||
break;
|
||||
case 2:
|
||||
_current.Time = ulong.Parse(line);
|
||||
break;
|
||||
case 3:
|
||||
_current.Name = line;
|
||||
break;
|
||||
case 4:
|
||||
_current.Message = line;
|
||||
break;
|
||||
}
|
||||
|
||||
nextPartIdx++;
|
||||
if (nextPartIdx > 4)
|
||||
nextPartIdx = 0;
|
||||
|
||||
start = end + 1;
|
||||
end = rs.StdOut.IndexOf('\n', start);
|
||||
}
|
||||
|
||||
_nextLineIdx++;
|
||||
if (_nextLineIdx > 4)
|
||||
_nextLineIdx = 0;
|
||||
if (start < rs.StdOut.Length)
|
||||
_current.Message = rs.StdOut.Substring(start);
|
||||
|
||||
return outs;
|
||||
}
|
||||
|
||||
private void ParseParent(string data)
|
||||
|
@ -53,8 +68,6 @@ namespace SourceGit.Commands
|
|||
_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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Submodule : Command
|
||||
{
|
||||
|
@ -10,9 +8,8 @@ namespace SourceGit.Commands
|
|||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Add(string url, string relativePath, bool recursive, Action<string> outputHandler)
|
||||
public bool Add(string url, string relativePath, bool recursive)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
Args = $"submodule add {url} \"{relativePath}\"";
|
||||
if (!Exec())
|
||||
return false;
|
||||
|
@ -29,7 +26,7 @@ namespace SourceGit.Commands
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Args = "submodule update";
|
||||
|
||||
|
@ -42,7 +39,6 @@ namespace SourceGit.Commands
|
|||
if (!string.IsNullOrEmpty(module))
|
||||
Args += $" -- \"{module}\"";
|
||||
|
||||
_outputHandler = outputHandler;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
|
@ -55,12 +51,5 @@ namespace SourceGit.Commands
|
|||
Args = $"rm -rf \"{relativePath}\"";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class Tag
|
||||
{
|
||||
public static bool Add(string repo, string name, string basedOn)
|
||||
public static bool Add(string repo, string name, string basedOn, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag {name} {basedOn}";
|
||||
cmd.Log = log;
|
||||
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, Models.ICommandLog log)
|
||||
{
|
||||
var param = sign ? "--sign -a" : "--no-sign -a";
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag {param} {name} {basedOn} ";
|
||||
cmd.Log = log;
|
||||
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
|
@ -36,22 +37,14 @@ namespace SourceGit.Commands
|
|||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool Delete(string repo, string name, List<Models.Remote> remotes)
|
||||
public static bool Delete(string repo, string name, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag --delete {name}";
|
||||
if (!cmd.Exec())
|
||||
return false;
|
||||
|
||||
if (remotes != null)
|
||||
{
|
||||
foreach (var r in remotes)
|
||||
new Push(repo, r.Name, $"refs/tags/{name}", true).Exec();
|
||||
}
|
||||
|
||||
return true;
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class UpdateRef : Command
|
||||
{
|
||||
public UpdateRef(string repo, string refName, string toRevision, Action<string> outputHandler)
|
||||
public UpdateRef(string repo, string refName, string toRevision)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"update-ref {refName} {toRevision}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace SourceGit.Commands
|
|||
return worktrees;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Args = "worktree add ";
|
||||
|
||||
|
@ -78,14 +78,12 @@ namespace SourceGit.Commands
|
|||
else if (!string.IsNullOrEmpty(name) && !createNew)
|
||||
Args += name;
|
||||
|
||||
_outputHandler = outputHandler;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Prune(Action<string> outputHandler)
|
||||
public bool Prune()
|
||||
{
|
||||
Args = "worktree prune -v";
|
||||
_outputHandler = outputHandler;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
|
@ -101,22 +99,14 @@ namespace SourceGit.Commands
|
|||
return Exec();
|
||||
}
|
||||
|
||||
public bool Remove(string fullpath, bool force, Action<string> outputHandler)
|
||||
public bool Remove(string fullpath, bool force)
|
||||
{
|
||||
if (force)
|
||||
Args = $"worktree remove -f \"{fullpath}\"";
|
||||
else
|
||||
Args = $"worktree remove \"{fullpath}\"";
|
||||
|
||||
_outputHandler = outputHandler;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace SourceGit.Models
|
|||
new ConventionalCommitType("Styles", "style", "Elements or code styles without changing the code logic"),
|
||||
new ConventionalCommitType("Tests", "test", "Adding or updating tests"),
|
||||
new ConventionalCommitType("Chores", "chore", "Other changes that don't modify src or test files"),
|
||||
|
||||
};
|
||||
|
||||
public ConventionalCommitType(string name, string type, string description)
|
||||
|
|
7
src/Models/ICommandLog.cs
Normal file
7
src/Models/ICommandLog.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace SourceGit.Models
|
||||
{
|
||||
public interface ICommandLog
|
||||
{
|
||||
void AppendLine(string line);
|
||||
}
|
||||
}
|
|
@ -78,6 +78,7 @@
|
|||
<StreamGeometry x:Key="Icons.Loading">M512 0C233 0 7 223 0 500C6 258 190 64 416 64c230 0 416 200 416 448c0 53 43 96 96 96s96-43 96-96c0-283-229-512-512-512zm0 1023c279 0 505-223 512-500c-6 242-190 436-416 436c-230 0-416-200-416-448c0-53-43-96-96-96s-96 43-96 96c0 283 229 512 512 512z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Local">M976 0h-928A48 48 0 000 48v652a48 48 0 0048 48h416V928H200a48 48 0 000 96h624a48 48 0 000-96H560v-180h416a48 48 0 0048-48V48A48 48 0 00976 0zM928 652H96V96h832v556z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Lock">M832 464h-68V240a128 128 0 00-128-128h-248a128 128 0 00-128 128v224H192c-18 0-32 14-32 32v384c0 18 14 32 32 32h640c18 0 32-14 32-32v-384c0-18-14-32-32-32zm-292 237v53a8 8 0 01-8 8h-40a8 8 0 01-8-8v-53a48 48 0 1156 0zm152-237H332V240a56 56 0 0156-56h248a56 56 0 0156 56v224z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Logs">M908 366h-25V248a18 18 0 00-0-2 20 20 0 00-5-13L681 7 681 7a19 19 0 00-4-3c-0-0-1-1-1-1a29 29 0 00-4-2L671 1a24 24 0 00-5-1H181a40 40 0 00-40 40v326h-25c-32 0-57 26-57 57v298c0 32 26 57 57 57h25v204c0 22 18 40 40 40H843a40 40 0 0040-40v-204h25c32 0 57-26 57-57V424a57 57 0 00-57-57zM181 40h465v205c0 11 9 20 20 20h177v101H181V40zm413 527c0 89-54 143-134 143-81 0-128-61-128-138 0-82 52-143 132-143 84 0 129 63 129 138zm-440 139V433h62v220h108v52h-170zm690 267H181v-193H843l0 193zm18-280a305 305 0 01-91 15c-50 0-86-12-111-37-25-23-39-59-38-99 0-90 66-142 155-142 35 0 62 7 76 13l-13 49c-15-6-33-12-63-12-51 0-90 29-90 88 0 56 35 89 86 89 14 0 25-2 30-4v-57h-42v-48h101v143zM397 570c0 53 25 91 66 91 42 0 65-40 65-92 0-49-23-91-66-91-42 0-66 40-66 93z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Menu">M192 192m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM864 160H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 480H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 800H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Merge">M824 645V307c0-56-46-102-102-102h-102V102l-154 154 154 154V307h102v338c-46 20-82 67-82 123 0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123zm-51 195c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72zM384 256c0-72-61-133-133-133-72 0-133 61-133 133 0 56 36 102 82 123v266C154 666 118 712 118 768c0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123V379C348 358 384 312 384 256zM323 768c0 41-31 72-72 72-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72zM251 328c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Modified">M896 64H128C96 64 64 96 64 128v768c0 32 32 64 64 64h768c32 0 64-32 64-64V128c0-32-32-64-64-64z m-64 736c0 16-17 32-32 32H224c-18 0-32-12-32-32V224c0-16 16-32 32-32h576c15 0 32 16 32 32v576zM512 384c-71 0-128 57-128 128s57 128 128 128 128-57 128-128-57-128-128-128z</StreamGeometry>
|
||||
|
|
|
@ -612,6 +612,7 @@
|
|||
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">Sort</x:String>
|
||||
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Open in Terminal</x:String>
|
||||
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">Use relative time in histories</x:String>
|
||||
<x:String x:Key="Text.Repository.ViewLogs" xml:space="preserve">View Logs</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">WORKTREES</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">ADD WORKTREE</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">PRUNE</x:String>
|
||||
|
@ -697,6 +698,7 @@
|
|||
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Submodule:</x:String>
|
||||
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Use --remote option</x:String>
|
||||
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
|
||||
<x:String x:Key="Text.ViewLogs" xml:space="preserve">Logs</x:String>
|
||||
<x:String x:Key="Text.Warn" xml:space="preserve">Warning</x:String>
|
||||
<x:String x:Key="Text.Welcome" xml:space="preserve">Welcome Page</x:String>
|
||||
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">Create Group</x:String>
|
||||
|
|
|
@ -616,6 +616,7 @@
|
|||
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">排序</x:String>
|
||||
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">在终端中打开</x:String>
|
||||
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">在提交列表中使用相对时间</x:String>
|
||||
<x:String x:Key="Text.Repository.ViewLogs" xml:space="preserve">查看命令日志</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">工作树列表</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">新增工作树</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">清理</x:String>
|
||||
|
@ -701,6 +702,7 @@
|
|||
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">子模块 :</x:String>
|
||||
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">启用 '--remote'</x:String>
|
||||
<x:String x:Key="Text.URL" xml:space="preserve">仓库地址 :</x:String>
|
||||
<x:String x:Key="Text.ViewLogs" xml:space="preserve">日志列表</x:String>
|
||||
<x:String x:Key="Text.Warn" xml:space="preserve">警告</x:String>
|
||||
<x:String x:Key="Text.Welcome" xml:space="preserve">起始页</x:String>
|
||||
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">新建分组</x:String>
|
||||
|
@ -757,4 +759,4 @@
|
|||
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">锁定工作树</x:String>
|
||||
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">移除工作树</x:String>
|
||||
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">解除工作树锁定</x:String>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary>
|
||||
|
|
|
@ -616,6 +616,7 @@
|
|||
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">排序</x:String>
|
||||
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">在終端機中開啟</x:String>
|
||||
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">在提交列表中使用相對時間</x:String>
|
||||
<x:String x:Key="Text.Repository.ViewLogs" xml:space="preserve">檢視 GIT 指令的日誌</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">工作區列表</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">新增工作區</x:String>
|
||||
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">清理</x:String>
|
||||
|
@ -701,6 +702,7 @@
|
|||
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">子模組:</x:String>
|
||||
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">啟用 [--remote] 選項</x:String>
|
||||
<x:String x:Key="Text.URL" xml:space="preserve">存放庫網址:</x:String>
|
||||
<x:String x:Key="Text.ViewLogs" xml:space="preserve">日誌清單</x:String>
|
||||
<x:String x:Key="Text.Warn" xml:space="preserve">警告</x:String>
|
||||
<x:String x:Key="Text.Welcome" xml:space="preserve">起始頁</x:String>
|
||||
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">新增群組</x:String>
|
||||
|
@ -757,4 +759,4 @@
|
|||
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">鎖定工作區</x:String>
|
||||
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">移除工作區</x:String>
|
||||
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">解除鎖定工作區</x:String>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary>
|
||||
|
|
|
@ -93,15 +93,19 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Adding remote ...";
|
||||
|
||||
var log = _repo.CreateLog("Add Remote");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Remote(_repo.FullPath).Add(_name, _url);
|
||||
var succ = new Commands.Remote(_repo.FullPath).Use(log).Add(_name, _url);
|
||||
if (succ)
|
||||
{
|
||||
SetProgressDescription("Fetching from added remote ...");
|
||||
new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null);
|
||||
new Commands.Fetch(_repo.FullPath, _name, false, false, SetProgressDescription).Exec();
|
||||
new Commands.Config(_repo.FullPath).Use(log).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null);
|
||||
new Commands.Fetch(_repo.FullPath, _name, false, false).Use(log).Exec();
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.MarkFetched();
|
||||
|
|
|
@ -61,9 +61,14 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Adding submodule...";
|
||||
|
||||
var log = _repo.CreateLog("Add Submodule");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Submodule(_repo.FullPath).Add(_url, _relativePath, Recursive, SetProgressDescription);
|
||||
var succ = new Commands.Submodule(_repo.FullPath).Use(log).Add(_url, _relativePath, Recursive);
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -114,10 +114,15 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var branchName = _selectedBranch;
|
||||
var tracking = _setTrackingBranch ? SelectedTrackingBranch : string.Empty;
|
||||
var log = _repo.CreateLog("Add Worktree");
|
||||
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Worktree(_repo.FullPath).Add(_path, branchName, _createNewBranch, tracking, SetProgressDescription);
|
||||
var succ = new Commands.Worktree(_repo.FullPath).Use(log).Add(_path, branchName, _createNewBranch, tracking);
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -47,9 +47,12 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Apply patch...";
|
||||
|
||||
var log = _repo.CreateLog("Apply Patch");
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Exec();
|
||||
var succ = new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Use(log).Exec();
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace SourceGit.ViewModels
|
|||
set;
|
||||
} = false;
|
||||
|
||||
public ApplyStash(string repo, Models.Stash stash)
|
||||
public ApplyStash(Repository repo, Models.Stash stash)
|
||||
{
|
||||
_repo = repo;
|
||||
Stash = stash;
|
||||
|
@ -33,16 +33,18 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
ProgressDescription = $"Applying stash: {Stash.Name}";
|
||||
|
||||
var log = _repo.CreateLog("Apply Stash");
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Stash(_repo).Apply(Stash.Name, RestoreIndex);
|
||||
var succ = new Commands.Stash(_repo.FullPath).Use(log).Apply(Stash.Name, RestoreIndex);
|
||||
if (succ && DropAfterApply)
|
||||
new Commands.Stash(_repo).Drop(Stash.Name);
|
||||
new Commands.Stash(_repo.FullPath).Use(log).Drop(Stash.Name);
|
||||
|
||||
log.Complete();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private readonly string _repo;
|
||||
private readonly Repository _repo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,9 +51,14 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Archiving ...";
|
||||
|
||||
var log = _repo.CreateLog("Archive");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Archive(_repo.FullPath, _revision, _saveFile, SetProgressDescription).Exec();
|
||||
var succ = new Commands.Archive(_repo.FullPath, _revision, _saveFile).Use(log).Exec();
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.SetWatcherEnabled(true);
|
||||
|
|
|
@ -16,11 +16,8 @@ namespace SourceGit.ViewModels
|
|||
|
||||
Task.Run(() =>
|
||||
{
|
||||
var collect = new Commands.AssumeUnchanged(_repo).View();
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
Files.AddRange(collect);
|
||||
});
|
||||
var collect = new Commands.QueryAssumeUnchangedFiles(_repo).Result();
|
||||
Dispatcher.UIThread.Invoke(() => Files.AddRange(collect));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -28,7 +25,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (!string.IsNullOrEmpty(file))
|
||||
{
|
||||
new Commands.AssumeUnchanged(_repo).Remove(file);
|
||||
new Commands.AssumeUnchanged(_repo, file, false).Exec();
|
||||
Files.Remove(file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Checkout '{Branch}' ...";
|
||||
|
||||
var log = _repo.CreateLog($"Checkout '{Branch}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
|
||||
|
@ -36,15 +39,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (DiscardLocalChanges)
|
||||
{
|
||||
SetProgressDescription("Discard local changes ...");
|
||||
Commands.Discard.All(_repo.FullPath, false);
|
||||
Commands.Discard.All(_repo.FullPath, false, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription("Stash local changes ...");
|
||||
var succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
|
||||
var succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AUTO_STASH");
|
||||
if (!succ)
|
||||
{
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return false;
|
||||
}
|
||||
|
@ -53,14 +55,11 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
SetProgressDescription("Checkout branch ...");
|
||||
var rs = new Commands.Checkout(_repo.FullPath).Branch(Branch, SetProgressDescription);
|
||||
|
||||
var rs = new Commands.Checkout(_repo.FullPath).Use(log).Branch(Branch);
|
||||
if (needPopStash)
|
||||
{
|
||||
SetProgressDescription("Re-apply local changes...");
|
||||
rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
|
||||
}
|
||||
rs = new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
|
|
|
@ -28,6 +28,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Checkout Commit '{Commit.SHA}' ...";
|
||||
|
||||
var log = _repo.CreateLog("Checkout Commit");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
|
||||
|
@ -36,15 +39,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (DiscardLocalChanges)
|
||||
{
|
||||
SetProgressDescription("Discard local changes ...");
|
||||
Commands.Discard.All(_repo.FullPath, false);
|
||||
Commands.Discard.All(_repo.FullPath, false, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription("Stash local changes ...");
|
||||
var succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
|
||||
var succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AUTO_STASH");
|
||||
if (!succ)
|
||||
{
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return false;
|
||||
}
|
||||
|
@ -53,15 +55,11 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
SetProgressDescription("Checkout commit ...");
|
||||
var rs = new Commands.Checkout(_repo.FullPath).Commit(Commit.SHA, SetProgressDescription);
|
||||
|
||||
var rs = new Commands.Checkout(_repo.FullPath).Use(log).Commit(Commit.SHA);
|
||||
if (needPopStash)
|
||||
{
|
||||
SetProgressDescription("Re-apply local changes...");
|
||||
rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
|
||||
}
|
||||
rs = new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return rs;
|
||||
});
|
||||
|
|
|
@ -70,6 +70,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Cherry-Pick commit(s) ...";
|
||||
|
||||
var log = _repo.CreateLog("Cherry-Pick");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (IsMergeCommit)
|
||||
|
@ -79,7 +82,7 @@ namespace SourceGit.ViewModels
|
|||
Targets[0].SHA,
|
||||
!AutoCommit,
|
||||
AppendSourceToMessage,
|
||||
$"-m {MainlineForMergeCommit + 1}").Exec();
|
||||
$"-m {MainlineForMergeCommit + 1}").Use(log).Exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -88,9 +91,10 @@ namespace SourceGit.ViewModels
|
|||
string.Join(' ', Targets.ConvertAll(c => c.SHA)),
|
||||
!AutoCommit,
|
||||
AppendSourceToMessage,
|
||||
string.Empty).Exec();
|
||||
string.Empty).Use(log).Exec();
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -15,9 +15,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Cleanup (GC & prune) ...";
|
||||
|
||||
var log = _repo.CreateLog("Cleanup (GC & prune)");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.GC(_repo.FullPath, SetProgressDescription).Exec();
|
||||
new Commands.GC(_repo.FullPath).Use(log).Exec();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -15,9 +15,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Clear all stashes...";
|
||||
|
||||
var log = _repo.CreateLog("Clear Stashes");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Stash(_repo.FullPath).Clear();
|
||||
new Commands.Stash(_repo.FullPath).Use(log).Clear();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -103,9 +103,13 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
ProgressDescription = "Clone ...";
|
||||
|
||||
// Create a temp log.
|
||||
var log = new CommandLog("Clone");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var cmd = new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs, SetProgressDescription);
|
||||
var cmd = new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs).Use(log);
|
||||
if (!cmd.Exec())
|
||||
return false;
|
||||
|
||||
|
@ -142,12 +146,11 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
var submoduleList = new Commands.QuerySubmodules(path).Result();
|
||||
foreach (var submodule in submoduleList)
|
||||
{
|
||||
var update = new Commands.Submodule(path);
|
||||
update.Update(submodule.Path, true, true, false, SetProgressDescription);
|
||||
}
|
||||
new Commands.Submodule(path).Use(log).Update(submodule.Path, true, true, false);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, null, true);
|
||||
|
|
87
src/ViewModels/CommandLog.cs
Normal file
87
src/ViewModels/CommandLog.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public class CommandLog : ObservableObject, Models.ICommandLog
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = string.Empty;
|
||||
|
||||
public DateTime Time
|
||||
{
|
||||
get;
|
||||
} = DateTime.Now;
|
||||
|
||||
public string TimeStr
|
||||
{
|
||||
get => Time.ToString("T");
|
||||
}
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = false;
|
||||
|
||||
public string Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsComplete ? _content : _builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public CommandLog(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void Register(Action<string> handler)
|
||||
{
|
||||
if (!IsComplete)
|
||||
_onNewLineReceived += handler;
|
||||
}
|
||||
|
||||
public void AppendLine(string line = null)
|
||||
{
|
||||
var newline = line ?? string.Empty;
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
_builder.AppendLine(newline);
|
||||
_onNewLineReceived?.Invoke(newline);
|
||||
});
|
||||
}
|
||||
|
||||
public void Complete()
|
||||
{
|
||||
IsComplete = true;
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
_content = _builder.ToString();
|
||||
_builder.Clear();
|
||||
_builder = null;
|
||||
|
||||
OnPropertyChanged(nameof(IsComplete));
|
||||
|
||||
if (_onNewLineReceived != null)
|
||||
{
|
||||
var dumpHandlers = _onNewLineReceived.GetInvocationList();
|
||||
foreach (var d in dumpHandlers)
|
||||
_onNewLineReceived -= (Action<string>)d;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private string _content = string.Empty;
|
||||
private StringBuilder _builder = new StringBuilder();
|
||||
private event Action<string> _onNewLineReceived;
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@
|
|||
_wc = wc;
|
||||
_change = change;
|
||||
|
||||
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).ReadToEnd().IsSuccess;
|
||||
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).Result();
|
||||
|
||||
var context = wc.InProgressContext;
|
||||
if (context is CherryPickInProgress cherryPick)
|
||||
|
|
|
@ -92,6 +92,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
|
||||
var fixedName = FixName(_name);
|
||||
var log = _repo.CreateLog($"Create Branch '{fixedName}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = false;
|
||||
|
@ -103,15 +106,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (DiscardLocalChanges)
|
||||
{
|
||||
SetProgressDescription("Discard local changes...");
|
||||
Commands.Discard.All(_repo.FullPath, false);
|
||||
Commands.Discard.All(_repo.FullPath, false, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription("Stash local changes");
|
||||
succ = new Commands.Stash(_repo.FullPath).Push("CREATE_BRANCH_AUTO_STASH");
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CREATE_BRANCH_AUTO_STASH");
|
||||
if (!succ)
|
||||
{
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return false;
|
||||
}
|
||||
|
@ -120,21 +122,17 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
SetProgressDescription($"Create new branch '{fixedName}'");
|
||||
succ = new Commands.Checkout(_repo.FullPath).Branch(fixedName, _baseOnRevision, SetProgressDescription);
|
||||
|
||||
succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision);
|
||||
if (needPopStash)
|
||||
{
|
||||
SetProgressDescription("Re-apply local changes...");
|
||||
new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
|
||||
}
|
||||
new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription($"Create new branch '{fixedName}'");
|
||||
succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision);
|
||||
succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision, log);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
if (succ && CheckoutAfterCreated)
|
||||
|
|
|
@ -83,23 +83,24 @@ namespace SourceGit.ViewModels
|
|||
ProgressDescription = "Create tag...";
|
||||
|
||||
var remotes = PushToRemotes ? _repo.Remotes : null;
|
||||
var log = _repo.CreateLog("Create Tag");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
bool succ;
|
||||
if (_annotated)
|
||||
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag);
|
||||
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag, log);
|
||||
else
|
||||
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn);
|
||||
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, log);
|
||||
|
||||
if (succ && remotes != null)
|
||||
{
|
||||
foreach (var remote in remotes)
|
||||
{
|
||||
SetProgressDescription($"Pushing tag to remote {remote.Name} ...");
|
||||
new Commands.Push(_repo.FullPath, remote.Name, $"refs/tags/{_tagName}", false).Exec();
|
||||
}
|
||||
new Commands.Push(_repo.FullPath, remote.Name, $"refs/tags/{_tagName}", false).Use(log).Exec();
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -48,23 +48,25 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Deleting branch...";
|
||||
|
||||
var log = _repo.CreateLog("Delete Branch");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (Target.IsLocal)
|
||||
{
|
||||
Commands.Branch.DeleteLocal(_repo.FullPath, Target.Name);
|
||||
Commands.Branch.DeleteLocal(_repo.FullPath, Target.Name, log);
|
||||
|
||||
if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null)
|
||||
{
|
||||
SetProgressDescription("Deleting remote-tracking branch...");
|
||||
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name);
|
||||
}
|
||||
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
Commands.Branch.DeleteRemote(_repo.FullPath, Target.Remote, Target.Name);
|
||||
Commands.Branch.DeleteRemote(_repo.FullPath, Target.Remote, Target.Name, log);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.MarkBranchesDirtyManually();
|
||||
|
|
|
@ -23,25 +23,24 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Deleting multiple branches...";
|
||||
|
||||
var log = _repo.CreateLog("Delete Multiple Branches");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (_isLocal)
|
||||
{
|
||||
foreach (var target in Targets)
|
||||
{
|
||||
SetProgressDescription($"Deleting local branch : {target.Name}");
|
||||
Commands.Branch.DeleteLocal(_repo.FullPath, target.Name);
|
||||
}
|
||||
Commands.Branch.DeleteLocal(_repo.FullPath, target.Name, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var target in Targets)
|
||||
{
|
||||
SetProgressDescription($"Deleting remote branch : {target.FriendlyName}");
|
||||
Commands.Branch.DeleteRemote(_repo.FullPath, target.Remote, target.Name);
|
||||
}
|
||||
Commands.Branch.DeleteRemote(_repo.FullPath, target.Remote, target.Name, log);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.MarkBranchesDirtyManually();
|
||||
|
|
|
@ -22,9 +22,14 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Deleting remote ...";
|
||||
|
||||
var log = _repo.CreateLog("Delete Remote");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Remote(_repo.FullPath).Delete(Remote.Name);
|
||||
var succ = new Commands.Remote(_repo.FullPath).Use(log).Delete(Remote.Name);
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.MarkBranchesDirtyManually();
|
||||
|
|
|
@ -23,9 +23,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Deleting submodule ...";
|
||||
|
||||
var log = _repo.CreateLog("Delete Submodule");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Submodule(_repo.FullPath).Delete(Submodule);
|
||||
var succ = new Commands.Submodule(_repo.FullPath).Use(log).Delete(Submodule);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -28,10 +28,21 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Deleting tag '{Target.Name}' ...";
|
||||
|
||||
var remotes = PushToRemotes ? _repo.Remotes : null;
|
||||
var remotes = PushToRemotes ? _repo.Remotes : [];
|
||||
var log = _repo.CreateLog("Delete Tag");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = Commands.Tag.Delete(_repo.FullPath, Target.Name, remotes);
|
||||
var succ = Commands.Tag.Delete(_repo.FullPath, Target.Name, log);
|
||||
if (succ)
|
||||
{
|
||||
foreach (var r in remotes)
|
||||
new Commands.Push(_repo.FullPath, r.Name, $"refs/tags/{Target.Name}", true).Use(log).Exec();
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.MarkTagsDirtyManually();
|
||||
|
|
|
@ -65,12 +65,17 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = _changes == null ? "Discard all local changes ..." : $"Discard total {_changes.Count} changes ...";
|
||||
|
||||
var log = _repo.CreateLog("Discard all");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (Mode is DiscardAllMode all)
|
||||
Commands.Discard.All(_repo.FullPath, all.IncludeIgnored);
|
||||
Commands.Discard.All(_repo.FullPath, all.IncludeIgnored, log);
|
||||
else
|
||||
Commands.Discard.Changes(_repo.FullPath, _changes);
|
||||
Commands.Discard.Changes(_repo.FullPath, _changes, log);
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
public Models.Stash Stash { get; private set; }
|
||||
|
||||
public DropStash(string repo, Models.Stash stash)
|
||||
public DropStash(Repository repo, Models.Stash stash)
|
||||
{
|
||||
_repo = repo;
|
||||
Stash = stash;
|
||||
|
@ -17,13 +17,17 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
ProgressDescription = $"Dropping stash: {Stash.Name}";
|
||||
|
||||
var log = _repo.CreateLog("Drop Stash");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Stash(_repo).Drop(Stash.Name);
|
||||
new Commands.Stash(_repo.FullPath).Use(log).Drop(Stash.Name);
|
||||
log.Complete();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private readonly string _repo;
|
||||
private readonly Repository _repo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,6 @@ namespace SourceGit.ViewModels
|
|||
if (pushURL != _url)
|
||||
new Commands.Remote(_repo.FullPath).SetURL(_name, _url, true);
|
||||
|
||||
SetProgressDescription("Post processing ...");
|
||||
new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null);
|
||||
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace SourceGit.ViewModels
|
|||
return Task.Run(() =>
|
||||
{
|
||||
if (CustomAction.WaitForExit)
|
||||
Commands.ExecuteCustomAction.RunAndWait(_repo.FullPath, CustomAction.Executable, _args, SetProgressDescription);
|
||||
Commands.ExecuteCustomAction.RunAndWait(_repo.FullPath, CustomAction.Executable, _args, output => CallUIThread(() => ProgressDescription = output));
|
||||
else
|
||||
Commands.ExecuteCustomAction.Run(_repo.FullPath, CustomAction.Executable, _args);
|
||||
|
||||
|
|
|
@ -29,9 +29,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Fast-Forward ...";
|
||||
|
||||
var log = _repo.CreateLog("Fast-Forward (No checkout)");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.UpdateRef(_repo.FullPath, Local.FullName, To.FullName, SetProgressDescription).Exec();
|
||||
new Commands.UpdateRef(_repo.FullPath, Local.FullName, To.FullName).Use(log).Exec();
|
||||
log.Complete();
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.NavigateToCommit(To.Head);
|
||||
|
|
|
@ -65,22 +65,23 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var notags = _repo.Settings.FetchWithoutTags;
|
||||
var force = _repo.Settings.EnableForceOnFetch;
|
||||
var log = _repo.CreateLog("Fetch");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (FetchAllRemotes)
|
||||
{
|
||||
foreach (var remote in _repo.Remotes)
|
||||
{
|
||||
SetProgressDescription($"Fetching remote: {remote.Name}");
|
||||
new Commands.Fetch(_repo.FullPath, remote.Name, notags, force, SetProgressDescription).Exec();
|
||||
}
|
||||
new Commands.Fetch(_repo.FullPath, remote.Name, notags, force).Use(log).Exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription($"Fetching remote: {SelectedRemote.Name}");
|
||||
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force, SetProgressDescription).Exec();
|
||||
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force).Use(log).Exec();
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.NavigateToBranchDelayed(_repo.CurrentBranch?.Upstream);
|
||||
|
|
|
@ -29,9 +29,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Fast-Forward ...";
|
||||
|
||||
var log = _repo.CreateLog($"Fetch Into '{Local.FriendlyName}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Fetch(_repo.FullPath, Local, Upstream, SetProgressDescription).Exec();
|
||||
new Commands.Fetch(_repo.FullPath, Local, Upstream).Use(log).Exec();
|
||||
log.Complete();
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.NavigateToBranchDelayed(Upstream.FullName);
|
||||
|
|
|
@ -33,11 +33,17 @@ namespace SourceGit.ViewModels
|
|||
public override Task<bool> Sure()
|
||||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
|
||||
var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
|
||||
ProgressDescription = $"Git Flow - finishing {_type} {name} ...";
|
||||
|
||||
var log = _repo.CreateLog("Gitflow - Finish");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
|
||||
SetProgressDescription($"Git Flow - finishing {_type} {name} ...");
|
||||
var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch);
|
||||
var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch, log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -50,10 +50,15 @@ namespace SourceGit.ViewModels
|
|||
public override Task<bool> Sure()
|
||||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Git Flow - starting {_type} {_name} ...";
|
||||
|
||||
var log = _repo.CreateLog("Gitflow - Start");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
SetProgressDescription($"Git Flow - starting {_type} {_name} ...");
|
||||
var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name);
|
||||
var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name, log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -302,17 +302,20 @@ namespace SourceGit.ViewModels
|
|||
var picker = await storageProvider.OpenFolderPickerAsync(options);
|
||||
if (picker.Count == 1)
|
||||
{
|
||||
var log = _repo.CreateLog("Save as Patch");
|
||||
var succ = false;
|
||||
for (var i = 0; i < selected.Count; i++)
|
||||
{
|
||||
var saveTo = GetPatchFileName(picker[0].Path.LocalPath, selected[i], i);
|
||||
succ = await Task.Run(() => new Commands.FormatPatch(_repo.FullPath, selected[i].SHA, saveTo).Exec());
|
||||
succ = await Task.Run(() => new Commands.FormatPatch(_repo.FullPath, selected[i].SHA, saveTo).Use(log).Exec());
|
||||
if (!succ)
|
||||
break;
|
||||
}
|
||||
|
||||
if (succ)
|
||||
App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess"));
|
||||
|
||||
log.Complete();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
|
|
|
@ -30,19 +30,24 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
ProgressDescription = $"Initialize git repository at: '{_targetPath}'";
|
||||
|
||||
var log = new CommandLog("Initialize");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Init(_pageId, _targetPath).Exec();
|
||||
if (!succ)
|
||||
return false;
|
||||
var succ = new Commands.Init(_pageId, _targetPath).Use(log).Exec();
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
if (succ)
|
||||
{
|
||||
Preferences.Instance.FindOrAddNodeByRepositoryPath(_targetPath, _parentNode, true);
|
||||
Welcome.Instance.Refresh();
|
||||
});
|
||||
CallUIThread(() =>
|
||||
{
|
||||
Preferences.Instance.FindOrAddNodeByRepositoryPath(_targetPath, _parentNode, true);
|
||||
Welcome.Instance.Refresh();
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
return succ;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -106,9 +106,23 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Init git-flow ...";
|
||||
|
||||
var log = _repo.CreateLog("Gitflow - Init");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = Commands.GitFlow.Init(_repo.FullPath, _repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix);
|
||||
var succ = Commands.GitFlow.Init(
|
||||
_repo.FullPath,
|
||||
_repo.Branches,
|
||||
_master,
|
||||
_develop,
|
||||
_featurePrefix,
|
||||
_releasePrefix,
|
||||
_hotfixPrefix,
|
||||
_tagPrefix,
|
||||
log);
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -24,9 +24,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Fetching LFS objects from remote ...";
|
||||
|
||||
var log = _repo.CreateLog("LFS Fetch");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.LFS(_repo.FullPath).Fetch(SelectedRemote.Name, SetProgressDescription);
|
||||
new Commands.LFS(_repo.FullPath).Fetch(SelectedRemote.Name, log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -15,9 +15,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "LFS prune ...";
|
||||
|
||||
var log = _repo.CreateLog("LFS Prune");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.LFS(_repo.FullPath).Prune(SetProgressDescription);
|
||||
new Commands.LFS(_repo.FullPath).Prune(log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -24,9 +24,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Pull LFS objects from remote ...";
|
||||
|
||||
var log = _repo.CreateLog("LFS Pull");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.LFS(_repo.FullPath).Pull(SelectedRemote.Name, SetProgressDescription);
|
||||
new Commands.LFS(_repo.FullPath).Pull(SelectedRemote.Name, log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -24,9 +24,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Push LFS objects to remote ...";
|
||||
|
||||
var log = _repo.CreateLog("LFS Push");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.LFS(_repo.FullPath).Push(SelectedRemote.Name, SetProgressDescription);
|
||||
new Commands.LFS(_repo.FullPath).Push(SelectedRemote.Name, log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -29,9 +29,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Adding custom LFS tracking pattern ...";
|
||||
|
||||
var log = _repo.CreateLog("LFS Add Custom Pattern");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.LFS(_repo.FullPath).Track(_pattern, IsFilename);
|
||||
var succ = new Commands.LFS(_repo.FullPath).Track(_pattern, IsFilename, log);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -59,9 +59,14 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Merging '{_sourceName}' into '{Into}' ...";
|
||||
|
||||
var log = _repo.CreateLog($"Merging '{_sourceName}' into '{Into}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, SetProgressDescription).Exec();
|
||||
new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg).Use(log).Exec();
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.NavigateToBranchDelayed(_repo.CurrentBranch?.FullName);
|
||||
|
|
|
@ -46,15 +46,18 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Merge head(s) ...";
|
||||
|
||||
var log = _repo.CreateLog("Merge Multiple Heads");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Merge(
|
||||
_repo.FullPath,
|
||||
ConvertTargetToMergeSources(),
|
||||
AutoCommit,
|
||||
Strategy.Arg,
|
||||
SetProgressDescription).Exec();
|
||||
Strategy.Arg).Use(log).Exec();
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -52,9 +52,9 @@ namespace SourceGit.ViewModels
|
|||
Dispatcher.UIThread.Invoke(action);
|
||||
}
|
||||
|
||||
protected void SetProgressDescription(string description)
|
||||
protected void Use(CommandLog log)
|
||||
{
|
||||
CallUIThread(() => ProgressDescription = description);
|
||||
log.Register(newline => ProgressDescription = newline.Trim());
|
||||
}
|
||||
|
||||
private bool _inProgress = false;
|
||||
|
|
|
@ -22,9 +22,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Run `prune` on remote ...";
|
||||
|
||||
var log = _repo.CreateLog($"Prune Remote '{Remote.Name}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Remote(_repo.FullPath).Prune(Remote.Name);
|
||||
var succ = new Commands.Remote(_repo.FullPath).Use(log).Prune(Remote.Name);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -15,9 +15,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Prune worktrees ...";
|
||||
|
||||
var log = _repo.CreateLog("Prune Worktrees");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Worktree(_repo.FullPath).Prune(SetProgressDescription);
|
||||
new Commands.Worktree(_repo.FullPath).Use(log).Prune();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -118,6 +118,9 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
|
||||
var log = _repo.CreateLog("Pull");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
|
||||
|
@ -126,15 +129,14 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (DiscardLocalChanges)
|
||||
{
|
||||
SetProgressDescription("Discard local changes ...");
|
||||
Commands.Discard.All(_repo.FullPath, false);
|
||||
Commands.Discard.All(_repo.FullPath, false, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription("Stash local changes...");
|
||||
var succ = new Commands.Stash(_repo.FullPath).Push("PULL_AUTO_STASH");
|
||||
var succ = new Commands.Stash(_repo.FullPath).Use(log).Push("PULL_AUTO_STASH");
|
||||
if (!succ)
|
||||
{
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return false;
|
||||
}
|
||||
|
@ -146,16 +148,14 @@ namespace SourceGit.ViewModels
|
|||
bool rs;
|
||||
if (FetchAllBranches)
|
||||
{
|
||||
SetProgressDescription($"Fetching remote: {_selectedRemote.Name}...");
|
||||
rs = new Commands.Fetch(
|
||||
_repo.FullPath,
|
||||
_selectedRemote.Name,
|
||||
NoTags,
|
||||
false,
|
||||
SetProgressDescription).Exec();
|
||||
|
||||
false).Use(log).Exec();
|
||||
if (!rs)
|
||||
{
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return false;
|
||||
}
|
||||
|
@ -164,39 +164,31 @@ namespace SourceGit.ViewModels
|
|||
|
||||
// Use merge/rebase instead of pull as fetch is done manually.
|
||||
if (UseRebase)
|
||||
{
|
||||
SetProgressDescription($"Rebase {_current.Name} on {_selectedBranch.FriendlyName} ...");
|
||||
rs = new Commands.Rebase(_repo.FullPath, _selectedBranch.FriendlyName, false).Exec();
|
||||
}
|
||||
rs = new Commands.Rebase(_repo.FullPath, _selectedBranch.FriendlyName, false).Use(log).Exec();
|
||||
else
|
||||
{
|
||||
SetProgressDescription($"Merge {_selectedBranch.FriendlyName} into {_current.Name} ...");
|
||||
rs = new Commands.Merge(_repo.FullPath, _selectedBranch.FriendlyName, "", SetProgressDescription).Exec();
|
||||
}
|
||||
rs = new Commands.Merge(_repo.FullPath, _selectedBranch.FriendlyName, "").Use(log).Exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription($"Pull {_selectedRemote.Name}/{_selectedBranch.Name}...");
|
||||
rs = new Commands.Pull(
|
||||
_repo.FullPath,
|
||||
_selectedRemote.Name,
|
||||
_selectedBranch.Name,
|
||||
UseRebase,
|
||||
NoTags,
|
||||
SetProgressDescription).Exec();
|
||||
NoTags).Use(log).Exec();
|
||||
}
|
||||
|
||||
if (rs && needPopStash)
|
||||
{
|
||||
SetProgressDescription("Re-apply local changes...");
|
||||
rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
|
||||
}
|
||||
rs = new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
|
||||
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.NavigateToBranchDelayed(_repo.CurrentBranch?.FullName);
|
||||
_repo.SetWatcherEnabled(true);
|
||||
});
|
||||
|
||||
return rs;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -164,6 +164,9 @@ namespace SourceGit.ViewModels
|
|||
var remoteBranchName = _selectedRemoteBranch.Name;
|
||||
ProgressDescription = $"Push {_selectedLocalBranch.Name} -> {_selectedRemote.Name}/{remoteBranchName} ...";
|
||||
|
||||
var log = _repo.CreateLog("Push");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Push(
|
||||
|
@ -174,8 +177,9 @@ namespace SourceGit.ViewModels
|
|||
PushAllTags,
|
||||
_repo.Submodules.Count > 0 && CheckSubmodules,
|
||||
_isSetTrackOptionVisible && Tracking,
|
||||
ForcePush,
|
||||
SetProgressDescription).Exec();
|
||||
ForcePush).Use(log).Exec();
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -41,6 +41,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Pushing tag ...";
|
||||
|
||||
var log = _repo.CreateLog("Push Tag");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = true;
|
||||
|
@ -49,18 +52,17 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
foreach (var remote in _repo.Remotes)
|
||||
{
|
||||
SetProgressDescription($"Pushing tag to remote {remote.Name} ...");
|
||||
succ = new Commands.Push(_repo.FullPath, remote.Name, tag, false).Exec();
|
||||
succ = new Commands.Push(_repo.FullPath, remote.Name, tag, false).Use(log).Exec();
|
||||
if (!succ)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetProgressDescription($"Pushing tag to remote {SelectedRemote.Name} ...");
|
||||
succ = new Commands.Push(_repo.FullPath, SelectedRemote.Name, tag, false).Exec();
|
||||
succ = new Commands.Push(_repo.FullPath, SelectedRemote.Name, tag, false).Use(log).Exec();
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -47,9 +47,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Rebasing ...";
|
||||
|
||||
var log = _repo.CreateLog("Rebase");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Exec();
|
||||
new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Use(log).Exec();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -26,11 +26,15 @@ namespace SourceGit.ViewModels
|
|||
public override Task<bool> Sure()
|
||||
{
|
||||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Remove worktrees ...";
|
||||
ProgressDescription = "Remove worktree ...";
|
||||
|
||||
var log = _repo.CreateLog("Remove worktree");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Worktree(_repo.FullPath).Remove(Target.FullPath, Force, SetProgressDescription);
|
||||
var succ = new Commands.Worktree(_repo.FullPath).Use(log).Remove(Target.FullPath, Force);
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -54,10 +54,15 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Rename '{Target.Name}'";
|
||||
|
||||
var log = _repo.CreateLog($"Rename Branch '{Target.Name}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var oldName = Target.FullName;
|
||||
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, fixedName);
|
||||
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, fixedName, log);
|
||||
log.Complete();
|
||||
|
||||
CallUIThread(() =>
|
||||
{
|
||||
if (succ)
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Text.Json;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
@ -409,6 +410,12 @@ namespace SourceGit.ViewModels
|
|||
set;
|
||||
} = 0;
|
||||
|
||||
public AvaloniaList<CommandLog> Logs
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new AvaloniaList<CommandLog>();
|
||||
|
||||
public Repository(bool isBare, string path, string gitDir)
|
||||
{
|
||||
IsBare = isBare;
|
||||
|
@ -472,6 +479,8 @@ namespace SourceGit.ViewModels
|
|||
public void Close()
|
||||
{
|
||||
SelectedView = null; // Do NOT modify. Used to remove exists widgets for GC.Collect
|
||||
Logs.Clear();
|
||||
|
||||
_settings.LastCommitMessage = _workingCopy.CommitMessage;
|
||||
|
||||
var settingsSerialized = JsonSerializer.Serialize(_settings, JsonCodeGen.Default.RepositorySettings);
|
||||
|
@ -538,6 +547,13 @@ namespace SourceGit.ViewModels
|
|||
GetOwnerPage()?.StartPopup(popup);
|
||||
}
|
||||
|
||||
public CommandLog CreateLog(string name)
|
||||
{
|
||||
var log = new CommandLog(name);
|
||||
Logs.Insert(0, log);
|
||||
return log;
|
||||
}
|
||||
|
||||
public void RefreshAll()
|
||||
{
|
||||
Task.Run(() =>
|
||||
|
@ -2560,7 +2576,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
Dispatcher.UIThread.Invoke(() => IsAutoFetching = true);
|
||||
foreach (var remote in remotes)
|
||||
new Commands.Fetch(_fullpath, remote, false, false, null) { RaiseError = false }.Exec();
|
||||
new Commands.Fetch(_fullpath, remote, false, false) { RaiseError = false }.Exec();
|
||||
_lastFetchTime = DateTime.Now;
|
||||
Dispatcher.UIThread.Invoke(() => IsAutoFetching = false);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Reset current branch to {To.SHA} ...";
|
||||
|
||||
var log = _repo.CreateLog($"Reset HEAD to '{To.SHA}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Reset(_repo.FullPath, To.SHA, SelectedMode.Arg).Exec();
|
||||
var succ = new Commands.Reset(_repo.FullPath, To.SHA, SelectedMode.Arg).Use(log).Exec();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -29,9 +29,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Revert commit '{Target.SHA}' ...";
|
||||
|
||||
var log = _repo.CreateLog($"Revert '{Target.SHA}'");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Exec();
|
||||
new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Use(log).Exec();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -37,9 +37,13 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Editing head commit message ...";
|
||||
|
||||
var log = _repo.CreateLog("Reword HEAD");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.Commit(_repo.FullPath, _message, true, _repo.Settings.EnableSignOffForCommit).Run();
|
||||
var succ = new Commands.Commit(_repo.FullPath, _message, true, _repo.Settings.EnableSignOffForCommit).Use(log).Run();
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace SourceGit.ViewModels
|
|||
subdir.Name.Equals(".idea", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
SetProgressDescription($"Scanning {subdir.FullName}...");
|
||||
CallUIThread(() => ProgressDescription = $"Scanning {subdir.FullName}...");
|
||||
|
||||
var normalizedSelf = subdir.FullName.Replace("\\", "/");
|
||||
if (_managed.Contains(normalizedSelf))
|
||||
|
|
|
@ -55,17 +55,22 @@ namespace SourceGit.ViewModels
|
|||
|
||||
public override Task<bool> Sure()
|
||||
{
|
||||
SetProgressDescription("Setting upstream...");
|
||||
ProgressDescription = "Setting upstream...";
|
||||
|
||||
var upstream = (_unset || SelectedRemoteBranch == null) ? string.Empty : SelectedRemoteBranch.FullName;
|
||||
if (upstream == Local.Upstream)
|
||||
return null;
|
||||
|
||||
var log = _repo.CreateLog("Set Upstream");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = Commands.Branch.SetUpstream(_repo.FullPath, Local.Name, upstream.Replace("refs/remotes/", ""));
|
||||
var succ = Commands.Branch.SetUpstream(_repo.FullPath, Local.Name, upstream.Replace("refs/remotes/", ""), log);
|
||||
if (succ)
|
||||
_repo.RefreshBranches();
|
||||
|
||||
log.Complete();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = "Squashing ...";
|
||||
|
||||
var log = _repo.CreateLog("Squash");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var autoStashed = false;
|
||||
|
@ -38,9 +41,10 @@ namespace SourceGit.ViewModels
|
|||
|
||||
if (_repo.LocalChangesCount > 0)
|
||||
{
|
||||
succ = new Commands.Stash(_repo.FullPath).Push("SQUASH_AUTO_STASH");
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).Push("SQUASH_AUTO_STASH");
|
||||
if (!succ)
|
||||
{
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return false;
|
||||
}
|
||||
|
@ -48,13 +52,14 @@ namespace SourceGit.ViewModels
|
|||
autoStashed = true;
|
||||
}
|
||||
|
||||
succ = new Commands.Reset(_repo.FullPath, Target.SHA, "--soft").Exec();
|
||||
succ = new Commands.Reset(_repo.FullPath, Target.SHA, "--soft").Use(log).Exec();
|
||||
if (succ)
|
||||
succ = new Commands.Commit(_repo.FullPath, _message, true, _repo.Settings.EnableSignOffForCommit).Run();
|
||||
succ = new Commands.Commit(_repo.FullPath, _message, true, _repo.Settings.EnableSignOffForCommit).Use(log).Run();
|
||||
|
||||
if (succ && autoStashed)
|
||||
new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
|
||||
new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -56,6 +56,9 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
ProgressDescription = $"Stash changes ...";
|
||||
|
||||
var log = _repo.CreateLog("Stash Local Changes");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = false;
|
||||
|
@ -66,7 +69,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_ONLY_STAGED)
|
||||
{
|
||||
succ = new Commands.Stash(_repo.FullPath).PushOnlyStaged(Message, KeepIndex);
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStaged(Message, KeepIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -77,22 +80,23 @@ namespace SourceGit.ViewModels
|
|||
staged.Add(c);
|
||||
}
|
||||
|
||||
succ = StashWithChanges(staged);
|
||||
succ = StashWithChanges(staged, log);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
succ = new Commands.Stash(_repo.FullPath).Push(Message, IncludeUntracked, KeepIndex);
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, IncludeUntracked, KeepIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
succ = StashWithChanges(_changes);
|
||||
succ = StashWithChanges(_changes, log);
|
||||
}
|
||||
|
||||
if (AutoRestore && succ)
|
||||
succ = new Commands.Stash(_repo.FullPath).Apply("stash@{0}", true);
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).Apply("stash@{0}", true);
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() =>
|
||||
{
|
||||
_repo.MarkWorkingCopyDirtyManually();
|
||||
|
@ -103,7 +107,7 @@ namespace SourceGit.ViewModels
|
|||
});
|
||||
}
|
||||
|
||||
private bool StashWithChanges(List<Models.Change> changes)
|
||||
private bool StashWithChanges(List<Models.Change> changes, CommandLog log)
|
||||
{
|
||||
if (changes.Count == 0)
|
||||
return true;
|
||||
|
@ -117,7 +121,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
File.WriteAllLines(tmpFile, paths);
|
||||
succ = new Commands.Stash(_repo.FullPath).Push(Message, tmpFile, KeepIndex);
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, tmpFile, KeepIndex);
|
||||
File.Delete(tmpFile);
|
||||
}
|
||||
else
|
||||
|
@ -126,7 +130,7 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
var count = Math.Min(10, changes.Count - i);
|
||||
var step = changes.GetRange(i, count);
|
||||
succ = new Commands.Stash(_repo.FullPath).Push(Message, step, KeepIndex);
|
||||
succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, step, KeepIndex);
|
||||
if (!succ)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ namespace SourceGit.ViewModels
|
|||
apply.Click += (_, ev) =>
|
||||
{
|
||||
if (_repo.CanCreatePopup())
|
||||
_repo.ShowPopup(new ApplyStash(_repo.FullPath, stash));
|
||||
_repo.ShowPopup(new ApplyStash(_repo, stash));
|
||||
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
@ -157,7 +157,7 @@ namespace SourceGit.ViewModels
|
|||
drop.Click += (_, ev) =>
|
||||
{
|
||||
if (_repo.CanCreatePopup())
|
||||
_repo.ShowPopup(new DropStash(_repo.FullPath, stash));
|
||||
_repo.ShowPopup(new DropStash(_repo, stash));
|
||||
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
|
|
@ -62,19 +62,21 @@ namespace SourceGit.ViewModels
|
|||
else
|
||||
targets = [SelectedSubmodule];
|
||||
|
||||
var log = _repo.CreateLog("Update Submodule");
|
||||
Use(log);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
foreach (var submodule in targets)
|
||||
{
|
||||
ProgressDescription = $"Updating submodule {submodule} ...";
|
||||
new Commands.Submodule(_repo.FullPath).Update(
|
||||
new Commands.Submodule(_repo.FullPath).Use(log).Update(
|
||||
submodule,
|
||||
EnableInit,
|
||||
EnableRecursive,
|
||||
EnableRemote,
|
||||
SetProgressDescription);
|
||||
EnableRemote);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return true;
|
||||
});
|
||||
|
|
27
src/ViewModels/ViewLogs.cs
Normal file
27
src/ViewModels/ViewLogs.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using Avalonia.Collections;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public class ViewLogs : ObservableObject
|
||||
{
|
||||
public AvaloniaList<CommandLog> Logs
|
||||
{
|
||||
get => _repo.Logs;
|
||||
}
|
||||
|
||||
public CommandLog SelectedLog
|
||||
{
|
||||
get => _selectedLog;
|
||||
set => SetProperty(ref _selectedLog, value);
|
||||
}
|
||||
|
||||
public ViewLogs(Repository repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
private Repository _repo = null;
|
||||
private CommandLog _selectedLog = null;
|
||||
}
|
||||
}
|
|
@ -711,7 +711,9 @@ namespace SourceGit.ViewModels
|
|||
assumeUnchanged.IsVisible = change.WorkTree != Models.ChangeState.Untracked;
|
||||
assumeUnchanged.Click += (_, e) =>
|
||||
{
|
||||
new Commands.AssumeUnchanged(_repo.FullPath).Add(change.Path);
|
||||
var log = _repo.CreateLog("Assume File Unchanged");
|
||||
new Commands.AssumeUnchanged(_repo.FullPath, change.Path, true).Use(log).Exec();
|
||||
log.Complete();
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -805,10 +807,12 @@ namespace SourceGit.ViewModels
|
|||
lfsTrackThisFile.Header = App.Text("GitLFS.Track", filename);
|
||||
lfsTrackThisFile.Click += async (_, e) =>
|
||||
{
|
||||
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track(filename, true));
|
||||
var log = _repo.CreateLog("Track LFS");
|
||||
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track(filename, true, log));
|
||||
if (succ)
|
||||
App.SendNotification(_repo.FullPath, $"Tracking file named {filename} successfully!");
|
||||
|
||||
log.Complete();
|
||||
e.Handled = true;
|
||||
};
|
||||
lfs.Items.Add(lfsTrackThisFile);
|
||||
|
@ -819,10 +823,12 @@ namespace SourceGit.ViewModels
|
|||
lfsTrackByExtension.Header = App.Text("GitLFS.TrackByExtension", extension);
|
||||
lfsTrackByExtension.Click += async (_, e) =>
|
||||
{
|
||||
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track("*" + extension));
|
||||
var log = _repo.CreateLog("Track LFS");
|
||||
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track("*" + extension, false, log));
|
||||
if (succ)
|
||||
App.SendNotification(_repo.FullPath, $"Tracking all *{extension} files successfully!");
|
||||
|
||||
log.Complete();
|
||||
e.Handled = true;
|
||||
};
|
||||
lfs.Items.Add(lfsTrackByExtension);
|
||||
|
@ -1581,9 +1587,11 @@ namespace SourceGit.ViewModels
|
|||
|
||||
IsStaging = true;
|
||||
_repo.SetWatcherEnabled(false);
|
||||
|
||||
var log = _repo.CreateLog("Stage");
|
||||
if (count == _unstaged.Count)
|
||||
{
|
||||
await Task.Run(() => new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Exec());
|
||||
await Task.Run(() => new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).Exec());
|
||||
}
|
||||
else if (Native.OS.GitVersion >= Models.GitVersions.ADD_WITH_PATHSPECFILE)
|
||||
{
|
||||
|
@ -1593,7 +1601,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
File.WriteAllLines(tmpFile, paths);
|
||||
await Task.Run(() => new Commands.Add(_repo.FullPath, tmpFile).Exec());
|
||||
await Task.Run(() => new Commands.Add(_repo.FullPath, tmpFile).Use(log).Exec());
|
||||
File.Delete(tmpFile);
|
||||
}
|
||||
else
|
||||
|
@ -1605,9 +1613,10 @@ namespace SourceGit.ViewModels
|
|||
for (int i = 0; i < count; i += 10)
|
||||
{
|
||||
var step = paths.GetRange(i, Math.Min(10, count - i));
|
||||
await Task.Run(() => new Commands.Add(_repo.FullPath, step).Exec());
|
||||
await Task.Run(() => new Commands.Add(_repo.FullPath, step).Use(log).Exec());
|
||||
}
|
||||
}
|
||||
log.Complete();
|
||||
_repo.MarkWorkingCopyDirtyManually();
|
||||
_repo.SetWatcherEnabled(true);
|
||||
IsStaging = false;
|
||||
|
@ -1624,22 +1633,26 @@ namespace SourceGit.ViewModels
|
|||
|
||||
IsUnstaging = true;
|
||||
_repo.SetWatcherEnabled(false);
|
||||
|
||||
var log = _repo.CreateLog("Unstage");
|
||||
if (_useAmend)
|
||||
{
|
||||
log.AppendLine("$ git update-index --index-info ");
|
||||
await Task.Run(() => new Commands.UnstageChangesForAmend(_repo.FullPath, changes).Exec());
|
||||
}
|
||||
else if (count == _staged.Count)
|
||||
{
|
||||
await Task.Run(() => new Commands.Reset(_repo.FullPath).Exec());
|
||||
await Task.Run(() => new Commands.Reset(_repo.FullPath).Use(log).Exec());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i += 10)
|
||||
{
|
||||
var step = changes.GetRange(i, Math.Min(10, count - i));
|
||||
await Task.Run(() => new Commands.Reset(_repo.FullPath, step).Exec());
|
||||
await Task.Run(() => new Commands.Reset(_repo.FullPath, step).Use(log).Exec());
|
||||
}
|
||||
}
|
||||
log.Complete();
|
||||
_repo.MarkWorkingCopyDirtyManually();
|
||||
_repo.SetWatcherEnabled(true);
|
||||
IsUnstaging = false;
|
||||
|
@ -1703,14 +1716,17 @@ namespace SourceGit.ViewModels
|
|||
_repo.Settings.PushCommitMessage(_commitMessage);
|
||||
_repo.SetWatcherEnabled(false);
|
||||
|
||||
var log = _repo.CreateLog("Commit");
|
||||
Task.Run(() =>
|
||||
{
|
||||
var succ = true;
|
||||
if (autoStage && _unstaged.Count > 0)
|
||||
succ = new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Exec();
|
||||
succ = new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).Exec();
|
||||
|
||||
if (succ)
|
||||
succ = new Commands.Commit(_repo.FullPath, _commitMessage, _useAmend, _repo.Settings.EnableSignOffForCommit).Run();
|
||||
succ = new Commands.Commit(_repo.FullPath, _commitMessage, _useAmend, _repo.Settings.EnableSignOffForCommit).Use(log).Run();
|
||||
|
||||
log.Complete();
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
<Path Width="13" Height="13" Data="{StaticResource Icons.Terminal}"/>
|
||||
</Button>
|
||||
|
||||
<Button Classes="icon_button" Width="32" Click="OpenGitLogs" ToolTip.Tip="{DynamicResource Text.Repository.ViewLogs}">
|
||||
<Path Width="14" Height="14" Margin="0,1,0,0" Data="{StaticResource Icons.Logs}"/>
|
||||
</Button>
|
||||
|
||||
<Button Classes="icon_button" Width="32" Click="OpenStatistics" ToolTip.Tip="{DynamicResource Text.Repository.Statistics}">
|
||||
<Path Width="13" Height="13" Data="{StaticResource Icons.Statistics}"/>
|
||||
</Button>
|
||||
|
@ -102,7 +106,7 @@
|
|||
|
||||
<Button Classes="icon_button" Width="32" Margin="8,0,0,0" Command="{Binding Cleanup}" ToolTip.Tip="{DynamicResource Text.Repository.Clean}">
|
||||
<Path Width="14" Height="14" Margin="0,1,0,0" Data="{StaticResource Icons.Clean}"/>
|
||||
</Button>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,4,0">
|
||||
|
|
|
@ -128,6 +128,16 @@ namespace SourceGit.Views
|
|||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void OpenGitLogs(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Repository repo && TopLevel.GetTopLevel(this) is Window owner)
|
||||
{
|
||||
var dialog = new ViewLogs() { DataContext = new ViewModels.ViewLogs(repo) };
|
||||
await dialog.ShowDialog(owner);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1972,7 +1972,7 @@ namespace SourceGit.Views
|
|||
|
||||
if (!selection.HasLeftChanges)
|
||||
{
|
||||
Commands.Discard.Changes(repo.FullPath, [change]);
|
||||
Commands.Discard.Changes(repo.FullPath, [change], null);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
112
src/Views/ViewLogs.axaml
Normal file
112
src/Views/ViewLogs.axaml
Normal file
|
@ -0,0 +1,112 @@
|
|||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.ViewLogs"
|
||||
x:DataType="vm:ViewLogs"
|
||||
x:Name="ThisControl"
|
||||
Title="{DynamicResource Text.ViewLogs}"
|
||||
Icon="/App.ico"
|
||||
Width="800" Height="500"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" Height="28" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
|
||||
<Border Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<Path Width="14" Height="14"
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Data="{StaticResource Icons.Logs}"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
|
||||
<TextBlock Classes="bold"
|
||||
Text="{DynamicResource Text.ViewLogs}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<v:CaptionButtons HorizontalAlignment="Right"
|
||||
IsCloseButtonOnly="True"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Row="1" ColumnDefinitions="300,4,*" Margin="8">
|
||||
<ListBox Grid.Column="0"
|
||||
Padding="4"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
ItemsSource="{Binding Logs}"
|
||||
SelectedItem="{Binding SelectedLog, Mode=TwoWay}"
|
||||
SelectionMode="Single"
|
||||
Grid.IsSharedSizeScope="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel Orientation="Vertical"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="vm:CommandLog">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="SearchCommitTimeColumn"/>
|
||||
<ColumnDefinition Width="28"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Classes="primary"
|
||||
Text="{Binding Name}"
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
|
||||
<v:LoadingIcon Grid.Column="1"
|
||||
Width="14" Height="14"
|
||||
Margin="2,0,0,0"
|
||||
IsVisible="{Binding !IsComplete}"/>
|
||||
|
||||
<TextBlock Grid.Column="2"
|
||||
Classes="primary"
|
||||
Margin="4,0"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
Text="{Binding TimeStr}"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"/>
|
||||
|
||||
<Button Grid.Column="3" Classes="icon_button" Click="OnRemoveLog">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Border Grid.Column="2"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
BorderThickness="1"
|
||||
Background="{DynamicResource Brush.Contents}">
|
||||
<v:LogContentPresenter Log="{Binding SelectedLog}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</v:ChromelessWindow>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue