@@ -20,25 +20,50 @@ pub fn find_git_repository_workdirs(
2020 threads : Option < usize > ,
2121) -> impl Iterator < Item = ( PathBuf , gix:: repository:: Kind ) > {
2222 progress. init ( None , progress:: count ( "filesystem items" ) ) ;
23- fn is_repository ( path : & Path ) -> Option < gix:: repository:: Kind > {
23+
24+ #[ derive( Debug , Clone , Copy ) ]
25+ struct RepoInfo {
26+ kind : gix:: repository:: Kind ,
27+ is_bare : bool ,
28+ }
29+
30+ fn is_repository ( path : & Path ) -> Option < RepoInfo > {
2431 // Can be git dir or worktree checkout (file)
2532 if path. file_name ( ) != Some ( OsStr :: new ( ".git" ) ) && path. extension ( ) != Some ( OsStr :: new ( "git" ) ) {
2633 return None ;
2734 }
2835
2936 if path. is_dir ( ) {
3037 if path. join ( "HEAD" ) . is_file ( ) && path. join ( "config" ) . is_file ( ) {
31- gix:: discover:: is_git ( path) . ok ( ) . map ( Into :: into)
38+ gix:: discover:: is_git ( path) . ok ( ) . map ( |discovered_kind| {
39+ let is_bare = discovered_kind. is_bare ( ) ;
40+ let kind = match discovered_kind {
41+ gix:: discover:: repository:: Kind :: PossiblyBare => gix:: repository:: Kind :: Common ,
42+ gix:: discover:: repository:: Kind :: WorkTree { linked_git_dir : None } => {
43+ gix:: repository:: Kind :: Common
44+ }
45+ gix:: discover:: repository:: Kind :: WorkTree {
46+ linked_git_dir : Some ( _) ,
47+ } => gix:: repository:: Kind :: LinkedWorkTree ,
48+ gix:: discover:: repository:: Kind :: WorkTreeGitDir { .. } => gix:: repository:: Kind :: LinkedWorkTree ,
49+ gix:: discover:: repository:: Kind :: Submodule { .. } => gix:: repository:: Kind :: Submodule ,
50+ gix:: discover:: repository:: Kind :: SubmoduleGitDir => gix:: repository:: Kind :: Submodule ,
51+ } ;
52+ RepoInfo { kind, is_bare }
53+ } )
3254 } else {
3355 None
3456 }
3557 } else {
36- // git files are always worktrees
37- Some ( gix:: repository:: Kind :: WorkTree { is_linked : true } )
58+ // git files are always linked worktrees
59+ Some ( RepoInfo {
60+ kind : gix:: repository:: Kind :: LinkedWorkTree ,
61+ is_bare : false ,
62+ } )
3863 }
3964 }
40- fn into_workdir ( git_dir : PathBuf , kind : & gix :: repository :: Kind ) -> PathBuf {
41- if matches ! ( kind , gix :: repository :: Kind :: Bare ) || gix :: discover :: is_bare ( & git_dir ) {
65+ fn into_workdir ( git_dir : PathBuf , info : & RepoInfo ) -> PathBuf {
66+ if info . is_bare {
4267 git_dir
4368 } else {
4469 git_dir. parent ( ) . expect ( "git is never in the root" ) . to_owned ( )
@@ -47,7 +72,7 @@ pub fn find_git_repository_workdirs(
4772
4873 #[ derive( Debug , Default ) ]
4974 struct State {
50- kind : Option < gix :: repository :: Kind > ,
75+ info : Option < RepoInfo > ,
5176 }
5277
5378 let walk = jwalk:: WalkDirGeneric :: < ( ( ) , State ) > :: new ( root)
@@ -64,9 +89,9 @@ pub fn find_git_repository_workdirs(
6489 let mut found_bare_repo = false ;
6590 for entry in siblings. iter_mut ( ) . flatten ( ) {
6691 let path = entry. path ( ) ;
67- if let Some ( kind ) = is_repository ( & path) {
68- let is_bare = kind . is_bare ( ) ;
69- entry. client_state = State { kind : kind . into ( ) } ;
92+ if let Some ( info ) = is_repository ( & path) {
93+ let is_bare = info . is_bare ;
94+ entry. client_state = State { info : info . into ( ) } ;
7095 entry. read_children_path = None ;
7196
7297 found_any_repo = true ;
@@ -76,17 +101,17 @@ pub fn find_git_repository_workdirs(
76101 // Only return paths which are repositories are further participating in the traversal
77102 // Don't let bare repositories cause siblings to be pruned.
78103 if found_any_repo && !found_bare_repo {
79- siblings. retain ( |e| e. as_ref ( ) . map ( |e| e. client_state . kind . is_some ( ) ) . unwrap_or ( false ) ) ;
104+ siblings. retain ( |e| e. as_ref ( ) . map ( |e| e. client_state . info . is_some ( ) ) . unwrap_or ( false ) ) ;
80105 }
81106 } )
82107 . into_iter ( )
83108 . inspect ( move |_| progress. inc ( ) )
84109 . filter_map ( Result :: ok)
85110 . filter_map ( |mut e| {
86111 e. client_state
87- . kind
112+ . info
88113 . take ( )
89- . map ( |kind | ( into_workdir ( e. path ( ) , & kind ) , kind) )
114+ . map ( |info | ( into_workdir ( e. path ( ) , & info ) , info . kind ) )
90115 } )
91116}
92117
@@ -108,7 +133,8 @@ fn handle(
108133 canonicalized_destination : & Path ,
109134 progress : & mut impl Progress ,
110135) -> anyhow:: Result < ( ) > {
111- if let gix:: repository:: Kind :: WorkTree { is_linked : true } = kind {
136+ // Skip linked worktrees - we only handle Common and Submodule kinds
137+ if matches ! ( kind, gix:: repository:: Kind :: LinkedWorkTree ) {
112138 return Ok ( ( ) ) ;
113139 }
114140 fn to_relative ( path : PathBuf ) -> PathBuf {
@@ -173,13 +199,24 @@ fn handle(
173199 let mut path = gix_url:: expand_path ( None , url. path . as_bstr ( ) ) ?;
174200 match kind {
175201 gix:: repository:: Kind :: Submodule => {
176- unreachable ! ( "BUG: We should not try to relocated submodules and not find them the first place" )
202+ unreachable ! ( "BUG: We should not try to relocate submodules and not find them the first place" )
203+ }
204+ gix:: repository:: Kind :: LinkedWorkTree => {
205+ unreachable ! ( "BUG: LinkedWorkTree should have been skipped earlier" )
177206 }
178- gix:: repository:: Kind :: Bare => path,
179- gix:: repository:: Kind :: WorkTree { .. } => {
180- if let Some ( ext) = path. extension ( ) {
181- if ext == "git" {
182- path. set_extension ( "" ) ;
207+ gix:: repository:: Kind :: Common => {
208+ // For Common kind, check if it's bare
209+ let git_dir = if git_workdir. join ( ".git" ) . is_dir ( ) {
210+ git_workdir. join ( ".git" )
211+ } else {
212+ git_workdir. to_owned ( )
213+ } ;
214+ if !gix:: discover:: is_bare ( & git_dir) {
215+ // Non-bare repository - strip .git extension if present
216+ if let Some ( ext) = path. extension ( ) {
217+ if ext == "git" {
218+ path. set_extension ( "" ) ;
219+ }
183220 }
184221 }
185222 path
0 commit comments