Handle unborn worktrees with resolvable base (#2398)
- Treat new remote worktrees without a HEAD commit as an empty compare when the base ref exists, avoiding a broken source-control compare state - Keep the existing unborn-head error for cases where the base cannot resolve
This commit is contained in:
parent
d9e38cb469
commit
dae696ab8f
|
|
@ -617,6 +617,7 @@ describe('getBranchCompare', () => {
|
|||
gitExecFileAsyncMock
|
||||
.mockResolvedValueOnce({ stdout: 'main\n' })
|
||||
.mockRejectedValueOnce(new Error('unborn'))
|
||||
.mockRejectedValueOnce(new Error('missing base'))
|
||||
|
||||
const result = await getBranchCompare('/repo', 'origin/main')
|
||||
|
||||
|
|
@ -625,6 +626,27 @@ describe('getBranchCompare', () => {
|
|||
expect(result.entries).toEqual([])
|
||||
})
|
||||
|
||||
it('treats an unborn branch with a resolvable base as having no committed branch changes', async () => {
|
||||
gitExecFileAsyncMock
|
||||
.mockResolvedValueOnce({ stdout: 'feature\n' })
|
||||
.mockRejectedValueOnce(new Error('unborn'))
|
||||
.mockResolvedValueOnce({ stdout: 'base-oid\n' })
|
||||
|
||||
const result = await getBranchCompare('/repo', 'origin/main')
|
||||
|
||||
expect(result.summary).toEqual({
|
||||
baseRef: 'origin/main',
|
||||
baseOid: 'base-oid',
|
||||
compareRef: 'feature',
|
||||
headOid: null,
|
||||
mergeBase: null,
|
||||
changedFiles: 0,
|
||||
commitsAhead: 0,
|
||||
status: 'ready'
|
||||
})
|
||||
expect(result.entries).toEqual([])
|
||||
})
|
||||
|
||||
it('returns no-merge-base when histories do not intersect', async () => {
|
||||
gitExecFileAsyncMock
|
||||
.mockResolvedValueOnce({ stdout: 'main\n' })
|
||||
|
|
|
|||
|
|
@ -438,17 +438,31 @@ export async function getBranchCompare(
|
|||
summary.compareRef = compareRef
|
||||
|
||||
let headOid = ''
|
||||
let baseOid = ''
|
||||
try {
|
||||
headOid = await resolveRefOid(worktreePath, 'HEAD')
|
||||
summary.headOid = headOid
|
||||
} catch {
|
||||
try {
|
||||
baseOid = await resolveRefOid(worktreePath, baseRef)
|
||||
summary.baseOid = baseOid
|
||||
// Why: new remote worktrees can be on an unborn branch until the first
|
||||
// commit. There are no committed branch changes yet; surfacing this as a
|
||||
// compare error makes the source-control panel look broken.
|
||||
summary.changedFiles = 0
|
||||
summary.commitsAhead = 0
|
||||
summary.status = 'ready'
|
||||
return { summary, entries: [] }
|
||||
} catch {
|
||||
// Preserve the existing unborn-head message when even the base is not
|
||||
// resolvable; callers cannot compare or present a useful empty state.
|
||||
}
|
||||
summary.status = 'unborn-head'
|
||||
summary.errorMessage =
|
||||
'This branch does not have a committed HEAD yet, so compare-to-base is unavailable.'
|
||||
return { summary, entries: [] }
|
||||
}
|
||||
|
||||
let baseOid = ''
|
||||
try {
|
||||
baseOid = await resolveRefOid(worktreePath, baseRef)
|
||||
summary.baseOid = baseOid
|
||||
|
|
|
|||
|
|
@ -151,18 +151,33 @@ export async function branchCompare(
|
|||
}
|
||||
|
||||
let headOid: string
|
||||
let baseOid = ''
|
||||
try {
|
||||
const { stdout } = await git(['rev-parse', '--verify', 'HEAD'], worktreePath)
|
||||
headOid = stdout.trim()
|
||||
summary.headOid = headOid
|
||||
} catch {
|
||||
try {
|
||||
const { stdout } = await git(['rev-parse', '--verify', baseRef], worktreePath)
|
||||
baseOid = stdout.trim()
|
||||
summary.baseOid = baseOid
|
||||
// Why: new remote worktrees can be on an unborn branch until the first
|
||||
// commit. There are no committed branch changes yet; surfacing this as a
|
||||
// compare error makes the source-control panel look broken.
|
||||
summary.changedFiles = 0
|
||||
summary.commitsAhead = 0
|
||||
summary.status = 'ready'
|
||||
return { summary, entries: [] }
|
||||
} catch {
|
||||
// Preserve the existing unborn-head message when even the base is not
|
||||
// resolvable; callers cannot compare or present a useful empty state.
|
||||
}
|
||||
summary.status = 'unborn-head'
|
||||
summary.errorMessage =
|
||||
'This branch does not have a committed HEAD yet, so compare-to-base is unavailable.'
|
||||
return { summary, entries: [] }
|
||||
}
|
||||
|
||||
let baseOid: string
|
||||
try {
|
||||
const { stdout } = await git(['rev-parse', '--verify', baseRef], worktreePath)
|
||||
baseOid = stdout.trim()
|
||||
|
|
|
|||
|
|
@ -433,6 +433,35 @@ describe('GitHandler', () => {
|
|||
expect(entry).toBeDefined()
|
||||
expect(entry!.path).toBe('docs/日本語/sample.md')
|
||||
})
|
||||
|
||||
it('treats an unborn branch with a resolvable base as having no committed branch changes', async () => {
|
||||
gitInit(tmpDir)
|
||||
writeFileSync(path.join(tmpDir, 'base.txt'), 'base')
|
||||
gitCommit(tmpDir, 'initial')
|
||||
const baseRef = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
||||
cwd: tmpDir,
|
||||
encoding: 'utf-8'
|
||||
}).trim()
|
||||
|
||||
execFileSync('git', ['checkout', '--orphan', 'feature'], { cwd: tmpDir, stdio: 'pipe' })
|
||||
execFileSync('git', ['rm', '-rf', '.'], { cwd: tmpDir, stdio: 'pipe' })
|
||||
|
||||
const result = (await dispatcher.callRequest('git.branchCompare', {
|
||||
worktreePath: tmpDir,
|
||||
baseRef
|
||||
})) as { summary: Record<string, unknown>; entries: Record<string, unknown>[] }
|
||||
|
||||
expect(result.summary).toMatchObject({
|
||||
baseRef,
|
||||
compareRef: 'feature',
|
||||
headOid: null,
|
||||
changedFiles: 0,
|
||||
commitsAhead: 0,
|
||||
status: 'ready'
|
||||
})
|
||||
expect(result.summary.baseOid).toMatch(/^[0-9a-f]{40}$/)
|
||||
expect(result.entries).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('branchDiff', () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue