diff FEATURE merge diff
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index 22ae0b9..a282659 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -26,7 +26,9 @@
     struct ly_ctx *ctx;
     struct lyd_node *first;
     struct lyd_node *second;
-    struct lyd_node *diff;
+    struct lyd_node *third;
+    struct lyd_node *diff1;
+    struct lyd_node *diff2;
     char *xml;
     char *xml1;
     char *xml2;
@@ -238,7 +240,9 @@
 
     lyd_free_siblings(st->first);
     lyd_free_siblings(st->second);
-    lyd_free_siblings(st->diff);
+    lyd_free_siblings(st->third);
+    lyd_free_siblings(st->diff1);
+    lyd_free_siblings(st->diff2);
     ly_ctx_destroy(st->ctx, NULL);
     free(st->xml);
     free(st->xml1);
@@ -259,7 +263,7 @@
     assert_non_null(st->first);
     st->second = NULL;
 
-    assert_int_equal(lyd_diff(st->first, lyd_node_children(st->first, 0), 0, &st->diff), LY_EINVAL);
+    assert_int_equal(lyd_diff(st->first, lyd_node_children(st->first, 0), 0, &st->diff1), LY_EINVAL);
 
     assert_int_equal(lyd_diff(NULL, NULL, 0, NULL), LY_EINVAL);
 }
@@ -284,10 +288,10 @@
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
-    assert_null(st->diff);
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
+    assert_null(st->diff1);
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
@@ -309,10 +313,10 @@
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">"
             "<foo>42</foo><b1_1>42</b1_1>"
@@ -322,7 +326,7 @@
         "</hidden>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
@@ -341,10 +345,10 @@
     assert_non_null(st->first);
     st->second = NULL;
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">"
             "<foo>42</foo><b1_1>42</b1_1>"
@@ -354,7 +358,7 @@
         "</hidden>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     assert_ptr_equal(st->first, st->second);
 }
 
@@ -368,13 +372,13 @@
     assert_non_null(st->first);
     st->second = NULL;
 
-    assert_int_equal(lyd_diff(NULL, NULL, 0, &st->diff), LY_SUCCESS);
-    assert_null(st->diff);
+    assert_int_equal(lyd_diff(NULL, NULL, 0, &st->diff1), LY_SUCCESS);
+    assert_null(st->diff1);
 
-    assert_int_equal(lyd_diff(NULL, lyd_node_children(st->first, 0), 0, &st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff(NULL, lyd_node_children(st->first, 0), 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
             "<foo yang:operation=\"create\">42</foo>"
@@ -382,11 +386,10 @@
     );
 
     free(st->xml);
-    lyd_free_siblings(st->diff);
-    assert_int_equal(lyd_diff(lyd_node_children(st->first, 0), NULL, 0, &st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff(lyd_node_children(st->first, 0), NULL, 0, &st->diff2), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff2);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
             "<foo yang:operation=\"delete\">42</foo>"
@@ -409,29 +412,79 @@
         "<df xmlns=\"urn:libyang:tests:defaults\">"
             "<foo>41</foo><b1_1>42</b1_1>"
         "</df>";
+    const char *xml3 =
+        "<df xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>40</foo>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>40</foo>"
+        "</hidden>";
 
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml1, LYD_XML, LYD_PARSE_ONLY, 0, &st->first));
     assert_non_null(st->first);
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml3, LYD_XML, LYD_PARSE_ONLY, 0, &st->third));
+    assert_non_null(st->third);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    /* diff1 */
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
-            "<foo yang:operation=\"replace\" yang:orig-value=\"42\">41</foo><b1_1 yang:operation=\"create\">42</b1_1>"
+            "<foo yang:operation=\"replace\" yang:orig-value=\"42\">41</foo>"
+            "<b1_1 yang:operation=\"create\">42</b1_1>"
         "</df>"
         "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">"
-            "<foo>42</foo><baz>42</baz>"
+            "<foo>42</foo>"
+            "<baz>42</baz>"
         "</hidden>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
