From 74afc469095da3a07aa9d27e475b7e0ab68a85f2 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 5 Jun 2026 10:47:14 +0200 Subject: [PATCH] feat(git): add conflict-stage blob reads and single-path staging --- src/ClaudeDo.Data/Git/GitService.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ClaudeDo.Data/Git/GitService.cs b/src/ClaudeDo.Data/Git/GitService.cs index 636fc3a..1b43c45 100644 --- a/src/ClaudeDo.Data/Git/GitService.cs +++ b/src/ClaudeDo.Data/Git/GitService.cs @@ -238,6 +238,24 @@ public sealed class GitService .ToList(); } + /// + /// Reads a conflicted file's blob at a merge stage: 1=base, 2=ours, 3=theirs. + /// Returns null when the stage doesn't exist (e.g. add/add conflict has no base). + /// Output is NOT trimmed so file content round-trips exactly. + /// + public async Task ShowStageAsync(string repoDir, int stage, string path, CancellationToken ct = default) + { + var (exitCode, stdout, _) = await RunGitAsync(repoDir, ["show", $":{stage}:{path}"], ct, trimOutput: false); + return exitCode == 0 ? stdout : null; + } + + public async Task AddPathAsync(string repoDir, string path, CancellationToken ct = default) + { + var (exitCode, _, stderr) = await RunGitAsync(repoDir, ["add", "--", path], ct); + if (exitCode != 0) + throw new InvalidOperationException($"git add '{path}' failed (exit {exitCode}): {stderr}"); + } + /// /// Non-destructive mergeability probe via `git merge-tree --write-tree`. Writes only /// loose objects — the working tree, index, and refs are left untouched. @@ -289,7 +307,7 @@ public sealed class GitService } private static async Task<(int ExitCode, string Stdout, string Stderr)> RunGitAsync( - string workDir, IEnumerable args, CancellationToken ct, string? stdinData = null) + string workDir, IEnumerable args, CancellationToken ct, string? stdinData = null, bool trimOutput = true) { var psi = new ProcessStartInfo { @@ -338,6 +356,6 @@ public sealed class GitService ct.ThrowIfCancellationRequested(); - return (proc.ExitCode, stdout.TrimEnd(), stderr.TrimEnd()); + return (proc.ExitCode, trimOutput ? stdout.TrimEnd() : stdout, stderr.TrimEnd()); } }