@@ -8,6 +8,8 @@ import { EXIT_CODES } from './cli/types.ts';
88import type { RepositoryInfo } from './repository.ts' ;
99import type { ServiceContainer } from './services/types.ts' ;
1010import { createServiceContainer } from './services/container.ts' ;
11+ import { WorktreeOperations } from './worktree.ts' ;
12+ import { loadConfig } from './config.ts' ;
1113
1214export class RepositoryInitError extends Error {
1315 constructor ( message : string , public readonly code : number = EXIT_CODES . GENERAL_ERROR ) {
@@ -120,7 +122,7 @@ export class InitOperations {
120122
121123 // Validate targetName characters
122124 if ( trimmedTarget . includes ( '/' ) || trimmedTarget . includes ( '\\' ) || trimmedTarget . includes ( '@' ) ) {
123- throw new RepositoryInitError ( 'Invalid repository name: contains invalid characters' , EXIT_CODES . INVALID_ARGUMENTS ) ;
125+ throw new RepositoryInitError ( 'Repository name: contains invalid characters' , EXIT_CODES . INVALID_ARGUMENTS ) ;
124126 }
125127
126128 repoName = trimmedTarget ;
@@ -157,15 +159,21 @@ export class InitOperations {
157159 this . services . logger . log ( 'Fetching all remote branches...' ) ;
158160 await this . fetchAllRemoteBranches ( bareDir ) ;
159161
160- this . services . logger . log ( `Repository initialized successfully in ${ targetDir } ` ) ;
161-
162- return {
162+ const repoInfo : RepositoryInfo = {
163163 rootDir : targetDir ,
164164 gitDir : bareDir ,
165165 type : 'bare' ,
166166 bareDir : bareDir
167167 } ;
168168
169+ // Detect and create default branch worktree
170+ this . services . logger . log ( 'Creating default branch worktree...' ) ;
171+ await this . createDefaultBranchWorktree ( repoInfo ) ;
172+
173+ this . services . logger . log ( `Repository initialized successfully in ${ targetDir } ` ) ;
174+
175+ return repoInfo ;
176+
169177 } catch ( error ) {
170178 if ( error instanceof GitError ) {
171179 // Check if it's a network-related error
@@ -228,6 +236,109 @@ export class InitOperations {
228236 throw new GitError ( `Failed to fetch branches: ${ error instanceof Error ? error . message : 'Unknown error' } ` , '' , - 1 ) ;
229237 }
230238 }
239+
240+ /**
241+ * Detects the default branch from the bare repository's HEAD file
242+ */
243+ private async detectDefaultBranch ( bareDir : string ) : Promise < string > {
244+ const headFilePath = join ( bareDir , 'HEAD' ) ;
245+
246+ try {
247+ const headContent = await this . services . fs . readFile ( headFilePath , 'utf8' ) ;
248+ const headLine = headContent . trim ( ) ;
249+
250+ // HEAD file should contain something like "ref: refs/heads/main"
251+ const match = headLine . match ( / ^ r e f : \s * r e f s \/ h e a d s \/ ( .+ ) $ / ) ;
252+ if ( match && match [ 1 ] ) {
253+ return match [ 1 ] ;
254+ }
255+
256+ // Fallback: try to detect from remote HEAD
257+ const result = await this . services . git . executeCommandWithResult ( bareDir , [ 'symbolic-ref' , 'refs/remotes/origin/HEAD' ] ) ;
258+ if ( result . exitCode === 0 ) {
259+ const remoteHeadMatch = result . stdout . trim ( ) . match ( / r e f s \/ r e m o t e s \/ o r i g i n \/ ( .+ ) $ / ) ;
260+ if ( remoteHeadMatch && remoteHeadMatch [ 1 ] ) {
261+ return remoteHeadMatch [ 1 ] ;
262+ }
263+ }
264+
265+ // Last resort fallback
266+ throw new Error ( 'Could not determine default branch' ) ;
267+ } catch ( error ) {
268+ // If we can't detect the default branch, try common defaults
269+ const commonDefaults = [ 'main' , 'master' , 'develop' , 'development' ] ;
270+
271+ for ( const branch of commonDefaults ) {
272+ try {
273+ const result = await this . services . git . executeCommandWithResult ( bareDir , [ 'show-ref' , '--verify' , '--quiet' , `refs/remotes/origin/${ branch } ` ] ) ;
274+ if ( result . exitCode === 0 ) {
275+ this . services . logger . warn ( `Could not detect default branch from HEAD file, using found branch: ${ branch } ` ) ;
276+ return branch ;
277+ }
278+ } catch {
279+ // Continue trying other branches
280+ }
281+ }
282+
283+ throw new RepositoryInitError (
284+ `Could not determine default branch: ${ error instanceof Error ? error . message : 'Unknown error' } . ` +
285+ 'Make sure the repository has a valid default branch.' ,
286+ EXIT_CODES . GIT_ERROR
287+ ) ;
288+ }
289+ }
290+
291+ /**
292+ * Creates a worktree for the default branch and sets up upstream tracking
293+ */
294+ private async createDefaultBranchWorktree ( repoInfo : RepositoryInfo ) : Promise < void > {
295+ try {
296+ // Detect the default branch
297+ const defaultBranch = await this . detectDefaultBranch ( repoInfo . gitDir ) ;
298+ this . services . logger . log ( `Detected default branch: ${ defaultBranch } ` ) ;
299+
300+ // Load config to get worktree directory setting
301+ const config = await loadConfig ( repoInfo ) ;
302+
303+ // Create worktree for the default branch
304+ const worktreeOps = new WorktreeOperations ( this . services ) ;
305+
306+ // Change to the repository directory temporarily to ensure relative paths work correctly
307+ const originalCwd = process . cwd ( ) ;
308+ this . services . fs . chdir ( repoInfo . rootDir ) ;
309+
310+ try {
311+ // Resolve branch and create worktree
312+ const resolution = await worktreeOps . resolveBranch ( repoInfo , defaultBranch , config ) ;
313+ const worktreePath = join ( repoInfo . rootDir , config . worktreeDir , defaultBranch ) ;
314+
315+ await worktreeOps . createWorktree ( repoInfo , resolution , worktreePath ) ;
316+
317+ // Set up upstream tracking for the created branch
318+ await this . setupUpstreamTracking ( repoInfo , defaultBranch , worktreePath ) ;
319+
320+ this . services . logger . log ( `Created worktree for default branch '${ defaultBranch } ' with upstream tracking` ) ;
321+ } finally {
322+ // Restore original working directory
323+ this . services . fs . chdir ( originalCwd ) ;
324+ }
325+ } catch ( error ) {
326+ // Don't fail the entire init process if worktree creation fails
327+ this . services . logger . warn ( `Warning: Failed to create default branch worktree: ${ error instanceof Error ? error . message : 'Unknown error' } ` ) ;
328+ }
329+ }
330+
331+ /**
332+ * Sets up upstream tracking for a worktree branch
333+ */
334+ private async setupUpstreamTracking ( repoInfo : RepositoryInfo , branchName : string , worktreePath : string ) : Promise < void > {
335+ try {
336+ // Set the upstream branch to track origin/branchName
337+ await this . services . git . executeCommandInDir ( worktreePath , [ 'branch' , '--set-upstream-to' , `origin/${ branchName } ` ] ) ;
338+ } catch ( error ) {
339+ this . services . logger . warn ( `Warning: Failed to set upstream tracking for branch '${ branchName } ': ${ error instanceof Error ? error . message : 'Unknown error' } ` ) ;
340+ }
341+ }
231342}
232343
233344/**
0 commit comments