Browse Source

sparse-checkout: create builtin with 'list' subcommand

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
parent
commit
94c0956b60
  1. 1
      .gitignore
  2. 2
      Documentation/git-read-tree.txt
  3. 89
      Documentation/git-sparse-checkout.txt
  4. 1
      Makefile
  5. 1
      builtin.h
  6. 86
      builtin/sparse-checkout.c
  7. 1
      command-list.txt
  8. 1
      git.c
  9. 45
      t/t1091-sparse-checkout-builtin.sh

1
.gitignore vendored

@ -158,6 +158,7 @@ @@ -158,6 +158,7 @@
/git-show-branch
/git-show-index
/git-show-ref
/git-sparse-checkout
/git-stage
/git-stash
/git-status

2
Documentation/git-read-tree.txt

@ -436,7 +436,7 @@ support. @@ -436,7 +436,7 @@ support.
SEE ALSO
--------
linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
linkgit:gitignore[5]
linkgit:gitignore[5]; linkgit:git-sparse-checkout[1];

GIT
---

89
Documentation/git-sparse-checkout.txt

@ -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

1
Makefile

@ -1125,6 +1125,7 @@ BUILTIN_OBJS += builtin/shortlog.o @@ -1125,6 +1125,7 @@ BUILTIN_OBJS += builtin/shortlog.o
BUILTIN_OBJS += builtin/show-branch.o
BUILTIN_OBJS += builtin/show-index.o
BUILTIN_OBJS += builtin/show-ref.o
BUILTIN_OBJS += builtin/sparse-checkout.o
BUILTIN_OBJS += builtin/stash.o
BUILTIN_OBJS += builtin/stripspace.o
BUILTIN_OBJS += builtin/submodule--helper.o

1
builtin.h

@ -225,6 +225,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix); @@ -225,6 +225,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix);
int cmd_show(int argc, const char **argv, const char *prefix);
int cmd_show_branch(int argc, const char **argv, const char *prefix);
int cmd_show_index(int argc, const char **argv, const char *prefix);
int cmd_sparse_checkout(int argc, const char **argv, const char *prefix);
int cmd_status(int argc, const char **argv, const char *prefix);
int cmd_stash(int argc, const char **argv, const char *prefix);
int cmd_stripspace(int argc, const char **argv, const char *prefix);

86
builtin/sparse-checkout.c

@ -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);
}

1
command-list.txt

@ -166,6 +166,7 @@ git-show-index plumbinginterrogators @@ -166,6 +166,7 @@ git-show-index plumbinginterrogators
git-show-ref plumbinginterrogators
git-sh-i18n purehelpers
git-sh-setup purehelpers
git-sparse-checkout mainporcelain worktree
git-stash mainporcelain
git-stage complete
git-status mainporcelain info

1
git.c

@ -572,6 +572,7 @@ static struct cmd_struct commands[] = { @@ -572,6 +572,7 @@ static struct cmd_struct commands[] = {
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show-index", cmd_show_index },
{ "show-ref", cmd_show_ref, RUN_SETUP },
{ "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
/*
* NEEDSWORK: Until the builtin stash is thoroughly robust and no

45
t/t1091-sparse-checkout-builtin.sh

@ -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…
Cancel
Save