]> git.ipfire.org Git - thirdparty/git.git/commitdiff
unpack-trees: avoid nuking untracked dir in way of unmerged file
authorElijah Newren <newren@gmail.com>
Mon, 27 Sep 2021 16:33:45 +0000 (16:33 +0000)
committerJunio C Hamano <gitster@pobox.com>
Mon, 27 Sep 2021 20:38:37 +0000 (13:38 -0700)
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t2500-untracked-overwriting.sh
unpack-trees.c

index 18604360df8c770f7a1a14ce0b32db345f615b40..5ec66058cfc20d43796f212261ec0227dc80f301 100755 (executable)
@@ -197,7 +197,7 @@ test_expect_failure 'git stash and untracked files' '
        )
 '
 
-test_expect_failure 'git am --abort and untracked dir vs. unmerged file' '
+test_expect_success 'git am --abort and untracked dir vs. unmerged file' '
        test_setup_sequencing am_abort_and_untracked &&
        (
                cd sequencing_am_abort_and_untracked &&
index 3fff5061569a37a6ffbab9d235a1d97e81c71ebb..821f532c8515087a7602028796d3c22d397fb73b 100644 (file)
@@ -2176,9 +2176,15 @@ static int icase_exists(struct unpack_trees_options *o, const char *name, int le
        return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 }
 
+enum absent_checking_type {
+       COMPLETELY_ABSENT,
+       ABSENT_ANY_DIRECTORY
+};
+
 static int check_ok_to_remove(const char *name, int len, int dtype,
                              const struct cache_entry *ce, struct stat *st,
                              enum unpack_trees_error_types error_type,
+                             enum absent_checking_type absent_type,
                              struct unpack_trees_options *o)
 {
        const struct cache_entry *result;
@@ -2213,6 +2219,10 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
                return 0;
        }
 
+       /* If we only care about directories, then we can remove */
+       if (absent_type == ABSENT_ANY_DIRECTORY)
+               return 0;
+
        /*
         * The previous round may already have decided to
         * delete this path, which is in a subdirectory that
@@ -2233,6 +2243,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
  */
 static int verify_absent_1(const struct cache_entry *ce,
                           enum unpack_trees_error_types error_type,
+                          enum absent_checking_type absent_type,
                           struct unpack_trees_options *o)
 {
        int len;
@@ -2259,7 +2270,8 @@ static int verify_absent_1(const struct cache_entry *ce,
                                                                NULL, o);
                        else
                                ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL,
-                                                        &st, error_type, o);
+                                                        &st, error_type,
+                                                        absent_type, o);
                }
                free(path);
                return ret;
@@ -2274,7 +2286,7 @@ static int verify_absent_1(const struct cache_entry *ce,
 
                return check_ok_to_remove(ce->name, ce_namelen(ce),
                                          ce_to_dtype(ce), ce, &st,
-                                         error_type, o);
+                                         error_type, absent_type, o);
        }
 }
 
@@ -2284,14 +2296,23 @@ static int verify_absent(const struct cache_entry *ce,
 {
        if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
                return 0;
-       return verify_absent_1(ce, error_type, o);
+       return verify_absent_1(ce, error_type, COMPLETELY_ABSENT, o);
+}
+
+static int verify_absent_if_directory(const struct cache_entry *ce,
+                                     enum unpack_trees_error_types error_type,
+                                     struct unpack_trees_options *o)
+{
+       if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
+               return 0;
+       return verify_absent_1(ce, error_type, ABSENT_ANY_DIRECTORY, o);
 }
 
 static int verify_absent_sparse(const struct cache_entry *ce,
                                enum unpack_trees_error_types error_type,
                                struct unpack_trees_options *o)
 {
-       return verify_absent_1(ce, error_type, o);
+       return verify_absent_1(ce, error_type, COMPLETELY_ABSENT, o);
 }
 
 static int merged_entry(const struct cache_entry *ce,
@@ -2365,6 +2386,12 @@ static int merged_entry(const struct cache_entry *ce,
                 * Previously unmerged entry left as an existence
                 * marker by read_index_unmerged();
                 */
+               if (verify_absent_if_directory(merge,
+                                 ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
+                       discard_cache_entry(merge);
+                       return -1;
+               }
+
                invalidate_ce_path(old, o);
        }