]> git.ipfire.org Git - thirdparty/git.git/commitdiff
checkout: allow "checkout -m path" to unmerge removed paths
authorJunio C Hamano <gitster@pobox.com>
Mon, 31 Jul 2023 22:44:09 +0000 (15:44 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 31 Jul 2023 23:16:44 +0000 (16:16 -0700)
"git checkout -m -- path" uses the unmerge_marked_index() API, whose
implementation is incapable of unresolving a path that was resolved
as removed.  Extend the unmerge_index() API function so that we can
mark the ce_flags member of the cache entries we add to the index as
unmerged, and replace use of unmerge_marked_index() with it.

Now, together with its unmerge_index_entry_at() helper function,
unmerge_marked_index() function is no longer called by anybody, and
can safely be removed.

This makes two known test failures in t2070 and t7201 to succeed.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/checkout.c
builtin/update-index.c
rerere.c
resolve-undo.c
resolve-undo.h
t/t2070-restore.sh
t/t7201-co.sh

index b8dfba57c68bcdc080123c995ca94d6e1106bb32..98fcf1220a4a9c06e29f0efdc473d341d35c5c20 100644 (file)
@@ -566,6 +566,8 @@ static int checkout_paths(const struct checkout_opts *opts,
 
        if (opts->source_tree)
                read_tree_some(opts->source_tree, &opts->pathspec);
+       if (opts->merge)
+               unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
 
        ps_matched = xcalloc(opts->pathspec.nr, 1);
 
@@ -589,10 +591,6 @@ static int checkout_paths(const struct checkout_opts *opts,
        }
        free(ps_matched);
 
-       /* "checkout -m path" to recreate conflicted state */
-       if (opts->merge)
-               unmerge_marked_index(&the_index);
-
        /* Any unmerged paths? */
        for (pos = 0; pos < the_index.cache_nr; pos++) {
                const struct cache_entry *ce = the_index.cache[pos];
index def7f9850468a9ea239a142a838362152101f368..69fe9c8fcb0444fd99f5aae978be6b2a6f70c35a 100644 (file)
@@ -646,7 +646,7 @@ static int unresolve_one(const char *path)
        item = string_list_lookup(the_index.resolve_undo, path);
        if (!item)
                return res; /* no resolve-undo record for the path */
-       res = unmerge_index_entry(&the_index, path, item->util);
+       res = unmerge_index_entry(&the_index, path, item->util, 0);
        FREE_AND_NULL(item->util);
        return res;
 }
index e968d413d65bd63ef8cc03285d51049505104482..b525dd92300ef57ea4e866414c9c47d041b8a988 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -1112,7 +1112,7 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
         * recover the original conflicted state and then
         * find the conflicted paths.
         */
-       unmerge_index(r->index, pathspec);
+       unmerge_index(r->index, pathspec, 0);
        find_conflict(r, &conflict);
        for (i = 0; i < conflict.nr; i++) {
                struct string_list_item *it = &conflict.items[i];
index 3b0244e210dad20cf306b9a6a3907b3029ba02b4..8e5a8072ed00c8fdc108c95ff50da15ee891a660 100644 (file)
@@ -115,75 +115,8 @@ void resolve_undo_clear_index(struct index_state *istate)
        istate->cache_changed |= RESOLVE_UNDO_CHANGED;
 }
 
-int unmerge_index_entry_at(struct index_state *istate, int pos)
-{
-       const struct cache_entry *ce;
-       struct string_list_item *item;
-       struct resolve_undo_info *ru;
-       int i, err = 0, matched;
-       char *name;
-
-       if (!istate->resolve_undo)
-               return pos;
-
-       ce = istate->cache[pos];
-       if (ce_stage(ce)) {
-               /* already unmerged */
-               while ((pos < istate->cache_nr) &&
-                      ! strcmp(istate->cache[pos]->name, ce->name))
-                       pos++;
-               return pos - 1; /* return the last entry processed */
-       }
-       item = string_list_lookup(istate->resolve_undo, ce->name);
-       if (!item)
-               return pos;
-       ru = item->util;
-       if (!ru)
-               return pos;
-       matched = ce->ce_flags & CE_MATCHED;
-       name = xstrdup(ce->name);
-       remove_index_entry_at(istate, pos);
-       for (i = 0; i < 3; i++) {
-               struct cache_entry *nce;
-               if (!ru->mode[i])
-                       continue;
-               nce = make_cache_entry(istate,
-                                      ru->mode[i],
-                                      &ru->oid[i],
-                                      name, i + 1, 0);
-               if (matched)
-                       nce->ce_flags |= CE_MATCHED;
-               if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
-                       err = 1;
-                       error("cannot unmerge '%s'", name);
-               }
-       }
-       free(name);
-       if (err)
-               return pos;
-       free(ru);
-       item->util = NULL;
-       return unmerge_index_entry_at(istate, pos);
-}
-
-void unmerge_marked_index(struct index_state *istate)
-{
-       int i;
-
-       if (!istate->resolve_undo)
-               return;
-
-       /* TODO: audit for interaction with sparse-index. */
-       ensure_full_index(istate);
-       for (i = 0; i < istate->cache_nr; i++) {
-               const struct cache_entry *ce = istate->cache[i];
-               if (ce->ce_flags & CE_MATCHED)
-                       i = unmerge_index_entry_at(istate, i);
-       }
-}
-
 int unmerge_index_entry(struct index_state *istate, const char *path,
-                       struct resolve_undo_info *ru)
+                       struct resolve_undo_info *ru, unsigned ce_flags)
 {
        int i = index_name_pos(istate, path, strlen(path));
 
@@ -206,13 +139,15 @@ int unmerge_index_entry(struct index_state *istate, const char *path,
                        continue;
                ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
                                      path, i + 1, 0);
+               ce->ce_flags |= ce_flags;
                if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
                        return error("cannot unmerge '%s'", path);
        }
        return 0;
 }
 
