]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'vd/sparse-sparsity-fix-on-read'
authorJunio C Hamano <gitster@pobox.com>
Fri, 10 Dec 2021 22:35:01 +0000 (14:35 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 10 Dec 2021 22:35:01 +0000 (14:35 -0800)
Ensure that the sparseness of the in-core index matches the
index.sparse configuration specified by the repository immediately
after the on-disk index file is read.

* vd/sparse-sparsity-fix-on-read:
  sparse-index: update do_read_index to ensure correct sparsity
  sparse-index: add ensure_correct_sparsity function
  sparse-index: avoid unnecessary cache tree clearing
  test-read-cache.c: prepare_repo_settings after config init

1  2 
read-cache.c
t/t1092-sparse-checkout-compatibility.sh

diff --combined read-cache.c
index f398659662325d728c2cfe8efc95acf781e5d049,b3772ba70a13664c36b024b7acb51aaaf4d88c8f..d999fff9e46fc1ab2d0f6a2c6f6c002662e1251b
@@@ -738,7 -738,7 +738,7 @@@ int add_to_index(struct index_state *is
        int intent_only = flags & ADD_CACHE_INTENT;
        int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
                          (intent_only ? ADD_CACHE_NEW_ONLY : 0));
 -      int hash_flags = HASH_WRITE_OBJECT;
 +      unsigned hash_flags = pretend ? 0 : HASH_WRITE_OBJECT;
        struct object_id oid;
  
        if (flags & ADD_CACHE_RENORMALIZE)
@@@ -849,19 -849,6 +849,19 @@@ struct cache_entry *make_empty_transien
        return xcalloc(1, cache_entry_size(len));
  }
  
 +enum verify_path_result {
 +      PATH_OK,
 +      PATH_INVALID,
 +      PATH_DIR_WITH_SEP,
 +};
 +
 +static enum verify_path_result verify_path_internal(const char *, unsigned);
 +
 +int verify_path(const char *path, unsigned mode)
 +{
 +      return verify_path_internal(path, mode) == PATH_OK;
 +}
 +
  struct cache_entry *make_cache_entry(struct index_state *istate,
                                     unsigned int mode,
                                     const struct object_id *oid,
        struct cache_entry *ce, *ret;
        int len;
  
 -      if (!verify_path(path, mode)) {
 +      if (verify_path_internal(path, mode) == PATH_INVALID) {
                error(_("invalid path '%s'"), path);
                return NULL;
        }
@@@ -1006,62 -993,60 +1006,62 @@@ static int verify_dotfile(const char *r
        return 1;
  }
  
 -int verify_path(const char *path, unsigned mode)
 +static enum verify_path_result verify_path_internal(const char *path,
 +                                                  unsigned mode)
  {
        char c = 0;
  
        if (has_dos_drive_prefix(path))
 -              return 0;
 +              return PATH_INVALID;
  
        if (!is_valid_path(path))
 -              return 0;
 +              return PATH_INVALID;
  
        goto inside;
        for (;;) {
                if (!c)
 -                      return 1;
 +                      return PATH_OK;
                if (is_dir_sep(c)) {
  inside:
                        if (protect_hfs) {
  
                                if (is_hfs_dotgit(path))
 -                                      return 0;
 +                                      return PATH_INVALID;
                                if (S_ISLNK(mode)) {
                                        if (is_hfs_dotgitmodules(path))
 -                                              return 0;
 +                                              return PATH_INVALID;
                                }
                        }
                        if (protect_ntfs) {
  #if defined GIT_WINDOWS_NATIVE || defined __CYGWIN__
                                if (c == '\\')
 -                                      return 0;
 +                                      return PATH_INVALID;
  #endif
                                if (is_ntfs_dotgit(path))
 -                                      return 0;
 +                                      return PATH_INVALID;
                                if (S_ISLNK(mode)) {
                                        if (is_ntfs_dotgitmodules(path))
 -                                              return 0;
 +                                              return PATH_INVALID;
                                }
                        }
  
                        c = *path++;
                        if ((c == '.' && !verify_dotfile(path, mode)) ||
                            is_dir_sep(c))
 -                              return 0;
 +                              return PATH_INVALID;
                        /*
                         * allow terminating directory separators for
                         * sparse directory entries.
                         */
                        if (c == '\0')
 -                              return S_ISDIR(mode);
 +                              return S_ISDIR(mode) ? PATH_DIR_WITH_SEP :
 +                                                     PATH_INVALID;
                } else if (c == '\\' && protect_ntfs) {
                        if (is_ntfs_dotgit(path))
 -                              return 0;
 +                              return PATH_INVALID;
                        if (S_ISLNK(mode)) {
                                if (is_ntfs_dotgitmodules(path))
 -                                      return 0;
 +                                      return PATH_INVALID;
                        }
                }
  
@@@ -1364,7 -1349,7 +1364,7 @@@ static int add_index_entry_with_check(s
  
        if (!ok_to_add)
                return -1;
 -      if (!verify_path(ce->name, ce->ce_mode))
 +      if (verify_path_internal(ce->name, ce->ce_mode) == PATH_INVALID)
                return error(_("invalid path '%s'"), ce->name);
  
        if (!skip_df_check &&
@@@ -2352,9 -2337,17 +2352,17 @@@ int do_read_index(struct index_state *i
  
        if (!istate->repo)
                istate->repo = the_repository;
+       /*
+        * If the command explicitly requires a full index, force it
+        * to be full. Otherwise, correct the sparsity based on repository
+        * settings and other properties of the index (if necessary).
+        */
        prepare_repo_settings(istate->repo);
        if (istate->repo->settings.command_requires_full_index)
                ensure_full_index(istate);
+       else
+               ensure_correct_sparsity(istate);
  
        return istate->cache_nr;
  
index 16fbd2c6db9db18456b6a02d443b2b518aafc9e0,59accde1fa3d2ed4f5e858223fb01f94adaeee6e..4eaac6a99b3b44e3ebc94e5ed083245f4d3cfd8f
@@@ -514,7 -514,7 +514,7 @@@ test_expect_success 'checkout and rese
  test_expect_success 'merge, cherry-pick, and rebase' '
        init_repos &&
  
 -      for OPERATION in "merge -m merge" cherry-pick rebase
 +      for OPERATION in "merge -m merge" cherry-pick "rebase --apply" "rebase --merge"
        do
                test_all_match git checkout -B temp update-deep &&
                test_all_match git $OPERATION update-folder1 &&
@@@ -694,6 -694,37 +694,37 @@@ test_expect_success 'sparse-index is ex
        test_region index ensure_full_index trace2.txt
  '
  
+ test_expect_success 'index.sparse disabled inline uses full index' '
+       init_repos &&
+       # When index.sparse is disabled inline with `git status`, the
+       # index is expanded at the beginning of the execution then never
+       # converted back to sparse. It is then written to disk as a full index.
+       rm -f trace2.txt &&
+       GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+               git -C sparse-index -c index.sparse=false status &&
+       ! test_region index convert_to_sparse trace2.txt &&
+       test_region index ensure_full_index trace2.txt &&
+       # Since index.sparse is set to true at a repo level, the index
+       # is converted from full to sparse when read, then never expanded
+       # over the course of `git status`. It is written to disk as a sparse
+       # index.
+       rm -f trace2.txt &&
+       GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+               git -C sparse-index status &&
+       test_region index convert_to_sparse trace2.txt &&
+       ! test_region index ensure_full_index trace2.txt &&
+       # Now that the index has been written to disk as sparse, it is not
+       # converted to sparse (or expanded to full) when read by `git status`.
+       rm -f trace2.txt &&
+       GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+               git -C sparse-index status &&
+       ! test_region index convert_to_sparse trace2.txt &&
+       ! test_region index ensure_full_index trace2.txt
+ '
  ensure_not_expanded () {
        rm -f trace2.txt &&
        echo >>sparse-index/untracked.txt &&