diff --git a/GitIntegration.Test/Builders/GitPatchBuilderTests.cs b/GitIntegration.Test/Builders/GitPatchBuilderTests.cs index 1193da3..daf23f1 100644 --- a/GitIntegration.Test/Builders/GitPatchBuilderTests.cs +++ b/GitIntegration.Test/Builders/GitPatchBuilderTests.cs @@ -28,6 +28,7 @@ public void BuildsTheDefaultPatchVector() "--no-color", "--src-prefix=a/", "--dst-prefix=b/", + "--submodule=short", "-U3", "--no-renames", ]; diff --git a/GitIntegration.Test/Integration/GitSubmoduleTests.cs b/GitIntegration.Test/Integration/GitSubmoduleTests.cs index 084a319..566e3d4 100644 --- a/GitIntegration.Test/Integration/GitSubmoduleTests.cs +++ b/GitIntegration.Test/Integration/GitSubmoduleTests.cs @@ -3,6 +3,7 @@ namespace ktsu.GitIntegration.Test; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -164,6 +165,53 @@ await IntegrationGitFixture.ConfigureIdentityAsync(checkout, AuthorName, AuthorE Assert.AreNotEqual(after[0].Sha, after[0].CheckedOutSha); } + [TestMethod] + [DataRow("log")] + [DataRow("diff")] + public async Task PatchReportsAMovedSubmoduleAsItsGitlinkWhateverDiffSubmoduleSaysAsync(string format) + { + CancellationToken cancellationToken = TestContext.CancellationTokenSource.Token; + await IntegrationGitFixture.RequireGitAsync(cancellationToken).ConfigureAwait(false); + + using TemporaryRepository subDirectory = new(); + using TemporaryRepository superDirectory = new(); + + GitRepository sub = await CreateRepositoryAsync(subDirectory, "s.txt", cancellationToken).ConfigureAwait(false); + GitRepository super = await CreateRepositoryAsync(superDirectory, "m.txt", cancellationToken).ConfigureAwait(false); + + await AddSubmoduleAsync(super, sub.LocalPath!, "libs/sub", cancellationToken).ConfigureAwait(false); + + // Move the submodule's checkout on by a commit, so the superproject sees its gitlink change. + GitRepository checkout = new() + { + LocalPath = System.IO.Path.Join(superDirectory.RootPath, "libs", "sub").As(), + ProcessRunner = super.ProcessRunner, + }; + + await IntegrationGitFixture.ConfigureIdentityAsync(checkout, AuthorName, AuthorEmail, cancellationToken) + .ConfigureAwait(false); + + superDirectory.WriteFile("libs/sub/s.txt", "two\n"); + _ = await checkout.Add().All().ExecuteAsync(cancellationToken).ConfigureAwait(false); + _ = await checkout.Commit("c2".As()).ExecuteAsync(cancellationToken).ConfigureAwait(false); + + // Written into the superproject's own config, which is the nearest scope git reads it from. + _ = await new GitTextBuilder(super.ProcessRunner!, super.LocalPath, "config", "diff.submodule", format) + .ExecuteAsync(cancellationToken).ConfigureAwait(false); + + GitPatch patch = await super.Patch().ExecuteAsync(cancellationToken).ConfigureAwait(false); + + // "log" left the change out entirely, and "diff" reported libs/sub/s.txt in its place + // (ktsu-dev/GitIntegration#124). + GitFilePatch file = patch.Files.Single(); + Assert.AreEqual("libs/sub".As(), file.Path); + + _ = await super.Apply(file.PatchFor(file.Hunks)).ToIndex().ExecuteAsync(cancellationToken).ConfigureAwait(false); + + GitPatch staged = await super.Patch().Staged().ExecuteAsync(cancellationToken).ConfigureAwait(false); + Assert.AreEqual("libs/sub".As(), staged.Files.Single().Path); + } + [TestMethod] public async Task ReportsAnUninitializedSubmoduleAndThenUpdatesItAsync() { diff --git a/GitIntegration/Builders/GitPatchBuilder.cs b/GitIntegration/Builders/GitPatchBuilder.cs index 927961e..c4ee8d1 100644 --- a/GitIntegration/Builders/GitPatchBuilder.cs +++ b/GitIntegration/Builders/GitPatchBuilder.cs @@ -178,6 +178,12 @@ protected override void AppendVerbArguments(ICollection arguments) arguments.Add("--src-prefix=a/"); arguments.Add("--dst-prefix=b/"); + // diff.submodule=log prints a moved submodule as a "Submodule sub a..b:" summary with no + // diff --git block, so the change is missing from the patch, and =diff prints the + // submodule's own files as if they were the superproject's, which apply then refuses. + // Only the short form is a gitlink patch that stages (ktsu-dev/GitIntegration#124). + arguments.Add("--submodule=short"); + if (_staged) { arguments.Add("--cached");