Git commit/Push/Pull with sparse checkout

Viewed 4506

I started Git yesterday and before that I was using SVN since many years. Let me explain you what exactly I am trying to achieve:

I have a main git repo for different projects. Something like this:

  • main_repo/proj1
  • main_repo/proj2
  • main_repo/proj3

I can't create separate repos for these sub-projects. Now I (or other users) should be able to checkout/commit/push/pull in these independent projects.

For this thing I am trying sparse-checkout with following commands:

  1. mkdir proj1; cd proj1
  2. git init
  3. git remote add origin https://main_repo
  4. git config core.sparsecheckout true
  5. echo "proj1/" > .git/info/sparse-checkout
  6. git pull origin master

Now what I need is to get all the files present in proj1 in the same current dir. What I am getting is something like this:

/proj1/proj1/files_and_dirs_in_proj1

What I need:

/proj1/files_and_dirs_in_proj1

Second this is that the checkout-dir doesn't behaves like a git repo. It doesn't carry any .git dir. So I don't understand how to do commits/push/pull in sparse-checkedout projs.

I hope I explained it well. Please suggest.

3 Answers

The recent git sparse-checkout I mention here can help, especially when combined with git clone --filter=blob:none --no-checkout

git clone --filter=blob:none --no-checkout https://github.com/<me>/<myrepo>
git config core.sparseCheckoutCone false
git sparse-checkout disable

# Add the expected pattern, to include just a subfolder without top files:
git sparse-checkout set /mySubFolder/

# populate working-tree with only the right files:
git read-tree -mu HEAD

Plus, with Git 2.32 (Q2 2021), "git add"(man) and git rm(man) learned not to touch those paths that are outside of sparse checkout.

So you won't make any mistake with paths outside of the relevant submodules.

See commit d5f4b82, commit a20f704, commit b243012, commit 719630e, commit d73dbaf, commit 6594afc, commit 4e95698 (08 Apr 2021) by Matheus Tavares (matheustavares).
(Merged by Junio C Hamano -- gitster -- in commit fe069dc, 07 May 2021)

rm: honor sparse checkout patterns

Suggested-by: Elijah Newren
Signed-off-by: Matheus Tavares

git add(man) refrains from adding or updating index entries that are outside the current sparse checkout, but git rm(man) doesn't follow the same restriction.
This is somewhat counter-intuitive and inconsistent.
So make rm honor the sparsity rules and advise on how to remove SKIP_WORKTREE entries just like add does.
Also add some tests for the new behavior.

git config now includes in its man page:

Advice shown when either git add or git rm is asked to update index entries outside the current sparse checkout.

git rm now includes in its man page:

allowing the file to be removed from just the index. When sparse-checkouts are in use (see git sparse-checkout), git rm will only remove paths within the sparse-checkout patterns.


With Git 2.34 (Q4 2021), "git add"(man) can work better with the sparse index.

See commit 42f8ed6, commit 939fa07, commit 4eaffd8, commit 5e7cbab, commit 83ad8ca (29 Jul 2021) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit 2f71366, 24 Aug 2021)

add: ignore outside the sparse-checkout in refresh()

Reviewed-by: Elijah Newren
Signed-off-by: Derrick Stolee

Since b243012 (refresh_index(): add flag to ignore SKIP_WORKTREE entries, 2021-04-08, Git v2.32.0-rc0 -- merge listed in batch #14) (refresh_index(): add flag to ignore SKIP_WORKTREE entries, 2021-04-08), 'git add --refresh'(man) <path> will output a warning message when the path is outside the sparse-checkout definition.
The implementation of this warning happened in parallel with the sparse-index work to add ensure_full_index() calls throughout the codebase.

Update this loop to have the proper logic that checks to see if the pathspec is outside the sparse-checkout definition.
This avoids the need to expand the sparse directory entry and determine if the path is tracked, untracked, or ignored.
We simply avoid updating the stat() information because there isn't even an entry that matches the path!

Related