fix(merge): refuse a merge that would overwrite an untracked file in the target
Before merging (or staging a conflict resolution's git add -A), compare the
branch's newly-added paths against what's currently untracked in the target
working directory. A collision aborts with a new untracked_collision status
naming the path and size, surfaced through merge_task/review_task,
preview_merge/preview_merge_set (which merge-tree alone can't see), and the
UI merge paths via FlashFooterError/ShowErrorAsync instead of a silent
catch{}. git's own preflight already refuses this while the path stays
untracked at merge time; this closes the gap once a path becomes trackable
in between (e.g. an unrelated conflict resolution's git add -A) or across
the continue_merge TOCTOU window.
This commit is contained in:
+10
-7
@@ -929,13 +929,16 @@ public sealed class ExternalMcpService
|
||||
|
||||
[McpServerTool, Description(
|
||||
"Check whether a task would merge cleanly before touching anything — `git merge-tree --write-tree`, so the " +
|
||||
"working tree, index and HEAD are untouched. status is 'clean' or 'conflict' (conflictFiles lists where git " +
|
||||
"would stop); behind counts commits on targetBranch not yet on this branch, which flags a stale branch even " +
|
||||
"when the preview is clean. IMPORTANT: a clean preview says nothing about whether the result compiles or " +
|
||||
"passes tests — git can merge two changes cleanly (one file deleting a symbol another still references) and " +
|
||||
"still break the build. isEmpty=true means the task's review range contributed nothing; check that flag " +
|
||||
"rather than reading a small changedFileCount as empty. Throws if the task has neither an active worktree " +
|
||||
"nor a handler commit range, or the list's working directory is missing from disk.")]
|
||||
"working tree, index and HEAD are untouched. status is 'clean', 'conflict' (conflictFiles lists where git " +
|
||||
"would stop), or 'untracked_collision' (conflictFiles lists a path the branch adds that already exists, " +
|
||||
"untracked, in the target working directory — merge-tree can't see the working tree at all, so this is the " +
|
||||
"only way to catch it before a real merge either refuses or, if that path became tracked in the meantime, " +
|
||||
"silently overwrites it); behind counts commits on targetBranch not yet on this branch, which flags a stale " +
|
||||
"branch even when the preview is clean. IMPORTANT: a clean preview says nothing about whether the result " +
|
||||
"compiles or passes tests — git can merge two changes cleanly (one file deleting a symbol another still " +
|
||||
"references) and still break the build. isEmpty=true means the task's review range contributed nothing; " +
|
||||
"check that flag rather than reading a small changedFileCount as empty. Throws if the task has neither an " +
|
||||
"active worktree nor a handler commit range, or the list's working directory is missing from disk.")]
|
||||
public async Task<MergePreviewToolDto> PreviewMerge(
|
||||
string taskId,
|
||||
[Description("Branch to preview against; defaults to the repo's current branch.")]
|
||||
|
||||
Reference in New Issue
Block a user