resolve-undo: teach "update-index --unresolve" to use resolve-undo info

The update-index plumbing command had a hacky --unresolve implementation
that was written back in the days when merge was the only way for users to
end up with higher stages in the index, and assumed that stage  must
have come from HEAD, stage  from MERGE_HEAD and didn't bother to compute
the stage  information.

There were several issues with this approach:

 - These days, merge is not the only command, and conflicts coming from
   commands like cherry-pick, "am -3", etc. cannot be recreated by looking
   at MERGE_HEAD;

 - For a conflict that came from a merge that had renames, picking up the
   same path from MERGE_HEAD and HEAD wouldn't help recreating it, either;

 - It may have been Ok not to recreate stage  back when it was written,
   because "diff --ours/--theirs" were the only availble ways to review
   conflicts and they don't need stage  information.  "diff --cc" that
   was invented much later is a lot more useful way but it needs stage .

We can use resolve-undo information recorded in the index extension to
solve all of these issues.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2009-12-25 13:40:02 -08:00
parent 4421a82357
commit 8aa38563b2
3 changed files with 20 additions and 1 deletions

@ -433,7 +433,18 @@ static int unresolve_one(const char *path)
/* See if there is such entry in the index. */
pos = cache_name_pos(path, namelen);
if (pos < 0) {
if (0 <= pos) {
/* already merged */
pos = unmerge_cache_entry_at(pos);
if (pos < active_nr) {
struct cache_entry *ce = active_cache[pos];
if (ce_stage(ce) &&
ce_namelen(ce) == namelen &&
!memcmp(ce->name, path, namelen))
return 0;
}
/* no resolve-undo information; fall back */
} else {
/* If there isn't, either it is unmerged, or
* resolved as "removed" by mistake. We do not
* want to do anything in the former case.

@ -338,6 +338,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
#endif

@ -108,4 +108,11 @@ test_expect_success 'add records checkout -m undoes' '
grep "^++<<<<<<<" actual
'
test_expect_success 'unmerge with plumbing' '
prime_resolve_undo &&
git update-index --unresolve file &&
git ls-files -u >actual &&
test $(wc -l <actual) = 3
'
test_done