|
19 | 19 |
|
20 | 20 | #include "diff.h"
|
21 | 21 | #include "diffcore.h"
|
| 22 | +#include "object-store.h" |
22 | 23 | #include "strmap.h"
|
23 | 24 | #include "tree.h"
|
24 | 25 | #include "xdiff-interface.h"
|
@@ -523,6 +524,62 @@ struct directory_versions {
|
523 | 524 | struct string_list versions;
|
524 | 525 | };
|
525 | 526 |
|
| 527 | +static int tree_entry_order(const void *a_, const void *b_) |
| 528 | +{ |
| 529 | + const struct string_list_item *a = a_; |
| 530 | + const struct string_list_item *b = b_; |
| 531 | + |
| 532 | + const struct merged_info *ami = a->util; |
| 533 | + const struct merged_info *bmi = b->util; |
| 534 | + return base_name_compare(a->string, strlen(a->string), ami->result.mode, |
| 535 | + b->string, strlen(b->string), bmi->result.mode); |
| 536 | +} |
| 537 | + |
| 538 | +static void write_tree(struct object_id *result_oid, |
| 539 | + struct string_list *versions, |
| 540 | + unsigned int offset, |
| 541 | + size_t hash_size) |
| 542 | +{ |
| 543 | + size_t maxlen = 0, extra; |
| 544 | + unsigned int nr = versions->nr - offset; |
| 545 | + struct strbuf buf = STRBUF_INIT; |
| 546 | + struct string_list relevant_entries = STRING_LIST_INIT_NODUP; |
| 547 | + int i; |
| 548 | + |
| 549 | + /* |
| 550 | + * We want to sort the last (versions->nr-offset) entries in versions. |
| 551 | + * Do so by abusing the string_list API a bit: make another string_list |
| 552 | + * that contains just those entries and then sort them. |
| 553 | + * |
| 554 | + * We won't use relevant_entries again and will let it just pop off the |
| 555 | + * stack, so there won't be allocation worries or anything. |
| 556 | + */ |
| 557 | + relevant_entries.items = versions->items + offset; |
| 558 | + relevant_entries.nr = versions->nr - offset; |
| 559 | + QSORT(relevant_entries.items, relevant_entries.nr, tree_entry_order); |
| 560 | + |
| 561 | + /* Pre-allocate some space in buf */ |
| 562 | + extra = hash_size + 8; /* 8: 6 for mode, 1 for space, 1 for NUL char */ |
| 563 | + for (i = 0; i < nr; i++) { |
| 564 | + maxlen += strlen(versions->items[offset+i].string) + extra; |
| 565 | + } |
| 566 | + strbuf_grow(&buf, maxlen); |
| 567 | + |
| 568 | + /* Write each entry out to buf */ |
| 569 | + for (i = 0; i < nr; i++) { |
| 570 | + struct merged_info *mi = versions->items[offset+i].util; |
| 571 | + struct version_info *ri = &mi->result; |
| 572 | + strbuf_addf(&buf, "%o %s%c", |
| 573 | + ri->mode, |
| 574 | + versions->items[offset+i].string, '\0'); |
| 575 | + strbuf_add(&buf, ri->oid.hash, hash_size); |
| 576 | + } |
| 577 | + |
| 578 | + /* Write this object file out, and record in result_oid */ |
| 579 | + write_object_file(buf.buf, buf.len, tree_type, result_oid); |
| 580 | + strbuf_release(&buf); |
| 581 | +} |
| 582 | + |
526 | 583 | static void record_entry_for_tree(struct directory_versions *dir_metadata,
|
527 | 584 | const char *path,
|
528 | 585 | struct merged_info *mi)
|
@@ -675,9 +732,17 @@ static void process_entries(struct merge_options *opt,
|
675 | 732 | }
|
676 | 733 | }
|
677 | 734 |
|
| 735 | + /* |
| 736 | + * TODO: We can't actually write a tree yet, because dir_metadata just |
| 737 | + * contains all basenames of all files throughout the tree with their |
| 738 | + * mode and hash. Not only is that a nonsensical tree, it will have |
| 739 | + * lots of duplicates for paths such as "Makefile" or ".gitignore". |
| 740 | + */ |
| 741 | + die("Not yet implemented; need to process subtrees separately"); |
| 742 | + write_tree(result_oid, &dir_metadata.versions, 0, |
| 743 | + opt->repo->hash_algo->rawsz); |
678 | 744 | string_list_clear(&plist, 0);
|
679 | 745 | string_list_clear(&dir_metadata.versions, 0);
|
680 |
| - die("Tree creation not yet implemented"); |
681 | 746 | }
|
682 | 747 |
|
683 | 748 | void merge_switch_to_result(struct merge_options *opt,
|
|
0 commit comments