Merge subtask

# Conflicts:
#	src/ClaudeDo.Data/Git/GitService.cs
#	src/ClaudeDo.Worker/Lifecycle/TaskMergeService.cs
This commit is contained in:
mika kuns
2026-08-10 15:18:30 +02:00
4 changed files with 300 additions and 0 deletions
+22
View File
@@ -493,6 +493,28 @@ public sealed class GitService
.ToList();
}
/// <summary>
/// Rebases the branch checked out at <paramref name="worktreePath"/> onto <paramref name="ontoRef"/>.
/// On conflict or any other failure the rebase is aborted before returning, so the worktree is left
/// exactly as it was rather than stranded mid-rebase; <c>ConflictFiles</c> is best-effort and only
/// populated when the failure was an actual conflict.
/// </summary>
public async Task<(int ExitCode, string Stderr, IReadOnlyList<string> ConflictFiles)> RebaseAsync(
string worktreePath, string ontoRef, CancellationToken ct = default)
{
var (exitCode, _, stderr) = await RunGitAsync(worktreePath, ["rebase", ontoRef], ct);
if (exitCode == 0)
return (0, stderr, Array.Empty<string>());
List<string> conflictFiles;
try { conflictFiles = await ListConflictedFilesAsync(worktreePath, ct); }
catch { conflictFiles = new(); }
await RunGitAsync(worktreePath, ["rebase", "--abort"], ct);
return (exitCode, stderr, conflictFiles);
}
private static async Task<(int ExitCode, string Stdout, string Stderr)> RunGitAsync(
string workDir, IEnumerable<string> args, CancellationToken ct, string? stdinData = null, bool trimOutput = true)
{
@@ -45,6 +45,17 @@ public sealed class WorktreeRepository
.SetProperty(w => w.MergeCommit, mergeCommit), ct);
}
/// <summary>Records a successful auto-rebase: the branch's fork point moves to the rebased-onto
/// commit and its head moves to the new tip <c>git rebase</c> produced.</summary>
public async Task SetRebasedAsync(string taskId, string baseCommit, string headCommit, CancellationToken ct = default)
{
await _context.Worktrees
.Where(w => w.TaskId == taskId)
.ExecuteUpdateAsync(s => s
.SetProperty(w => w.BaseCommit, baseCommit)
.SetProperty(w => w.HeadCommit, headCommit), ct);
}
public async Task DeleteAsync(string taskId, CancellationToken ct = default)
{
await _context.Worktrees.Where(w => w.TaskId == taskId).ExecuteDeleteAsync(ct);