Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any example to use git merge patience strategy?

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

like image 621
IgnazioC Avatar asked Nov 06 '17 21:11

IgnazioC


2 Answers

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.)

like image 178
Mort Avatar answered Sep 24 '22 13:09

Mort


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.

like image 45
torek Avatar answered Sep 25 '22 13:09

torek