|
17 | 17 | #include "cache.h"
|
18 | 18 | #include "merge-ort.h"
|
19 | 19 |
|
| 20 | +#include "strmap.h" |
| 21 | + |
| 22 | +struct merge_options_internal { |
| 23 | + /* |
| 24 | + * paths: primary data structure in all of merge ort. |
| 25 | + * |
| 26 | + * The keys of paths: |
| 27 | + * * are full relative paths from the toplevel of the repository |
| 28 | + * (e.g. "drivers/firmware/raspberrypi.c"). |
| 29 | + * * store all relevant paths in the repo, both directories and |
| 30 | + * files (e.g. drivers, drivers/firmware would also be included) |
| 31 | + * * these keys serve to intern all the path strings, which allows |
| 32 | + * us to do pointer comparison on directory names instead of |
| 33 | + * strcmp; we just have to be careful to use the interned strings. |
| 34 | + * |
| 35 | + * The values of paths: |
| 36 | + * * either a pointer to a merged_info, or a conflict_info struct |
| 37 | + * * merged_info contains all relevant information for a |
| 38 | + * non-conflicted entry. |
| 39 | + * * conflict_info contains a merged_info, plus any additional |
| 40 | + * information about a conflict such as the higher orders stages |
| 41 | + * involved and the names of the paths those came from (handy |
| 42 | + * once renames get involved). |
| 43 | + * * a path may start "conflicted" (i.e. point to a conflict_info) |
| 44 | + * and then a later step (e.g. three-way content merge) determines |
| 45 | + * it can be cleanly merged, at which point it'll be marked clean |
| 46 | + * and the algorithm will ignore any data outside the contained |
| 47 | + * merged_info for that entry |
| 48 | + * * If an entry remains conflicted, the merged_info portion of a |
| 49 | + * conflict_info will later be filled with whatever version of |
| 50 | + * the file should be placed in the working directory (e.g. an |
| 51 | + * as-merged-as-possible variation that contains conflict markers). |
| 52 | + */ |
| 53 | + struct strmap paths; |
| 54 | + |
| 55 | + /* |
| 56 | + * conflicted: a subset of keys->values from "paths" |
| 57 | + * |
| 58 | + * conflicted is basically an optimization between process_entries() |
| 59 | + * and record_conflicted_index_entries(); the latter could loop over |
| 60 | + * ALL the entries in paths AGAIN and look for the ones that are |
| 61 | + * still conflicted, but since process_entries() has to loop over |
| 62 | + * all of them, it saves the ones it couldn't resolve in this strmap |
| 63 | + * so that record_conflicted_index_entries() can iterate just the |
| 64 | + * relevant entries. |
| 65 | + */ |
| 66 | + struct strmap conflicted; |
| 67 | + |
| 68 | + /* |
| 69 | + * current_dir_name: temporary var used in collect_merge_info_callback() |
| 70 | + * |
| 71 | + * Used to set merged_info.directory_name; see documentation for that |
| 72 | + * variable and the requirements placed on that field. |
| 73 | + */ |
| 74 | + const char *current_dir_name; |
| 75 | + |
| 76 | + /* call_depth: recursion level counter for merging merge bases */ |
| 77 | + int call_depth; |
| 78 | +}; |
| 79 | + |
| 80 | +struct version_info { |
| 81 | + struct object_id oid; |
| 82 | + unsigned short mode; |
| 83 | +}; |
| 84 | + |
| 85 | +struct merged_info { |
| 86 | + /* if is_null, ignore result. otherwise result has oid & mode */ |
| 87 | + struct version_info result; |
| 88 | + unsigned is_null:1; |
| 89 | + |
| 90 | + /* |
| 91 | + * clean: whether the path in question is cleanly merged. |
| 92 | + * |
| 93 | + * see conflict_info.merged for more details. |
| 94 | + */ |
| 95 | + unsigned clean:1; |
| 96 | + |
| 97 | + /* |
| 98 | + * basename_offset: offset of basename of path. |
| 99 | + * |
| 100 | + * perf optimization to avoid recomputing offset of final '/' |
| 101 | + * character in pathname (0 if no '/' in pathname). |
| 102 | + */ |
| 103 | + size_t basename_offset; |
| 104 | + |
| 105 | + /* |
| 106 | + * directory_name: containing directory name. |
| 107 | + * |
| 108 | + * Note that we assume directory_name is constructed such that |
| 109 | + * strcmp(dir1_name, dir2_name) == 0 iff dir1_name == dir2_name, |
| 110 | + * i.e. string equality is equivalent to pointer equality. For this |
| 111 | + * to hold, we have to be careful setting directory_name. |
| 112 | + */ |
| 113 | + const char *directory_name; |
| 114 | +}; |
| 115 | + |
| 116 | +struct conflict_info { |
| 117 | + /* |
| 118 | + * merged: the version of the path that will be written to working tree |
| 119 | + * |
| 120 | + * WARNING: It is critical to check merged.clean and ensure it is 0 |
| 121 | + * before reading any conflict_info fields outside of merged. |
| 122 | + * Allocated merge_info structs will always have clean set to 1. |
| 123 | + * Allocated conflict_info structs will have merged.clean set to 0 |
| 124 | + * initially. The merged.clean field is how we know if it is safe |
| 125 | + * to access other parts of conflict_info besides merged; if a |
| 126 | + * conflict_info's merged.clean is changed to 1, the rest of the |
| 127 | + * algorithm is not allowed to look at anything outside of the |
| 128 | + * merged member anymore. |
| 129 | + */ |
| 130 | + struct merged_info merged; |
| 131 | + |
| 132 | + /* oids & modes from each of the three trees for this path */ |
| 133 | + struct version_info stages[3]; |
| 134 | + |
| 135 | + /* pathnames for each stage; may differ due to rename detection */ |
| 136 | + const char *pathnames[3]; |
| 137 | + |
| 138 | + /* Whether this path is/was involved in a directory/file conflict */ |
| 139 | + unsigned df_conflict:1; |
| 140 | + |
| 141 | + /* |
| 142 | + * For filemask and dirmask, see tree-walk.h's struct traverse_info, |
| 143 | + * particularly the documentation above the "fn" member. Note that |
| 144 | + * filemask = mask & ~dirmask from that documentation. |
| 145 | + */ |
| 146 | + unsigned filemask:3; |
| 147 | + unsigned dirmask:3; |
| 148 | + |
| 149 | + /* |
| 150 | + * Optimization to track which stages match, to avoid the need to |
| 151 | + * recompute it in multiple steps. Either 0 or at least 2 bits are |
| 152 | + * set; if at least 2 bits are set, their corresponding stages match. |
| 153 | + */ |
| 154 | + unsigned match_mask:3; |
| 155 | +}; |
| 156 | + |
20 | 157 | void merge_switch_to_result(struct merge_options *opt,
|
21 | 158 | struct tree *head,
|
22 | 159 | struct merge_result *result,
|
|
0 commit comments