public async Task <R> UndoUncommittedFileAsync(string path, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"checkout --force -- \"{path}\"", CancellationToken.None); if (result.IsFaulted) { if (IsFileUnkwon(result, path)) { R deleteResult = DeleteFile(path, result); if (deleteResult.IsFaulted) { return(R.Error($"Failed to delete {path}", deleteResult.Exception)); } Log.Info($"Undid file {path}"); return(R.Ok); } return(R.Error($"Failed to undo file {path}", result.AsException())); } Log.Info($"Undid file {path}"); return(R.Ok); }
public async Task <R <string> > GetFileDiffAsync(string sha, string path, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"diff --patch --root --find-renames --unified=100000 {sha}^..{sha} -- \"{path}\" ", ct); if (result.IsFaulted) { if (result.Error.StartsWith("fatal: ambiguous argument")) { // Failed to get diff for sha, might be root commit, so try again CmdResult2 showRootResult = await gitCmdService.RunCmdAsync( $"show --patch --root {sha} -- \"{path}\"", ct); if (showRootResult.IsOk) { Log.Info($"Got file diff patch for root {sha}"); return(R.From(showRootResult.Output)); } } return(R.Error($"Failed to get file diff for {sha}", result.AsException())); } Log.Info($"Got path for {sha}"); return(R.From(result.Output)); }
private async Task <R <IReadOnlyList <string> > > UndoAndCleanFolderAsync( string cleanArgs, CancellationToken ct) { R <CmdResult2> result = await gitCmdService.RunAsync("reset --hard", ct); if (result.IsFaulted) { return(R.Error("Reset failed.", result.Exception)); } CmdResult2 cleanResult = await gitCmdService.RunCmdAsync($"clean {cleanArgs}", ct); if (cleanResult.IsFaulted) { if (IsFailedToRemoveSomeFiles(cleanResult, out IReadOnlyList <string> failedFiles)) { Log.Warn($"Failed to clean {failedFiles.Count} files"); return(R.From(failedFiles)); } return(R.Error(cleanResult.AsException())); } return(R.From(EmptyFileList)); }
public async Task <R> FetchRefsAsync(IEnumerable <string> refspecs, CancellationToken ct) { string refsText = string.Join(" ", refspecs); string args = $"{FetchRefsArgs} {refsText}"; Log.Debug($"Fetching {refsText} ..."); void Progress(string text) { Log.Debug($"Progress: {text}"); } CmdResult2 result = await gitCmdService.RunCmdWitProgressAsync(args, Progress, ct); if (result.IsFaulted) { if (IsNoRemote(result)) { return(R.Ok); } return(R.Error("Failed to fetch", result.AsException())); } return(R.Ok); }
private async Task <CmdResult2> RunGitCmsAsync( string gitArgs, GitOptions options, string sessionId, CancellationToken ct) { AdjustOptions(options, sessionId); // Log.Debug($"Running: {GitCmdPath} {gitArgs}"); CmdOptions cmdOptions = ToCmdOptions(options); string gitCmdPath = GitCmdPath; CmdResult2 result = await cmd.RunAsync(gitCmdPath, gitArgs, cmdOptions, ct); if (result.IsFaulted && !result.IsCanceled && !(result.ExitCode == 1 && string.IsNullOrEmpty(result.Error))) { Track.Event("Git-error", $"{result.ElapsedMs}ms: Exit {result.ExitCode}: {result.Command} {result.Arguments}\nError:\n{result.ErrorMessage}"); } else { Track.Event("Git", $"{result.ElapsedMs}ms: {result.Command} {result.Arguments}"); var replace = result.ToString().Replace($"\"{gitCmdPath}\"", "git"); Log.Debug($"{result.ElapsedMs}ms: {replace}"); } return(result); }
private static bool IsFailedToRemoveSomeFiles(CmdResult2 result, out IReadOnlyList <string> failedFiles) { // Check if error message contains any "warning: failed to remove <file>:" failedFiles = CleanOutputRegEx.Matches(result.Error).OfType <Match>() .Select(match => match.Groups[1].Value).ToList(); return(failedFiles.Any()); }
private string TryGetCmdVersion(string cmdPath) { CmdResult2 result = cmd.Run(cmdPath, "version"); return(result.ExitCode == 0 && result.Output.StartsWithOic("git version ") ? result.Output.Substring(12).Trim() : null); }
private R <CmdResult2> AsR(CmdResult2 result) { if (result.IsFaulted) { Error error = R.Error(result.AsException()); return(error); } return(result); }
public async Task <R> RemoveAsync(string path, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync($"rm \"{path}\"", ct); if (result.IsFaulted) { return(R.Error($"Failed remove {path}", result.AsException())); } return(R.Ok); }
public async Task <R <GitTag> > AddTagAsync(string sha, string tagName, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync($"tag {tagName} {sha}", ct); if (result.IsFaulted) { return(R.Error($"Failed to add tag {tagName} at {sha}", result.AsException())); } Log.Info($"Added {tagName} at {sha}"); return(new GitTag(sha, tagName)); }
public async Task <R> RemoveNoteAsync(string sha, string notesRef, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"-c core.notesRef={notesRef} notes remove --ignore-missing {sha}", ct); if (result.IsFaulted) { return(R.Error("Failed to remove note", result.AsException())); } Log.Info($"Removed note"); return(R.Ok); }
public async Task <R> PushAsync(CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync(PushArgs, ct); if (result.IsFaulted) { if (IsNoRemoteBranch(result)) { return(R.Ok); } return(R.Error("Failed to push", result.AsException())); } return(R.Ok); }
public async Task <R> AppendNoteAsync( string sha, string notesRef, string note, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"-c core.notesRef={notesRef} notes append --allow-empty -m\"{note}\" {sha}", ct); if (result.IsFaulted) { return(R.Error("Failed to add note", result.AsException())); } Log.Info($"Added note {note.Length} length"); return(R.Ok); }
public async Task <R> PushDeleteRemoteBranchAsync(string branchName, CancellationToken ct) { Log.Debug($"Pushing delete branch {branchName} ..."); CmdResult2 result = await gitCmdService.RunCmdAsync($"{PushArgs} --delete {branchName}", ct); if (result.IsFaulted) { if (IsNoRemote(result)) { return(R.Ok); } return(R.Error("Failed to push", result.AsException())); } return(R.Ok); }
private static bool GetMergeStatus(CmdResult2 result, out string mergeMessage) { bool isMergeInProgress = false; mergeMessage = null; string mergeIpPath = Path.Combine(result.WorkingDirectory, ".git", "MERGE_HEAD"); string mergeMsgPath = Path.Combine(result.WorkingDirectory, ".git", "MERGE_MSG"); if (File.Exists(mergeIpPath)) { isMergeInProgress = true; mergeMessage = File.ReadAllText(mergeMsgPath).Trim(); } return(isMergeInProgress); }
private IReadOnlyList <GitFile> ParseFiles(CmdResult2 result) { List <GitFile> files = new List <GitFile>(); foreach (string line in result.OutputLines) { string filePath = line.Substring(2).Trim(); GitFileStatus status = GitFileStatus.Modified; if (line.StartsWith("DD ") || line.StartsWith("AU ") || line.StartsWith("UA ")) { // How to do reproduce this ??? status = GitFileStatus.Conflict; } else if (line.StartsWith("UU ")) { status = GitFileStatus.Conflict | GitFileStatus.ConflictMM; } else if (line.StartsWith("AA ")) { status = GitFileStatus.Conflict | GitFileStatus.ConflictAA; } else if (line.StartsWith("UD ")) { status = GitFileStatus.Conflict | GitFileStatus.ConflictMD; } else if (line.StartsWith("DU ")) { status = GitFileStatus.Conflict | GitFileStatus.ConflictDM; } else if (line.StartsWith("?? ") || line.StartsWith(" A ")) { status = GitFileStatus.Added; } else if (line.StartsWith(" D ") || line.StartsWith("D")) { status = GitFileStatus.Deleted; } files.Add(new GitFile(result.WorkingDirectory, filePath, null, status)); } return(files); }
public async Task <R <IReadOnlyList <GitTag> > > GetAllTagsAsync(CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync("show-ref -d --tags", ct); if (result.IsFaulted) { if (!(result.ExitCode == 1 && string.IsNullOrEmpty(result.Output))) { return(R.Error("Failed to list tags", result.AsException())); } } IReadOnlyList <GitTag> tags = ParseTags(result); Log.Info($"Got {tags.Count} tags"); return(R.From(tags)); }
public async Task <R <IReadOnlyList <string> > > GetRefsIdsAsync(CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync("show-ref", ct); if (result.IsFaulted) { if (result.ExitCode != 1) { return(R.Error("Failed to get refs", result.AsException())); } } IReadOnlyList <string> refs = result.OutputLines.ToList(); Log.Info($"Got {refs.Count} refs"); return(R.From(refs)); }
public async Task <R> PushTagAsync(string tagName, CancellationToken ct) { Log.Debug($"Pushing tag {tagName} ..."); CmdResult2 result = await gitCmdService.RunCmdAsync($"{PushArgs} {tagName}", ct); if (result.IsFaulted) { if (IsNoRemote(result)) { return(R.Ok); } return(R.Error("Failed to push tag", result.AsException())); } return(R.Ok); }
private GitConflicts ParseConflicts(CmdResult2 result) { List <GitConflictFile> files = new List <GitConflictFile>(); string filePath = null; string baseId = null; string localId = null; string remoteId = null; // Parsing lines, where there are 1,2 or 3 lines for one file before the next file lines foreach (string line in result.OutputLines) { string[] parts1 = line.Split("\t".ToCharArray()); string[] parts2 = parts1[0].Split(" ".ToCharArray()); string path = parts1[1].Trim(); if (path != filePath && filePath != null) { // Next file, store previous file GitFileStatus status = GetConflictStatus(baseId, localId, remoteId); if (status.HasFlag(GitFileStatus.Conflict)) { files.Add(new GitConflictFile(result.WorkingDirectory, filePath, baseId, localId, remoteId, status)); } baseId = null; localId = null; remoteId = null; } filePath = path; SetIds(parts2, ref baseId, ref localId, ref remoteId); } if (filePath != null) { // Add last file GitFileStatus status = GetConflictStatus(baseId, localId, remoteId); if (status.HasFlag(GitFileStatus.Conflict)) { files.Add(new GitConflictFile(result.WorkingDirectory, filePath, baseId, localId, remoteId, status)); } } return(new GitConflicts(files)); }
private static R DeleteFile(string path, CmdResult2 result) { try { string fullPath = Path.Combine(result.WorkingDirectory, path); if (File.Exists(fullPath)) { File.Delete(fullPath); Log.Debug($"Deleted {fullPath}"); } return(R.Ok); } catch (Exception e) { return(R.Error(e)); } }
public async Task <R <bool> > TryCheckoutAsync(string name, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync($"checkout --progress {name}", ct); if (result.IsFaulted) { if (IsUnknownName(result, name)) { Log.Info($"Unknown name: {name}"); return(false); } return(R.Error($"Failed to checkout {name}", result.AsException())); } Log.Info($"Checked out {name}"); return(true); }
public async Task <R> PushBranchAsync(string branchName, CancellationToken ct) { Log.Debug($"Pushing branch {branchName} ..."); string args = $"{PushArgs} -u refs/heads/{branchName}:refs/heads/{branchName}"; CmdResult2 result = await gitCmdService.RunCmdAsync(args, ct); if (result.IsFaulted) { if (IsNoRemote(result)) { return(R.Ok); } return(R.Error("Failed to push", result.AsException())); } return(R.Ok); }
public async Task <R> PushRefsAsync(IEnumerable <string> refspecs, CancellationToken ct) { string refsText = string.Join(" ", refspecs); Log.Debug($"Pushing refs {refsText} ..."); CmdResult2 result = await gitCmdService.RunCmdAsync($"{PushArgs} {refsText}", ct); if (result.IsFaulted) { if (IsNoRemote(result)) { return(R.Ok); } return(R.Error("Failed to push", result.AsException())); } return(R.Ok); }
private GitStatus ParseStatus(CmdResult2 result) { //if (result.Output.StartsWith("## No commits yet on")) //{ // return GitStatus2.Default; //} IReadOnlyList <GitFile> files = ParseFiles(result); int added = files.Count(file => file.Status.HasFlag(GitFileStatus.Added)); int deleted = files.Count(file => file.Status.HasFlag(GitFileStatus.Deleted)); int conflicted = files.Count(file => file.Status.HasFlag(GitFileStatus.Conflict)); int modified = files.Count - (added + deleted + conflicted); bool isMergeInProgress = GetMergeStatus(result, out string mergeMessage); return(new GitStatus( modified, added, deleted, conflicted, isMergeInProgress, mergeMessage, files)); }
public async Task <R> MergeAsync(string name, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"merge --no-ff --no-commit --stat --progress {name}", ct); if (result.IsFaulted) { if (result.ExitCode == 1 && IsConflicts(result)) { Log.Info($"Merge of {name} resulted in conflict(s)"); return(R.Ok); } return(R.Error($"Failed to merge branch {name}", result.AsException())); } Log.Info($"Merge of {name} was OK"); return(R.Ok); }
public async Task <R <bool> > TryMergeFastForwardAsync(string name, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"merge --ff-only --stat --progress {name}", ct); if (result.IsFaulted) { if (result.Error.StartsWith("fatal: Not possible to fast-forward")) { Log.Info($"Merge of {name} could not be fast forward merged"); return(false); } return(R.Error($"Failed to ff merge branch {name}", result.AsException())); } Log.Info($"Merge of {name} was OK"); return(true); }
public async Task <R <string> > GetNoteAsync(string sha, string notesRef, CancellationToken ct) { CmdResult2 result = await gitCmdService.RunCmdAsync( $"-c core.notesRef={notesRef} notes show {sha}", ct); if (result.IsFaulted) { if (result.ExitCode == 1 && result.Error.StartsWith($"error: no note found for object {sha}")) { return(R.NoValue); } return(R.Error("Failed to get note", result.AsException())); } string notes = result.Output; Log.Info($"Got note {notes.Length} length"); return(notes); }
public async Task <R> AddNoteAsync( string sha, string notesRef, string note, CancellationToken ct) { Log.Debug($"Adding {note.Length}chars on {sha} {notesRef} ..."); string filePath = Path.GetTempFileName(); File.WriteAllText(filePath, note); CmdResult2 result = await gitCmdService.RunCmdAsync( $"-c core.notesRef={notesRef} notes add -f --allow-empty -F \"{filePath}\" {sha}", ct); DeleteNotesFile(filePath); if (result.IsFaulted) { return(R.Error("Failed to add note", result.AsException())); } Log.Info($"Added note {note.Length} length"); return(R.Ok); }
public async Task <R> FetchAsync(CancellationToken ct) { Log.Debug("Fetching ..."); void Progress(string text) { Log.Debug($"Progress: {text}"); } CmdResult2 result = await gitCmdService.RunCmdWitProgressAsync(FetchArgs, Progress, ct); if (result.IsFaulted) { if (IsNoRemote(result)) { return(R.Ok); } return(R.Error("Failed to fetch", result.AsException())); } return(R.Ok); }