23

If I don't want .html files tracked I can add the pattern to .gitignore and they'll be ignored. I'd like to know how I can do the converse - at checkout, how could I ask git to only checkout certain types of files or not checkout certain types of files?

For example, if I didn't want html files I could write:

git checkout HEAD . --no .html

if that existed. Is there a way already built in, or do I just have to run something else post-checkout?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
ian
  • 12,003
  • 9
  • 51
  • 107
  • 7
    Readers that found this question while seeking a way to work with Git normally (e.g. checkouts, commits, merges, etc.) but with only a subset of the whole working tree present (i.e. another way to interpret “ignore/specify files for checkout”) should consider Git’s sparse checkout feature. It is documented in the [“Sparse Checkout” section](http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_sparse_checkout) of the [*git read-tree* manpage](http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html). – Chris Johnsen Apr 01 '11 at 03:04

5 Answers5

24

Git's Sparse-Checkout

If you only want to checkout a portion of your repository, you can use git's sparse-checkout option which has powerful include/exclude rules.

The following StackOverflow question has some helpful instructions:
GIT checkout except one folder

But as a summary:

  1. Enable the sparseCheckout option:

    git config core.sparseCheckout true
    
  2. Create the file called .git/info/sparse-checkout containing:

    /*
    !node_modules
    

    which effectively means include everything except the node_modules directory when checking out a repository into the working directory.

Simon East
  • 55,742
  • 17
  • 139
  • 133
  • 1
    the config here is checked against all folders in the directory, so I believe it should be: `!^node_modules`, else it will also ignore subdirectories named `node_modules`. – Nathan Jun 16 '20 at 02:34
20

If you want to package up files for deployment, you probably don't need - or want - the repo itself. This is exactly what git archive is for. A couple examples from the manpage (linked):

git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)

Create a tar archive that contains the contents of the latest commit on the current branch, and extract it in the /var/tmp/junk directory.

git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip > git-1.4.0.tar.gz

Create a compressed tarball for v1.4.0 release.

You ought to be able to get it to do exactly what you want, with the help of the export-ignore attribute:

export-ignore

Files and directories with the attribute export-ignore won’t be added to archive files. See gitattributes(5) for details.

For example, to exclude the directory private and the files mine.txt and secret.c, you could put in the file .gitattributes:

private/     export-ignore
secret.c     export-ignore

Just like gitignore files, you can put those anywhere in your repository, and they'll operate from that directory, but starting from the top level is a good bet.

ChrisDelsart
  • 463
  • 2
  • 11
Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • 1
    this is a lot closer to what I'm looking for. At the very least I can pipe it through other commands so it's not an onerous process. Thanks. – ian Mar 31 '11 at 13:20
3

If you want just a one-time change (or not consistent) or you just don't want to put files in .gitignore then do the below:

  1. Stash specific files that you want to exclude from checkout
git stash push -m "files_to_ignore" my/path/of/the/file/file.txt
  1. Do checkout as you expected before:
git checkout .
  1. Extract stashed content:
git stash apply stash^{/files_to_ignore}

The complete solution using git aliases can look like this:

alias reset-non-dev='git stash push -m "ignore_files" MyRepo/file1.txt MyRepo/dir/file2.js MyRepo/dir/dir2/file3.cs PSOne/Startup/PSOne/Views/Login.xaml.cs ; git checkout . ; git stash apply stash^{/ignore_files} ;'

Later you can use this alias simply by putting its name in git bash and hitting enter.

One benefit here that I observed is that with this approach you can change the files or skip them whenever you really need it and not marked such files as always ignored.

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
2

So I wanted to ship my code without the test files to the production server.

Easiest way for me was just to remove all the test files with: rsync --exclude 'tests' after unpacking the archive.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Kristian
  • 2,071
  • 23
  • 15
0

Not only can you use git sparse-checkout as mentioned in Simon East's answer, with rules like

/*
!^node_modules

But, starting with Git 2.41 (Q2 2023), you can validate those rules!

"git sparse-checkout"(man) command learns a debugging aid for the sparse rule definitions.

See commit 00408ad, commit 24fc2cd (27 Mar 2023) by William Sprent (williams-unity).
(Merged by Junio C Hamano -- gitster -- in commit d02343b, 11 Apr 2023)

builtin/sparse-checkout: add check-rules command

Signed-off-by: William Sprent

There exists no direct way to interrogate git about which paths are matched by a given set of sparsity rules.
It is possible to get this information from git, but it includes checking out the commit that contains the paths, applying the sparse checkout patterns and then using something like 'git ls-files -t'(man) to check if the skip worktree bit is set.
This works in some case, but there are cases where it is awkward or infeasible to generate a checkout for this purpose.

Exposing the pattern matching of sparse checkout enables more tooling to be built and avoids a situation where tools that want to reason about sparse checkouts start containing parallel implementation of the rules.
To accommodate this, add a 'check-rules' subcommand to the 'sparse-checkout' builtin along the lines of the 'git check-ignore'(man) and 'git check-attr'(man) commands.
The new command accepts a list of paths on stdin and outputs just the ones the match the sparse checkout.

To allow for use in a bare repository and to allow for interrogating about other patterns than the current ones, include a '--rules-file' option which allows the caller to explicitly pass sparse checkout rules in the format accepted by 'sparse-checkout set --stdin'.

To allow for reuse of the handling of input patterns for the '--rules-file' flag, modify 'add_patterns_from_input()' to be able to read from a 'FILE' instead of just stdin.

To allow for reuse of the logic which decides whether or not rules should be interpreted as cone-mode patterns, split that part out of 'update_modes()' such that can be called without modifying the config.

An alternative could have been to create a new 'check-sparsity' command.
However, placing it under 'sparse-checkout' allows for

  • a) more easily re-using the sparse checkout pattern matching and cone/non-code mode handling, and
  • b) keeps the documentation for the command next to the experimental warning and the cone-mode discussion.

git sparse-checkout now includes in its man page:

'git sparse-checkout' (init | list | set | add | reapply | disable | check-rules) [<options>]

git sparse-checkout now includes in its man page:

'check-rules'

Check whether sparsity rules match one or more paths.

By default check-rules reads a list of paths from stdin and outputs only the ones that match the current sparsity rules. The input is expected to consist of one path per line, matching the output of git ls-tree --name-only including that pathnames that begin with a double quote (") are interpreted as C-style quoted strings.

When called with the --rules-file <file> flag the input files are matched against the sparse checkout rules found in <file> instead of the current ones. The rules in the files are expected to be in the same form as accepted by git sparse-checkout set --stdin (in particular, they must be newline-delimited).

By default, the rules passed to the --rules-file option are interpreted as cone mode directories. To pass non-cone mode patterns with --rules-file, combine the option with the --no-cone option.

When called with the -z flag, the format of the paths input on stdin as well as the output paths are \0 terminated and not quoted. Note that this does not apply to the format of the rules passed with the --rules-file option.

Examples:

cat >rules <<-\EOF &&
    folder1
    deep/deeper1/deepest
    EOF
    git -C bare ls-tree -r --name-only HEAD >all-files &&
    git -C bare sparse-checkout check-rules --cone \
        --rules-file ../rules >check-rules-file <all-files &&
    git -C repo sparse-checkout set --cone --stdin <rules&&
    git -C repo ls-files -t >out &&
    sed -n "/^S /!s/^. //p" out >ls-files &&
    git -C repo sparse-checkout check-rules >check-rules-default <all-files
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250