merge-tree.con commit Make "read-tree" merge the trees it reads by giving them consecutive states. (d99082e)
   1#include "cache.h"
   2
   3static int line_termination = '\n';
   4
   5struct tree_entry {
   6        unsigned mode;
   7        unsigned char *sha1;
   8        char *path;
   9        struct tree_entry *next;
  10};
  11
  12static struct tree_entry *read_tree(unsigned char *sha1)
  13{
  14        char type[20];
  15        unsigned long size;
  16        void *buf = read_sha1_file(sha1, type, &size);
  17        struct tree_entry *ret = NULL, **tp = &ret;
  18
  19        if (!buf || strcmp(type, "tree"))
  20                die("unable to read 'tree' object %s", sha1_to_hex(sha1));
  21        while (size) {
  22                int len = strlen(buf)+1;
  23                struct tree_entry * entry = malloc(sizeof(struct tree_entry));
  24                if (size < len + 20 || sscanf(buf, "%o", &entry->mode) != 1)
  25                        die("corrupt 'tree' object %s", sha1_to_hex(sha1));
  26                entry->path = strchr(buf, ' ')+1;
  27                entry->sha1 = buf + len;
  28                entry->next = NULL;
  29                *tp = entry;
  30                tp = &entry->next;
  31                len += 20;
  32                buf += len;
  33                size -= len;
  34        }
  35        return ret;
  36}
  37
  38static void show(const struct tree_entry *a, const char *path)
  39{
  40        printf("select %o %s %s%c", a->mode, sha1_to_hex(a->sha1), path,
  41               line_termination);
  42}
  43
  44static void merge(const struct tree_entry *a, const struct tree_entry *b, const struct tree_entry *c, const char *path)
  45{
  46        char hex_a[60], hex_b[60], hex_c[60];
  47        strcpy(hex_a, sha1_to_hex(a->sha1));
  48        strcpy(hex_b, sha1_to_hex(b->sha1));
  49        strcpy(hex_c, sha1_to_hex(c->sha1));
  50        printf("merge %o->%o,%o %s->%s,%s %s%c",
  51                a->mode, b->mode, c->mode,
  52                hex_a, hex_b, hex_c, path, line_termination);
  53}
  54
  55static int same(const struct tree_entry *a, const struct tree_entry *b)
  56{
  57        return a->mode == b->mode && !memcmp(a->sha1, b->sha1, 20);
  58}
  59
  60static void merge_entry(const struct tree_entry *src, const struct tree_entry *dst1, const struct tree_entry *dst2)
  61{
  62        static unsigned char nullsha1[20];
  63        static const struct tree_entry none = { 0, nullsha1, "", NULL };
  64        const char *path = NULL;
  65        const struct tree_entry *a, *b, *c;
  66
  67        a = &none;
  68        b = &none;
  69        c = &none;
  70        if (src) { a = src; path = src->path; }
  71        if (dst1) { b = dst1; path = dst1->path; }
  72        if (dst2) { c = dst2; path = dst2->path; }
  73        if (same(b, c)) {
  74                show(b, path);
  75                return;
  76        }
  77        if (same(a, b)) {
  78                show(c, path);
  79                return;
  80        }
  81        if (same(a, c)) {
  82                show(b, path);
  83                return;
  84        }
  85        merge(a, b, c, path);
  86}
  87
  88/* For two entries, select the smaller one, clear the bigger one */
  89static void smaller(struct tree_entry **ap, struct tree_entry **bp)
  90{
  91        struct tree_entry *a = *ap, *b = *bp;
  92        if (a && b) {
  93                int cmp = cache_name_compare(a->path, strlen(a->path), b->path, strlen(b->path));
  94                if (cmp) {
  95                        if (cmp < 0)
  96                                *bp = NULL;
  97                        else
  98                                *ap = NULL;
  99                }
 100        }
 101}
 102
 103static void merge_tree(struct tree_entry *src, struct tree_entry *dst1, struct tree_entry *dst2)
 104{
 105        while (src || dst1 || dst2) {
 106                struct tree_entry *a, *b, *c;
 107                a = src;
 108                b = dst1;
 109                c = dst2;
 110                smaller(&a,&b);
 111                smaller(&a,&c);
 112                smaller(&b,&c);
 113                if (a) src = a->next;
 114                if (b) dst1 = b->next;
 115                if (c) dst2 = c->next;
 116                merge_entry(a,b,c);
 117        }
 118}
 119
 120static const char *merge_tree_usage =
 121    "merge-tree [-z] <src> <dst1> <dst2>";
 122
 123int main(int argc, char **argv)
 124{
 125        unsigned char src[20], dst1[20], dst2[20];
 126
 127        while ((1 < argc) && argv[1][0] == '-') {
 128                switch (argv[1][1]) {
 129                case 'z':
 130                        line_termination = 0;
 131                        break;
 132                default:
 133                        usage(merge_tree_usage);
 134                }
 135                argc--; argv++;
 136        }
 137
 138        if (argc != 4 ||
 139            get_sha1_hex(argv[1], src) ||
 140            get_sha1_hex(argv[2], dst1) ||
 141            get_sha1_hex(argv[3], dst2))
 142                usage(merge_tree_usage);
 143        merge_tree(read_tree(src), read_tree(dst1), read_tree(dst2));
 144        return 0;
 145}