diff --git a/src/parser/ArcanistBundle.php b/src/parser/ArcanistBundle.php --- a/src/parser/ArcanistBundle.php +++ b/src/parser/ArcanistBundle.php @@ -560,7 +560,16 @@ } } - if ($jj - $last_change > (($context + 1) * 2)) { + // If the context value is "3" and there are 7 unchanged lines + // between the two changes, we could either generate one or two hunks + // and end up with the same number of output lines. If we generate + // one hunk, the middle line will be a line of source. If we generate + // two hunks, the middle line will be an "@@ -1,2 +3,4 @@" header. + + // We choose to generate two hunks because this is the behavior of + // "diff -u". See PHI838. + + if ($jj - $last_change >= ($context * 2 + 1)) { // We definitely aren't going to merge this with the next hunk, so // break out of the loop. We'll end the hunk at $break_here. break; diff --git a/src/parser/__tests__/ArcanistBundleTestCase.php b/src/parser/__tests__/ArcanistBundleTestCase.php --- a/src/parser/__tests__/ArcanistBundleTestCase.php +++ b/src/parser/__tests__/ArcanistBundleTestCase.php @@ -642,6 +642,24 @@ 'disjoint-hunks.new')->toUnifiedDiff()); } + public function testMergeHunks() { + // Hunks should merge if represented by sufficiently few unchanged + // lines. + $this->assertEqual( + $this->loadResource('merge-hunks.diff'), + $this->loadOneChangeBundle( + 'merge-hunks.old', + 'merge-hunks.new')->toUnifiedDiff()); + + // Hunks should not merge if they are separated by too many unchanged + // lines. + $this->assertEqual( + $this->loadResource('no-merge-hunks.diff'), + $this->loadOneChangeBundle( + 'no-merge-hunks.old', + 'no-merge-hunks.new')->toUnifiedDiff()); + } + public function testNonlocalTrailingNewline() { // Diffs without changes near the end of the file should not generate a // bogus, change-free hunk if the file has no trailing newline. diff --git a/src/parser/__tests__/bundle/merge-hunks.diff b/src/parser/__tests__/bundle/merge-hunks.diff new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/bundle/merge-hunks.diff @@ -0,0 +1,19 @@ +Index: file +=================================================================== +--- file ++++ file +@@ -2,12 +2,14 @@ + B + C + D ++Chocolate + E + F + G + H + I + J ++Caramel + K + L + M diff --git a/src/parser/__tests__/bundle/merge-hunks.new b/src/parser/__tests__/bundle/merge-hunks.new new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/bundle/merge-hunks.new @@ -0,0 +1,17 @@ +A +B +C +D +Chocolate +E +F +G +H +I +J +Caramel +K +L +M +N +O diff --git a/src/parser/__tests__/bundle/merge-hunks.old b/src/parser/__tests__/bundle/merge-hunks.old new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/bundle/merge-hunks.old @@ -0,0 +1,15 @@ +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O diff --git a/src/parser/__tests__/bundle/no-merge-hunks.diff b/src/parser/__tests__/bundle/no-merge-hunks.diff new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/bundle/no-merge-hunks.diff @@ -0,0 +1,20 @@ +Index: file +=================================================================== +--- file ++++ file +@@ -2,6 +2,7 @@ + B + C + D ++Chocolate + E + F + G +@@ -9,6 +10,7 @@ + I + J + K ++Caramel + L + M + N diff --git a/src/parser/__tests__/bundle/no-merge-hunks.new b/src/parser/__tests__/bundle/no-merge-hunks.new new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/bundle/no-merge-hunks.new @@ -0,0 +1,17 @@ +A +B +C +D +Chocolate +E +F +G +H +I +J +K +Caramel +L +M +N +O diff --git a/src/parser/__tests__/bundle/no-merge-hunks.old b/src/parser/__tests__/bundle/no-merge-hunks.old new file mode 100644 --- /dev/null +++ b/src/parser/__tests__/bundle/no-merge-hunks.old @@ -0,0 +1,15 @@ +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O