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