mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(source-control): keep status refresh for worktrees whose admin dirs differ only by case (#28586)
On case-sensitive filesystems Git can register two linked worktrees whose admin dirs are `Foo` and `foo`. The status-attribution memo lookup folds case, so it kept only one checkout per key and a `git add` in the other was attributed to its sibling, skipping that worktree's Source Control refresh. Name every checkout that shares the folded key instead. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { cachedWorktreePathsForScope } from './worktree-head-identity-cached-paths'
|
||||
import { createWorktreeHeadIdentityCache } from './worktree-head-identity-reader'
|
||||
import { headIdentityScopeForEntry } from './worktree-head-identity-scope'
|
||||
|
||||
const HEAD = 'a'.repeat(40)
|
||||
|
||||
describe('cachedWorktreePathsForScope', () => {
|
||||
it('names every checkout whose admin dir folds to the same key', () => {
|
||||
// Case-sensitive filesystems let Git create both `Foo` and `foo` admin dirs.
|
||||
const cache = createWorktreeHeadIdentityCache()
|
||||
cache.entries.set('Foo', { worktreePath: '/a/Foo', head: HEAD, branch: 'refs/heads/x' })
|
||||
cache.entries.set('foo', { worktreePath: '/b/foo', head: HEAD, branch: 'refs/heads/y' })
|
||||
|
||||
const paths = cachedWorktreePathsForScope(cache, headIdentityScopeForEntry('Foo'))
|
||||
|
||||
expect(paths).toEqual(expect.arrayContaining(['/a/Foo', '/b/foo']))
|
||||
})
|
||||
|
||||
it('stays unattributed when an entry is not in the memo', () => {
|
||||
const cache = createWorktreeHeadIdentityCache()
|
||||
expect(cachedWorktreePathsForScope(cache, headIdentityScopeForEntry('wt'))).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -20,16 +20,19 @@ export function cachedWorktreePathsForScope(
|
||||
}
|
||||
paths.push(cache.primary.worktreePath)
|
||||
}
|
||||
const pathsByEntryKey = new Map<string, string>()
|
||||
// Why: keys fold case, so on case-sensitive filesystems `Foo` and `foo` are
|
||||
// distinct admin dirs sharing one key; name both rather than drop the writer.
|
||||
const pathsByEntryKey = new Map<string, string[]>()
|
||||
for (const [name, identity] of cache.entries) {
|
||||
pathsByEntryKey.set(headIdentityEntryKey(name), identity.worktreePath)
|
||||
const key = headIdentityEntryKey(name)
|
||||
pathsByEntryKey.set(key, [...(pathsByEntryKey.get(key) ?? []), identity.worktreePath])
|
||||
}
|
||||
for (const key of scope.entryNames) {
|
||||
const path = pathsByEntryKey.get(key)
|
||||
if (path === undefined) {
|
||||
const entryPaths = pathsByEntryKey.get(key)
|
||||
if (entryPaths === undefined) {
|
||||
return null
|
||||
}
|
||||
paths.push(path)
|
||||
paths.push(...entryPaths)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user