I am performing a rebase operation with libgit2sharp and it works all nice, but I and would like to skip a rebase step when a conflict occurs (if the commit has a specific message)
rebaseResult = _repository.Rebase.Start(branch, GetBranch(requiredBaseBranch), null, new Identity(_configuration.CommitUserName, _configuration.CommitEmailAddress), options);
if (rebaseResult.Status == RebaseStatus.Complete)
return true;
else
{
if (rebaseResult.Status == RebaseStatus.Conflicts)
{
var currentStep = _repository.Rebase.GetCurrentStepInfo();
if (currentStep.Commit.Message.Trim().EndsWith("Update packages", StringComparison.OrdinalIgnoreCase))
{
//is it possible to somehow skip and continue?
}
}
}
Is it possible? I had a look and the API doesn't seem to support it directly, but perhaps there is some more convoluted way to achieve this...
I ended up writing a small command line based class that skips the rebase. Posting the full solution that worked for me, for future reference:
public class PoorManRebaseMachine
{
private readonly Action<string, ConsoleColor> _logDelegate;
private readonly string _localRepoPath;
public PoorManRebaseMachine(string localRepoPath, Action<string, ConsoleColor> logDelegate)
{
_logDelegate = logDelegate;
_localRepoPath = localRepoPath;
}
public bool TryPoorManRebase(string storyNumber)
{
var errorOutput = RunGitCommandProcess("rebase master");
if (IsUpdatePackagesRebaseConflict(errorOutput, storyNumber))
{
try
{
return TrySkippingUpdatePackagesCommitsRecursive(storyNumber, errorOutput);
}
catch ( ex)
{
_logDelegate($" while attempting automated rebase: {ex}", ConsoleColor.Red);
return false;
}
}
_logDelegate($"Will not attempt automated rebase due to a conflict not resolvable automatically: {errorOutput}", ConsoleColor.Red);
return false;
}
private bool TrySkippingUpdatePackagesCommitsRecursive(string storyNumber, string lastError)
{
if (IsUpdatePackagesRebaseConflict(lastError, storyNumber))
{
_logDelegate($"{GetRebaseStepNumber(lastError)} - Skipping rebase of: {GetRebaseConflictInfo(lastError)}", ConsoleColor.Cyan);
var errorOutput = RunGitCommandProcess("rebase --skip");
if (errorOutput.Contains("Successfully rebased and updated"))
{
_logDelegate($"Automated rebase done: {errorOutput}", ConsoleColor.Green);
return true;
}
_logDelegate($"{GetRebaseStepNumber(lastError)} - DONE, Starting {GetRebaseStepNumber(errorOutput)}", ConsoleColor.DarkCyan);
return TrySkippingUpdatePackagesCommitsRecursive(storyNumber, errorOutput);
}
throw new InvalidOperation($"The rebase conflict {lastError} cannot be solved automatically");
}
private static bool IsUpdatePackagesRebaseConflict(string conflictMessage, string storyNumber) => System.Text.RegularExpressions.Regex.IsMatch(conflictMessage, $"Could not apply .+... {storyNumber}[ -]*Update packages");
private static string GetRebaseStepNumber(string conflictMessage) => conflictMessage.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
private static string GetRebaseConflictInfo(string conflictMessage)
{
var line = conflictMessage.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries).LastOrDefault();
return line?.Replace("Could not apply ", "");
}
private string RunGitCommandProcess(string commandName)
{
var p = new Process();
var si = new ProcessStartInfo("git", commandName)
{
WorkingDirectory = _localRepoPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
p.StartInfo = si;
p.Start();
_ = p.StandardOutput.ReadToEnd(); //need to read output, as without it sometimes the process hangs on reading error
var errorOutput = p.StandardError.ReadToEnd();
p.WaitForExit();
return errorOutput;
}
}