Skip to content

Commit ef2b369

Browse files
newrengitster
authored andcommitted
merge-ort: add implementation of record_conflicted_index_entries()
After checkout(), the working tree has the appropriate contents, and the index matches the working copy. That means that all unmodified and cleanly merged files have correct index entries, but conflicted entries need to be updated. We do this by looping over the conflicted entries, marking the existing index entry for the path with CE_REMOVE, adding new higher order staged for the path at the end of the index (ignoring normal index sort order), and then at the end of the loop removing the CE_REMOVED-marked cache entries and sorting the index. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 70912f6 commit ef2b369

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

merge-ort.c

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "cache.h"
1818
#include "merge-ort.h"
1919

20+
#include "cache-tree.h"
2021
#include "diff.h"
2122
#include "diffcore.h"
2223
#include "dir.h"
@@ -1026,10 +1027,95 @@ static int record_conflicted_index_entries(struct merge_options *opt,
10261027
struct strmap *paths,
10271028
struct strmap *conflicted)
10281029
{
1030+
struct hashmap_iter iter;
1031+
struct strmap_entry *e;
1032+
int errs = 0;
1033+
int original_cache_nr;
1034+
10291035
if (strmap_empty(conflicted))
10301036
return 0;
10311037

1032-
die("Not yet implemented.");
1038+
original_cache_nr = index->cache_nr;
1039+
1040+
/* Put every entry from paths into plist, then sort */
1041+
strmap_for_each_entry(conflicted, &iter, e) {
1042+
const char *path = e->key;
1043+
struct conflict_info *ci = e->value;
1044+
int pos;
1045+
struct cache_entry *ce;
1046+
int i;
1047+
1048+
VERIFY_CI(ci);
1049+
1050+
/*
1051+
* The index will already have a stage=0 entry for this path,
1052+
* because we created an as-merged-as-possible version of the
1053+
* file and checkout() moved the working copy and index over
1054+
* to that version.
1055+
*
1056+
* However, previous iterations through this loop will have
1057+
* added unstaged entries to the end of the cache which
1058+
* ignore the standard alphabetical ordering of cache
1059+
* entries and break invariants needed for index_name_pos()
1060+
* to work. However, we know the entry we want is before
1061+
* those appended cache entries, so do a temporary swap on
1062+
* cache_nr to only look through entries of interest.
1063+
*/
1064+
SWAP(index->cache_nr, original_cache_nr);
1065+
pos = index_name_pos(index, path, strlen(path));
1066+
SWAP(index->cache_nr, original_cache_nr);
1067+
if (pos < 0) {
1068+
if (ci->filemask != 1)
1069+
BUG("Conflicted %s but nothing in basic working tree or index; this shouldn't happen", path);
1070+
cache_tree_invalidate_path(index, path);
1071+
} else {
1072+
ce = index->cache[pos];
1073+
1074+
/*
1075+
* Clean paths with CE_SKIP_WORKTREE set will not be
1076+
* written to the working tree by the unpack_trees()
1077+
* call in checkout(). Our conflicted entries would
1078+
* have appeared clean to that code since we ignored
1079+
* the higher order stages. Thus, we need override
1080+
* the CE_SKIP_WORKTREE bit and manually write those
1081+
* files to the working disk here.
1082+
*
1083+
* TODO: Implement this CE_SKIP_WORKTREE fixup.
1084+
*/
1085+
1086+
/*
1087+
* Mark this cache entry for removal and instead add
1088+
* new stage>0 entries corresponding to the
1089+
* conflicts. If there are many conflicted entries, we
1090+
* want to avoid memmove'ing O(NM) entries by
1091+
* inserting the new entries one at a time. So,
1092+
* instead, we just add the new cache entries to the
1093+
* end (ignoring normal index requirements on sort
1094+
* order) and sort the index once we're all done.
1095+
*/
1096+
ce->ce_flags |= CE_REMOVE;
1097+
}
1098+
1099+
for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
1100+
struct version_info *vi;
1101+
if (!(ci->filemask & (1ul << i)))
1102+
continue;
1103+
vi = &ci->stages[i];
1104+
ce = make_cache_entry(index, vi->mode, &vi->oid,
1105+
path, i+1, 0);
1106+
add_index_entry(index, ce, ADD_CACHE_JUST_APPEND);
1107+
}
1108+
}
1109+
1110+
/*
1111+
* Remove the unused cache entries (and invalidate the relevant
1112+
* cache-trees), then sort the index entries to get the conflicted
1113+
* entries we added to the end into their right locations.
1114+
*/
1115+
remove_marked_cache_entries(index, 1);
1116+
QSORT(index->cache, index->cache_nr, cmp_cache_name_compare);
1117+
1118+
return errs;
10331119
}
10341120

10351121
void merge_switch_to_result(struct merge_options *opt,

0 commit comments

Comments
 (0)