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