feature: simple interactive rebase support (#188)

* Only allow to start interactive rebase from merged commit in current branch
* The order of commits in the interactive rebase window is as same as it's in histories page.
* Unlike anthor git frontend app `Fork`, you should edit the final message on the last commit rather than the  previous commit that will be meld into while squashing commits
This commit is contained in:
leo 2024-06-20 17:02:12 +08:00
parent 6c9f7e6da3
commit 7070a07e15
No known key found for this signature in database
17 changed files with 816 additions and 7 deletions

View file

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace SourceGit.Models
{
public enum InteractiveRebaseAction
{
Pick,
Edit,
Reword,
Squash,
Fixup,
Drop,
}
public class InteractiveRebaseJob
{
public string SHA { get; set; } = string.Empty;
public InteractiveRebaseAction Action { get; set; } = InteractiveRebaseAction.Pick;
public string Message { get; set; } = string.Empty;
}
public static class InteractiveRebaseEditor
{
public static int Process(string file)
{
File.AppendAllLines("E:\\unknown.txt", ["------------", file]);
try
{
var filename = Path.GetFileName(file);
if (filename.Equals("git-rebase-todo", StringComparison.OrdinalIgnoreCase))
{
File.AppendAllLines("E:\\unknown.txt", ["git-rebase-todo start"]);
var dirInfo = new DirectoryInfo(Path.GetDirectoryName(file));
if (!dirInfo.Exists || !dirInfo.Name.Equals("rebase-merge", StringComparison.Ordinal))
{
File.WriteAllLines("E:\\test.txt", ["git-rebase-todo", file]);
return -1;
}
var jobsFile = Path.Combine(dirInfo.Parent.FullName, "sourcegit_rebase_jobs.json");
if (!File.Exists(jobsFile))
{
File.WriteAllLines("E:\\test.txt", ["git-rebase-todo", file, jobsFile]);
return -1;
}
var jobs = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.ListInteractiveRebaseJob);
var lines = new List<string>();
foreach (var job in jobs)
{
switch (job.Action)
{
case InteractiveRebaseAction.Pick:
lines.Add($"p {job.SHA}");
break;
case InteractiveRebaseAction.Edit:
lines.Add($"e {job.SHA}");
break;
case InteractiveRebaseAction.Reword:
lines.Add($"r {job.SHA}");
break;
case InteractiveRebaseAction.Squash:
lines.Add($"s {job.SHA}");
break;
case InteractiveRebaseAction.Fixup:
lines.Add($"f {job.SHA}");
break;
default:
lines.Add($"d {job.SHA}");
break;
}
}
File.AppendAllLines("E:\\unknown.txt", ["git-rebase-todo end"]);
File.WriteAllLines(file, lines);
}
else if (filename.Equals("COMMIT_EDITMSG", StringComparison.OrdinalIgnoreCase))
{
File.AppendAllLines("E:\\unknown.txt", ["COMMIT_EDITMSG start"]);
var jobsFile = Path.Combine(Path.GetDirectoryName(file), "sourcegit_rebase_jobs.json");
if (!File.Exists(jobsFile))
return 0;
var jobs = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.ListInteractiveRebaseJob);
var doneFile = Path.Combine(Path.GetDirectoryName(file), "rebase-merge", "done");
if (!File.Exists(doneFile))
return -1;
var done = File.ReadAllText(doneFile).Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
if (done.Length > jobs.Count)
return -1;
var job = jobs[done.Length - 1];
File.WriteAllText(file, job.Message);
File.AppendAllLines("E:\\unknown.txt", ["COMMIT_EDITMSG end", File.ReadAllText(doneFile).ReplaceLineEndings("|")]);
}
else
{
File.AppendAllLines("E:\\unknown.txt", [file]);
}
return 0;
}
catch
{
return -1;
}
}
}
}