diff --git a/GitIntegration.Test/Builders/GitCommitBuilderTests.cs b/GitIntegration.Test/Builders/GitCommitBuilderTests.cs index 0496962..4baa79c 100644 --- a/GitIntegration.Test/Builders/GitCommitBuilderTests.cs +++ b/GitIntegration.Test/Builders/GitCommitBuilderTests.cs @@ -203,6 +203,24 @@ await Assert.ThrowsExactlyAsync( .ConfigureAwait(false); } + [TestMethod] + public async Task ThrowsNothingToCommitWhenTrackedChangesAreUnstagedAsync() + { + // The third phrasing, and the most common case: a tracked file is modified but nothing is + // staged. It contains neither of the other two phrases. + ScriptedGitProcessRunner runner = new ScriptedGitProcessRunner() + .Then( + standardOutput: + "On branch main\nChanges not staged for commit:\n\tmodified: f\n\n" + + "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n", + exitCode: 1); + GitCommitBuilder builder = new(runner, TestPaths.Root, Message); + + await Assert.ThrowsExactlyAsync( + async () => await builder.ExecuteAsync(TestContext.CancellationTokenSource.Token).ConfigureAwait(false)) + .ConfigureAwait(false); + } + [TestMethod] public async Task AnOrdinaryCommitFailureStaysAGenericCommandExceptionAsync() { diff --git a/GitIntegration/Builders/GitCommitBuilder.cs b/GitIntegration/Builders/GitCommitBuilder.cs index feb8be7..483feaf 100644 --- a/GitIntegration/Builders/GitCommitBuilder.cs +++ b/GitIntegration/Builders/GitCommitBuilder.cs @@ -218,9 +218,10 @@ protected override string GetDiagnostic(GitProcessResult result) => /// /// /// Overridden because the base class inspects standard error and git reports "nothing to - /// commit" on standard output, leaving standard error empty. Both of git's phrasings - /// are matched: the tree may be clean, or it may hold only untracked files, and neither message - /// contains the other. The match depends on the LC_ALL=C that + /// commit" on standard output, leaving standard error empty. All three of git's + /// phrasings are matched: the tree may be clean ("nothing to commit"), it may hold only untracked + /// files ("nothing added to commit"), or tracked files may be modified with nothing staged ("no + /// changes added to commit"). None of these messages contains another. The match depends on the LC_ALL=C that /// RunCommandGitProcessRunner forces on every invocation. A failing pre-commit hook whose /// own standard output happened to contain one of these phrases would be misclassified as /// ; that risk is accepted as narrow. @@ -232,7 +233,8 @@ protected override GitCommandException CreateException(GitProcessResult result) Ensure.NotNull(result); if (result.StandardOutput.Contains("nothing to commit", StringComparison.Ordinal) || - result.StandardOutput.Contains("nothing added to commit", StringComparison.Ordinal)) + result.StandardOutput.Contains("nothing added to commit", StringComparison.Ordinal) || + result.StandardOutput.Contains("no changes added to commit", StringComparison.Ordinal)) { return new GitNothingToCommitException( $"There is nothing staged to commit: {result.StandardOutput.Trim()}",