fix(planning): return to the list base branch after integration cleanup, not a guessed task branch

This commit is contained in:
mika kuns
2026-10-01 10:55:12 +02:00
parent 8ac272df50
commit cd5b27c063
3 changed files with 53 additions and 6 deletions
@@ -133,15 +133,29 @@ public sealed class PlanningAggregator
var current = await _git.GetCurrentBranchAsync(repoDir, ct);
if (string.Equals(current, branch, StringComparison.Ordinal))
{
var branches = await _git.ListLocalBranchesAsync(repoDir, ct);
var target = branches.FirstOrDefault(b => b != branch && !b.StartsWith("claudedo/", StringComparison.Ordinal)) ?? "main";
await _git.CheckoutBranchAsync(repoDir, target, ct);
await _git.CheckoutBranchAsync(repoDir, await ResolveReturnBranchAsync(planning, repoDir, ct), ct);
}
try { await _git.BranchDeleteAsync(repoDir, branch, force: true, ct); }
catch { /* already gone — idempotent */ }
}
/// <summary>
/// Rücksprung vom Integration-Branch: <c>list_config.base_branch</c>, sonst <c>main</c> (bzw. <c>master</c>).
/// Nie aus der Branchliste raten — die enthält auch Task-Branches, die in Worktrees ausgecheckt sind.
/// </summary>
private async Task<string> ResolveReturnBranchAsync(TaskEntity planning, string repoDir, CancellationToken ct)
{
using var ctx = _dbFactory.CreateDbContext();
var baseBranch = await ctx.ListConfigs.AsNoTracking()
.Where(c => c.ListId == planning.ListId)
.Select(c => c.BaseBranch)
.FirstOrDefaultAsync(ct);
if (!string.IsNullOrWhiteSpace(baseBranch)) return baseBranch;
var branches = await _git.ListLocalBranchesAsync(repoDir, ct);
return !branches.Contains("main") && branches.Contains("master") ? "master" : "main";
}
private async Task<(TaskEntity planning, string repoDir, IReadOnlyList<TaskEntity> children)>
LoadPlanningContextAsync(string planningTaskId, CancellationToken ct)
{
@@ -243,9 +243,6 @@ public sealed class WorktreeManager
_logger.LogInformation("Discarded worktree for task {TaskId} (branch {Branch})", wt.TaskId, wt.BranchName);
}
// Improvement children (parent is a non-planning task with its own worktree) branch
// from the parent's recorded HEAD so they build on the parent's not-yet-merged work.
// Planning children and standalone tasks base off the list's current HEAD.
/// <summary>Ticket-Id des Tasks, sonst die seines Parents (Children erben das Ticket ihrer Unit).</summary>
private async Task<int?> ResolveTicketIdAsync(TaskEntity task, CancellationToken ct)
{
@@ -259,6 +256,9 @@ public sealed class WorktreeManager
return TicketStatusMap.ParseBandelTicketId(parentRef);
}
// Improvement children (parent is a non-planning task with its own worktree) branch
// from the parent's recorded HEAD so they build on the parent's not-yet-merged work.
// Planning children and standalone tasks base off list_config.base_branch, else the current HEAD.
private async Task<string> ResolveBaseCommitAsync(TaskEntity task, string workingDir, CancellationToken ct)
{
if (task.ParentTaskId is not null)