read-tree.con commit Make "read-tree" know how to do a "1-way merge". (a3a6523)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7
   8static int stage = 0;
   9
  10static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
  11{
  12        int len = strlen(pathname);
  13        unsigned int size = cache_entry_size(baselen + len);
  14        struct cache_entry *ce = malloc(size);
  15
  16        memset(ce, 0, size);
  17
  18        ce->ce_mode = create_ce_mode(mode);
  19        ce->ce_flags = create_ce_flags(baselen + len, stage);
  20        memcpy(ce->name, base, baselen);
  21        memcpy(ce->name + baselen, pathname, len+1);
  22        memcpy(ce->sha1, sha1, 20);
  23        return add_cache_entry(ce, 1);
  24}
  25
  26static int read_tree(unsigned char *sha1, const char *base, int baselen)
  27{
  28        void *buffer;
  29        unsigned long size;
  30        char type[20];
  31
  32        buffer = read_sha1_file(sha1, type, &size);
  33        if (!buffer)
  34                return -1;
  35        if (strcmp(type, "tree"))
  36                return -1;
  37        while (size) {
  38                int len = strlen(buffer)+1;
  39                unsigned char *sha1 = buffer + len;
  40                char *path = strchr(buffer, ' ')+1;
  41                unsigned int mode;
  42
  43                if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
  44                        return -1;
  45
  46                buffer = sha1 + 20;
  47                size -= len + 20;
  48
  49                if (S_ISDIR(mode)) {
  50                        int retval;
  51                        int pathlen = strlen(path);
  52                        char *newbase = malloc(baselen + 1 + pathlen);
  53                        memcpy(newbase, base, baselen);
  54                        memcpy(newbase + baselen, path, pathlen);
  55                        newbase[baselen + pathlen] = '/';
  56                        retval = read_tree(sha1, newbase, baselen + pathlen + 1);
  57                        free(newbase);
  58                        if (retval)
  59                                return -1;
  60                        continue;
  61                }
  62                if (read_one_entry(sha1, base, baselen, path, mode) < 0)
  63                        return -1;
  64        }
  65        return 0;
  66}
  67
  68static int remove_lock = 0;
  69
  70static void remove_lock_file(void)
  71{
  72        if (remove_lock)
  73                unlink(".git/index.lock");
  74}
  75
  76static int path_matches(struct cache_entry *a, struct cache_entry *b)
  77{
  78        int len = ce_namelen(a);
  79        return ce_namelen(b) == len &&
  80                !memcmp(a->name, b->name, len);
  81}
  82
  83static int same(struct cache_entry *a, struct cache_entry *b)
  84{
  85        return a->ce_mode == b->ce_mode && 
  86                !memcmp(a->sha1, b->sha1, 20);
  87}
  88
  89
  90/*
  91 * This removes all trivial merges that don't change the tree
  92 * and collapses them to state 0.
  93 *
  94 * _Any_ other merge is left to user policy.  That includes "both
  95 * created the same file", and "both removed the same file" - which are
  96 * trivial, but the user might still want to _note_ it. 
  97 */
  98static struct cache_entry *merge_entries(struct cache_entry *a,
  99                                         struct cache_entry *b,
 100                                         struct cache_entry *c)
 101{
 102        int len = ce_namelen(a);
 103
 104        /*
 105         * Are they all the same filename? We won't do
 106         * any name merging
 107         */
 108        if (ce_namelen(b) != len ||
 109            ce_namelen(c) != len ||
 110            memcmp(a->name, b->name, len) ||
 111            memcmp(a->name, c->name, len))
 112                return NULL;
 113
 114        /*
 115         * Ok, all three entries describe the same
 116         * filename, but maybe the contents or file
 117         * mode have changed?
 118         *
 119         * The trivial cases end up being the ones where two
 120         * out of three files are the same:
 121         *  - both destinations the same, trivially take either
 122         *  - one of the destination versions hasn't changed,
 123         *    take the other.
 124         *
 125         * The "all entries exactly the same" case falls out as
 126         * a special case of any of the "two same" cases.
 127         *
 128         * Here "a" is "original", and "b" and "c" are the two
 129         * trees we are merging.
 130         */
 131        if (same(b,c))
 132                return c;
 133        if (same(a,b))
 134                return c;
 135        if (same(a,c))
 136                return b;
 137        return NULL;
 138}
 139
 140static void trivially_merge_cache(struct cache_entry **src, int nr)
 141{
 142        static struct cache_entry null_entry;
 143        struct cache_entry **dst = src;
 144        struct cache_entry *old = &null_entry;
 145
 146        while (nr) {
 147                struct cache_entry *ce, *result;
 148
 149                ce = src[0];
 150
 151                /* We throw away original cache entries except for the stat information */
 152                if (!ce_stage(ce)) {
 153                        old = ce;
 154                        src++;
 155                        nr--;
 156                        active_nr--;
 157                        continue;
 158                }
 159                if (nr > 2 && (result = merge_entries(ce, src[1], src[2])) != NULL) {
 160                        /*
 161                         * See if we can re-use the old CE directly?
 162                         * That way we get the uptodate stat info.
 163                         */
 164                        if (path_matches(result, old) && same(result, old))
 165                                *result = *old;
 166                        ce = result;
 167                        ce->ce_flags &= ~htons(CE_STAGEMASK);
 168                        src += 2;
 169                        nr -= 2;
 170                        active_nr -= 2;
 171                }
 172                *dst++ = ce;
 173                src++;
 174                nr--;
 175        }
 176}
 177
 178static void merge_stat_info(struct cache_entry **src, int nr)
 179{
 180        static struct cache_entry null_entry;
 181        struct cache_entry **dst = src;
 182        struct cache_entry *old = &null_entry;
 183
 184        while (nr) {
 185                struct cache_entry *ce;
 186
 187                ce = src[0];
 188
 189                /* We throw away original cache entries except for the stat information */
 190                if (!ce_stage(ce)) {
 191                        old = ce;
 192                        src++;
 193                        nr--;
 194                        active_nr--;
 195                        continue;
 196                }
 197                if (path_matches(ce, old) && same(ce, old))
 198                        *ce = *old;
 199                ce->ce_flags &= ~htons(CE_STAGEMASK);
 200                *dst++ = ce;
 201                src++;
 202                nr--;
 203        }
 204}
 205
 206int main(int argc, char **argv)
 207{
 208        int i, newfd, merge;
 209        unsigned char sha1[20];
 210
 211        newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 212        if (newfd < 0)
 213                die("unable to create new cachefile");
 214        atexit(remove_lock_file);
 215        remove_lock = 1;
 216
 217        merge = 0;
 218        for (i = 1; i < argc; i++) {
 219                const char *arg = argv[i];
 220
 221                /* "-m" stands for "merge", meaning we start in stage 1 */
 222                if (!strcmp(arg, "-m")) {
 223                        int i;
 224                        if (stage)
 225                                usage("-m needs to come first");
 226                        read_cache();
 227                        for (i = 0; i < active_nr; i++) {
 228                                if (ce_stage(active_cache[i]))
 229                                        usage("you need to resolve your current index first");
 230                        }
 231                        stage = 1;
 232                        merge = 1;
 233                        continue;
 234                }
 235                if (get_sha1_hex(arg, sha1) < 0)
 236                        usage("read-tree [-m] <sha1>");
 237                if (stage > 3)
 238                        usage("can't merge more than two trees");
 239                if (read_tree(sha1, "", 0) < 0)
 240                        die("failed to unpack tree object %s", arg);
 241                stage++;
 242        }
 243        if (merge) {
 244                switch (stage) {
 245                case 4: /* Three-way merge */
 246                        trivially_merge_cache(active_cache, active_nr);
 247                        break;
 248                case 2: /* Just read a tree, merge with old cache contents */
 249                        merge_stat_info(active_cache, active_nr);
 250                        break;
 251                default:
 252                        die("just how do you expect me to merge %d trees?", stage-1);
 253                }
 254        }
 255        if (write_cache(newfd, active_cache, active_nr) ||
 256            rename(".git/index.lock", ".git/index"))
 257                die("unable to write new index file");
 258        remove_lock = 0;
 259        return 0;
 260}