Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 3 additions & 93 deletions src/Files.App/Utils/Git/GitHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ internal static partial class GitHelpers
/// <inheritdoc cref="IVersionControl.GetRepositoryHead(string?)"/>
public static Task<BranchItem?> GetRepositoryHead(string? path) => _implementation.GetRepositoryHead(path);

/// <inheritdoc cref="IVersionControl.Checkout(string?, string?)"/>
public static Task<bool> Checkout(string? repositoryPath, string? branch) => _implementation.Checkout(repositoryPath, branch);

#region Legacy implementation

// Property already moved into abstraction
Expand Down Expand Up @@ -95,99 +98,6 @@ private set
// Event handler already moved into abstraction
public static event EventHandler? GitFetchCompleted;

public static async Task<bool> Checkout(string? repositoryPath, string? branch)
{
SentrySdk.Experimental.Metrics.EmitCounter("Triggered git checkout", 1);

if (string.IsNullOrWhiteSpace(repositoryPath) || !IsRepoValid(repositoryPath))
return false;

using var repository = new Repository(repositoryPath);
var checkoutBranch = repository.Branches[branch];
if (checkoutBranch is null)
return false;

var options = new CheckoutOptions();
var isBringingChanges = false;

IsExecutingGitAction = true;

if (repository.Index.Conflicts.Any())
{
var dialog = DynamicDialogFactory.GetFor_GitMergeConflicts(checkoutBranch.FriendlyName, repository.Head.FriendlyName);
await dialog.ShowAsync();

var resolveConflictOption = (GitCheckoutOptions)dialog.ViewModel.AdditionalData;

switch (resolveConflictOption)
{
case GitCheckoutOptions.None:
IsExecutingGitAction = false;
return false;
case GitCheckoutOptions.AbortMerge:
repository.Reset(ResetMode.Hard);
break;
}
}
else if (repository.RetrieveStatus().IsDirty)
{
var dialog = DynamicDialogFactory.GetFor_GitCheckoutConflicts(checkoutBranch.FriendlyName, repository.Head.FriendlyName);
await dialog.ShowAsync();

var resolveConflictOption = (GitCheckoutOptions)dialog.ViewModel.AdditionalData;

switch (resolveConflictOption)
{
case GitCheckoutOptions.None:
IsExecutingGitAction = false;
return false;
case GitCheckoutOptions.DiscardChanges:
options.CheckoutModifiers = CheckoutModifiers.Force;
break;
case GitCheckoutOptions.BringChanges:
case GitCheckoutOptions.StashChanges:
var signature = repository.Config.BuildSignature(DateTimeOffset.Now);
if (signature is null)
{
IsExecutingGitAction = false;
return false;
}

repository.Stashes.Add(signature);

isBringingChanges = resolveConflictOption is GitCheckoutOptions.BringChanges;
break;
}
}

var result = await DoGitOperationAsync<GitOperationResult>(() =>
{
try
{
if (checkoutBranch.IsRemote)
CheckoutRemoteBranch(repository, checkoutBranch);
else
LibGit2Sharp.Commands.Checkout(repository, checkoutBranch, options);

if (isBringingChanges)
{
var lastStashIndex = repository.Stashes.Count() - 1;
repository.Stashes.Pop(lastStashIndex, new StashApplyOptions());
}
}
catch (Exception)
{
return GitOperationResult.GenericError;
}

return GitOperationResult.Success;
});

IsExecutingGitAction = false;

return result is GitOperationResult.Success;
}

public static async Task CreateNewBranchAsync(string repositoryPath, string activeBranch)
{
SentrySdk.Experimental.Metrics.EmitCounter("Triggered create git branch", 1);
Expand Down
94 changes: 94 additions & 0 deletions src/Files.App/Utils/Git/LibGit2.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using Sentry;
using System.Text;
using System.Text.RegularExpressions;

Expand Down Expand Up @@ -159,6 +160,99 @@ public async Task<BranchItem[]> GetBranchNames(string? path)
return returnValue;
}

public async Task<bool> Checkout(string? repositoryPath, string? branch)
{
SentrySdk.Experimental.Metrics.EmitCounter("Triggered git checkout", 1);

if (string.IsNullOrWhiteSpace(repositoryPath) || !IsRepoValid(repositoryPath))
return false;

using var repository = new Repository(repositoryPath);
var checkoutBranch = repository.Branches[branch];
if (checkoutBranch is null)
return false;

var options = new CheckoutOptions();
var isBringingChanges = false;

IsExecutingGitAction = true;

if (repository.Index.Conflicts.Any())
{
var dialog = DynamicDialogFactory.GetFor_GitMergeConflicts(checkoutBranch.FriendlyName, repository.Head.FriendlyName);
await dialog.ShowAsync();

var resolveConflictOption = (GitCheckoutOptions)dialog.ViewModel.AdditionalData;

switch (resolveConflictOption)
{
case GitCheckoutOptions.None:
IsExecutingGitAction = false;
return false;
case GitCheckoutOptions.AbortMerge:
repository.Reset(ResetMode.Hard);
break;
}
}
else if (repository.RetrieveStatus().IsDirty)
{
var dialog = DynamicDialogFactory.GetFor_GitCheckoutConflicts(checkoutBranch.FriendlyName, repository.Head.FriendlyName);
await dialog.ShowAsync();

var resolveConflictOption = (GitCheckoutOptions)dialog.ViewModel.AdditionalData;

switch (resolveConflictOption)
{
case GitCheckoutOptions.None:
IsExecutingGitAction = false;
return false;
case GitCheckoutOptions.DiscardChanges:
options.CheckoutModifiers = CheckoutModifiers.Force;
break;
case GitCheckoutOptions.BringChanges:
case GitCheckoutOptions.StashChanges:
var signature = repository.Config.BuildSignature(DateTimeOffset.Now);
if (signature is null)
{
IsExecutingGitAction = false;
return false;
}

repository.Stashes.Add(signature);

isBringingChanges = resolveConflictOption is GitCheckoutOptions.BringChanges;
break;
}
}

var result = await DoGitOperationAsync<GitOperationResult>(() =>
{
try
{
if (checkoutBranch.IsRemote)
CheckoutRemoteBranch(repository, checkoutBranch);
else
LibGit2Sharp.Commands.Checkout(repository, checkoutBranch, options);

if (isBringingChanges)
{
var lastStashIndex = repository.Stashes.Count() - 1;
repository.Stashes.Pop(lastStashIndex, new StashApplyOptions());
}
}
catch (Exception)
{
return GitOperationResult.GenericError;
}

return GitOperationResult.Success;
});

IsExecutingGitAction = false;

return result is GitOperationResult.Success;
}

private static bool IsRepoValid(string path)
{
return SafetyExtensions.IgnoreExceptions(() => Repository.IsValid(path));
Expand Down
Loading