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