skip complex conflicts in merge auto-resolution
This commit is contained in:
parent
386954b3c4
commit
c6b6f52b1f
|
|
@ -6,6 +6,8 @@ import { spinner } from "../spinner.ts"
|
||||||
import { die } from "../fmt.ts"
|
import { die } from "../fmt.ts"
|
||||||
import { action as closeAction } from "./close.ts"
|
import { action as closeAction } from "./close.ts"
|
||||||
|
|
||||||
|
const MAX_DIFF_LINES = 300
|
||||||
|
|
||||||
function truncate(text: string, maxLines = 200): string {
|
function truncate(text: string, maxLines = 200): string {
|
||||||
const lines = text.split("\n")
|
const lines = text.split("\n")
|
||||||
if (lines.length <= maxLines) return text
|
if (lines.length <= maxLines) return text
|
||||||
|
|
@ -42,13 +44,41 @@ export async function action(branch: string) {
|
||||||
const branchLog = await git.commitLog(`${base}..${branch}`, root)
|
const branchLog = await git.commitLog(`${base}..${branch}`, root)
|
||||||
const branchDiffStat = await git.diffStat(`${base}..${branch}`, root)
|
const branchDiffStat = await git.diffStat(`${base}..${branch}`, root)
|
||||||
|
|
||||||
for (const file of conflicts) {
|
// Fetch diffs for all conflicted files and partition by complexity
|
||||||
|
spin.text = "Checking conflict complexity"
|
||||||
|
const fileDiffs = await Promise.all(
|
||||||
|
conflicts.map(async (file) => {
|
||||||
|
const [oursDiff, theirsDiff] = await Promise.all([
|
||||||
|
git.fileDiff(base, "HEAD", file, root),
|
||||||
|
git.fileDiff(base, branch, file, root),
|
||||||
|
])
|
||||||
|
return { file, oursDiff, theirsDiff }
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const resolvable: typeof fileDiffs = []
|
||||||
|
const skipped: string[] = []
|
||||||
|
for (const entry of fileDiffs) {
|
||||||
|
const oursLines = entry.oursDiff ? entry.oursDiff.split("\n").length : 0
|
||||||
|
const theirsLines = entry.theirsDiff ? entry.theirsDiff.split("\n").length : 0
|
||||||
|
if (oursLines > MAX_DIFF_LINES || theirsLines > MAX_DIFF_LINES) {
|
||||||
|
skipped.push(entry.file)
|
||||||
|
} else {
|
||||||
|
resolvable.push(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvable.length === 0) {
|
||||||
|
await git.abortMerge(root)
|
||||||
|
spin.fail("All conflicts are too complex for auto-resolution")
|
||||||
|
console.log("\nThe following files need manual resolution:")
|
||||||
|
for (const file of skipped) console.log(` - ${file}`)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { file, oursDiff, theirsDiff } of resolvable) {
|
||||||
spin.text = `Resolving ${file}`
|
spin.text = `Resolving ${file}`
|
||||||
|
|
||||||
const [oursDiff, theirsDiff] = await Promise.all([
|
|
||||||
git.fileDiff(base, "HEAD", file, root),
|
|
||||||
git.fileDiff(base, branch, file, root),
|
|
||||||
])
|
|
||||||
const content = await Bun.file(join(root, file)).text()
|
const content = await Bun.file(join(root, file)).text()
|
||||||
|
|
||||||
const context = [
|
const context = [
|
||||||
|
|
@ -87,6 +117,14 @@ export async function action(branch: string) {
|
||||||
await git.stageFile(file, root)
|
await git.stageFile(file, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skipped.length > 0) {
|
||||||
|
spin.succeed(`Resolved ${resolvable.length} of ${conflicts.length} conflict(s)`)
|
||||||
|
console.log("\nThe following files are too complex for auto-resolution:")
|
||||||
|
for (const file of skipped) console.log(` - ${file}`)
|
||||||
|
console.log("\nResolve them manually, then run: git commit --no-edit")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await git.commitMerge(root)
|
await git.commitMerge(root)
|
||||||
spin.succeed(`Resolved ${conflicts.length} conflict(s) and merged ${branch}`)
|
spin.succeed(`Resolved ${conflicts.length} conflict(s) and merged ${branch}`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user