优化代码冲突解决

This commit is contained in:
xintaofei
2026-03-14 21:17:26 +08:00
parent 4129f02985
commit 2b679b5ba8
19 changed files with 165 additions and 15 deletions

View File

@@ -81,6 +81,7 @@ import {
openCommitWindow,
setFolderParentBranch,
gitListConflicts,
gitHasMergeHead,
} from "@/lib/tauri"
import { RemoteManageDialog } from "@/components/layout/remote-manage-dialog"
import { ConflictDialog } from "@/components/layout/conflict-dialog"
@@ -292,6 +293,9 @@ export function BranchDropdown({
})
}
// Uses operation "merge" intentionally: MERGE_HEAD exists so merge state is
// already active. MergeWorkspace won't call gitStartPullMerge (only for "pull"),
// and ConflictDialog abort correctly runs git merge --abort.
async function showMergeConflictDialog() {
try {
const remaining = await gitListConflicts(folderPath)
@@ -310,6 +314,16 @@ export function BranchDropdown({
}
async function handlePush() {
// Pre-check: if MERGE_HEAD exists, show conflict dialog immediately
try {
if (await gitHasMergeHead(folderPath)) {
await showMergeConflictDialog()
return
}
} catch {
// Pre-check failed, continue with normal push flow
}
const taskId = `git-${++taskSeq.current}-${Date.now()}`
const label = t("tasks.pushCode")
setLoading(true)

View File

@@ -44,6 +44,7 @@ export function ConflictDialog({
const [resolvedFiles, setResolvedFiles] = useState<Set<string>>(new Set())
const [aborting, setAborting] = useState(false)
const [completing, setCompleting] = useState(false)
const [done, setDone] = useState(false)
const open = conflictInfo !== null
const operation = conflictInfo?.operation ?? "merge"
@@ -53,6 +54,7 @@ export function ConflictDialog({
if (conflictInfo) {
setConflictedFiles(conflictInfo.conflicted_files)
setResolvedFiles(new Set())
setDone(false)
}
}, [conflictInfo])
@@ -76,6 +78,7 @@ export function ConflictDialog({
let unlistenResolved: UnlistenFn | null = null
let unlistenCompleted: UnlistenFn | null = null
let unlistenAborted: UnlistenFn | null = null
listen<{ folder_id: number; file: string }>(
"folder://merge-conflict-resolved",
@@ -91,6 +94,7 @@ export function ConflictDialog({
listen<{ folder_id: number }>("folder://merge-completed", (event) => {
if (event.payload.folder_id !== folderId) return
setDone(true)
onResolved()
onClose()
})
@@ -99,12 +103,26 @@ export function ConflictDialog({
})
.catch(() => {})
// Merge was aborted (user clicked abort in merge window, or window closed)
// Reset resolved state since abort reverts all changes
listen<{ folder_id: number }>("folder://merge-aborted", (event) => {
if (event.payload.folder_id !== folderId) return
setDone(true)
setResolvedFiles(new Set())
onClose()
})
.then((fn) => {
unlistenAborted = fn
})
.catch(() => {})
return () => {
disposeTauriListener(
unlistenResolved,
"ConflictDialog.mergeConflictResolved"
)
disposeTauriListener(unlistenCompleted, "ConflictDialog.mergeCompleted")
disposeTauriListener(unlistenAborted, "ConflictDialog.mergeAborted")
}
}, [open, folderId, onResolved, onClose])
@@ -122,7 +140,7 @@ export function ConflictDialog({
async function handleOpenMergeTool() {
try {
await openMergeWindow(folderId, operation)
await openMergeWindow(folderId, operation, conflictInfo?.upstream_commit)
} catch (err) {
toast.error(String(err))
}
@@ -149,6 +167,7 @@ export function ConflictDialog({
}
async function handleComplete() {
if (done) return
setCompleting(true)
try {
await gitContinueOperation(folderPath, operation)
@@ -227,7 +246,7 @@ export function ConflictDialog({
<Button
size="sm"
onClick={handleComplete}
disabled={completing || aborting}
disabled={completing || aborting || done}
>
{completing && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />