Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use git sparse-checkout in 2.27+

Tags:

git

I was trying to reproduce the few tutorial steps from:

https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout

Which was made for git 2.25, but now in 2.27, nothing happen at all when running:

$ git sparse-checkout set client/android

I can't find a way to make it works.

Here is a MWE:

$ git clone --no-checkout https://github.com/derrickstolee/sparse-checkout-example
Cloning into 'sparse-checkout-example'...

$ cd sparse-checkout-example/

$ git sparse-checkout init --cone

Using git 2.25, I obtain a non empty directory:

$ ls -a
.  .. bootstrap.sh LICENSE.md  README.md .git

Using git 2.27, I obtain an empty directory:

$ ls -a
.  .. .git
like image 689
agemO Avatar asked Jun 17 '20 07:06

agemO


People also ask

How do I enable sparse checkout?

Enable the necessary sparse-checkout config settings ( core. sparseCheckout , core. sparseCheckoutCone , and index. sparse ) if they are not already set to the desired values, populate the sparse-checkout file from the list of arguments following the set subcommand, and update the working directory to match.

How do you get out of sparse checkout?

If you get stuck, run git sparse-checkout disable to return to a full working directory. The init subcommand sets the necessary Git config options and fills the sparse-checkout file with patterns that mean “only match files in the root directory”.


2 Answers

I believe I found the reason for this. Commit f56f31af0301 to Git changed the implementation of sparse-checkout so that, when you have an uninitialized working tree (as you would right after running git clone --no-checkout), running git sparse-checkout init will not check out any files into your working tree. In previous versions, the command would actually check out files, which could have unexpected effects given that you wouldn't have an active branch at that point.

The relevant commit, f56f31af0301 was included in Git 2.27, but not in 2.25. That accounts for why the behavior you see is not the behavior shown on the web page you're trying to follow. Basically, the behavior on the web page was a bug that nobody realized was a bug at the time, but with Git 2.27, it has been fixed.

This is explained very well, I think, in the message for commit b5bfc08a972d:

So...that brings us to the special case: a git clone performed with --no-checkout. As per the meaning of the flag, --no-checkout does not check out any branch, with the implication that you aren't on one and need to switch to one after the clone. Implementationally, HEAD is still set (so in some sense you are partially on a branch), but

  • the index is "unborn" (non-existent)
  • there are no files in the working tree (other than .git/)
  • the next time git switch (or git checkout) is run it will run unpack_trees with initial_checkout flag set to true.

It is not until you run, e.g. git switch <somebranch> that the index will be written and files in the working tree populated.

With this special --no-checkout case, the traditional read-tree -mu HEAD behavior would have done the equivalent of acting like checkout -- switch to the default branch (HEAD), write out an index that matches HEAD, and update the working tree to match. This special case slipped through the avoid-making-changes checks in the original sparse-checkout command and thus continued there.

After update_sparsity() was introduced and used (see commit f56f31a ("sparse-checkout: use new update_sparsity() function", 2020-03-27)), the behavior for the --no-checkout case changed: Due to git's auto-vivification of an empty in-memory index (see do_read_index() and note that must_exist is false), and due to sparse-checkout's update_working_directory() code to always write out the index after it was done, we got a new bug. That made it so that sparse-checkout would switch the repository from a clone with an "unborn" index (i.e. still needing an initial_checkout), to one that had a recorded index with no entries. Thus, instead of all the files appearing deleted in git status being known to git as a special artifact of not yet being on a branch, our recording of an empty index made it suddenly look to git as though it was definitely on a branch with ALL files staged for deletion! A subsequent checkout or switch then had to contend with the fact that it wasn't on an initial_checkout but had a bunch of staged deletions.

like image 193
David Z Avatar answered Oct 06 '22 01:10

David Z


Here is a solution that will populate only files in the root folder:

$ git clone --filter=blob:none --sparse https://github.com/derrickstolee/sparse-checkout-example

Then subsequent sparse-checkout calls work like a charm.

Still no idea why the tutorial is broken.

like image 22
agemO Avatar answered Oct 06 '22 01:10

agemO