+
+    /* diff2 */
+    assert_int_equal(lyd_diff(st->second, st->third, 0, &st->diff2), LY_SUCCESS);
+
+    assert_non_null(st->diff2);
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"replace\" yang:orig-value=\"41\">40</foo>"
+            "<b1_1 yang:operation=\"delete\">42</b1_1>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">"
+            "<foo>40</foo>"
+        "</hidden>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->second, st->diff2), LY_SUCCESS);
+    free(st->xml1);
+    lyd_print_mem(&st->xml1, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    free(st->xml2);
+    lyd_print_mem(&st->xml2, st->third, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+
+    /* merge */
+    assert_int_equal(lyd_diff_merge(st->diff2, &st->diff1), LY_SUCCESS);
+
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"replace\" yang:orig-value=\"42\">40</foo>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"replace\" yang:orig-value=\"42\">40</foo>"
+            "<baz yang:operation=\"delete\">42</baz>"
+        "</hidden>"
+    );
 }
 
 static void
@@ -446,30 +499,88 @@
                          "<list><name>b</name><value>-2</value></list>"
                          "<list><name>c</name><value>3</value></list>"
                        "</df>";
+    const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<list><name>a</name><value>2</value></list>"
+                         "<list><name>b</name><value>-2</value></list>"
+                       "</df>";
 
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml1, LYD_XML, LYD_PARSE_ONLY, 0, &st->first));
     assert_non_null(st->first);
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml3, LYD_XML, LYD_PARSE_ONLY, 0, &st->third));
+    assert_non_null(st->third);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    /* diff1 */
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
-            "<list yang:operation=\"delete\"><name>a</name><value>1</value></list>"
-            "<list yang:operation=\"none\">"
-                "<name>b</name><value yang:operation=\"replace\" yang:orig-value=\"2\">-2</value>"
+            "<list yang:operation=\"delete\">"
+                "<name>a</name>"
+                "<value>1</value>"
             "</list>"
-            "<list yang:operation=\"create\"><name>c</name><value>3</value></list>"
+            "<list yang:operation=\"none\">"
+                "<name>b</name>"
+                "<value yang:operation=\"replace\" yang:orig-value=\"2\">-2</value>"
+            "</list>"
+            "<list yang:operation=\"create\">"
+                "<name>c</name>"
+                "<value>3</value>"
+            "</list>"
         "</df>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
+
+    /* diff2 */
+    assert_int_equal(lyd_diff(st->second, st->third, 0, &st->diff2), LY_SUCCESS);
+
+    assert_non_null(st->diff2);
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<list yang:operation=\"delete\">"
+                "<name>c</name>"
+                "<value>3</value>"
+            "</list>"
+            "<list yang:operation=\"create\">"
+                "<name>a</name>"
+                "<value>2</value>"
+            "</list>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->second, st->diff2), LY_SUCCESS);
+    free(st->xml1);
+    lyd_print_mem(&st->xml1, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    free(st->xml2);
+    lyd_print_mem(&st->xml2, st->third, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    /* TODO ordering assert_string_equal(st->xml1, st->xml2); */
+
+    /* merge */
+    assert_int_equal(lyd_diff_merge(st->diff2, &st->diff1), LY_SUCCESS);
+
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<list yang:operation=\"none\">"
+                "<name>a</name>"
+                "<value yang:operation=\"replace\" yang:orig-value=\"1\">2</value>"
+            "</list>"
+            "<list yang:operation=\"none\">"
+                "<name>b</name>"
+                "<value yang:operation=\"replace\" yang:orig-value=\"2\">-2</value>"
+            "</list>"
+        "</df>"
+    );
 }
 
 static void
@@ -490,16 +601,25 @@
                          "<llist>2</llist>"
                          "<llist>5</llist>"
                        "</df>";
+    const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>5</llist>"
+                         "<llist>4</llist>"
+                         "<llist>3</llist>"
+                         "<llist>2</llist>"
+                       "</df>";
 
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml1, LYD_XML, LYD_PARSE_ONLY, 0, &st->first));
     assert_non_null(st->first);
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml3, LYD_XML, LYD_PARSE_ONLY, 0, &st->third));
+    assert_non_null(st->third);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    /* diff1 */
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
             "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"1\">4</llist>"
@@ -507,10 +627,44 @@
         "</df>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
