feat(worker): record merge commit SHA and add revert_merge tool
Persists the merge commit SHA on WorktreeEntity for every successful single-task and unit merge, and adds a TaskMergeService.RevertMergeAsync + revert_merge MCP tool that undoes a merged task's merge via `git revert -m 1` (never reset/rewrite, since the target checkout is shared). Rejects cleanly when there's no recorded SHA, the repo is mid-merge/mid-revert, or the target has foreign uncommitted changes; a conflicting revert aborts immediately. Also exposes the new mergeCommit field via get_task_worktree.
This commit is contained in:
@@ -280,6 +280,36 @@ public sealed class GitService
|
||||
throw new InvalidOperationException($"git merge --abort failed (exit {exitCode}): {stderr}");
|
||||
}
|
||||
|
||||
public async Task<bool> IsMidRevertAsync(string repoDir, CancellationToken ct = default)
|
||||
{
|
||||
var (exitCode, stdout, _) = await RunGitAsync(repoDir, ["rev-parse", "--git-dir"], ct);
|
||||
if (exitCode != 0) return false;
|
||||
var gitDir = stdout.Trim();
|
||||
if (!Path.IsPathRooted(gitDir))
|
||||
gitDir = Path.Combine(repoDir, gitDir);
|
||||
return File.Exists(Path.Combine(gitDir, "REVERT_HEAD"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverts a single commit with `-m 1` (diff against its first parent) — the form needed to
|
||||
/// revert a merge commit. On success this creates a new commit with the inverse changes;
|
||||
/// the original commit and all history stay intact (no rewrite, no reset).
|
||||
/// </summary>
|
||||
public async Task<(int ExitCode, string Stderr)> RevertMergeCommitAsync(
|
||||
string repoDir, string mergeCommitSha, CancellationToken ct = default)
|
||||
{
|
||||
var (exitCode, _, stderr) = await RunGitAsync(repoDir,
|
||||
["-c", "merge.conflictStyle=diff3", "revert", "--no-edit", "-m", "1", mergeCommitSha], ct);
|
||||
return (exitCode, stderr);
|
||||
}
|
||||
|
||||
public async Task RevertAbortAsync(string repoDir, CancellationToken ct = default)
|
||||
{
|
||||
var (exitCode, _, stderr) = await RunGitAsync(repoDir, ["revert", "--abort"], ct);
|
||||
if (exitCode != 0)
|
||||
throw new InvalidOperationException($"git revert --abort failed (exit {exitCode}): {stderr}");
|
||||
}
|
||||
|
||||
public async Task<List<string>> ListConflictedFilesAsync(string repoDir, CancellationToken ct = default)
|
||||
{
|
||||
var (exitCode, stdout, stderr) = await RunGitAsync(repoDir,
|
||||
|
||||
Reference in New Issue
Block a user