Merge branch 'en/present-despite-skipped'
In sparse-checkouts, files mis-marked as missing from the working tree could lead to later problems. Such files were hard to discover, and harder to correct. Automatically detecting and correcting the marking of such files has been added to avoid these problems. * en/present-despite-skipped: repo_read_index: add config to expect files outside sparse patterns Accelerate clear_skip_worktree_from_present_files() by caching Update documentation related to sparsity and the skip-worktree bit repo_read_index: clear SKIP_WORKTREE bit from files present in worktree unpack-trees: fix accidental loss of user changes t1011: add testcase demonstrating accidental loss of user modifications
This commit is contained in:
commit
82386b4496
@ -503,6 +503,8 @@ include::config/sequencer.txt[]
|
||||
|
||||
include::config/showbranch.txt[]
|
||||
|
||||
include::config/sparse.txt[]
|
||||
|
||||
include::config/splitindex.txt[]
|
||||
|
||||
include::config/ssh.txt[]
|
||||
|
27
Documentation/config/sparse.txt
Normal file
27
Documentation/config/sparse.txt
Normal file
@ -0,0 +1,27 @@
|
||||
sparse.expectFilesOutsideOfPatterns::
|
||||
Typically with sparse checkouts, files not matching any
|
||||
sparsity patterns are marked with a SKIP_WORKTREE bit in the
|
||||
index and are missing from the working tree. Accordingly, Git
|
||||
will ordinarily check whether files with the SKIP_WORKTREE bit
|
||||
are in fact present in the working tree contrary to
|
||||
expectations. If Git finds any, it marks those paths as
|
||||
present by clearing the relevant SKIP_WORKTREE bits. This
|
||||
option can be used to tell Git that such
|
||||
present-despite-skipped files are expected and to stop
|
||||
checking for them.
|
||||
+
|
||||
The default is `false`, which allows Git to automatically recover
|
||||
from the list of files in the index and working tree falling out of
|
||||
sync.
|
||||
+
|
||||
Set this to `true` if you are in a setup where some external factor
|
||||
relieves Git of the responsibility for maintaining the consistency
|
||||
between the presence of working tree files and sparsity patterns. For
|
||||
example, if you have a Git-aware virtual file system that has a robust
|
||||
mechanism for keeping the working tree and the sparsity patterns up to
|
||||
date based on access patterns.
|
||||
+
|
||||
Regardless of this setting, Git does not check for
|
||||
present-despite-skipped files unless sparse checkout is enabled, so
|
||||
this config option has no effect unless `core.sparseCheckout` is
|
||||
`true`.
|
@ -375,9 +375,14 @@ have finished your work-in-progress), attempt the merge again.
|
||||
SPARSE CHECKOUT
|
||||
---------------
|
||||
|
||||
Note: The `update-index` and `read-tree` primitives for supporting the
|
||||
skip-worktree bit predated the introduction of
|
||||
linkgit:git-sparse-checkout[1]. Users are encouraged to use
|
||||
`sparse-checkout` in preference to these low-level primitives.
|
||||
|
||||
"Sparse checkout" allows populating the working directory sparsely.
|
||||
It uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell
|
||||
Git whether a file in the working directory is worth looking at.
|
||||
It uses the skip-worktree bit (see linkgit:git-update-index[1]) to
|
||||
tell Git whether a file in the working directory is worth looking at.
|
||||
|
||||
'git read-tree' and other merge-based commands ('git merge', 'git
|
||||
checkout'...) can help maintaining the skip-worktree bitmap and working
|
||||
@ -385,7 +390,8 @@ directory update. `$GIT_DIR/info/sparse-checkout` is used to
|
||||
define the skip-worktree reference bitmap. When 'git read-tree' needs
|
||||
to update the working directory, it resets the skip-worktree bit in the index
|
||||
based on this file, which uses the same syntax as .gitignore files.
|
||||
If an entry matches a pattern in this file, skip-worktree will not be
|
||||
If an entry matches a pattern in this file, or the entry corresponds to
|
||||
a file present in the working tree, then skip-worktree will not be
|
||||
set on that entry. Otherwise, skip-worktree will be set.
|
||||
|
||||
Then it compares the new skip-worktree value with the previous one. If
|
||||
|
@ -3,9 +3,7 @@ git-sparse-checkout(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-sparse-checkout - Initialize and modify the sparse-checkout
|
||||
configuration, which reduces the checkout to a set of paths
|
||||
given by a list of patterns.
|
||||
git-sparse-checkout - Reduce your working tree to a subset of tracked files
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
@ -17,8 +15,20 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Initialize and modify the sparse-checkout configuration, which reduces
|
||||
the checkout to a set of paths given by a list of patterns.
|
||||
This command is used to create sparse checkouts, which means that it
|
||||
changes the working tree from having all tracked files present, to only
|
||||
have a subset of them. It can also switch which subset of files are
|
||||
present, or undo and go back to having all tracked files present in the
|
||||
working copy.
|
||||
|
||||
The subset of files is chosen by providing a list of directories in
|
||||
cone mode (which is recommended), or by providing a list of patterns
|
||||
in non-cone mode.
|
||||
|
||||
When in a sparse-checkout, other Git commands behave a bit differently.
|
||||
For example, switching branches will not update paths outside the
|
||||
sparse-checkout directories/patterns, and `git commit -a` will not record
|
||||
paths outside the sparse-checkout directories/patterns as deleted.
|
||||
|
||||
THIS COMMAND IS EXPERIMENTAL. ITS BEHAVIOR, AND THE BEHAVIOR OF OTHER
|
||||
COMMANDS IN THE PRESENCE OF SPARSE-CHECKOUTS, WILL LIKELY CHANGE IN
|
||||
@ -28,7 +38,7 @@ THE FUTURE.
|
||||
COMMANDS
|
||||
--------
|
||||
'list'::
|
||||
Describe the patterns in the sparse-checkout file.
|
||||
Describe the directories or patterns in the sparse-checkout file.
|
||||
|
||||
'set'::
|
||||
Enable the necessary sparse-checkout config settings
|
||||
@ -46,20 +56,26 @@ the 'set' subcommand are stored in the worktree-specific sparse-checkout
|
||||
file. See linkgit:git-worktree[1] and the documentation of
|
||||
`extensions.worktreeConfig` in linkgit:git-config[1] for more details.
|
||||
+
|
||||
When the `--stdin` option is provided, the patterns are read from
|
||||
standard in as a newline-delimited list instead of from the arguments.
|
||||
When the `--stdin` option is provided, the directories or patterns are
|
||||
read from standard in as a newline-delimited list instead of from the
|
||||
arguments.
|
||||
+
|
||||
When `--cone` is passed or `core.sparseCheckoutCone` is enabled, the
|
||||
input list is considered a list of directories instead of
|
||||
sparse-checkout patterns. This allows for better performance with a
|
||||
limited set of patterns (see 'CONE PATTERN SET' below). Note that the
|
||||
set command will write patterns to the sparse-checkout file to include
|
||||
all files contained in those directories (recursively) as well as
|
||||
files that are siblings of ancestor directories. The input format
|
||||
matches the output of `git ls-tree --name-only`. This includes
|
||||
interpreting pathnames that begin with a double quote (") as C-style
|
||||
quoted strings. This may become the default in the future; --no-cone
|
||||
can be passed to request non-cone mode.
|
||||
input list is considered a list of directories. This allows for
|
||||
better performance with a limited set of patterns (see 'CONE PATTERN
|
||||
SET' below). The input format matches the output of `git ls-tree
|
||||
--name-only`. This includes interpreting pathnames that begin with a
|
||||
double quote (") as C-style quoted strings. Note that the set command
|
||||
will write patterns to the sparse-checkout file to include all files
|
||||
contained in those directories (recursively) as well as files that are
|
||||
siblings of ancestor directories. This may become the default in the
|
||||
future; --no-cone can be passed to request non-cone mode.
|
||||
+
|
||||
When `--no-cone` is passed or `core.sparseCheckoutCone` is not enabled,
|
||||
the input list is considered a list of patterns. This mode is harder
|
||||
to use and less performant, and is thus not recommended. See the
|
||||
"Sparse Checkout" section of linkgit:git-read-tree[1] and the "Pattern
|
||||
Set" sections below for more details.
|
||||
+
|
||||
Use the `--[no-]sparse-index` option to use a sparse index (the
|
||||
default is to not use it). A sparse index reduces the size of the
|
||||
@ -77,11 +93,10 @@ understand the sparse directory entries index extension and may fail to
|
||||
interact with your repository until it is disabled.
|
||||
|
||||
'add'::
|
||||
Update the sparse-checkout file to include additional patterns.
|
||||
By default, these patterns are read from the command-line arguments,
|
||||
but they can be read from stdin using the `--stdin` option. When
|
||||
`core.sparseCheckoutCone` is enabled, the given patterns are interpreted
|
||||
as directory names as in the 'set' subcommand.
|
||||
Update the sparse-checkout file to include additional directories
|
||||
(in cone mode) or patterns (in non-cone mode). By default, these
|
||||
directories or patterns are read from the command-line arguments,
|
||||
but they can be read from stdin using the `--stdin` option.
|
||||
|
||||
'reapply'::
|
||||
Reapply the sparsity pattern rules to paths in the working tree.
|
||||
@ -125,13 +140,14 @@ decreased in utility.
|
||||
SPARSE CHECKOUT
|
||||
---------------
|
||||
|
||||
"Sparse checkout" allows populating the working directory sparsely.
|
||||
It uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell
|
||||
Git whether a file in the working directory is worth looking at. If
|
||||
the skip-worktree bit is set, then the file is ignored in the working
|
||||
directory. Git will avoid populating the contents of those files, which
|
||||
makes a sparse checkout helpful when working in a repository with many
|
||||
files, but only a few are important to the current user.
|
||||
"Sparse checkout" allows populating the working directory sparsely. It
|
||||
uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell Git
|
||||
whether a file in the working directory is worth looking at. If the
|
||||
skip-worktree bit is set, and the file is not present in the working tree,
|
||||
then its absence is ignored. Git will avoid populating the contents of
|
||||
those files, which makes a sparse checkout helpful when working in a
|
||||
repository with many files, but only a few are important to the current
|
||||
user.
|
||||
|
||||
The `$GIT_DIR/info/sparse-checkout` file is used to define the
|
||||
skip-worktree reference bitmap. When Git updates the working
|
||||
|
@ -351,6 +351,10 @@ unchanged". Note that "assume unchanged" bit is *not* set if
|
||||
the index (use `git update-index --really-refresh` if you want
|
||||
to mark them as "assume unchanged").
|
||||
|
||||
Sometimes users confuse the assume-unchanged bit with the
|
||||
skip-worktree bit. See the final paragraph in the "Skip-worktree bit"
|
||||
section below for an explanation of the differences.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
@ -392,22 +396,47 @@ M foo.c
|
||||
SKIP-WORKTREE BIT
|
||||
-----------------
|
||||
|
||||
Skip-worktree bit can be defined in one (long) sentence: When reading
|
||||
an entry, if it is marked as skip-worktree, then Git pretends its
|
||||
working directory version is up to date and read the index version
|
||||
instead.
|
||||
Skip-worktree bit can be defined in one (long) sentence: Tell git to
|
||||
avoid writing the file to the working directory when reasonably
|
||||
possible, and treat the file as unchanged when it is not
|
||||
present in the working directory.
|
||||
|
||||
To elaborate, "reading" means checking for file existence, reading
|
||||
file attributes or file content. The working directory version may be
|
||||
present or absent. If present, its content may match against the index
|
||||
version or not. Writing is not affected by this bit, content safety
|
||||
is still first priority. Note that Git _can_ update working directory
|
||||
file, that is marked skip-worktree, if it is safe to do so (i.e.
|
||||
working directory version matches index version)
|
||||
Note that not all git commands will pay attention to this bit, and
|
||||
some only partially support it.
|
||||
|
||||
The update-index flags and the read-tree capabilities relating to the
|
||||
skip-worktree bit predated the introduction of the
|
||||
linkgit:git-sparse-checkout[1] command, which provides a much easier
|
||||
way to configure and handle the skip-worktree bits. If you want to
|
||||
reduce your working tree to only deal with a subset of the files in
|
||||
the repository, we strongly encourage the use of
|
||||
linkgit:git-sparse-checkout[1] in preference to the low-level
|
||||
update-index and read-tree primitives.
|
||||
|
||||
The primary purpose of the skip-worktree bit is to enable sparse
|
||||
checkouts, i.e. to have working directories with only a subset of
|
||||
paths present. When the skip-worktree bit is set, Git commands (such
|
||||
as `switch`, `pull`, `merge`) will avoid writing these files.
|
||||
However, these commands will sometimes write these files anyway in
|
||||
important cases such as conflicts during a merge or rebase. Git
|
||||
commands will also avoid treating the lack of such files as an
|
||||
intentional deletion; for example `git add -u` will not not stage a
|
||||
deletion for these files and `git commit -a` will not make a commit
|
||||
deleting them either.
|
||||
|
||||
Although this bit looks similar to assume-unchanged bit, its goal is
|
||||
different from assume-unchanged bit's. Skip-worktree also takes
|
||||
precedence over assume-unchanged bit when both are set.
|
||||
different. The assume-unchanged bit is for leaving the file in the
|
||||
working tree but having Git omit checking it for changes and presuming
|
||||
that the file has not been changed (though if it can determine without
|
||||
stat'ing the file that it has changed, it is free to record the
|
||||
changes). skip-worktree tells Git to ignore the absence of the file,
|
||||
avoid updating it when possible with commands that normally update
|
||||
much of the working directory (e.g. `checkout`, `switch`, `pull`,
|
||||
etc.), and not have its absence be recorded in commits. Note that in
|
||||
sparse checkouts (setup by `git sparse-checkout` or by configuring
|
||||
core.sparseCheckout to true), if a file is marked as skip-worktree in
|
||||
the index but is found in the working tree, Git will clear the
|
||||
skip-worktree bit for that file.
|
||||
|
||||
SPLIT INDEX
|
||||
-----------
|
||||
|
1
cache.h
1
cache.h
@ -1003,6 +1003,7 @@ extern const char *core_fsmonitor;
|
||||
|
||||
extern int core_apply_sparse_checkout;
|
||||
extern int core_sparse_checkout_cone;
|
||||
extern int sparse_expect_files_outside_of_patterns;
|
||||
|
||||
/*
|
||||
* Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
|
||||
|
14
config.c
14
config.c
@ -1654,6 +1654,17 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
|
||||
return platform_core_config(var, value, cb);
|
||||
}
|
||||
|
||||
static int git_default_sparse_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) {
|
||||
sparse_expect_files_outside_of_patterns = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config/sparse.txt. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int git_default_i18n_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "i18n.commitencoding"))
|
||||
@ -1785,6 +1796,9 @@ int git_default_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (starts_with(var, "sparse."))
|
||||
return git_default_sparse_config(var, value);
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ char *notes_ref_name;
|
||||
int grafts_replace_parents = 1;
|
||||
int core_apply_sparse_checkout;
|
||||
int core_sparse_checkout_cone;
|
||||
int sparse_expect_files_outside_of_patterns;
|
||||
int merge_log_config = -1;
|
||||
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
|
||||
unsigned long pack_size_limit_cfg;
|
||||
|
@ -301,6 +301,13 @@ int repo_read_index(struct repository *repo)
|
||||
if (repo->settings.command_requires_full_index)
|
||||
ensure_full_index(repo->index);
|
||||
|
||||
/*
|
||||
* If sparse checkouts are in use, check whether paths with the
|
||||
* SKIP_WORKTREE attribute are missing from the worktree; if not,
|
||||
* clear that attribute for that path.
|
||||
*/
|
||||
clear_skip_worktree_from_present_files(repo->index);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -337,6 +337,80 @@ void ensure_correct_sparsity(struct index_state *istate)
|
||||
ensure_full_index(istate);
|
||||
}
|
||||
|
||||
static int path_found(const char *path, const char **dirname, size_t *dir_len,
|
||||
int *dir_found)
|
||||
{
|
||||
struct stat st;
|
||||
char *newdir;
|
||||
char *tmp;
|
||||
|
||||
/*
|
||||
* If dirname corresponds to a directory that doesn't exist, and this
|
||||
* path starts with dirname, then path can't exist.
|
||||
*/
|
||||
if (!*dir_found && !memcmp(path, *dirname, *dir_len))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If path itself exists, return 1.
|
||||
*/
|
||||
if (!lstat(path, &st))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Otherwise, path does not exist so we'll return 0...but we'll first
|
||||
* determine some info about its parent directory so we can avoid
|
||||
* lstat calls for future cache entries.
|
||||
*/
|
||||
newdir = strrchr(path, '/');
|
||||
if (!newdir)
|
||||
return 0; /* Didn't find a parent dir; just return 0 now. */
|
||||
|
||||
/*
|
||||
* If path starts with directory (which we already lstat'ed and found),
|
||||
* then no need to lstat parent directory again.
|
||||
*/
|
||||
if (*dir_found && *dirname && memcmp(path, *dirname, *dir_len))
|
||||
return 0;
|
||||
|
||||
/* Free previous dirname, and cache path's dirname */
|
||||
*dirname = path;
|
||||
*dir_len = newdir - path + 1;
|
||||
|
||||
tmp = xstrndup(path, *dir_len);
|
||||
*dir_found = !lstat(tmp, &st);
|
||||
free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear_skip_worktree_from_present_files(struct index_state *istate)
|
||||
{
|
||||
const char *last_dirname = NULL;
|
||||
size_t dir_len = 0;
|
||||
int dir_found = 1;
|
||||
|
||||
int i;
|
||||
|
||||
if (!core_apply_sparse_checkout ||
|
||||
sparse_expect_files_outside_of_patterns)
|
||||
return;
|
||||
|
||||
restart:
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct cache_entry *ce = istate->cache[i];
|
||||
|
||||
if (ce_skip_worktree(ce) &&
|
||||
path_found(ce->name, &last_dirname, &dir_len, &dir_found)) {
|
||||
if (S_ISSPARSEDIR(ce->ce_mode)) {
|
||||
ensure_full_index(istate);
|
||||
goto restart;
|
||||
}
|
||||
ce->ce_flags &= ~CE_SKIP_WORKTREE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This static global helps avoid infinite recursion between
|
||||
* expand_to_path() and index_file_exists().
|
||||
|
@ -5,6 +5,7 @@ struct index_state;
|
||||
#define SPARSE_INDEX_MEMORY_ONLY (1 << 0)
|
||||
int convert_to_sparse(struct index_state *istate, int flags);
|
||||
void ensure_correct_sparsity(struct index_state *istate);
|
||||
void clear_skip_worktree_from_present_files(struct index_state *istate);
|
||||
|
||||
/*
|
||||
* Some places in the codebase expect to search for a specific path.
|
||||
|
@ -187,11 +187,32 @@ test_expect_success 'read-tree updates worktree, absent case' '
|
||||
test ! -f init.t
|
||||
'
|
||||
|
||||
test_expect_success 'read-tree will not throw away dirty changes, non-sparse' '
|
||||
echo "/*" >.git/info/sparse-checkout &&
|
||||
read_tree_u_must_succeed -m -u HEAD &&
|
||||
|
||||
echo dirty >init.t &&
|
||||
read_tree_u_must_fail -m -u HEAD^ &&
|
||||
test_path_is_file init.t &&
|
||||
grep -q dirty init.t
|
||||
'
|
||||
|
||||
test_expect_success 'read-tree will not throw away dirty changes, sparse' '
|
||||
echo "/*" >.git/info/sparse-checkout &&
|
||||
read_tree_u_must_succeed -m -u HEAD &&
|
||||
|
||||
echo dirty >init.t &&
|
||||
echo sub/added >.git/info/sparse-checkout &&
|
||||
read_tree_u_must_fail -m -u HEAD^ &&
|
||||
test_path_is_file init.t &&
|
||||
grep -q dirty init.t
|
||||
'
|
||||
|
||||
test_expect_success 'read-tree updates worktree, dirty case' '
|
||||
echo sub/added >.git/info/sparse-checkout &&
|
||||
git checkout -f top &&
|
||||
echo dirty >init.t &&
|
||||
read_tree_u_must_succeed -m -u HEAD^ &&
|
||||
read_tree_u_must_fail -m -u HEAD^ &&
|
||||
grep -q dirty init.t &&
|
||||
rm init.t
|
||||
'
|
||||
|
@ -52,6 +52,25 @@ test_expect_success 'return to full checkout of main' '
|
||||
test "$(cat b)" = "modified"
|
||||
'
|
||||
|
||||
test_expect_success 'skip-worktree on files outside sparse patterns' '
|
||||
git sparse-checkout disable &&
|
||||
git sparse-checkout set --no-cone "a*" &&
|
||||
git checkout-index --all --ignore-skip-worktree-bits &&
|
||||
|
||||
git ls-files -t >output &&
|
||||
! grep ^S output >actual &&
|
||||
test_must_be_empty actual &&
|
||||
|
||||
test_config sparse.expectFilesOutsideOfPatterns true &&
|
||||
cat <<-\EOF >expect &&
|
||||
S b
|
||||
S c
|
||||
EOF
|
||||
git ls-files -t >output &&
|
||||
grep ^S output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'in partial clone, sparse checkout only fetches needed blobs' '
|
||||
test_create_repo server &&
|
||||
git clone "file://$(pwd)/server" client &&
|
||||
|
@ -367,7 +367,7 @@ test_expect_success 'status/add: outside sparse cone' '
|
||||
write_script edit-contents <<-\EOF &&
|
||||
echo text >>$1
|
||||
EOF
|
||||
run_on_sparse ../edit-contents folder1/a &&
|
||||
run_on_all ../edit-contents folder1/a &&
|
||||
run_on_all ../edit-contents folder1/new &&
|
||||
|
||||
test_sparse_match git status --porcelain=v2 &&
|
||||
@ -376,8 +376,8 @@ test_expect_success 'status/add: outside sparse cone' '
|
||||
test_sparse_match test_must_fail git add folder1/a &&
|
||||
grep "Disable or modify the sparsity rules" sparse-checkout-err &&
|
||||
test_sparse_unstaged folder1/a &&
|
||||
test_sparse_match test_must_fail git add --refresh folder1/a &&
|
||||
grep "Disable or modify the sparsity rules" sparse-checkout-err &&
|
||||
test_all_match git add --refresh folder1/a &&
|
||||
test_must_be_empty sparse-checkout-err &&
|
||||
test_sparse_unstaged folder1/a &&
|
||||
test_sparse_match test_must_fail git add folder1/new &&
|
||||
grep "Disable or modify the sparsity rules" sparse-checkout-err &&
|
||||
@ -643,11 +643,11 @@ test_expect_success 'update-index modify outside sparse definition' '
|
||||
run_on_sparse cp ../initial-repo/folder1/a folder1/a &&
|
||||
run_on_all ../edit-contents folder1/a &&
|
||||
|
||||
# If file has skip-worktree enabled, update-index does not modify the
|
||||
# index entry
|
||||
test_sparse_match git update-index folder1/a &&
|
||||
test_sparse_match git status --porcelain=v2 &&
|
||||
test_must_be_empty sparse-checkout-out &&
|
||||
# If file has skip-worktree enabled, but the file is present, it is
|
||||
# treated the same as if skip-worktree is disabled
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
test_all_match git update-index folder1/a &&
|
||||
test_all_match git status --porcelain=v2 &&
|
||||
|
||||
# When skip-worktree is disabled (even on files outside sparse cone), file
|
||||
# is updated in the index
|
||||
@ -1331,30 +1331,27 @@ test_expect_success 'ls-files' '
|
||||
test_cmp dense sparse &&
|
||||
|
||||
# Set up a strange condition of having a file edit
|
||||
# outside of the sparse-checkout cone. This is just
|
||||
# to verify that sparse-checkout and sparse-index
|
||||
# behave the same in this case.
|
||||
# outside of the sparse-checkout cone. We want to verify
|
||||
# that all modes handle this the same, and detect the
|
||||
# modification.
|
||||
write_script edit-content <<-\EOF &&
|
||||
mkdir folder1 &&
|
||||
mkdir -p folder1 &&
|
||||
echo content >>folder1/a
|
||||
EOF
|
||||
run_on_sparse ../edit-content &&
|
||||
run_on_all ../edit-content &&
|
||||
|
||||
# ls-files does not currently notice modified files whose
|
||||
# cache entries are marked SKIP_WORKTREE. This may change
|
||||
# in the future, but here we test that sparse index does
|
||||
# not accidentally create a change of behavior.
|
||||
test_sparse_match git ls-files --modified &&
|
||||
test_must_be_empty sparse-checkout-out &&
|
||||
test_must_be_empty sparse-index-out &&
|
||||
test_all_match git ls-files --modified &&
|
||||
|
||||
git -C sparse-index ls-files --sparse --modified >sparse-index-out &&
|
||||
test_must_be_empty sparse-index-out &&
|
||||
cat >expect <<-\EOF &&
|
||||
folder1/a
|
||||
EOF
|
||||
test_cmp expect sparse-index-out &&
|
||||
|
||||
# Add folder1 to the sparse-checkout cone and
|
||||
# check that ls-files shows the expanded files.
|
||||
test_sparse_match git sparse-checkout add folder1 &&
|
||||
test_sparse_match git ls-files --modified &&
|
||||
test_all_match git ls-files --modified &&
|
||||
|
||||
test_all_match git ls-files &&
|
||||
git -C sparse-index ls-files --sparse >actual &&
|
||||
|
@ -19,6 +19,7 @@ setup_sparse_entry () {
|
||||
fi &&
|
||||
git add sparse_entry &&
|
||||
git update-index --skip-worktree sparse_entry &&
|
||||
git config core.sparseCheckout false &&
|
||||
git commit --allow-empty -m "ensure sparse_entry exists at HEAD" &&
|
||||
SPARSE_ENTRY_BLOB=$(git rev-parse :sparse_entry)
|
||||
}
|
||||
@ -126,6 +127,7 @@ test_expect_success 'git add --chmod does not update sparse entries' '
|
||||
'
|
||||
|
||||
test_expect_success 'git add --renormalize does not update sparse entries' '
|
||||
test_when_finished rm .gitattributes &&
|
||||
test_config core.autocrlf false &&
|
||||
setup_sparse_entry "LINEONE\r\nLINETWO\r\n" &&
|
||||
echo "sparse_entry text=auto" >.gitattributes &&
|
||||
|
@ -112,7 +112,7 @@ test_expect_success 'conflicting entries written to worktree even if sparse' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_merge_algorithm failure success 'present-despite-SKIP_WORKTREE handled reasonably' '
|
||||
test_expect_success 'present-despite-SKIP_WORKTREE handled reasonably' '
|
||||
test_setup_numerals in_the_way &&
|
||||
(
|
||||
cd numerals_in_the_way &&
|
||||
@ -132,26 +132,13 @@ test_expect_merge_algorithm failure success 'present-despite-SKIP_WORKTREE handl
|
||||
|
||||
test_must_fail git merge -s recursive B^0 &&
|
||||
|
||||
git ls-files -t >index_files &&
|
||||
test_cmp expected-index index_files &&
|
||||
test_path_is_missing .git/MERGE_HEAD &&
|
||||
|
||||
test_path_is_file README &&
|
||||
test_path_is_file numerals &&
|
||||
|
||||
test_cmp expected-merge numerals &&
|
||||
|
||||
# There should still be a file with "foobar" in it
|
||||
grep foobar * &&
|
||||
|
||||
# 5 other files:
|
||||
# * expected-merge
|
||||
# * expected-index
|
||||
# * index_files
|
||||
# * others
|
||||
# * whatever name was given to the numerals file that had
|
||||
# "foobar" in it
|
||||
git ls-files -o >others &&
|
||||
test_line_count = 5 others
|
||||
# numerals should still have "foobar" in it
|
||||
echo foobar >expect &&
|
||||
test_cmp expect numerals
|
||||
)
|
||||
'
|
||||
|
||||
|
@ -171,50 +171,20 @@ test_expect_success 'stash restore in sparse checkout' '
|
||||
|
||||
# Put a file in the working directory in the way
|
||||
echo in the way >modified &&
|
||||
git stash apply &&
|
||||
test_must_fail git stash apply 2>error&&
|
||||
|
||||
# Ensure stash vivifies modifies paths...
|
||||
cat >expect <<-EOF &&
|
||||
H addme
|
||||
H modified
|
||||
H removeme
|
||||
H subdir/A
|
||||
S untouched
|
||||
EOF
|
||||
git ls-files -t >actual &&
|
||||
test_cmp expect actual &&
|
||||
grep "changes.*would be overwritten by merge" error &&
|
||||
|
||||
# ...and that the paths show up in status as changed...
|
||||
cat >expect <<-EOF &&
|
||||
A addme
|
||||
M modified
|
||||
D removeme
|
||||
M subdir/A
|
||||
?? actual
|
||||
?? expect
|
||||
?? modified.stash.XXXXXX
|
||||
EOF
|
||||
git status --porcelain | \
|
||||
sed -e s/stash......./stash.XXXXXX/ >actual &&
|
||||
test_cmp expect actual &&
|
||||
echo in the way >expect &&
|
||||
test_cmp expect modified &&
|
||||
git diff --quiet HEAD ":!modified" &&
|
||||
|
||||
# ...and that working directory reflects the files correctly
|
||||
test_path_is_file addme &&
|
||||
test_path_is_missing addme &&
|
||||
test_path_is_file modified &&
|
||||
test_path_is_missing removeme &&
|
||||
test_path_is_file subdir/A &&
|
||||
test_path_is_missing untouched &&
|
||||
|
||||
# ...including that we have the expected "modified" file...
|
||||
cat >expect <<-EOF &&
|
||||
modified
|
||||
tweaked
|
||||
EOF
|
||||
test_cmp expect modified &&
|
||||
|
||||
# ...and that the other "modified" file is still present...
|
||||
echo in the way >expect &&
|
||||
test_cmp expect modified.stash.*
|
||||
test_path_is_missing untouched
|
||||
)
|
||||
'
|
||||
|
||||
|
@ -83,10 +83,13 @@ test_expect_success 'setup' '
|
||||
|
||||
# The test below covers a special case: the sparsity patterns exclude '/b' and
|
||||
# sparse checkout is enabled, but the path exists in the working tree (e.g.
|
||||
# manually created after `git sparse-checkout init`). git grep should skip it.
|
||||
# manually created after `git sparse-checkout init`). Although b is marked
|
||||
# as SKIP_WORKTREE, git grep should notice it IS present in the worktree and
|
||||
# report it.
|
||||
test_expect_success 'working tree grep honors sparse checkout' '
|
||||
cat >expect <<-EOF &&
|
||||
a:text
|
||||
b:new-text
|
||||
EOF
|
||||
test_when_finished "rm -f b" &&
|
||||
echo "new-text" >b &&
|
||||
@ -126,12 +129,16 @@ test_expect_success 'grep --cached searches entries with the SKIP_WORKTREE bit'
|
||||
'
|
||||
|
||||
# Note that sub2/ is present in the worktree but it is excluded by the sparsity
|
||||
# patterns, so grep should not recurse into it.
|
||||
# patterns. We also explicitly mark it as SKIP_WORKTREE in case it got cleared
|
||||
# by previous git commands. Thus sub2 starts as SKIP_WORKTREE but since it is
|
||||
# present in the working tree, grep should recurse into it.
|
||||
test_expect_success 'grep --recurse-submodules honors sparse checkout in submodule' '
|
||||
cat >expect <<-EOF &&
|
||||
a:text
|
||||
sub/B/b:text
|
||||
sub2/a:text
|
||||
EOF
|
||||
git update-index --skip-worktree sub2 &&
|
||||
git grep --recurse-submodules "text" >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
@ -2065,7 +2065,9 @@ static int verify_uptodate_1(const struct cache_entry *ce,
|
||||
int verify_uptodate(const struct cache_entry *ce,
|
||||
struct unpack_trees_options *o)
|
||||
{
|
||||
if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
|
||||
if (!o->skip_sparse_checkout &&
|
||||
(ce->ce_flags & CE_SKIP_WORKTREE) &&
|
||||
(ce->ce_flags & CE_NEW_SKIP_WORKTREE))
|
||||
return 0;
|
||||
return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user