@@ -43,6 +43,11 @@ describe("normalizePathspec", () => {
4343 expect ( normalizePathspec ( "!/desktop/**" ) ) . toBe ( "!desktop/**" ) ;
4444 } ) ;
4545
46+ it ( "should trim whitespace between the negation and the path" , ( ) => {
47+ expect ( normalizePathspec ( "! mobile/**" ) ) . toBe ( "!mobile/**" ) ;
48+ expect ( normalizePathspec ( "! ./desktop/**" ) ) . toBe ( "!desktop/**" ) ;
49+ } ) ;
50+
4651 it ( "should handle empty strings" , ( ) => {
4752 expect ( normalizePathspec ( "" ) ) . toBe ( "" ) ;
4853 } ) ;
@@ -92,6 +97,7 @@ describe("buildPathspecArgs", () => {
9297
9398 it ( "should ignore an empty negated pattern" , ( ) => {
9499 expect ( buildPathspecArgs ( [ "!" ] ) ) . toEqual ( [ ] ) ;
100+ expect ( buildPathspecArgs ( [ "! " ] ) ) . toEqual ( [ ] ) ;
95101 } ) ;
96102} ) ;
97103
@@ -1182,6 +1188,19 @@ describe("merge commit handling", () => {
11821188 expect ( branchNames ) . toContain ( "feat/XYZ-2-impl" ) ;
11831189 } ) ;
11841190
1191+ it ( "applies merge retention under an exclusion-only filter" , async ( ) => {
1192+ // With `!app-a/**` the stale merge delivered only excluded paths, so it
1193+ // must be dropped, while the merge that delivered app-b/ is retained.
1194+ const result = await getCommitContextsBetweenShas ( repo . commits . base , repo . commits . subjectMerge , {
1195+ includePaths : [ "!app-a/**" ] ,
1196+ cwd : repo . cwd ,
1197+ } ) ;
1198+
1199+ const branchNames = result . map ( ( c ) => c . branchName ) . filter ( ( b ) : b is string => ! ! b ) ;
1200+ expect ( branchNames ) . not . toContain ( "feat/ABC-1-stale" ) ;
1201+ expect ( branchNames ) . toContain ( "feat/XYZ-2-impl" ) ;
1202+ } ) ;
1203+
11851204 it ( "still attributes a stale merge to the surface it actually touched" , async ( ) => {
11861205 // The same stale merge DID deliver app-a/ changes, so under an app-a filter
11871206 // its subject key is correctly retained — the fix discards leaks, not work.
0 commit comments