diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs index 8fc9caea7..2b118aa1b 100644 --- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs +++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs @@ -106,13 +106,13 @@ public void ResolveReference_Packed() using var temp = new TempRoot(); var gitDir = temp.CreateDirectory(); + var commonDir = temp.CreateDirectory(); - gitDir.CreateFile("packed-refs").WriteAllText( + commonDir.CreateFile("packed-refs").WriteAllText( @"# pack-refs with: peeled fully-peeled sorted 1111111111111111111111111111111111111111 refs/heads/master 2222222222222222222222222222222222222222 refs/heads/br2 "); - var commonDir = temp.CreateDirectory(); var refsHeadsDir = commonDir.CreateDirectory("refs").CreateDirectory("heads"); refsHeadsDir.CreateFile("br1").WriteAllText("ref: refs/heads/br2"); @@ -130,14 +130,14 @@ public void ResolveReference_Packed_SHA256() using var temp = new TempRoot(); var gitDir = temp.CreateDirectory(); + var commonDir = temp.CreateDirectory(); // Packed refs with SHA256 hashes (64 characters) - gitDir.CreateFile("packed-refs").WriteAllText( + commonDir.CreateFile("packed-refs").WriteAllText( @"# pack-refs with: peeled fully-peeled sorted 1111111111111111111111111111111111111111111111111111111111111111 refs/heads/master 2222222222222222222222222222222222222222222222222222222222222222 refs/heads/br2 "); - var commonDir = temp.CreateDirectory(); var refsHeadsDir = commonDir.CreateDirectory("refs").CreateDirectory("heads"); refsHeadsDir.CreateFile("br1").WriteAllText("ref: refs/heads/br2"); @@ -230,7 +230,7 @@ public void ResolveReference_RefTable() var gitDir = temp.CreateDirectory(); var commonDir = temp.CreateDirectory(); - var refTableDir = gitDir.CreateDirectory("reftable"); + var refTableDir = commonDir.CreateDirectory("reftable"); refTableDir.CreateFile("tables.list").WriteAllText(""" 2.ref diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs index e32f3af2f..1a9a469e8 100644 --- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs +++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs @@ -130,6 +130,46 @@ public void TryFindRepository_Worktree_Realistic() Assert.Null(repository.WorkingDirectory); } + [Fact] + public void Worktree_Packed_GetHeadCommitSha() + { + using var temp = new TempRoot(); + + var mainWorkingDir = temp.CreateDirectory(); + var mainWorkingSubDir = mainWorkingDir.CreateDirectory("A"); + var mainGitDir = mainWorkingDir.CreateDirectory(".git"); + mainGitDir.CreateFile("HEAD"); + mainGitDir.CreateFile("packed-refs").WriteAllText( +@"# pack-refs with: peeled fully-peeled sorted +1111111111111111111111111111111111111111 refs/heads/master +2222222222222222222222222222222222222222 refs/heads/br2 +"); + + var worktreesDir = mainGitDir.CreateDirectory("worktrees"); + var worktreeGitDir = worktreesDir.CreateDirectory("C"); + var worktreeGitSubDir = worktreeGitDir.CreateDirectory("B"); + var worktreeDir = temp.CreateDirectory(); + var worktreeSubDir = worktreeDir.CreateDirectory("C"); + var worktreeGitFile = worktreeDir.CreateFile(".git").WriteAllText("gitdir: " + worktreeGitDir + " \r\n\t\v"); + + worktreeGitDir.CreateFile("HEAD").WriteAllText("ref: refs/heads/br2\n"); + worktreeGitDir.CreateFile("commondir").WriteAllText("../..\n"); + worktreeGitDir.CreateFile("gitdir").WriteAllText(worktreeGitFile.Path + " \r\n\t\v"); + + // start under worktree directory: + Assert.True(GitRepository.TryFindRepository(worktreeSubDir.Path, out var location)); + Assert.Equal(worktreeGitDir.Path, location.GitDirectory); + Assert.Equal(mainGitDir.Path, location.CommonDirectory); + Assert.Equal(worktreeDir.Path, location.WorkingDirectory); + + var repository = GitRepository.OpenRepository(location, GitEnvironment.Empty); + Assert.Equal(location.GitDirectory, repository.GitDirectory); + Assert.Equal(location.WorkingDirectory, repository.WorkingDirectory); + Assert.Equal(location.CommonDirectory, repository.CommonDirectory); + + Assert.Equal("2222222222222222222222222222222222222222", repository.GetHeadCommitSha()); + } + [Fact] public void LocateRepository_Submodule() { diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs index 8f06c0f4d..dff6a4be0 100644 --- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs +++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs @@ -42,8 +42,8 @@ public GitReferenceResolver(string gitDirectory, string commonDirectory, Referen _commonDirectory = commonDirectory; _storageFormat = storageFormat; _objectNameFormat = objectNameFormat; - _lazyPackedReferences = new(() => ReadPackedReferences(_gitDirectory)); - _lazyRefTableReferenceReaders = new(() => CreateRefTableReaders(_gitDirectory, _openedRefTableReaders)); + _lazyPackedReferences = new(() => ReadPackedReferences(_commonDirectory)); + _lazyRefTableReferenceReaders = new(() => CreateRefTableReaders(_commonDirectory, _openedRefTableReaders)); } public void Dispose() @@ -59,11 +59,15 @@ public void Dispose() } } - private ImmutableDictionary ReadPackedReferences(string gitDirectory) + private ImmutableDictionary ReadPackedReferences(string commonDirectory) { // https://git-scm.com/docs/git-pack-refs - var packedRefsPath = Path.Combine(gitDirectory, PackedRefsFileName); + // Although the above doc specifies 'packaged-refs' file is in GIT_DIR, + // it is actually in the common directory as specified in + // https://git-scm.com/docs/gitrepository-layout#Documentation/gitrepository-layout.txt-packed-refs + + var packedRefsPath = Path.Combine(commonDirectory, PackedRefsFileName); if (!File.Exists(packedRefsPath)) { return ImmutableDictionary.Empty; @@ -174,9 +178,12 @@ internal ImmutableDictionary ReadPackedReferences(TextReader rea /// /// - private static IEnumerable CreateRefTableReaders(string gitDirectory, List openReaders) + private static IEnumerable CreateRefTableReaders(string commonDirectory, List openReaders) { - var refTableDirectory = Path.Combine(gitDirectory, RefTableDirectoryName); + // Although https://git-scm.com/docs/reftable#_layout specifies reftable to be in GIT_DIR, + // it is actually in the common directory. This is currently not documented. + + var refTableDirectory = Path.Combine(commonDirectory, RefTableDirectoryName); var tablesFilePath = Path.Combine(refTableDirectory, TablesListFileName); // Create lazily-evaluated sequence of readers for each entry in the tables.list file (in reverse order).