From 5e2c4f1d59413df38059baed8ddf73350fb5139a Mon Sep 17 00:00:00 2001 From: Chris Rummel Date: Thu, 12 Aug 2021 13:29:16 -0500 Subject: [PATCH] Allow using .git directory instead of gitdir redirect in submodules. (#653) * Allow using .git directory instead of gitdir redirect in submodules. * Address review comments and add test for old-style submodule behavior. * Use .git dir as the common directory as well. * Add more details to the comments about how this case can happen. * Address code review comments. * Allow empty dir Co-authored-by: tmat --- .../GitRepositoryTests.cs | 23 +++++++++++++++++-- .../GitDataReader/GitRepository.cs | 8 ++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs index c0e502af..f1fe9428 100644 --- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs +++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs @@ -297,6 +297,7 @@ public void Submodules_Errors() { "S10: 'sub10' 'http://github.com'", "S11: 'sub11' 'http://github.com'", + "S6: 'sub6' 'http://github.com'", "S9: 'sub9' 'http://github.com'" }, submodules.Select(s => $"{s.Name}: '{s.WorkingDirectoryRelativePath}' '{s.Url}'")); @@ -313,8 +314,6 @@ public void Submodules_Errors() TestUtilities.GetExceptionMessage(() => File.ReadAllText(Path.Combine(workingDir.Path, "sub4", ".git"))), // Could not find a part of the path 'sub5\.git'. TestUtilities.GetExceptionMessage(() => File.ReadAllText(Path.Combine(workingDir.Path, "sub5", ".git"))), - // Access to the path 'sub6\.git' is denied - TestUtilities.GetExceptionMessage(() => File.ReadAllText(Path.Combine(workingDir.Path, "sub6", ".git"))), // The format of the file 'sub7\.git' is invalid. string.Format(Resources.FormatOfFileIsInvalid, Path.Combine(workingDir.Path, "sub7", ".git")), // Path specified in file 'sub8\.git' is invalid. @@ -358,5 +357,25 @@ public void GetSubmoduleHeadCommitSha() var repository = new GitRepository(GitEnvironment.Empty, GitConfig.Empty, gitDir.Path, gitDir.Path, workingDir.Path); Assert.Equal("0000000000000000000000000000000000000000", repository.ReadSubmoduleHeadCommitSha(submoduleWorkingDir.Path)); } + + [Fact] + public void GetOldStyleSubmoduleHeadCommitSha() + { + using var temp = new TempRoot(); + + var gitDir = temp.CreateDirectory(); + var workingDir = temp.CreateDirectory(); + + // this is a unusual but legal case which can occur with older versions of Git or other tools. + // see https://git-scm.com/docs/gitsubmodules#_forms for more details. + var oldStyleSubmoduleWorkingDir = workingDir.CreateDirectory("old-style-submodule"); + var oldStyleSubmoduleGitDir = oldStyleSubmoduleWorkingDir.CreateDirectory(".git"); + var oldStyleSubmoduleRefsHeadDir = oldStyleSubmoduleGitDir.CreateDirectory("refs").CreateDirectory("heads"); + oldStyleSubmoduleRefsHeadDir.CreateFile("branch1").WriteAllText("1111111111111111111111111111111111111111"); + oldStyleSubmoduleGitDir.CreateFile("HEAD").WriteAllText("ref: refs/heads/branch1"); + + var repository = new GitRepository(GitEnvironment.Empty, GitConfig.Empty, gitDir.Path, gitDir.Path, workingDir.Path); + Assert.Equal("1111111111111111111111111111111111111111", repository.ReadSubmoduleHeadCommitSha(oldStyleSubmoduleWorkingDir.Path)); + } } } diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs index 30ee72bc..7b77bbc7 100644 --- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs +++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs @@ -211,7 +211,13 @@ public static GitRepository OpenRepository(GitRepositoryLocation location, GitEn /// Null if the HEAD tip reference can't be resolved. internal string? ReadSubmoduleHeadCommitSha(string submoduleWorkingDirectoryFullPath) { - var gitDirectory = ReadDotGitFile(Path.Combine(submoduleWorkingDirectoryFullPath, GitDirName)); + // Submodules don't usually have their own .git directories but this is still legal. + // This can occur with older versions of Git or other tools, or when a user clones one + // repo into another's source tree (but it was not yet registered as a submodule). + // See https://git-scm.com/docs/gitsubmodules#_forms for more details. + var dotGitPath = Path.Combine(submoduleWorkingDirectoryFullPath, GitDirName); + + var gitDirectory = Directory.Exists(dotGitPath) ? dotGitPath : ReadDotGitFile(dotGitPath); if (!IsGitDirectory(gitDirectory, out var commonDirectory)) { return null;