@matheusbsbs / matheus-bagliano / commits / a6a09095a0
Fork 0

git notes merge: Add another auto-resolving strategy: "cat_sort_uniq"

This new strategy is similar to "concatenate", but in addition to concatenating the two note candidates, this strategy sorts the resulting lines, and removes duplicate lines from the result. This is equivalent to applying the "cat | sort | uniq" shell pipeline to the two note candidates. This strategy is useful if the notes follow a line-based format where one wants to avoid duplicate lines in the merge result. Note that if either of the note candidates contain duplicate lines _prior_ to the merge, these will also be removed by this merge strategy. The patch also contains tests and documentation for the new strategy. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johan Herland committed Nov 15, 2010 at 00:57 UTC a6a09095a08339afc8468d053ff978ed4662a1d5
7 files changed +248 -4
Documentation/git-notes.txt
+11 -1
@@ -155,7 +155,7 @@ OPTIONS
155 --strategy=<strategy>::
156 When merging notes, resolve notes conflicts using the given
157 strategy. The following strategies are recognized: "manual"
158 - (default), "ours", "theirs" and "union".
158 + (default), "ours", "theirs", "union" and "cat_sort_uniq".
159 See the "NOTES MERGE STRATEGIES" section below for more
160 information on each notes merge strategy.
161
@@ -230,6 +230,16 @@ ref).
230 "union" automatically resolves notes conflicts by concatenating the
231 local and remote versions.
232
233 +"cat_sort_uniq" is similar to "union", but in addition to concatenating
234 +the local and remote versions, this strategy also sorts the resulting
235 +lines, and removes duplicate lines from the result. This is equivalent
236 +to applying the "cat | sort | uniq" shell pipeline to the local and
237 +remote versions. This strategy is useful if the notes follow a line-based
238 +format where one wants to avoid duplicated lines in the merge result.
239 +Note that if either the local or remote version contain duplicate lines
240 +prior to the merge, these will also be removed by this notes merge
241 +strategy.
242 +
243
244 EXAMPLES
245 --------
builtin/notes.c
+6 -2
@@ -324,6 +324,8 @@ combine_notes_fn parse_combine_notes_fn(const char *v)
324 return combine_notes_ignore;
325 else if (!strcasecmp(v, "concatenate"))
326 return combine_notes_concatenate;
327 + else if (!strcasecmp(v, "cat_sort_uniq"))
328 + return combine_notes_cat_sort_uniq;
329 else
330 return NULL;
331 }
@@ -846,8 +848,8 @@ static int merge(int argc, const char **argv, const char *prefix)
848 OPT__VERBOSITY(&verbosity),
849 OPT_GROUP("Merge options"),
850 OPT_STRING('s', "strategy", &strategy, "strategy",
849 - "resolve notes conflicts using the given "
850 - "strategy (manual/ours/theirs/union)"),
851 + "resolve notes conflicts using the given strategy "
852 + "(manual/ours/theirs/union/cat_sort_uniq)"),
853 OPT_GROUP("Committing unmerged notes"),
854 { OPTION_BOOLEAN, 0, "commit", &do_commit, NULL,
855 "finalize notes merge by committing unmerged notes",
@@ -899,6 +901,8 @@ static int merge(int argc, const char **argv, const char *prefix)
901 o.strategy = NOTES_MERGE_RESOLVE_THEIRS;
902 else if (!strcmp(strategy, "union"))
903 o.strategy = NOTES_MERGE_RESOLVE_UNION;
904 + else if (!strcmp(strategy, "cat_sort_uniq"))
905 + o.strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ;
906 else {
907 error("Unknown -s/--strategy: %s", strategy);
908 usage_with_options(git_notes_merge_usage, options);
notes-merge.c
+7
@@ -453,6 +453,13 @@ static int merge_one_change(struct notes_merge_options *o,
453 die("failed to concatenate notes "
454 "(combine_notes_concatenate)");
455 return 0;
456 + case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
457 + OUTPUT(o, 2, "Concatenating unique lines in local and remote "
458 + "notes for %s", sha1_to_hex(p->obj));
459 + if (add_note(t, p->obj, p->remote, combine_notes_cat_sort_uniq))
460 + die("failed to concatenate notes "
461 + "(combine_notes_cat_sort_uniq)");
462 + return 0;
463 }
464 die("Unknown strategy (%i).", o->strategy);
465 }
notes-merge.h
+2 -1
@@ -17,7 +17,8 @@ struct notes_merge_options {
17 NOTES_MERGE_RESOLVE_MANUAL = 0,
18 NOTES_MERGE_RESOLVE_OURS,
19 NOTES_MERGE_RESOLVE_THEIRS,
20 - NOTES_MERGE_RESOLVE_UNION
20 + NOTES_MERGE_RESOLVE_UNION,
21 + NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ
22 } strategy;
23 unsigned has_worktree:1;
24 };
notes.c
+76
@@ -845,6 +845,82 @@ int combine_notes_ignore(unsigned char *cur_sha1,
845 return 0;
846 }
847
848 +static int string_list_add_note_lines(struct string_list *sort_uniq_list,
849 + const unsigned char *sha1)
850 +{
851 + char *data;
852 + unsigned long len;
853 + enum object_type t;
854 + struct strbuf buf = STRBUF_INIT;
855 + struct strbuf **lines = NULL;
856 + int i, list_index;
857 +
858 + if (is_null_sha1(sha1))
859 + return 0;
860 +
861 + /* read_sha1_file NUL-terminates */
862 + data = read_sha1_file(sha1, &t, &len);
863 + if (t != OBJ_BLOB || !data || !len) {
864 + free(data);
865 + return t != OBJ_BLOB || !data;
866 + }
867 +
868 + strbuf_attach(&buf, data, len, len + 1);
869 + lines = strbuf_split(&buf, '\n');
870 +
871 + for (i = 0; lines[i]; i++) {
872 + if (lines[i]->buf[lines[i]->len - 1] == '\n')
873 + strbuf_setlen(lines[i], lines[i]->len - 1);
874 + if (!lines[i]->len)
875 + continue; /* skip empty lines */
876 + list_index = string_list_find_insert_index(sort_uniq_list,
877 + lines[i]->buf, 0);
878 + if (list_index < 0)
879 + continue; /* skip duplicate lines */
880 + string_list_insert_at_index(sort_uniq_list, list_index,
881 + lines[i]->buf);
882 + }
883 +
884 + strbuf_list_free(lines);
885 + strbuf_release(&buf);
886 + return 0;
887 +}
888 +
889 +static int string_list_join_lines_helper(struct string_list_item *item,
890 + void *cb_data)
891 +{
892 + struct strbuf *buf = cb_data;
893 + strbuf_addstr(buf, item->string);
894 + strbuf_addch(buf, '\n');
895 + return 0;
896 +}
897 +
898 +int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
899 + const unsigned char *new_sha1)
900 +{
901 + struct string_list sort_uniq_list = { NULL, 0, 0, 1 };
902 + struct strbuf buf = STRBUF_INIT;
903 + int ret = 1;
904 +
905 + /* read both note blob objects into unique_lines */
906 + if (string_list_add_note_lines(&sort_uniq_list, cur_sha1))
907 + goto out;
908 + if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
909 + goto out;
910 +
911 + /* create a new blob object from sort_uniq_list */
912 + if (for_each_string_list(&sort_uniq_list,
913 + string_list_join_lines_helper, &buf))
914 + goto out;
915 +
916 + ret = write_sha1_file(buf.buf, buf.len, blob_type, cur_sha1);
917 +
918 +out:
919 + strbuf_release(&buf);
920 + string_list_clear(&sort_uniq_list, 0);
921 + return ret;
922 +}
923 +
924 static int string_list_add_one_ref(const char *path, const unsigned char *sha1,
925 int flag, void *cb)
926 {
notes.h
+1
@@ -27,6 +27,7 @@ typedef int (*combine_notes_fn)(unsigned char *cur_sha1, const unsigned char *ne
27 int combine_notes_concatenate(unsigned char *cur_sha1, const unsigned char *new_sha1);
28 int combine_notes_overwrite(unsigned char *cur_sha1, const unsigned char *new_sha1);
29 int combine_notes_ignore(unsigned char *cur_sha1, const unsigned char *new_sha1);
30 +int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, const unsigned char *new_sha1);
31
32 /*
33 * Notes tree object
t/t3309-notes-merge-auto-resolve.sh
+145
@@ -499,4 +499,149 @@ test_expect_success 'merge z into y with "union" strategy => Non-conflicting 3-w
499 verify_notes y union
500 '
501
502 +test_expect_success 'reset to pre-merge state (y)' '
503 + git update-ref refs/notes/y refs/notes/y^1 &&
504 + # Verify pre-merge state
505 + verify_notes y y
506 +'
507 +
508 +cat <<EOF | sort >expect_notes_union2
509 +d682107b8bf7a7aea1e537a8d5cb6a12b60135f1 $commit_sha15
510 +5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14
511 +3a631fdb6f41b05b55d8f4baf20728ba8f6fccbc $commit_sha13
512 +a66055fa82f7a03fe0c02a6aba3287a85abf7c62 $commit_sha12
513 +7e3c53503a3db8dd996cb62e37c66e070b44b54d $commit_sha11
514 +b8d03e173f67f6505a76f6e00cf93440200dd9be $commit_sha10
515 +851e1638784a884c7dd26c5d41f3340f6387413a $commit_sha8
516 +357b6ca14c7afd59b7f8b8aaaa6b8b723771135b $commit_sha5
517 +e2bfd06a37dd2031684a59a6e2b033e212239c78 $commit_sha4
518 +5772f42408c0dd6f097a7ca2d24de0e78d1c46b1 $commit_sha3
519 +283b48219aee9a4105f6cab337e789065c82c2b9 $commit_sha2
520 +EOF
521 +
522 +cat >expect_log_union2 <<EOF
523 +$commit_sha15 15th
524 +z notes on 15th commit
525 +
526 +y notes on 15th commit
527 +
528 +$commit_sha14 14th
529 +y notes on 14th commit
530 +
531 +$commit_sha13 13th
532 +y notes on 13th commit
533 +
534 +$commit_sha12 12th
535 +y notes on 12th commit
536 +
537 +$commit_sha11 11th
538 +z notes on 11th commit
539 +
540 +$commit_sha10 10th
541 +x notes on 10th commit
542 +
543 +$commit_sha9 9th
544 +
545 +$commit_sha8 8th
546 +z notes on 8th commit
547 +
548 +$commit_sha7 7th
549 +
550 +$commit_sha6 6th
551 +
552 +$commit_sha5 5th
553 +z notes on 5th commit
554 +
555 +y notes on 5th commit
556 +
557 +$commit_sha4 4th
558 +y notes on 4th commit
559 +
560 +$commit_sha3 3rd
561 +y notes on 3rd commit
562 +
563 +$commit_sha2 2nd
564 +z notes on 2nd commit
565 +
566 +$commit_sha1 1st
567 +
568 +EOF
569 +
570 +test_expect_success 'merge y into z with "union" strategy => Non-conflicting 3-way merge' '
571 + git config core.notesRef refs/notes/z &&
572 + git notes merge --strategy=union y &&
573 + verify_notes z union2
574 +'
575 +
576 +test_expect_success 'reset to pre-merge state (z)' '
577 + git update-ref refs/notes/z refs/notes/z^1 &&
578 + # Verify pre-merge state
579 + verify_notes z z
580 +'
581 +
582 +cat <<EOF | sort >expect_notes_cat_sort_uniq
583 +6be90240b5f54594203e25d9f2f64b7567175aee $commit_sha15
584 +5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14
585 +3a631fdb6f41b05b55d8f4baf20728ba8f6fccbc $commit_sha13
586 +a66055fa82f7a03fe0c02a6aba3287a85abf7c62 $commit_sha12
587 +7e3c53503a3db8dd996cb62e37c66e070b44b54d $commit_sha11
588 +b8d03e173f67f6505a76f6e00cf93440200dd9be $commit_sha10
589 +851e1638784a884c7dd26c5d41f3340f6387413a $commit_sha8
590 +660311d7f78dc53db12ac373a43fca7465381a7e $commit_sha5
591 +e2bfd06a37dd2031684a59a6e2b033e212239c78 $commit_sha4
592 +5772f42408c0dd6f097a7ca2d24de0e78d1c46b1 $commit_sha3
593 +283b48219aee9a4105f6cab337e789065c82c2b9 $commit_sha2
594 +EOF
595 +
596 +cat >expect_log_cat_sort_uniq <<EOF
597 +$commit_sha15 15th
598 +y notes on 15th commit
599 +z notes on 15th commit
600 +
601 +$commit_sha14 14th
602 +y notes on 14th commit
603 +
604 +$commit_sha13 13th
605 +y notes on 13th commit
606 +
607 +$commit_sha12 12th
608 +y notes on 12th commit
609 +
610 +$commit_sha11 11th
611 +z notes on 11th commit
612 +
613 +$commit_sha10 10th
614 +x notes on 10th commit
615 +
616 +$commit_sha9 9th
617 +
618 +$commit_sha8 8th
619 +z notes on 8th commit
620 +
621 +$commit_sha7 7th
622 +
623 +$commit_sha6 6th
624 +
625 +$commit_sha5 5th
626 +y notes on 5th commit
627 +z notes on 5th commit
628 +
629 +$commit_sha4 4th
630 +y notes on 4th commit
631 +
632 +$commit_sha3 3rd
633 +y notes on 3rd commit
634 +
635 +$commit_sha2 2nd
636 +z notes on 2nd commit
637 +
638 +$commit_sha1 1st
639 +
640 +EOF
641 +
642 +test_expect_success 'merge y into z with "cat_sort_uniq" strategy => Non-conflicting 3-way merge' '
643 + git notes merge --strategy=cat_sort_uniq y &&
644 + verify_notes z cat_sort_uniq
645 +'
646 +
647 test_done