builtin / merge-tree.con commit Merge branch 'ea/merge-code-cleanup' (dd0bc5b)
   1#define USE_THE_INDEX_COMPATIBILITY_MACROS
   2#include "builtin.h"
   3#include "tree-walk.h"
   4#include "xdiff-interface.h"
   5#include "object-store.h"
   6#include "repository.h"
   7#include "blob.h"
   8#include "exec-cmd.h"
   9#include "merge-blobs.h"
  10
  11static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
  12
  13struct merge_list {
  14        struct merge_list *next;
  15        struct merge_list *link;        /* other stages for this object */
  16
  17        unsigned int stage : 2;
  18        unsigned int mode;
  19        const char *path;
  20        struct blob *blob;
  21};
  22
  23static struct merge_list *merge_result, **merge_result_end = &merge_result;
  24
  25static void add_merge_entry(struct merge_list *entry)
  26{
  27        *merge_result_end = entry;
  28        merge_result_end = &entry->next;
  29}
  30
  31static void merge_trees(struct tree_desc t[3], const char *base);
  32
  33static const char *explanation(struct merge_list *entry)
  34{
  35        switch (entry->stage) {
  36        case 0:
  37                return "merged";
  38        case 3:
  39                return "added in remote";
  40        case 2:
  41                if (entry->link)
  42                        return "added in both";
  43                return "added in local";
  44        }
  45
  46        /* Existed in base */
  47        entry = entry->link;
  48        if (!entry)
  49                return "removed in both";
  50
  51        if (entry->link)
  52                return "changed in both";
  53
  54        if (entry->stage == 3)
  55                return "removed in local";
  56        return "removed in remote";
  57}
  58
  59static void *result(struct merge_list *entry, unsigned long *size)
  60{
  61        enum object_type type;
  62        struct blob *base, *our, *their;
  63        const char *path = entry->path;
  64
  65        if (!entry->stage)
  66                return read_object_file(&entry->blob->object.oid, &type, size);
  67        base = NULL;
  68        if (entry->stage == 1) {
  69                base = entry->blob;
  70                entry = entry->link;
  71        }
  72        our = NULL;
  73        if (entry && entry->stage == 2) {
  74                our = entry->blob;
  75                entry = entry->link;
  76        }
  77        their = NULL;
  78        if (entry)
  79                their = entry->blob;
  80        return merge_blobs(the_repository->index, path,
  81                           base, our, their, size);
  82}
  83
  84static void *origin(struct merge_list *entry, unsigned long *size)
  85{
  86        enum object_type type;
  87        while (entry) {
  88                if (entry->stage == 2)
  89                        return read_object_file(&entry->blob->object.oid,
  90                                                &type, size);
  91                entry = entry->link;
  92        }
  93        return NULL;
  94}
  95
  96static int show_outf(void *priv_, mmbuffer_t *mb, int nbuf)
  97{
  98        int i;
  99        for (i = 0; i < nbuf; i++)
 100                printf("%.*s", (int) mb[i].size, mb[i].ptr);
 101        return 0;
 102}
 103
 104static void show_diff(struct merge_list *entry)
 105{
 106        unsigned long size;
 107        mmfile_t src, dst;
 108        xpparam_t xpp;
 109        xdemitconf_t xecfg;
 110        xdemitcb_t ecb;
 111
 112        xpp.flags = 0;
 113        memset(&xecfg, 0, sizeof(xecfg));
 114        xecfg.ctxlen = 3;
 115        ecb.out_hunk = NULL;
 116        ecb.out_line = show_outf;
 117        ecb.priv = NULL;
 118
 119        src.ptr = origin(entry, &size);
 120        if (!src.ptr)
 121                size = 0;
 122        src.size = size;
 123        dst.ptr = result(entry, &size);
 124        if (!dst.ptr)
 125                size = 0;
 126        dst.size = size;
 127        if (xdi_diff(&src, &dst, &xpp, &xecfg, &ecb))
 128                die("unable to generate diff");
 129        free(src.ptr);
 130        free(dst.ptr);
 131}
 132
 133static void show_result_list(struct merge_list *entry)
 134{
 135        printf("%s\n", explanation(entry));
 136        do {
 137                struct merge_list *link = entry->link;
 138                static const char *desc[4] = { "result", "base", "our", "their" };
 139                printf("  %-6s %o %s %s\n", desc[entry->stage], entry->mode, oid_to_hex(&entry->blob->object.oid), entry->path);
 140                entry = link;
 141        } while (entry);
 142}
 143
 144static void show_result(void)
 145{
 146        struct merge_list *walk;
 147
 148        walk = merge_result;
 149        while (walk) {
 150                show_result_list(walk);
 151                show_diff(walk);
 152                walk = walk->next;
 153        }
 154}
 155
 156/* An empty entry never compares same, not even to another empty entry */
 157static int same_entry(struct name_entry *a, struct name_entry *b)
 158{
 159        return  !is_null_oid(&a->oid) &&
 160                !is_null_oid(&b->oid) &&
 161                oideq(&a->oid, &b->oid) &&
 162                a->mode == b->mode;
 163}
 164
 165static int both_empty(struct name_entry *a, struct name_entry *b)
 166{
 167        return is_null_oid(&a->oid) && is_null_oid(&b->oid);
 168}
 169
 170static struct merge_list *create_entry(unsigned stage, unsigned mode, const struct object_id *oid, const char *path)
 171{
 172        struct merge_list *res = xcalloc(1, sizeof(*res));
 173
 174        res->stage = stage;
 175        res->path = path;
 176        res->mode = mode;
 177        res->blob = lookup_blob(the_repository, oid);
 178        return res;
 179}
 180
 181static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
 182{
 183        char *path = xmallocz(traverse_path_len(info, n) + the_hash_algo->rawsz);
 184        return make_traverse_path(path, info, n);
 185}
 186
 187static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
 188{
 189        struct merge_list *orig, *final;
 190        const char *path;
 191
 192        /* If it's already ours, don't bother showing it */
 193        if (!ours)
 194                return;
 195
 196        path = traverse_path(info, result);
 197        orig = create_entry(2, ours->mode, &ours->oid, path);
 198        final = create_entry(0, result->mode, &result->oid, path);
 199
 200        final->link = orig;
 201
 202        add_merge_entry(final);
 203}
 204
 205static void unresolved_directory(const struct traverse_info *info,
 206                                 struct name_entry n[3])
 207{
 208        struct repository *r = the_repository;
 209        char *newbase;
 210        struct name_entry *p;
 211        struct tree_desc t[3];
 212        void *buf0, *buf1, *buf2;
 213
 214        for (p = n; p < n + 3; p++) {
 215                if (p->mode && S_ISDIR(p->mode))
 216                        break;
 217        }
 218        if (n + 3 <= p)
 219                return; /* there is no tree here */
 220
 221        newbase = traverse_path(info, p);
 222
 223#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
 224        buf0 = fill_tree_descriptor(r, t + 0, ENTRY_OID(n + 0));
 225        buf1 = fill_tree_descriptor(r, t + 1, ENTRY_OID(n + 1));
 226        buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
 227#undef ENTRY_OID
 228
 229        merge_trees(t, newbase);
 230
 231        free(buf0);
 232        free(buf1);
 233        free(buf2);
 234        free(newbase);
 235}
 236
 237
 238static struct merge_list *link_entry(unsigned stage, const struct traverse_info *info, struct name_entry *n, struct merge_list *entry)
 239{
 240        const char *path;
 241        struct merge_list *link;
 242
 243        if (!n->mode)
 244                return entry;
 245        if (entry)
 246                path = entry->path;
 247        else
 248                path = traverse_path(info, n);
 249        link = create_entry(stage, n->mode, &n->oid, path);
 250        link->link = entry;
 251        return link;
 252}
 253
 254static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 255{
 256        struct merge_list *entry = NULL;
 257        int i;
 258        unsigned dirmask = 0, mask = 0;
 259
 260        for (i = 0; i < 3; i++) {
 261                mask |= (1 << i);
 262                /*
 263                 * Treat missing entries as directories so that we return
 264                 * after unresolved_directory has handled this.
 265                 */
 266                if (!n[i].mode || S_ISDIR(n[i].mode))
 267                        dirmask |= (1 << i);
 268        }
 269
 270        unresolved_directory(info, n);
 271
 272        if (dirmask == mask)
 273                return;
 274
 275        if (n[2].mode && !S_ISDIR(n[2].mode))
 276                entry = link_entry(3, info, n + 2, entry);
 277        if (n[1].mode && !S_ISDIR(n[1].mode))
 278                entry = link_entry(2, info, n + 1, entry);
 279        if (n[0].mode && !S_ISDIR(n[0].mode))
 280                entry = link_entry(1, info, n + 0, entry);
 281
 282        add_merge_entry(entry);
 283}
 284
 285/*
 286 * Merge two trees together (t[1] and t[2]), using a common base (t[0])
 287 * as the origin.
 288 *
 289 * This walks the (sorted) trees in lock-step, checking every possible
 290 * name. Note that directories automatically sort differently from other
 291 * files (see "base_name_compare"), so you'll never see file/directory
 292 * conflicts, because they won't ever compare the same.
 293 *
 294 * IOW, if a directory changes to a filename, it will automatically be
 295 * seen as the directory going away, and the filename being created.
 296 *
 297 * Think of this as a three-way diff.
 298 *
 299 * The output will be either:
 300 *  - successful merge
 301 *       "0 mode sha1 filename"
 302 *    NOTE NOTE NOTE! FIXME! We really really need to walk the index
 303 *    in parallel with this too!
 304 *
 305 *  - conflict:
 306 *      "1 mode sha1 filename"
 307 *      "2 mode sha1 filename"
 308 *      "3 mode sha1 filename"
 309 *    where not all of the 1/2/3 lines may exist, of course.
 310 *
 311 * The successful merge rules are the same as for the three-way merge
 312 * in git-read-tree.
 313 */
 314static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *info)
 315{
 316        /* Same in both? */
 317        if (same_entry(entry+1, entry+2) || both_empty(entry+1, entry+2)) {
 318                /* Modified, added or removed identically */
 319                resolve(info, NULL, entry+1);
 320                return mask;
 321        }
 322
 323        if (same_entry(entry+0, entry+1)) {
 324                if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
 325                        /* We did not touch, they modified -- take theirs */
 326                        resolve(info, entry+1, entry+2);
 327                        return mask;
 328                }
 329                /*
 330                 * If we did not touch a directory but they made it
 331                 * into a file, we fall through and unresolved()
 332                 * recurses down.  Likewise for the opposite case.
 333                 */
 334        }
 335
 336        if (same_entry(entry+0, entry+2) || both_empty(entry+0, entry+2)) {
 337                /* We added, modified or removed, they did not touch -- take ours */
 338                resolve(info, NULL, entry+1);
 339                return mask;
 340        }
 341
 342        unresolved(info, entry);
 343        return mask;
 344}
 345
 346static void merge_trees(struct tree_desc t[3], const char *base)
 347{
 348        struct traverse_info info;
 349
 350        setup_traverse_info(&info, base);
 351        info.fn = threeway_callback;
 352        traverse_trees(&the_index, 3, t, &info);
 353}
 354
 355static void *get_tree_descriptor(struct repository *r,
 356                                 struct tree_desc *desc,
 357                                 const char *rev)
 358{
 359        struct object_id oid;
 360        void *buf;
 361
 362        if (repo_get_oid(r, rev, &oid))
 363                die("unknown rev %s", rev);
 364        buf = fill_tree_descriptor(r, desc, &oid);
 365        if (!buf)
 366                die("%s is not a tree", rev);
 367        return buf;
 368}
 369
 370int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 371{
 372        struct repository *r = the_repository;
 373        struct tree_desc t[3];
 374        void *buf1, *buf2, *buf3;
 375
 376        if (argc != 4)
 377                usage(merge_tree_usage);
 378
 379        buf1 = get_tree_descriptor(r, t+0, argv[1]);
 380        buf2 = get_tree_descriptor(r, t+1, argv[2]);
 381        buf3 = get_tree_descriptor(r, t+2, argv[3]);
 382        merge_trees(t, "");
 383        free(buf1);
 384        free(buf2);
 385        free(buf3);
 386
 387        show_result();
 388        return 0;
 389}