read-tree.c 4.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * GIT - The information manager from hell
 *
 * Copyright (C) Linus Torvalds, 2005
 */
6 7
#include "cache.h"

8 9
static int stage = 0;

10
static int unpack_tree(unsigned char *sha1)
11 12 13 14
{
	void *buffer;
	unsigned long size;

15
	buffer = read_object_with_reference(sha1, "tree", &size, 0);
16 17
	if (!buffer)
		return -1;
18
	return read_tree(buffer, size, stage);
19 20
}

21
static char *lockfile_name;
22 23 24

static void remove_lock_file(void)
{
25 26
	if (lockfile_name)
		unlink(lockfile_name);
27 28
}

29 30 31 32 33 34 35
static int path_matches(struct cache_entry *a, struct cache_entry *b)
{
	int len = ce_namelen(a);
	return ce_namelen(b) == len &&
		!memcmp(a->name, b->name, len);
}

36 37 38 39 40 41 42
static int same(struct cache_entry *a, struct cache_entry *b)
{
	return a->ce_mode == b->ce_mode && 
		!memcmp(a->sha1, b->sha1, 20);
}


43
/*
44 45
 * This removes all trivial merges that don't change the tree
 * and collapses them to state 0.
46
 *
47 48 49
 * _Any_ other merge is left to user policy.  That includes "both
 * created the same file", and "both removed the same file" - which are
 * trivial, but the user might still want to _note_ it. 
50
 */
51 52 53
static struct cache_entry *merge_entries(struct cache_entry *a,
					 struct cache_entry *b,
					 struct cache_entry *c)
54 55
{
	int len = ce_namelen(a);
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

	/*
	 * Are they all the same filename? We won't do
	 * any name merging
	 */
	if (ce_namelen(b) != len ||
	    ce_namelen(c) != len ||
	    memcmp(a->name, b->name, len) ||
	    memcmp(a->name, c->name, len))
		return NULL;

	/*
	 * Ok, all three entries describe the same
	 * filename, but maybe the contents or file
	 * mode have changed?
	 *
	 * The trivial cases end up being the ones where two
	 * out of three files are the same:
	 *  - both destinations the same, trivially take either
	 *  - one of the destination versions hasn't changed,
	 *    take the other.
	 *
	 * The "all entries exactly the same" case falls out as
	 * a special case of any of the "two same" cases.
	 *
	 * Here "a" is "original", and "b" and "c" are the two
	 * trees we are merging.
	 */
	if (same(b,c))
		return c;
	if (same(a,b))
		return c;
	if (same(a,c))
		return b;
	return NULL;
91 92 93 94
}

static void trivially_merge_cache(struct cache_entry **src, int nr)
{
95
	static struct cache_entry null_entry;
96
	struct cache_entry **dst = src;
97
	struct cache_entry *old = &null_entry;
98 99

	while (nr) {
100
		struct cache_entry *ce, *result;
101 102

		ce = src[0];
103 104 105 106 107 108 109 110 111

		/* We throw away original cache entries except for the stat information */
		if (!ce_stage(ce)) {
			old = ce;
			src++;
			nr--;
			active_nr--;
			continue;
		}
112
		if (nr > 2 && (result = merge_entries(ce, src[1], src[2])) != NULL) {
113 114 115 116 117 118
			/*
			 * See if we can re-use the old CE directly?
			 * That way we get the uptodate stat info.
			 */
			if (path_matches(result, old) && same(result, old))
				*result = *old;
119
			ce = result;
120 121 122 123 124
			ce->ce_flags &= ~htons(CE_STAGEMASK);
			src += 2;
			nr -= 2;
			active_nr -= 2;
		}
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		*dst++ = ce;
		src++;
		nr--;
	}
}

static void merge_stat_info(struct cache_entry **src, int nr)
{
	static struct cache_entry null_entry;
	struct cache_entry **dst = src;
	struct cache_entry *old = &null_entry;

	while (nr) {
		struct cache_entry *ce;

		ce = src[0];

		/* We throw away original cache entries except for the stat information */
		if (!ce_stage(ce)) {
			old = ce;
			src++;
			nr--;
			active_nr--;
			continue;
		}
		if (path_matches(ce, old) && same(ce, old))
			*ce = *old;
		ce->ce_flags &= ~htons(CE_STAGEMASK);
		*dst++ = ce;
154 155 156 157 158
		src++;
		nr--;
	}
}

J
Junio C Hamano 已提交
159 160
static char *read_tree_usage = "read-tree (<sha> | -m <sha1> [<sha2> <sha3>])";

161 162
int main(int argc, char **argv)
{
163
	int i, newfd, merge;
164
	unsigned char sha1[20];
165 166
	static char lockfile[MAXPATHLEN+1];
	const char *indexfile = get_index_file();
167

168 169 170
	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);

	newfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600);
171
	if (newfd < 0)
172
		die("unable to create new cachefile");
173
	atexit(remove_lock_file);
174
	lockfile_name = lockfile;
175

176
	merge = 0;
177 178 179
	for (i = 1; i < argc; i++) {
		const char *arg = argv[i];

180
		/* "-m" stands for "merge", meaning we start in stage 1 */
181
		if (!strcmp(arg, "-m")) {
182 183
			int i;
			if (stage)
J
Junio C Hamano 已提交
184
				die("-m needs to come first");
185 186 187
			read_cache();
			for (i = 0; i < active_nr; i++) {
				if (ce_stage(active_cache[i]))
J
Junio C Hamano 已提交
188
					die("you need to resolve your current index first");
189
			}
190
			stage = 1;
191
			merge = 1;
192 193
			continue;
		}
194
		if (get_sha1(arg, sha1) < 0)
J
Junio C Hamano 已提交
195
			usage(read_tree_usage);
196
		if (stage > 3)
J
Junio C Hamano 已提交
197
			usage(read_tree_usage);
198
		if (unpack_tree(sha1) < 0)
199
			die("failed to unpack tree object %s", arg);
200
		stage++;
201
	}
202
	if (merge) {
203 204 205 206 207 208 209 210 211 212
		switch (stage) {
		case 4:	/* Three-way merge */
			trivially_merge_cache(active_cache, active_nr);
			break;
		case 2:	/* Just read a tree, merge with old cache contents */
			merge_stat_info(active_cache, active_nr);
			break;
		default:
			die("just how do you expect me to merge %d trees?", stage-1);
		}
213
	}
214
	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
215
		die("unable to write new index file");
216
	lockfile_name = NULL;
217
	return 0;
218
}