+
+    /* diff2 */
+    assert_int_equal(lyd_diff(st->second, st->third, 0, &st->diff2), LY_SUCCESS);
+
+    assert_non_null(st->diff2);
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"delete\" yang:orig-value=\"\">1</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"2\" yang:value=\"\">5</llist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->second, st->diff2), LY_SUCCESS);
+    free(st->xml1);
+    lyd_print_mem(&st->xml1, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    free(st->xml2);
+    lyd_print_mem(&st->xml2, st->third, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+
+    /* merge */
+    assert_int_equal(lyd_diff_merge(st->diff2, &st->diff1), LY_SUCCESS);
+
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"1\">4</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"2\" yang:value=\"4\">3</llist>"
+            "<llist yang:orig-value=\"\" yang:operation=\"delete\">1</llist>"
+            "<llist yang:orig-value=\"2\" yang:value=\"\" yang:operation=\"replace\">5</llist>"
+        "</df>"
+    );
 }
 
 static void
@@ -531,26 +685,67 @@
                          "<llist>4</llist>"
                          "<llist>3</llist>"
                        "</df>";
+    const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>4</llist>"
+                         "<llist>1</llist>"
+                         "<list><name>a</name><value>1</value></list>"
+                         "<llist>3</llist>"
+                       "</df>";
 
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml1, LYD_XML, LYD_PARSE_ONLY, 0, &st->first));
     assert_non_null(st->first);
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml3, LYD_XML, LYD_PARSE_ONLY, 0, &st->third));
+    assert_non_null(st->third);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    /* diff1 */
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
             "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"2\">4</llist>"
         "</df>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
+
+    /* diff2 */
+    assert_int_equal(lyd_diff(st->second, st->third, 0, &st->diff2), LY_SUCCESS);
+
+    assert_non_null(st->diff2);
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"1\" yang:value=\"\">4</llist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->second, st->diff2), LY_SUCCESS);
+    free(st->xml1);
+    lyd_print_mem(&st->xml1, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    free(st->xml2);
+    lyd_print_mem(&st->xml2, st->third, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+
+    /* merge */
+    assert_int_equal(lyd_diff_merge(st->diff2, &st->diff1), LY_SUCCESS);
+
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"\">4</llist>"
+            "<llist yang:orig-value=\"1\" yang:operation=\"delete\">2</llist>"
+        "</df>"
+    );
 }
 
 static void
@@ -566,16 +761,24 @@
                          "<llist>3</llist>"
                          "<llist>1</llist>"
                        "</df>";
+    const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<llist>4</llist>"
+                         "<llist>3</llist>"
+                       "</df>";
 
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml1, LYD_XML, LYD_PARSE_ONLY, 0, &st->first));
     assert_non_null(st->first);
     assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
     assert_non_null(st->second);
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml3, LYD_XML, LYD_PARSE_ONLY, 0, &st->third));
+    assert_non_null(st->third);
 
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    /* diff1 */
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
             "<llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>"
@@ -583,48 +786,44 @@
         "</df>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
-}
 
-static void
-test_userord_mix2(void **state)
-{
-    struct state *st = (*state);
-    const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">"
-                         "<llist>1</llist>"
-                         "<llist>2</llist>"
-                         "<llist>3</llist>"
-                       "</df>";
-    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
-                         "<llist>4</llist>"
-                         "<llist>3</llist>"
-                         "<llist>1</llist>"
-                       "</df>";
+    /* diff2 */
+    assert_int_equal(lyd_diff(st->second, st->third, 0, &st->diff2), LY_SUCCESS);
 
-    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml1, LYD_XML, LYD_PARSE_ONLY, 0, &st->first));
-    assert_non_null(st->first);
-    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, LYD_PARSE_ONLY, 0, &st->second));
-    assert_non_null(st->second);
-
-    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
-
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff2);
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
-            "<llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>"
-            "<llist yang:operation=\"create\" yang:value=\"\">4</llist>"
-            "<llist yang:operation=\"replace\" yang:orig-value=\"1\" yang:value=\"4\">3</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"\">1</llist>"
+            "<llist yang:operation=\"create\" yang:value=\"1\">4</llist>"
         "</df>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
