Fix commondir discovery for git submodules (#28802)

The implementation of commondir discovery in #27885 was wrong, most
significantly for submodules but also for worktrees in rarer cases. The
correct procedure, implemented in this PR, is:

> If `.git` is a file, look at the `gitdir` it points to. If that
directory has a file called `commondir`, read that file to find the
commondir. (This is what happens for worktrees.) Otherwise, the
commondir is the same as the gitdir. (This is what happens for
submodules.)

Release Notes:

- N/A
This commit is contained in:
Cole Miller 2025-04-15 23:32:59 -04:00 committed by GitHub
parent 41cffa64b0
commit f3f2c6d811
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 118 additions and 33 deletions

View file

@ -1333,13 +1333,23 @@ impl FakeFs {
let Some((git_dir_entry, canonical_path)) = state.try_read_path(&path, true) else {
anyhow::bail!("pointed-to git dir {path:?} not found")
};
let FakeFsEntry::Dir { git_repo_state, .. } = &mut *git_dir_entry.lock() else {
let FakeFsEntry::Dir {
git_repo_state,
entries,
..
} = &mut *git_dir_entry.lock()
else {
anyhow::bail!("gitfile points to a non-directory")
};
let common_dir = canonical_path
.ancestors()
.find(|ancestor| ancestor.ends_with(".git"))
.ok_or_else(|| anyhow!("repository dir not contained in any .git"))?;
let common_dir = if let Some(child) = entries.get("commondir") {
Path::new(
std::str::from_utf8(child.lock().file_content("commondir".as_ref())?)
.context("commondir content")?,
)
.to_owned()
} else {
canonical_path.clone()
};
let repo_state = git_repo_state.get_or_insert_with(|| {
Arc::new(Mutex::new(FakeGitRepositoryState::new(
state.git_event_tx.clone(),
@ -1347,7 +1357,7 @@ impl FakeFs {
});
let mut repo_state = repo_state.lock();
let result = f(&mut repo_state, &canonical_path, common_dir);
let result = f(&mut repo_state, &canonical_path, &common_dir);
if emit_git_event {
state.emit_event([(canonical_path, None)]);