diff --git a/src/main.rs b/src/main.rs index 9fdce2e..2797a3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,7 +66,7 @@ fn main() { }); for repo in rx { - let repo_path = repo.path().parent().expect("GIT_DIR cannot be root").display(); + let repo_path = repo.workdir().unwrap_or_else(|| repo.commondir()).display(); println!("{repo_path}"); @@ -126,16 +126,16 @@ impl Walker { continue; } - let git_dir = entry_path.join(GIT_DIR); - - if !git_dir.is_dir() { - // Descend deeper into directories that are not git repositories. - ok_or_continue!(self.walk(&entry_path, tx.clone())); - continue; + match ok_or_continue!(try_get_git_dir(&entry_path)) { + Some(git_dir) => tx + .send(ok_or_continue!(Repository::open(git_dir))) + .expect("main thread paniced"), + None => { + // Descend deeper into directories that are not git repositories. + ok_or_continue!(self.walk(&entry_path, tx.clone())); + continue; + } } - - tx.send(ok_or_continue!(Repository::open(git_dir))) - .expect("main thread paniced"); } Ok(()) @@ -154,6 +154,44 @@ fn is_cache_dir(path: &Path) -> io::Result { Ok(CACHE_DIR_TAG_HEADER == buf) } +fn try_get_git_dir(path: &Path) -> io::Result> { + let git_dir = path.join(GIT_DIR); + + if git_dir.is_dir() { + return Ok(Some(git_dir)); + } + + if !git_dir.is_file() { + return Ok(None); + } + + let mut buf = [0u8; 1024 * 8]; + let mut file = File::open(&git_dir)?; + let n = file.read(&mut buf)?; + + let Some(str) = buf[0..n].strip_prefix(b"gitdir: ") else { + log::info!("ingoring .git: unreleated contents: {}", git_dir.display()); + return Ok(None); + }; + + let Ok(str) = String::from_utf8(str.trim_ascii().into()) else { + log::info!("ingoring .git: non-utf8 gitdir path: {}", git_dir.display()); + return Ok(None); + }; + + let parent_git_dir = git_dir + .parent() + .expect("GIT_DIR cannot be at root") + .join(str); + + if parent_git_dir.is_dir() { + return Ok(Some(parent_git_dir)); + } + + log::info!("ingoring .git: orphan worktree: {}", git_dir.display()); + Ok(None) +} + fn is_hidden_file(path: &Path) -> bool { let Some(str) = path.file_name() else { return false;