]> git.ipfire.org Git - thirdparty/git.git/blobdiff - unpack-trees.c
t1405: check for_each_reflog_ent_reverse() more thoroughly
[thirdparty/git.git] / unpack-trees.c
index 8ea0a542da8d9f92efcb30964bc8b14c534f834f..89ca95ce90b369bc521fc52fc9b071c467a74022 100644 (file)
@@ -1694,9 +1694,15 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        static struct cache_entry *dfc;
        struct pattern_list pl;
        int free_pattern_list = 0;
+       struct dir_struct dir = DIR_INIT;
+
+       if (o->reset == UNPACK_RESET_INVALID)
+               BUG("o->reset had a value of 1; should be UNPACK_TREES_*_UNTRACKED");
 
        if (len > MAX_UNPACK_TREES)
                die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
+       if (o->dir)
+               BUG("o->dir is for internal use only");
 
        trace_performance_enter();
        trace2_region_enter("unpack_trees", "unpack_trees", the_repository);
@@ -1707,6 +1713,16 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                ensure_full_index(o->dst_index);
        }
 
+       if (o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED &&
+           o->preserve_ignored)
+               BUG("UNPACK_RESET_OVERWRITE_UNTRACKED incompatible with preserved ignored files");
+
+       if (!o->preserve_ignored) {
+               o->dir = &dir;
+               o->dir->flags |= DIR_SHOW_IGNORED;
+               setup_standard_excludes(o->dir);
+       }
+
        if (!core_apply_sparse_checkout || !o->update)
                o->skip_sparse_checkout = 1;
        if (!o->skip_sparse_checkout && !o->pl) {
@@ -1868,6 +1884,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 done:
        if (free_pattern_list)
                clear_pattern_list(&pl);
+       if (o->dir) {
+               dir_clear(o->dir);
+               o->dir = NULL;
+       }
        trace2_region_leave("unpack_trees", "unpack_trees", the_repository);
        trace_performance_leave("unpack_trees");
        return ret;
@@ -2136,9 +2156,10 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
        if (o->dir)
                d.exclude_per_dir = o->dir->exclude_per_dir;
        i = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);
+       dir_clear(&d);
+       free(pathbuf);
        if (i)
                return add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
-       free(pathbuf);
        return cnt;
 }
 
@@ -2158,9 +2179,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;
@@ -2195,6 +2222,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
@@ -2215,12 +2246,14 @@ 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;
        struct stat st;
 
-       if (o->index_only || o->reset || !o->update)
+       if (o->index_only || !o->update ||
+           o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED)
                return 0;
 
        len = check_leading_path(ce->name, ce_namelen(ce), 0);
@@ -2240,7 +2273,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;
@@ -2255,7 +2289,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);
        }
 }
 
@@ -2265,14 +2299,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,
@@ -2346,6 +2389,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);
        }
 
@@ -2363,7 +2412,10 @@ static int deleted_entry(const struct cache_entry *ce,
                if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
                        return -1;
                return 0;
+       } else if (verify_absent_if_directory(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o)) {
+               return -1;
        }
+
        if (!(old->ce_flags & CE_CONFLICTED) && verify_uptodate(old, o))
                return -1;
        add_entry(o, ce, CE_REMOVE, 0);