@@ -70,20 +70,6 @@ export abstract class ShadowCheckpointService extends EventEmitter {
7070 throw new Error ( "Shadow git repo already initialized" )
7171 }
7272
73- const nestedGitPath = await this . getNestedGitRepository ( )
74-
75- if ( nestedGitPath ) {
76- // Show persistent error message with the offending path
77- const relativePath = path . relative ( this . workspaceDir , nestedGitPath )
78- const message = t ( "common:errors.nested_git_repos_warning" , { path : relativePath } )
79- vscode . window . showErrorMessage ( message )
80-
81- throw new Error (
82- `Checkpoints are disabled because a nested git repository was detected at: ${ relativePath } . ` +
83- "Please remove or relocate nested git repositories to use the checkpoints feature." ,
84- )
85- }
86-
8773 await fs . mkdir ( this . checkpointsDir , { recursive : true } )
8874 const git = simpleGit ( this . checkpointsDir )
8975 const gitVersion = await git . version ( )
@@ -102,6 +88,7 @@ export abstract class ShadowCheckpointService extends EventEmitter {
10288 )
10389 }
10490
91+ // Write exclude file which will include nested git repos
10592 await this . writeExcludeFile ( )
10693 this . baseHash = await git . revparse ( [ "HEAD" ] )
10794 } else {
@@ -111,6 +98,7 @@ export abstract class ShadowCheckpointService extends EventEmitter {
11198 await git . addConfig ( "commit.gpgSign" , "false" ) // Disable commit signing for shadow repo.
11299 await git . addConfig ( "user.name" , "Roo Code" )
113100 await git . addConfig ( "user.email" , "[email protected] " ) 101+ // Write exclude file which will include nested git repos
114102 await this . writeExcludeFile ( )
115103 await this . stageAll ( git )
116104 const { commit } = await git . commit ( "initial commit" , { "--allow-empty" : null } )
@@ -147,6 +135,16 @@ export abstract class ShadowCheckpointService extends EventEmitter {
147135 protected async writeExcludeFile ( ) {
148136 await fs . mkdir ( path . join ( this . dotGitDir , "info" ) , { recursive : true } )
149137 const patterns = await getExcludePatterns ( this . workspaceDir )
138+
139+ // Add nested git repositories to exclude patterns
140+ const nestedGitPaths = await this . getNestedGitRepositories ( )
141+ for ( const gitPath of nestedGitPaths ) {
142+ const relativePath = path . relative ( this . workspaceDir , gitPath )
143+ // Add the directory and all its contents to exclude patterns
144+ patterns . push ( relativePath + "/" )
145+ this . log ( `[${ this . constructor . name } #writeExcludeFile] excluding nested git repo: ${ relativePath } ` )
146+ }
147+
150148 await fs . writeFile ( path . join ( this . dotGitDir , "info" , "exclude" ) , patterns . join ( "\n" ) )
151149 }
152150
@@ -160,7 +158,7 @@ export abstract class ShadowCheckpointService extends EventEmitter {
160158 }
161159 }
162160
163- private async getNestedGitRepository ( ) : Promise < string | null > {
161+ private async getNestedGitRepositories ( ) : Promise < string [ ] > {
164162 try {
165163 // Find all .git/HEAD files that are not at the root level.
166164 const args = [ "--files" , "--hidden" , "--follow" , "-g" , "**/.git/HEAD" , this . workspaceDir ]
@@ -182,32 +180,46 @@ export abstract class ShadowCheckpointService extends EventEmitter {
182180 )
183181 } )
184182
185- if ( nestedGitPaths . length > 0 ) {
186- // Get the first nested git repository path
183+ const repoDirs : string [ ] = [ ]
184+ for ( const gitPath of nestedGitPaths ) {
187185 // Remove .git/HEAD from the path to get the repository directory
188- const headPath = nestedGitPaths [ 0 ] . path
186+ const headPath = gitPath . path
189187
190188 // Use path module to properly extract the repository directory
191189 // The HEAD file is at .git/HEAD, so we need to go up two directories
192190 const gitDir = path . dirname ( headPath ) // removes HEAD, gives us .git
193191 const repoDir = path . dirname ( gitDir ) // removes .git, gives us the repo directory
194192
195193 const absolutePath = path . join ( this . workspaceDir , repoDir )
194+ repoDirs . push ( absolutePath )
195+ }
196196
197+ if ( repoDirs . length > 0 ) {
197198 this . log (
198- `[${ this . constructor . name } #getNestedGitRepository ] found ${ nestedGitPaths . length } nested git repositories, first at: ${ repoDir } ` ,
199+ `[${ this . constructor . name } #getNestedGitRepositories ] found ${ repoDirs . length } nested git repositories` ,
199200 )
200- return absolutePath
201+
202+ // Show informational message to user
203+ if ( repoDirs . length === 1 ) {
204+ const relativePath = path . relative ( this . workspaceDir , repoDirs [ 0 ] )
205+ vscode . window . showInformationMessage (
206+ t ( "common:info.nested_git_repo_excluded" , { path : relativePath } ) ,
207+ )
208+ } else {
209+ vscode . window . showInformationMessage (
210+ t ( "common:info.nested_git_repos_excluded" , { count : repoDirs . length } ) ,
211+ )
212+ }
201213 }
202214
203- return null
215+ return repoDirs
204216 } catch ( error ) {
205217 this . log (
206- `[${ this . constructor . name } #getNestedGitRepository ] failed to check for nested git repos: ${ error instanceof Error ? error . message : String ( error ) } ` ,
218+ `[${ this . constructor . name } #getNestedGitRepositories ] failed to check for nested git repos: ${ error instanceof Error ? error . message : String ( error ) } ` ,
207219 )
208220
209- // If we can't check, assume there are no nested repos to avoid blocking the feature.
210- return null
221+ // If we can't check, return empty array to avoid blocking the feature.
222+ return [ ]
211223 }
212224 }
213225
0 commit comments