@@ -17,6 +17,7 @@
#include "cache.h"
#include "merge-ort.h"
+#include "cache-tree.h"
#include "diff.h"
#include "diffcore.h"
#include "dir.h"
@@ -988,10 +989,96 @@ static int record_conflicted_index_entries(struct merge_options *opt,
struct strmap *paths,
struct strmap *conflicted)
{
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+ int errs = 0;
+ int original_cache_nr;
+
if (strmap_empty(conflicted))
return 0;
- die("Not yet implemented.");
+ original_cache_nr = index->cache_nr;
+
+ /* Put every entry from paths into plist, then sort */
+ strmap_for_each_entry(conflicted, &iter, e) {
+ const char *path = e->key;
+ struct conflict_info *ci = e->value;
+ int pos;
+ struct cache_entry *ce;
+ int i;
+
+ VERIFY_CI(ci);
+
+ /*
+ * The index will already have a stage=0 entry for this path,
+ * because we created an as-merged-as-possible version of the
+ * file and checkout() moved the working copy and index over
+ * to that version.
+ *
+ * However, previous iterations through this loop will have
+ * added unstaged entries to the end of the cache which
+ * ignore the standard alphabetical ordering of cache
+ * entries and break invariants needed for index_name_pos()
+ * to work. However, we know the entry we want is before
+ * those appended cache entries, so do a temporary swap on
+ * cache_nr to only look through entries of interest.
+ */
+ SWAP(index->cache_nr, original_cache_nr);
+ pos = index_name_pos(index, path, strlen(path));
+ SWAP(index->cache_nr, original_cache_nr);
+ if (pos < 0) {
+ if (ci->filemask == 1)
+ cache_tree_invalidate_path(index, path);
+ else
+ BUG("Conflicted %s but nothing in basic working tree or index; this shouldn't happen", path);
+ } else {
+ ce = index->cache[pos];
+
+ /*
+ * Clean paths with CE_SKIP_WORKTREE set will not be
+ * written to the working tree by the unpack_trees()
+ * call in checkout(). Our conflicted entries would
+ * have appeared clean to that code since we ignored
+ * the higher order stages. Thus, we need override
+ * the CE_SKIP_WORKTREE bit and manually write those
+ * files to the working disk here.
+ *
+ * TODO: Implement this CE_SKIP_WORKTREE fixup.
+ */
+
+ /*
+ * Mark this cache entry for removal and instead add
+ * new stage>0 entries corresponding to the
+ * conflicts. If there are many conflicted entries, we
+ * want to avoid memmove'ing O(NM) entries by
+ * inserting the new entries one at a time. So,
+ * instead, we just add the new cache entries to the
+ * end (ignoring normal index requirements on sort
+ * order) and sort the index once we're all done.
+ */
+ ce->ce_flags |= CE_REMOVE;
+ }
+
+ for (i = 0; i < 3; i++) {
+ struct version_info *vi;
+ if (!(ci->filemask & (1ul << i)))
+ continue;
+ vi = &ci->stages[i];
+ ce = make_cache_entry(index, vi->mode, &vi->oid,
+ path, i+1, 0);
+ add_index_entry(index, ce, ADD_CACHE_JUST_APPEND);
+ }
+ }
+
+ /*
+ * Remove the unused cache entries (and invalidate the relevant
+ * cache-trees), then sort the index entries to get the conflicted
+ * entries we added to the end into their right locations.
+ */
+ remove_marked_cache_entries(index, 1);
+ QSORT(index->cache, index->cache_nr, cmp_cache_name_compare);
+
+ return errs;
}
void merge_switch_to_result(struct merge_options *opt,