]> 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 f07304f1b714cfb5cbd4eb8c9b2bc5255807514e..89ca95ce90b369bc521fc52fc9b071c467a74022 100644 (file)
@@ -111,17 +111,17 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
        strvec_init(&opts->msgs_to_free);
 
        if (!strcmp(cmd, "checkout"))
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("Your local changes to the following files would be overwritten by checkout:\n%%s"
                          "Please commit your changes or stash them before you switch branches.")
                      : _("Your local changes to the following files would be overwritten by checkout:\n%%s");
        else if (!strcmp(cmd, "merge"))
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("Your local changes to the following files would be overwritten by merge:\n%%s"
                          "Please commit your changes or stash them before you merge.")
                      : _("Your local changes to the following files would be overwritten by merge:\n%%s");
        else
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("Your local changes to the following files would be overwritten by %s:\n%%s"
                          "Please commit your changes or stash them before you %s.")
                      : _("Your local changes to the following files would be overwritten by %s:\n%%s");
@@ -132,17 +132,17 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                _("Updating the following directories would lose untracked files in them:\n%s");
 
        if (!strcmp(cmd, "checkout"))
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("The following untracked working tree files would be removed by checkout:\n%%s"
                          "Please move or remove them before you switch branches.")
                      : _("The following untracked working tree files would be removed by checkout:\n%%s");
        else if (!strcmp(cmd, "merge"))
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("The following untracked working tree files would be removed by merge:\n%%s"
                          "Please move or remove them before you merge.")
                      : _("The following untracked working tree files would be removed by merge:\n%%s");
        else
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("The following untracked working tree files would be removed by %s:\n%%s"
                          "Please move or remove them before you %s.")
                      : _("The following untracked working tree files would be removed by %s:\n%%s");
@@ -150,17 +150,17 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
 
        if (!strcmp(cmd, "checkout"))
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("The following untracked working tree files would be overwritten by checkout:\n%%s"
                          "Please move or remove them before you switch branches.")
                      : _("The following untracked working tree files would be overwritten by checkout:\n%%s");
        else if (!strcmp(cmd, "merge"))
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("The following untracked working tree files would be overwritten by merge:\n%%s"
                          "Please move or remove them before you merge.")
                      : _("The following untracked working tree files would be overwritten by merge:\n%%s");
        else
-               msg = advice_commit_before_merge
+               msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
                      ? _("The following untracked working tree files would be overwritten by %s:\n%%s"
                          "Please move or remove them before you %s.")
                      : _("The following untracked working tree files would be overwritten by %s:\n%%s");
@@ -1255,7 +1255,7 @@ static int sparse_dir_matches_path(const struct cache_entry *ce,
 static struct cache_entry *find_cache_entry(struct traverse_info *info,
                                            const struct name_entry *p)
 {
-       struct cache_entry *ce;
+       const char *path;
        int pos = find_cache_pos(info, p->path, p->pathlen);
        struct unpack_trees_options *o = info->data;
 
@@ -1281,9 +1281,11 @@ static struct cache_entry *find_cache_entry(struct traverse_info *info,
         * paths (e.g. "subdir-").
         */
        while (pos >= 0) {
-               ce = o->src_index->cache[pos];
+               struct cache_entry *ce = o->src_index->cache[pos];
 
-               if (strncmp(ce->name, p->path, p->pathlen))
+               if (!skip_prefix(ce->name, info->traverse_path, &path) ||
+                   strncmp(path, p->path, p->pathlen) ||
+                   path[p->pathlen] != '/')
                        return NULL;
 
                if (S_ISSPARSEDIR(ce->ce_mode) &&
@@ -1692,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);
@@ -1705,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) {
@@ -1866,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;
@@ -2134,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;
 }
 
@@ -2156,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;
@@ -2193,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
@@ -2213,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);
@@ -2238,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;
@@ -2253,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);
        }
 }
 
@@ -2263,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,
@@ -2344,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);
        }
 
@@ -2361,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);