Browse Source
The sparse-checkout feature is mostly hidden to users, as its only documentation is supplementary information in the docs for 'git read-tree'. In addition, users need to know how to edit the .git/info/sparse-checkout file with the right patterns, then run the appropriate 'git read-tree -mu HEAD' command. Keeping the working directory in sync with the sparse-checkout file requires care. Begin an effort to make the sparse-checkout feature a porcelain feature by creating a new 'git sparse-checkout' builtin. This builtin will be the preferred mechanism for manipulating the sparse-checkout file and syncing the working directory. The documentation provided is adapted from the "git read-tree" documentation with a few edits for clarity in the new context. Extra sections are added to hint toward a future change to a more restricted pattern set. Helped-by: Elijah Newren <newren@gmail.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
Derrick Stolee
5 years ago
committed by
Junio C Hamano
9 changed files with 226 additions and 1 deletions
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
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 atterns. |
||||
|
||||
|
||||
SYNOPSIS |
||||
-------- |
||||
[verse] |
||||
'git sparse-checkout <subcommand> [options]' |
||||
|
||||
|
||||
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 EXPERIMENTAL. ITS BEHAVIOR, AND THE BEHAVIOR OF OTHER |
||||
COMMANDS IN THE PRESENCE OF SPARSE-CHECKOUTS, WILL LIKELY CHANGE IN |
||||
THE FUTURE. |
||||
|
||||
|
||||
COMMANDS |
||||
-------- |
||||
'list':: |
||||
Provide a list of the contents in the sparse-checkout file. |
||||
|
||||
|
||||
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 not populate 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 |
||||
directory, it updates the skip-worktree bits in the index based |
||||
on this file. The files matching the patterns in the file will |
||||
appear in the working directory, and the rest will not. |
||||
|
||||
## FULL PATTERN SET |
||||
|
||||
By default, the sparse-checkout file uses the same syntax as `.gitignore` |
||||
files. |
||||
|
||||
While `$GIT_DIR/info/sparse-checkout` is usually used to specify what |
||||
files are included, you can also specify what files are _not_ included, |
||||
using negative patterns. For example, to remove the file `unwanted`: |
||||
|
||||
---------------- |
||||
/* |
||||
!unwanted |
||||
---------------- |
||||
|
||||
Another tricky thing is fully repopulating the working directory when you |
||||
no longer want sparse checkout. You cannot just disable "sparse |
||||
checkout" because skip-worktree bits are still in the index and your working |
||||
directory is still sparsely populated. You should re-populate the working |
||||
directory with the `$GIT_DIR/info/sparse-checkout` file content as |
||||
follows: |
||||
|
||||
---------------- |
||||
/* |
||||
---------------- |
||||
|
||||
Then you can disable sparse checkout. Sparse checkout support in 'git |
||||
checkout' and similar commands is disabled by default. You need to |
||||
set `core.sparseCheckout` to `true` in order to have sparse checkout |
||||
support. |
||||
|
||||
SEE ALSO |
||||
-------- |
||||
|
||||
linkgit:git-read-tree[1] |
||||
linkgit:gitignore[5] |
||||
|
||||
GIT |
||||
--- |
||||
Part of the linkgit:git[1] suite |
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
#include "builtin.h" |
||||
#include "config.h" |
||||
#include "dir.h" |
||||
#include "parse-options.h" |
||||
#include "pathspec.h" |
||||
#include "repository.h" |
||||
#include "run-command.h" |
||||
#include "strbuf.h" |
||||
|
||||
static char const * const builtin_sparse_checkout_usage[] = { |
||||
N_("git sparse-checkout list"), |
||||
NULL |
||||
}; |
||||
|
||||
static char *get_sparse_checkout_filename(void) |
||||
{ |
||||
return git_pathdup("info/sparse-checkout"); |
||||
} |
||||
|
||||
static void write_patterns_to_file(FILE *fp, struct pattern_list *pl) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < pl->nr; i++) { |
||||
struct path_pattern *p = pl->patterns[i]; |
||||
|
||||
if (p->flags & PATTERN_FLAG_NEGATIVE) |
||||
fprintf(fp, "!"); |
||||
|
||||
fprintf(fp, "%s", p->pattern); |
||||
|
||||
if (p->flags & PATTERN_FLAG_MUSTBEDIR) |
||||
fprintf(fp, "/"); |
||||
|
||||
fprintf(fp, "\n"); |
||||
} |
||||
} |
||||
|
||||
static int sparse_checkout_list(int argc, const char **argv) |
||||
{ |
||||
struct pattern_list pl; |
||||
char *sparse_filename; |
||||
int res; |
||||
|
||||
memset(&pl, 0, sizeof(pl)); |
||||
|
||||
sparse_filename = get_sparse_checkout_filename(); |
||||
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL); |
||||
free(sparse_filename); |
||||
|
||||
if (res < 0) { |
||||
warning(_("this worktree is not sparse (sparse-checkout file may not exist)")); |
||||
return 0; |
||||
} |
||||
|
||||
write_patterns_to_file(stdout, &pl); |
||||
clear_pattern_list(&pl); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cmd_sparse_checkout(int argc, const char **argv, const char *prefix) |
||||
{ |
||||
static struct option builtin_sparse_checkout_options[] = { |
||||
OPT_END(), |
||||
}; |
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "-h")) |
||||
usage_with_options(builtin_sparse_checkout_usage, |
||||
builtin_sparse_checkout_options); |
||||
|
||||
argc = parse_options(argc, argv, prefix, |
||||
builtin_sparse_checkout_options, |
||||
builtin_sparse_checkout_usage, |
||||
PARSE_OPT_STOP_AT_NON_OPTION); |
||||
|
||||
git_config(git_default_config, NULL); |
||||
|
||||
if (argc > 0) { |
||||
if (!strcmp(argv[0], "list")) |
||||
return sparse_checkout_list(argc, argv); |
||||
} |
||||
|
||||
usage_with_options(builtin_sparse_checkout_usage, |
||||
builtin_sparse_checkout_options); |
||||
} |
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh |
||||
|
||||
test_description='sparse checkout builtin tests' |
||||
|
||||
. ./test-lib.sh |
||||
|
||||
test_expect_success 'setup' ' |
||||
git init repo && |
||||
( |
||||
cd repo && |
||||
echo "initial" >a && |
||||
mkdir folder1 folder2 deep && |
||||
mkdir deep/deeper1 deep/deeper2 && |
||||
mkdir deep/deeper1/deepest && |
||||
cp a folder1 && |
||||
cp a folder2 && |
||||
cp a deep && |
||||
cp a deep/deeper1 && |
||||
cp a deep/deeper2 && |
||||
cp a deep/deeper1/deepest && |
||||
git add . && |
||||
git commit -m "initial commit" |
||||
) |
||||
' |
||||
|
||||
test_expect_success 'git sparse-checkout list (empty)' ' |
||||
git -C repo sparse-checkout list >list 2>err && |
||||
test_must_be_empty list && |
||||
test_i18ngrep "this worktree is not sparse (sparse-checkout file may not exist)" err |
||||
' |
||||
|
||||
test_expect_success 'git sparse-checkout list (populated)' ' |
||||
test_when_finished rm -f repo/.git/info/sparse-checkout && |
||||
cat >repo/.git/info/sparse-checkout <<-EOF && |
||||
/folder1/* |
||||
/deep/ |
||||
**/a |
||||
!*bin* |
||||
EOF |
||||
cp repo/.git/info/sparse-checkout expect && |
||||
git -C repo sparse-checkout list >list && |
||||
test_cmp expect list |
||||
' |
||||
|
||||
test_done |
Loading…
Reference in new issue