Skip to content

Commit 85cf82f

Browse files
committed
Merge branch 'en/merge-ort-2'
More "ORT" merge strategy. * en/merge-ort-2: merge-ort: add modify/delete handling and delayed output processing merge-ort: add die-not-implemented stub handle_content_merge() function merge-ort: add function grouping comments merge-ort: add a paths_to_free field to merge_options_internal merge-ort: add a path_conflict field to merge_options_internal merge-ort: add a clear_internal_opts helper merge-ort: add a few includes
2 parents f9d29da + c5a6f65 commit 85cf82f

File tree

1 file changed

+191
-19
lines changed

1 file changed

+191
-19
lines changed

merge-ort.c

Lines changed: 191 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "cache.h"
1818
#include "merge-ort.h"
1919

20+
#include "blob.h"
2021
#include "cache-tree.h"
22+
#include "commit-reach.h"
2123
#include "diff.h"
2224
#include "diffcore.h"
2325
#include "dir.h"
@@ -56,6 +58,8 @@ struct merge_options_internal {
5658
* * these keys serve to intern all the path strings, which allows
5759
* us to do pointer comparison on directory names instead of
5860
* strcmp; we just have to be careful to use the interned strings.
61+
* (Technically paths_to_free may track some strings that were
62+
* removed from froms paths.)
5963
*
6064
* The values of paths:
6165
* * either a pointer to a merged_info, or a conflict_info struct
@@ -90,6 +94,25 @@ struct merge_options_internal {
9094
*/
9195
struct strmap conflicted;
9296

97+
/*
98+
* paths_to_free: additional list of strings to free
99+
*
100+
* If keys are removed from "paths", they are added to paths_to_free
101+
* to ensure they are later freed. We avoid free'ing immediately since
102+
* other places (e.g. conflict_info.pathnames[]) may still be
103+
* referencing these paths.
104+
*/
105+
struct string_list paths_to_free;
106+
107+
/*
108+
* output: special messages and conflict notices for various paths
109+
*
110+
* This is a map of pathnames (a subset of the keys in "paths" above)
111+
* to strbufs. It gathers various warning/conflict/notice messages
112+
* for later processing.
113+
*/
114+
struct strmap output;
115+
93116
/*
94117
* current_dir_name: temporary var used in collect_merge_info_callback()
95118
*
@@ -163,6 +186,13 @@ struct conflict_info {
163186
/* Whether this path is/was involved in a directory/file conflict */
164187
unsigned df_conflict:1;
165188

189+
/*
190+
* Whether this path is/was involved in a non-content conflict other
191+
* than a directory/file conflict (e.g. rename/rename, rename/delete,
192+
* file location based on possible directory rename).
193+
*/
194+
unsigned path_conflict:1;
195+
166196
/*
167197
* For filemask and dirmask, the ith bit corresponds to whether the
168198
* ith entry is a file (filemask) or a directory (dirmask). Thus,
@@ -189,6 +219,8 @@ struct conflict_info {
189219
unsigned match_mask:3;
190220
};
191221

222+
/*** Function Grouping: various utility functions ***/
223+
192224
/*
193225
* For the next three macros, see warning for conflict_info.merged.
194226
*
@@ -219,6 +251,61 @@ static void free_strmap_strings(struct strmap *map)
219251
}
220252
}
221253

254+
static void clear_internal_opts(struct merge_options_internal *opti,
255+
int reinitialize)
256+
{
257+
assert(!reinitialize);
258+
259+
/*
260+
* We marked opti->paths with strdup_strings = 0, so that we
261+
* wouldn't have to make another copy of the fullpath created by
262+
* make_traverse_path from setup_path_info(). But, now that we've
263+
* used it and have no other references to these strings, it is time
264+
* to deallocate them.
265+
*/
266+
free_strmap_strings(&opti->paths);
267+
strmap_clear(&opti->paths, 1);
268+
269+
/*
270+
* All keys and values in opti->conflicted are a subset of those in
271+
* opti->paths. We don't want to deallocate anything twice, so we
272+
* don't free the keys and we pass 0 for free_values.
273+
*/
274+
strmap_clear(&opti->conflicted, 0);
275+
276+
/*
277+
* opti->paths_to_free is similar to opti->paths; we created it with
278+
* strdup_strings = 0 to avoid making _another_ copy of the fullpath
279+
* but now that we've used it and have no other references to these
280+
* strings, it is time to deallocate them. We do so by temporarily
281+
* setting strdup_strings to 1.
282+
*/
283+
opti->paths_to_free.strdup_strings = 1;
284+
string_list_clear(&opti->paths_to_free, 0);
285+
opti->paths_to_free.strdup_strings = 0;
286+
287+
if (!reinitialize) {
288+
struct hashmap_iter iter;
289+
struct strmap_entry *e;
290+
291+
/* Release and free each strbuf found in output */
292+
strmap_for_each_entry(&opti->output, &iter, e) {
293+
struct strbuf *sb = e->value;
294+
strbuf_release(sb);
295+
/*
296+
* While strictly speaking we don't need to free(sb)
297+
* here because we could pass free_values=1 when
298+
* calling strmap_clear() on opti->output, that would
299+
* require strmap_clear to do another
300+
* strmap_for_each_entry() loop, so we just free it
301+
* while we're iterating anyway.
302+
*/
303+
free(sb);
304+
}
305+
strmap_clear(&opti->output, 0);
306+
}
307+
}
308+
222309
static int err(struct merge_options *opt, const char *err, ...)
223310
{
224311
va_list params;
@@ -235,6 +322,29 @@ static int err(struct merge_options *opt, const char *err, ...)
235322
return -1;
236323
}
237324

325+
__attribute__((format (printf, 4, 5)))
326+
static void path_msg(struct merge_options *opt,
327+
const char *path,
328+
int omittable_hint, /* skippable under --remerge-diff */
329+
const char *fmt, ...)
330+
{
331+
va_list ap;
332+
struct strbuf *sb = strmap_get(&opt->priv->output, path);
333+
if (!sb) {
334+
sb = xmalloc(sizeof(*sb));
335+
strbuf_init(sb, 0);
336+
strmap_put(&opt->priv->output, path, sb);
337+
}
338+
339+
va_start(ap, fmt);
340+
strbuf_vaddf(sb, fmt, ap);
341+
va_end(ap);
342+
343+
strbuf_addch(sb, '\n');
344+
}
345+
346+
/*** Function Grouping: functions related to collect_merge_info() ***/
347+
238348
static void setup_path_info(struct merge_options *opt,
239349
struct string_list_item *result,
240350
const char *current_dir_name,
@@ -489,6 +599,27 @@ static int collect_merge_info(struct merge_options *opt,
489599
return ret;
490600
}
491601

602+
/*** Function Grouping: functions related to threeway content merges ***/
603+
604+
static int handle_content_merge(struct merge_options *opt,
605+
const char *path,
606+
const struct version_info *o,
607+
const struct version_info *a,
608+
const struct version_info *b,
609+
const char *pathnames[3],
610+
const int extra_marker_size,
611+
struct version_info *result)
612+
{
613+
die("Not yet implemented");
614+
}
615+
616+
/*** Function Grouping: functions related to detect_and_process_renames(), ***
617+
*** which are split into directory and regular rename detection sections. ***/
618+
619+
/*** Function Grouping: functions related to directory rename detection ***/
620+
621+
/*** Function Grouping: functions related to regular rename detection ***/
622+
492623
static int detect_and_process_renames(struct merge_options *opt,
493624
struct tree *merge_base,
494625
struct tree *side1,
@@ -506,6 +637,8 @@ static int detect_and_process_renames(struct merge_options *opt,
506637
return clean;
507638
}
508639

640+
/*** Function Grouping: functions related to process_entries() ***/
641+
509642
static int string_list_df_name_compare(const char *one, const char *two)
510643
{
511644
int onelen = strlen(one);
@@ -887,9 +1020,27 @@ static void process_entry(struct merge_options *opt,
8871020
ci->merged.clean = 0;
8881021
ci->merged.result.mode = ci->stages[1].mode;
8891022
oidcpy(&ci->merged.result.oid, &ci->stages[1].oid);
1023+
/* When we fix above, we'll call handle_content_merge() */
1024+
(void)handle_content_merge;
8901025
} else if (ci->filemask == 3 || ci->filemask == 5) {
8911026
/* Modify/delete */
892-
die("Not yet implemented.");
1027+
const char *modify_branch, *delete_branch;
1028+
int side = (ci->filemask == 5) ? 2 : 1;
1029+
int index = opt->priv->call_depth ? 0 : side;
1030+
1031+
ci->merged.result.mode = ci->stages[index].mode;
1032+
oidcpy(&ci->merged.result.oid, &ci->stages[index].oid);
1033+
ci->merged.clean = 0;
1034+
1035+
modify_branch = (side == 1) ? opt->branch1 : opt->branch2;
1036+
delete_branch = (side == 1) ? opt->branch2 : opt->branch1;
1037+
1038+
path_msg(opt, path, 0,
1039+
_("CONFLICT (modify/delete): %s deleted in %s "
1040+
"and modified in %s. Version %s of %s left "
1041+
"in tree."),
1042+
path, delete_branch, modify_branch,
1043+
modify_branch, path);
8931044
} else if (ci->filemask == 2 || ci->filemask == 4) {
8941045
/* Added on one side */
8951046
int side = (ci->filemask == 4) ? 2 : 1;
@@ -984,6 +1135,8 @@ static void process_entries(struct merge_options *opt,
9841135
string_list_clear(&dir_metadata.offsets, 0);
9851136
}
9861137

1138+
/*** Function Grouping: functions related to merge_switch_to_result() ***/
1139+
9871140
static int checkout(struct merge_options *opt,
9881141
struct tree *prev,
9891142
struct tree *next)
@@ -1154,7 +1307,29 @@ void merge_switch_to_result(struct merge_options *opt,
11541307
}
11551308

11561309
if (display_update_msgs) {
1157-
/* TODO: print out CONFLICT and other informational messages. */
1310+
struct merge_options_internal *opti = result->priv;
1311+
struct hashmap_iter iter;
1312+
struct strmap_entry *e;
1313+
struct string_list olist = STRING_LIST_INIT_NODUP;
1314+
int i;
1315+
1316+
/* Hack to pre-allocate olist to the desired size */
1317+
ALLOC_GROW(olist.items, strmap_get_size(&opti->output),
1318+
olist.alloc);
1319+
1320+
/* Put every entry from output into olist, then sort */
1321+
strmap_for_each_entry(&opti->output, &iter, e) {
1322+
string_list_append(&olist, e->key)->util = e->value;
1323+
}
1324+
string_list_sort(&olist);
1325+
1326+
/* Iterate over the items, printing them */
1327+
for (i = 0; i < olist.nr; ++i) {
1328+
struct strbuf *sb = olist.items[i].util;
1329+
1330+
printf("%s", sb->buf);
1331+
}
1332+
string_list_clear(&olist, 0);
11581333
}
11591334

11601335
merge_finalize(opt, result);
@@ -1167,25 +1342,12 @@ void merge_finalize(struct merge_options *opt,
11671342

11681343
assert(opt->priv == NULL);
11691344

1170-
/*
1171-
* We marked opti->paths with strdup_strings = 0, so that we
1172-
* wouldn't have to make another copy of the fullpath created by
1173-
* make_traverse_path from setup_path_info(). But, now that we've
1174-
* used it and have no other references to these strings, it is time
1175-
* to deallocate them.
1176-
*/
1177-
free_strmap_strings(&opti->paths);
1178-
strmap_clear(&opti->paths, 1);
1179-
1180-
/*
1181-
* All keys and values in opti->conflicted are a subset of those in
1182-
* opti->paths. We don't want to deallocate anything twice, so we
1183-
* don't free the keys and we pass 0 for free_values.
1184-
*/
1185-
strmap_clear(&opti->conflicted, 0);
1345+
clear_internal_opts(opti, 0);
11861346
FREE_AND_NULL(opti);
11871347
}
11881348

1349+
/*** Function Grouping: helper functions for merge_incore_*() ***/
1350+
11891351
static void merge_start(struct merge_options *opt, struct merge_result *result)
11901352
{
11911353
/* Sanity checks on opt */
@@ -1226,15 +1388,25 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
12261388
* Although we initialize opt->priv->paths with strdup_strings=0,
12271389
* that's just to avoid making yet another copy of an allocated
12281390
* string. Putting the entry into paths means we are taking
1229-
* ownership, so we will later free it.
1391+
* ownership, so we will later free it. paths_to_free is similar.
12301392
*
12311393
* In contrast, conflicted just has a subset of keys from paths, so
12321394
* we don't want to free those (it'd be a duplicate free).
12331395
*/
12341396
strmap_init_with_options(&opt->priv->paths, NULL, 0);
12351397
strmap_init_with_options(&opt->priv->conflicted, NULL, 0);
1398+
string_list_init(&opt->priv->paths_to_free, 0);
1399+
1400+
/*
1401+
* keys & strbufs in output will sometimes need to outlive "paths",
1402+
* so it will have a copy of relevant keys. It's probably a small
1403+
* subset of the overall paths that have special output.
1404+
*/
1405+
strmap_init(&opt->priv->output);
12361406
}
12371407

1408+
/*** Function Grouping: merge_incore_*() and their internal variants ***/
1409+
12381410
/*
12391411
* Originally from merge_trees_internal(); heavily adapted, though.
12401412
*/

0 commit comments

Comments
 (0)