@@ -823,6 +823,95 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
823823 // File should be back to original state
824824 expect ( await fs . readFile ( testFile , "utf-8" ) ) . toBe ( "Hello, world!" )
825825 } )
826+
827+ it ( "isolates checkpoint operations from GIT_DIR environment variable" , async ( ) => {
828+ // This test verifies the fix for the issue where GIT_DIR environment variable
829+ // causes checkpoint commits to go to the wrong repository.
830+ // In the real-world Dev Container scenario, GIT_DIR is set BEFORE Roo starts,
831+ // so we need to set it BEFORE creating the checkpoint service.
832+
833+ // Create a separate git directory to simulate GIT_DIR pointing elsewhere
834+ const externalGitDir = path . join ( tmpDir , `external-git-${ Date . now ( ) } ` )
835+ await fs . mkdir ( externalGitDir , { recursive : true } )
836+ const externalGit = simpleGit ( externalGitDir )
837+ await externalGit . init ( )
838+ await externalGit . addConfig ( "user.name" , "External User" )
839+ await externalGit . addConfig ( "user.email" , "[email protected] " ) 840+
841+ // Create and commit a file in the external repo
842+ const externalFile = path . join ( externalGitDir , "external.txt" )
843+ await fs . writeFile ( externalFile , "External content" )
844+ await externalGit . add ( "." )
845+ await externalGit . commit ( "External commit" )
846+
847+ // Store the original commit count in the external repo
848+ const externalLogBefore = await externalGit . log ( )
849+ const externalCommitCountBefore = externalLogBefore . total
850+
851+ // Initialize the workspace repo BEFORE setting GIT_DIR
852+ // (In Dev Containers, the workspace repo already exists before GIT_DIR is set)
853+ const testShadowDir = path . join ( tmpDir , `shadow-git-dir-test-${ Date . now ( ) } ` )
854+ const testWorkspaceDir = path . join ( tmpDir , `workspace-git-dir-test-${ Date . now ( ) } ` )
855+ const testRepo = await initWorkspaceRepo ( { workspaceDir : testWorkspaceDir } )
856+
857+ // Set GIT_DIR to point to the external repository BEFORE creating the service
858+ // This simulates the Dev Container environment where GIT_DIR is already set
859+ const originalGitDir = process . env . GIT_DIR
860+ const externalDotGit = path . join ( externalGitDir , ".git" )
861+ process . env . GIT_DIR = externalDotGit
862+
863+ try {
864+ // Create a new checkpoint service with GIT_DIR already set
865+ // This is the key difference - we're creating the service
866+ // while GIT_DIR is set, just like in a real Dev Container
867+ const testService = await klass . create ( {
868+ taskId : `test-git-dir-${ Date . now ( ) } ` ,
869+ shadowDir : testShadowDir ,
870+ workspaceDir : testWorkspaceDir ,
871+ log : ( ) => { } ,
872+ } )
873+ await testService . initShadowGit ( )
874+
875+ // Make a change in the workspace and save a checkpoint
876+ const testWorkspaceFile = path . join ( testWorkspaceDir , "test.txt" )
877+ await fs . writeFile ( testWorkspaceFile , "Modified with GIT_DIR set" )
878+ const commit = await testService . saveCheckpoint ( "Checkpoint with GIT_DIR set" )
879+ expect ( commit ?. commit ) . toBeTruthy ( )
880+
881+ // Verify the checkpoint was saved in the shadow repo, not the external repo
882+ // Temporarily clear GIT_DIR to check the external repo
883+ delete process . env . GIT_DIR
884+ const externalGitCheck = simpleGit ( externalGitDir )
885+ const externalLogAfter = await externalGitCheck . log ( )
886+ const externalCommitCountAfter = externalLogAfter . total
887+ // Restore GIT_DIR
888+ process . env . GIT_DIR = externalDotGit
889+
890+ // External repo should have the same number of commits (no new commits)
891+ expect ( externalCommitCountAfter ) . toBe ( externalCommitCountBefore )
892+
893+ // Verify the checkpoint is accessible in the shadow repo
894+ const diff = await testService . getDiff ( { to : commit ! . commit } )
895+ expect ( diff ) . toHaveLength ( 1 )
896+ expect ( diff [ 0 ] . paths . relative ) . toBe ( "test.txt" )
897+ expect ( diff [ 0 ] . content . after ) . toBe ( "Modified with GIT_DIR set" )
898+
899+ // Verify we can restore the checkpoint
900+ await fs . writeFile ( testWorkspaceFile , "Another modification" )
901+ await testService . restoreCheckpoint ( commit ! . commit )
902+ expect ( await fs . readFile ( testWorkspaceFile , "utf-8" ) ) . toBe ( "Modified with GIT_DIR set" )
903+ } finally {
904+ // Restore original GIT_DIR
905+ if ( originalGitDir !== undefined ) {
906+ process . env . GIT_DIR = originalGitDir
907+ } else {
908+ delete process . env . GIT_DIR
909+ }
910+
911+ // Clean up external git directory
912+ await fs . rm ( externalGitDir , { recursive : true , force : true } )
913+ }
914+ } )
826915 } )
827916 } ,
828917)
0 commit comments