@@ -278,6 +278,45 @@ function createGitCommandError(
278278 } ) ;
279279}
280280
281+ function buildCreateWorktreeBaseBranchDetail ( input : {
282+ branch : string ;
283+ branches : ReadonlyArray < { name : string } > ;
284+ isRepo : boolean ;
285+ } ) : string {
286+ const branchDetail = `Base branch '${ input . branch } ' does not resolve to a commit yet.` ;
287+ if ( ! input . isRepo ) {
288+ return `${ branchDetail } This directory is not a git repository. Open a git repository or switch to Local mode before starting a worktree thread.` ;
289+ }
290+
291+ const availableBranches = input . branches . map ( ( branch ) => branch . name ) . slice ( 0 , 5 ) ;
292+ if ( availableBranches . length === 0 ) {
293+ return `${ branchDetail } This repository has no committed branches yet. Create the first commit or switch to Local mode before starting a worktree thread.` ;
294+ }
295+
296+ return `${ branchDetail } Available branches: ${ availableBranches . join ( ", " ) } . Create the first commit or select a different branch before starting a worktree thread.` ;
297+ }
298+
299+ function resolveCreateWorktreeFallbackBranch ( input : {
300+ branches : ReadonlyArray < {
301+ current : boolean ;
302+ isDefault : boolean ;
303+ isRemote : boolean ;
304+ name : string ;
305+ } > ;
306+ } ) : string | null {
307+ const localBranches = input . branches . filter ( ( branch ) => ! branch . isRemote ) ;
308+ if ( localBranches . length === 0 ) {
309+ return null ;
310+ }
311+
312+ return (
313+ localBranches . find ( ( branch ) => branch . current ) ?. name ??
314+ localBranches . find ( ( branch ) => branch . isDefault ) ?. name ??
315+ localBranches [ 0 ] ?. name ??
316+ null
317+ ) ;
318+ }
319+
281320function quoteGitCommand ( args : ReadonlyArray < string > ) : string {
282321 return `git ${ args . join ( " " ) } ` ;
283322}
@@ -1638,10 +1677,64 @@ export const makeGitCore = (options?: { executeOverride?: GitCoreShape["execute"
16381677 const sanitizedBranch = targetBranch . replace ( / \/ / g, "-" ) ;
16391678 const repoName = path . basename ( input . cwd ) ;
16401679 const worktreePath = input . path ?? path . join ( worktreesDir , repoName , sanitizedBranch ) ;
1641- const args = input . newBranch
1642- ? [ "worktree" , "add" , "-b" , input . newBranch , worktreePath , input . branch ]
1643- : [ "worktree" , "add" , worktreePath , input . branch ] ;
1680+ let baseBranch = input . branch ;
16441681
1682+ const baseRefCheck = yield * executeGit (
1683+ "GitCore.createWorktree.baseRefCheck" ,
1684+ input . cwd ,
1685+ [ "rev-parse" , "--verify" , "--quiet" , `${ input . branch } ^{commit}` ] ,
1686+ {
1687+ allowNonZeroExit : true ,
1688+ timeoutMs : 5_000 ,
1689+ } ,
1690+ ) ;
1691+ if ( baseRefCheck . code !== 0 ) {
1692+ const branchesResult = yield * Effect . result ( listBranches ( { cwd : input . cwd } ) ) ;
1693+ if ( branchesResult . _tag === "Success" ) {
1694+ const fallbackBranch = resolveCreateWorktreeFallbackBranch ( {
1695+ branches : branchesResult . success . branches . map ( ( branch ) => ( {
1696+ current : branch . current ,
1697+ isDefault : branch . isDefault ,
1698+ isRemote : Boolean ( branch . isRemote ) ,
1699+ name : branch . name ,
1700+ } ) ) ,
1701+ } ) ;
1702+ if ( fallbackBranch && fallbackBranch !== input . branch ) {
1703+ baseBranch = fallbackBranch ;
1704+ } else {
1705+ const detail = buildCreateWorktreeBaseBranchDetail ( {
1706+ branch : input . branch ,
1707+ branches : branchesResult . success . branches . map ( ( branch ) => ( {
1708+ name : branch . name ,
1709+ } ) ) ,
1710+ isRepo : branchesResult . success . isRepo ,
1711+ } ) ;
1712+ const args = input . newBranch
1713+ ? [ "worktree" , "add" , "-b" , input . newBranch , worktreePath , input . branch ]
1714+ : [ "worktree" , "add" , worktreePath , input . branch ] ;
1715+ return yield * createGitCommandError (
1716+ "GitCore.createWorktree" ,
1717+ input . cwd ,
1718+ args ,
1719+ detail ,
1720+ ) ;
1721+ }
1722+ } else {
1723+ const args = input . newBranch
1724+ ? [ "worktree" , "add" , "-b" , input . newBranch , worktreePath , input . branch ]
1725+ : [ "worktree" , "add" , worktreePath , input . branch ] ;
1726+ return yield * createGitCommandError (
1727+ "GitCore.createWorktree" ,
1728+ input . cwd ,
1729+ args ,
1730+ `Base branch '${ input . branch } ' does not resolve to a commit yet. Create the first commit or switch to Local mode before starting a worktree thread.` ,
1731+ ) ;
1732+ }
1733+ }
1734+
1735+ const args = input . newBranch
1736+ ? [ "worktree" , "add" , "-b" , input . newBranch , worktreePath , baseBranch ]
1737+ : [ "worktree" , "add" , worktreePath , baseBranch ] ;
16451738 yield * executeGit ( "GitCore.createWorktree" , input . cwd , args , {
16461739 fallbackErrorMessage : "git worktree add failed" ,
16471740 } ) ;
@@ -1650,6 +1743,7 @@ export const makeGitCore = (options?: { executeOverride?: GitCoreShape["execute"
16501743 worktree : {
16511744 path : worktreePath ,
16521745 branch : targetBranch ,
1746+ baseBranch,
16531747 } ,
16541748 } ;
16551749 } ) ;
0 commit comments