-void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,
+                  unsigned ce_flags)
 {
        struct string_list_item *item;
 
@@ -231,7 +166,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
                                    item->string, strlen(item->string),
                                    0, NULL, 0))
                        continue;
-               unmerge_index_entry(istate, path, ru);
+               unmerge_index_entry(istate, path, ru, ce_flags);
                free(ru);
                item->util = NULL;
        }
index 1ae321c88ba9c4023cc572733a1739e5480a6e02..f3f8462751bfd2e7fb2ab38b2632f059b8f07013 100644 (file)
@@ -17,9 +17,7 @@ void record_resolve_undo(struct index_state *, struct cache_entry *);
 void resolve_undo_write(struct strbuf *, struct string_list *);
 struct string_list *resolve_undo_read(const char *, unsigned long);
 void resolve_undo_clear_index(struct index_state *);
-int unmerge_index_entry_at(struct index_state *, int);
-int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *);
-void unmerge_index(struct index_state *, const struct pathspec *);
-void unmerge_marked_index(struct index_state *);
+int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned);
+void unmerge_index(struct index_state *, const struct pathspec *, unsigned);
 
 #endif
index d97ecc2483b4b922b70858aca0c18481d85be376..16d6348b692806ab25faf89d77a73cd62fab4d93 100755 (executable)
@@ -180,7 +180,7 @@ test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
        test_cmp expect file
 '
 
-test_expect_failure 'restore --merge to unresolve after (mistaken) resolution' '
+test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
        O=$(echo original | git hash-object -w --stdin) &&
        A=$(echo ourside | git hash-object -w --stdin) &&
        B=$(echo theirside | git hash-object -w --stdin) &&
index 4b07a26c1458aedb9c1bb64dd1fe21c9eaa53178..df582295dfe0a1b0c8ac25da91186280ae8ec98e 100755 (executable)
@@ -543,7 +543,7 @@ test_expect_success 'checkout -m works after (mistaken) resolution' '
        test_cmp merged file
 '
 
-test_expect_failure 'checkout -m works after (mistaken) resolution to remove' '
+test_expect_success 'checkout -m works after (mistaken) resolution to remove' '
        setup_conflicting_index &&
        echo "none of the above" >sample &&
        cat sample >fild &&