-    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
-    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_int_equal(lyd_diff_apply(&st->second, st->diff2), LY_SUCCESS);
+    free(st->xml1);
+    lyd_print_mem(&st->xml1, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    free(st->xml2);
+    lyd_print_mem(&st->xml2, st->third, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     assert_string_equal(st->xml1, st->xml2);
+
+    /* merge */
+    assert_int_equal(lyd_diff_merge(st->diff2, &st->diff1), LY_SUCCESS);
+
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"1\" yang:value=\"\">3</llist>"
+            "<llist yang:orig-value=\"3\" yang:value=\"\" yang:operation=\"replace\">1</llist>"
+            "<llist yang:value=\"1\" yang:operation=\"create\">4</llist>"
+        "</df>"
+    );
 }
 
 static void
@@ -632,9 +831,12 @@
 {
     struct state *st = (*state);
     const struct lys_module *mod;
-    const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\">"
-                        "<foo>41</foo><dllist>4</dllist>"
-                      "</df>";
+    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<foo>41</foo><dllist>4</dllist>"
+                       "</df>";
+    const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<foo>42</foo><dllist>1</dllist><dllist>4</dllist>"
+                       "</df>";
 
     mod = ly_ctx_get_module_implemented(st->ctx, "defaults");
     assert_non_null(mod);
@@ -642,13 +844,16 @@
     st->first = NULL;
     assert_int_equal(lyd_validate_module(&st->first, mod, 0), LY_SUCCESS);
     assert_ptr_not_equal(st->first, NULL);
-    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->second));
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml2, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->second));
     assert_non_null(st->second);
+    assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(st->ctx, xml3, LYD_XML, 0, LYD_VALIDATE_PRESENT, &st->third));
+    assert_non_null(st->third);
 
-    assert_int_equal(lyd_diff(st->first, st->second, LYD_DIFF_WITHDEFAULTS, &st->diff), LY_SUCCESS);
+    /* diff1 */
+    assert_int_equal(lyd_diff(st->first, st->second, LYD_DIFF_WITHDEFAULTS, &st->diff1), LY_SUCCESS);
 
-    assert_non_null(st->diff);
-    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    assert_non_null(st->diff1);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
     assert_string_equal(st->xml,
         "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
             "<foo yang:operation=\"replace\" yang:orig-default=\"true\" yang:orig-value=\"42\">41</foo>"
@@ -659,11 +864,46 @@
         "</df>"
     );
 
-    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff1), LY_SUCCESS);
     lyd_print_mem(&st->xml1, st->first, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     lyd_print_mem(&st->xml2, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
     /* TODO just an ordering problem
     assert_string_equal(st->xml1, st->xml2);*/
+
+    /* diff2 */
+    assert_int_equal(lyd_diff(st->second, st->third, LYD_DIFF_WITHDEFAULTS, &st->diff2), LY_SUCCESS);
+
+    assert_non_null(st->diff2);
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff2, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"replace\" yang:orig-value=\"41\">42</foo>"
+            "<dllist yang:operation=\"create\">1</dllist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->second, st->diff2), LY_SUCCESS);
+    free(st->xml1);
+    lyd_print_mem(&st->xml1, st->second, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    free(st->xml2);
+    lyd_print_mem(&st->xml2, st->third, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+    /* TODO ordering assert_string_equal(st->xml1, st->xml2); */
+
+    /* merge */
+    assert_int_equal(lyd_diff_merge(st->diff2, &st->diff1), LY_SUCCESS);
+
+    free(st->xml);
+    lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:orig-default=\"true\" yang:operation=\"none\">42</foo>"
+            "<dllist yang:operation=\"none\" yang:orig-default=\"true\">1</dllist>"
+            "<dllist yang:operation=\"delete\">2</dllist>"
+            "<dllist yang:operation=\"delete\">3</dllist>"
+            "<dllist yang:operation=\"create\">4</dllist>"
+        "</df>"
+    );
 }
 
 int main(void)
@@ -679,7 +919,6 @@
         cmocka_unit_test_setup_teardown(test_userord_llist, setup_f, teardown_f),
         cmocka_unit_test_setup_teardown(test_userord_llist2, setup_f, teardown_f),
         cmocka_unit_test_setup_teardown(test_userord_mix, setup_f, teardown_f),
-        cmocka_unit_test_setup_teardown(test_userord_mix2, setup_f, teardown_f),
         cmocka_unit_test_setup_teardown(test_wd, setup_f, teardown_f),
     };