]> git.ipfire.org Git - thirdparty/git.git/commitdiff
update-index: use unmerge_index_entry() to support removal
authorJunio C Hamano <gitster@pobox.com>
Mon, 31 Jul 2023 22:44:05 +0000 (15:44 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 31 Jul 2023 23:02:17 +0000 (16:02 -0700)
"update-index --unresolve" uses the unmerge_index_entry_at() that
assumes that the path to be unresolved must be in the index, which
makes it impossible to unresolve a path that was resolved as removal.

Rewrite unresolve_one() to use the unmerge_index_entry() to support
unresolving such a path.

Existing tests for "update-index --unresolve" forgot to check one
thing that tests for "checkout --merge -- paths" tested, which is to
make sure that resolve-undo record that has already been used to
recreate higher-stage index entries is removed.  Add new invocations
of "ls-files --resolve-undo" after running "update-index --unresolve"
to make sure that unresolving with update-index does remove the used
resolve-undo records.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/update-index.c
t/t2030-unresolve-info.sh

index 47cd68e9d582e7ae1a6a93e0e746c73dc285623a..ecd1c0c2d301606a27b54417e2c5778632559f5e 100644 (file)
@@ -660,26 +660,31 @@ static int unresolve_one(const char *path)
        int pos;
        int ret = 0;
        struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
+       struct resolve_undo_info *ru = NULL;
+
+       if (the_index.resolve_undo) {
+               struct string_list_item *item;
+               item = string_list_lookup(the_index.resolve_undo, path);
+               if (item) {
+                       ru = item->util;
+                       item->util = NULL;
+               }
+       }
+
+       /* resolve-undo record exists for the path */
+       if (ru) {
+               ret = unmerge_index_entry(&the_index, path, ru);
+               free(ru);
+               return ret;
+       }
 
        /* See if there is such entry in the index. */
        pos = index_name_pos(&the_index, path, namelen);
        if (0 <= pos) {
-               /* already merged */
-               pos = unmerge_index_entry_at(&the_index, pos);
-               if (pos < the_index.cache_nr) {
-                       const struct cache_entry *ce = the_index.cache[pos];
-                       if (ce_stage(ce) &&
-                           ce_namelen(ce) == namelen &&
-                           !memcmp(ce->name, path, namelen))
-                               return 0;
-               }
-               /* no resolve-undo information; fall back */
+               ; /* resolve-undo record was used already -- 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.
-                */
-               pos = -pos-1;
+               /* Is it unmerged? */
+               pos = -pos - 1;
                if (pos < the_index.cache_nr) {
                        const struct cache_entry *ce = the_index.cache[pos];
                        if (ce_namelen(ce) == namelen &&
@@ -687,9 +692,10 @@ static int unresolve_one(const char *path)
                                fprintf(stderr,
                                        "%s: skipping still unmerged path.\n",
                                        path);
-                               goto free_return;
                        }
+                       goto free_return;
                }
+               /* No, such a path does not exist -- removed */
        }
 
        /*
index d4e7760df58b89420c15a2c6ebb45a1053ee33a2..3eda385ca207578996164500a8ee168342682376 100755 (executable)
@@ -37,11 +37,17 @@ prime_resolve_undo () {
        git checkout second^0 &&
        test_tick &&
        test_must_fail git merge third^0 &&
-       echo merge does not leave anything &&
        check_resolve_undo empty &&
-       echo different >fi/le &&
-       git add fi/le &&
-       echo resolving records &&
+
+       # how should the conflict be resolved?
+       case "$1" in
+       remove)
+               rm -f file/le && git rm fi/le
+               ;;
+       *) # modify
+               echo different >fi/le && git add fi/le
+               ;;
+       esac
        check_resolve_undo recorded fi/le initial:fi/le second:fi/le third:fi/le
 }
 
@@ -122,6 +128,8 @@ test_expect_success 'add records checkout -m undoes' '
 test_expect_success 'unmerge with plumbing' '
        prime_resolve_undo &&
        git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
        git ls-files -u >actual &&
        test_line_count = 3 actual
 '
@@ -130,6 +138,27 @@ test_expect_success 'unmerge can be done even after committing' '
        prime_resolve_undo &&
        git commit -m "record to nuke MERGE_HEAD" &&
        git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
+       git ls-files -u >actual &&
+       test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge removal' '
+       prime_resolve_undo remove &&
+       git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
+       git ls-files -u >actual &&
+       test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge removal after committing' '
+       prime_resolve_undo remove &&
+       git commit -m "record to nuke MERGE_HEAD" &&
+       git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
        git ls-files -u >actual &&
        test_line_count = 3 actual
 '