5

I cannot find any real example where the --patience gives different result than the normal strategy.

Based on this answer, if I have this file:

.foo1 {
    margin: 0;
}

.bar {
    margin: 0;
}

and I update it in this way:

.bar {
    margin: 0;
}

.foo1 {
    margin: 0;
    color: green;
}

I should see two different diffs depend which algorithm I'm using.

But for me the output of these commands is always the same

git diff --diff-algorithm=patience
git diff

diff --git a/foo.bar b/foo.bar
index 453dcb1..42cd4b4 100644
--- a/foo.bar
+++ b/foo.bar
@@ -1,7 +1,8 @@
-.foo1 {
+.bar {
     margin: 0;
 }

-.bar {
+.foo1 {
     margin: 0;
+    color: green;
 }
\ No newline at end of file

I'm using git version 2.14.2

IgnazioC
  • 4,554
  • 4
  • 33
  • 46

3 Answers3

4

I see --patience being useful all the time in cases where there are a string of functions and one new one is added in the middle.

int foo(void)
{
  ...
}

int baz(void)
{
  ...
}

If you add int bar() in between the two, the diff can often look like this:

+ }
+
+ int bar()
+ {
+    ...

Which is correct, but unintuitive.

But with --patience you get the expected

+ int bar()
+ {
+   ...
+ }
+

As well as adding a level of intuitiveness, it adds predictability. This can be useful if you're doing a meta-diff (diff of diffs): taking two sets of changes and comparing them to see if the same change was made in both places. If one diff calculates the bracketing in one way and the other one calculates the bracketing in another way, you will incorrectly determine that your two sets of changes are not equivalent. But if you tell git to use --patience you get the predictability of a consistent format. (This is not theoretical, but rather learned through bitter experience.)

Mort
  • 3,379
  • 1
  • 25
  • 40
1

The "patience" algorithm throws out lines that repeat, before matching up the remaining lines. (This is a little oversimplified—it throws out repeated lines in the sub-box it's differencing; on each recursion, it throws out whichever lines repeat within the sub-box only, rather than across the entire file. For the first pass, though, the sub-box is "the entire file".)

In your example, there are two lines that repeat, namely margin: 0; and }. So the initial input to the patience diff subsequence-finder is:

.foo1 {

.bar {

for the left or "A" side and:

.bar {

.foo1 {
    color: green;

for the right or "B" side.

The blank line matches, and the .foo1 { line matches. But these are not in order, and are only one element long anyway, so they are not useful.

The algorithm as a whole then falls back to normal diff, and you get the same output as for normal diff.

Edit: how to construct examples

It's not that easy to construct inputs for which the algorithm gives different results. What you need is to have long common subsequences that are found after discarding repeated lines, but not found without doing so. Consider writing something like:

line 1
line 2
noise
noise
noise
noise
line 3
noise
noise
noise
line 4

as part of the input (on one or both "sides", A and B, of the diff), and then making changes only in "non-noise" lines. Plain git diff will synchronize on the noise lines (use a different number of noise lines in each section), while patience diff will throw them away. If one of the many noise lines sections makes up part of the longest common subsequence, plain diff will choose to match that up, and then recurse to find differences within the sections above or below the match. When the de-noised version has a different longest common subsequence, patience diff will match those up, and recurse on the (now-different) unmatched sub-sequences.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Any thoughts on minimal and histogram? – mleykamp Dec 19 '17 at 23:20
  • @mleykamp: `minimal` removes short-cuts that make Myers faster. In my opinion it's not really useful in practice (there are few cases where it results in a shorter diff and the shorter diff isn't really "better"). `histogram` is like `patience` except that it's weighted, instead of just excluding repeat lines. It biases in favor of matching non-repeated lines. There was a bug in its implementation pre-Git-2.12. In theory it should now be the best diff, but I haven't tried it on a lot of inputs. – torek Dec 20 '17 at 05:03
0

Reminder: With Git 2.33.1 (Q4 2021), the pamtience merge strategy is no more, replaced by the default merge ORT ("Ostensibly Recursive's Twin").

See commit 81483fe, commit 67feccd, commit 6320813, commit b36ade2, commit 4d15c85, commit 002a6df, commit 510415e, commit e80178e, commit b378df7, commit e037c2e (04 Aug 2021) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit aca13c2, 30 Aug 2021)

merge-strategies.txt: avoid giving special preference to patience algorithm

Acked-by: Derrick Stolee
Acked-by: Johannes Schindelin
Signed-off-by: Elijah Newren

We already have diff-algorithm that explains why there are special diff algorithms, so we do not need to re-explain patience.
patience exists as its own toplevel option for historical reasons, but there's no reason to give it special preference or document it again and suggest it's more important than other diff algorithms, so just refer to it as a deprecated shorthand for diff-algorithm=patience.

merge-strategies now includes in its man page:

Deprecated synonym for diff-algorithm=patience.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250