Truncate large diffs in merge context and add error handling to git log/diff helpers
This commit is contained in:
parent
ae6604caad
commit
386954b3c4
|
|
@ -6,6 +6,12 @@ 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"
|
||||||
|
|
||||||
|
function truncate(text: string, maxLines = 200): string {
|
||||||
|
const lines = text.split("\n")
|
||||||
|
if (lines.length <= maxLines) return text
|
||||||
|
return lines.slice(0, maxLines).join("\n") + `\n... (truncated, ${lines.length - maxLines} more lines)`
|
||||||
|
}
|
||||||
|
|
||||||
export async function action(branch: string) {
|
export async function action(branch: string) {
|
||||||
const root = await git.repoRoot()
|
const root = await git.repoRoot()
|
||||||
const session = await state.getSession(root, branch)
|
const session = await state.getSession(root, branch)
|
||||||
|
|
@ -33,14 +39,16 @@ export async function action(branch: string) {
|
||||||
spin.text = "Gathering merge context"
|
spin.text = "Gathering merge context"
|
||||||
const current = await git.currentBranch(root)
|
const current = await git.currentBranch(root)
|
||||||
const base = await git.mergeBase("HEAD", branch, root)
|
const base = await git.mergeBase("HEAD", branch, root)
|
||||||
const branchLog = await git.log(`${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) {
|
for (const file of conflicts) {
|
||||||
spin.text = `Resolving ${file}`
|
spin.text = `Resolving ${file}`
|
||||||
|
|
||||||
const oursDiff = await git.fileDiff(base, "HEAD", file, root)
|
const [oursDiff, theirsDiff] = await Promise.all([
|
||||||
const theirsDiff = await git.fileDiff(base, branch, file, root)
|
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 = [
|
||||||
|
|
@ -48,19 +56,19 @@ export async function action(branch: string) {
|
||||||
`Merging branch \`${branch}\` into \`${current}\``,
|
`Merging branch \`${branch}\` into \`${current}\``,
|
||||||
``,
|
``,
|
||||||
`### Commits on \`${branch}\`:`,
|
`### Commits on \`${branch}\`:`,
|
||||||
branchLog || "(no commits)",
|
(branchLog && truncate(branchLog, 50)) || "(no commits)",
|
||||||
``,
|
``,
|
||||||
`### Overall changes on \`${branch}\`:`,
|
`### Overall changes on \`${branch}\`:`,
|
||||||
branchDiffStat || "(no changes)",
|
(branchDiffStat && truncate(branchDiffStat, 100)) || "(no changes)",
|
||||||
``,
|
``,
|
||||||
`---`,
|
`---`,
|
||||||
`## Conflicted File: ${file}`,
|
`## Conflicted File: ${file}`,
|
||||||
``,
|
``,
|
||||||
`### Changes made on current branch (\`${current}\`):`,
|
`### Changes made on current branch (\`${current}\`):`,
|
||||||
oursDiff || "(no changes to this file)",
|
(oursDiff && truncate(oursDiff)) || "(no changes to this file)",
|
||||||
``,
|
``,
|
||||||
`### Changes made on incoming branch (\`${branch}\`):`,
|
`### Changes made on incoming branch (\`${branch}\`):`,
|
||||||
theirsDiff || "(no changes to this file)",
|
(theirsDiff && truncate(theirsDiff)) || "(no changes to this file)",
|
||||||
``,
|
``,
|
||||||
`### File with conflict markers:`,
|
`### File with conflict markers:`,
|
||||||
content,
|
content,
|
||||||
|
|
|
||||||
11
src/git.ts
11
src/git.ts
|
|
@ -136,20 +136,29 @@ export async function mergeBase(ref1: string, ref2: string, cwd: string): Promis
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a one-line-per-commit log for a revision range. */
|
/** Get a one-line-per-commit log for a revision range. */
|
||||||
export async function log(range: string, cwd: string): Promise<string> {
|
export async function commitLog(range: string, cwd: string): Promise<string> {
|
||||||
const result = await $`git log --oneline ${range}`.cwd(cwd).nothrow().quiet()
|
const result = await $`git log --oneline ${range}`.cwd(cwd).nothrow().quiet()
|
||||||
|
if (result.exitCode !== 0) {
|
||||||
|
throw new Error(`Failed to get log for range "${range}"`)
|
||||||
|
}
|
||||||
return result.text().trim()
|
return result.text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a diff stat summary for a revision range. */
|
/** Get a diff stat summary for a revision range. */
|
||||||
export async function diffStat(range: string, cwd: string): Promise<string> {
|
export async function diffStat(range: string, cwd: string): Promise<string> {
|
||||||
const result = await $`git diff --stat ${range}`.cwd(cwd).nothrow().quiet()
|
const result = await $`git diff --stat ${range}`.cwd(cwd).nothrow().quiet()
|
||||||
|
if (result.exitCode !== 0) {
|
||||||
|
throw new Error(`Failed to get diff stat for range "${range}"`)
|
||||||
|
}
|
||||||
return result.text().trim()
|
return result.text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the diff for a specific file between two refs. */
|
/** Get the diff for a specific file between two refs. */
|
||||||
export async function fileDiff(ref1: string, ref2: string, file: string, cwd: string): Promise<string> {
|
export async function fileDiff(ref1: string, ref2: string, file: string, cwd: string): Promise<string> {
|
||||||
const result = await $`git diff ${ref1} ${ref2} -- ${file}`.cwd(cwd).nothrow().quiet()
|
const result = await $`git diff ${ref1} ${ref2} -- ${file}`.cwd(cwd).nothrow().quiet()
|
||||||
|
if (result.exitCode !== 0) {
|
||||||
|
throw new Error(`Failed to get diff for "${file}" between "${ref1}" and "${ref2}"`)
|
||||||
|
}
|
||||||
return result.text().trim()
|
return result.text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user