MCPcopy
hub / github.com/claude-code-best/claude-code / performPostCreationSetup

Function performPostCreationSetup

src/utils/worktree.ts:510–624  ·  view source on GitHub ↗

* Post-creation setup for a newly created worktree. * Propagates settings.local.json, configures git hooks, and symlinks directories.

(
  repoRoot: string,
  worktreePath: string,
)

Source from the content-addressed store, hash-verified

508 * Propagates settings.local.json, configures git hooks, and symlinks directories.
509 */
510async function performPostCreationSetup(
511 repoRoot: string,
512 worktreePath: string,
513): Promise<void> {
514 // Copy settings.local.json to the worktree's .claude directory
515 // This propagates local settings (which may contain secrets) to the worktree
516 const localSettingsRelativePath =
517 getRelativeSettingsFilePathForSource('localSettings')
518 const sourceSettingsLocal = join(repoRoot, localSettingsRelativePath)
519 try {
520 const destSettingsLocal = join(worktreePath, localSettingsRelativePath)
521 await mkdirRecursive(dirname(destSettingsLocal))
522 await copyFile(sourceSettingsLocal, destSettingsLocal)
523 logForDebugging(
524 `Copied settings.local.json to worktree: ${destSettingsLocal}`,
525 )
526 } catch (e: unknown) {
527 const code = getErrnoCode(e)
528 if (code !== 'ENOENT') {
529 logForDebugging(
530 `Failed to copy settings.local.json: ${(e as Error).message}`,
531 { level: 'warn' },
532 )
533 }
534 }
535
536 // Configure the worktree to use hooks from the main repository
537 // This solves issues with .husky and other git hooks that use relative paths
538 const huskyPath = join(repoRoot, '.husky')
539 const gitHooksPath = join(repoRoot, '.git', 'hooks')
540 let hooksPath: string | null = null
541 for (const candidatePath of [huskyPath, gitHooksPath]) {
542 try {
543 const s = await stat(candidatePath)
544 if (s.isDirectory()) {
545 hooksPath = candidatePath
546 break
547 }
548 } catch {
549 // Path doesn't exist or can't be accessed
550 }
551 }
552 if (hooksPath) {
553 // `git config` (no --worktree flag) writes to the main repo's .git/config,
554 // shared by all worktrees. Once set, every subsequent worktree create is a
555 // no-op — skip the subprocess (~14ms spawn) when the value already matches.
556 const gitDir = await resolveGitDir(repoRoot)
557 const configDir = gitDir ? ((await getCommonDir(gitDir)) ?? gitDir) : null
558 const existing = configDir
559 ? await parseGitConfigValue(configDir, 'core', null, 'hooksPath')
560 : null
561 if (existing !== hooksPath) {
562 const { code: configCode, stderr: configError } =
563 await execFileNoThrowWithCwd(
564 gitExe(),
565 ['config', 'core.hooksPath', hooksPath],
566 { cwd: worktreePath },
567 )

Callers 3

createWorktreeForSessionFunction · 0.85
createAgentWorktreeFunction · 0.85
execIntoTmuxWorktreeFunction · 0.85

Calls 12

mkdirRecursiveFunction · 0.85
getErrnoCodeFunction · 0.85
statFunction · 0.85
resolveGitDirFunction · 0.85
getCommonDirFunction · 0.85
parseGitConfigValueFunction · 0.85
execFileNoThrowWithCwdFunction · 0.85
symlinkDirectoriesFunction · 0.85
copyWorktreeIncludeFilesFunction · 0.85
logForDebuggingFunction · 0.70
getInitialSettingsFunction · 0.50

Tested by

no test coverage detected