22

I want to checkout to other branch, or previous commit, but I want to keep one folder the same files (not checkout the folder).

I want that the folder, will be shown in git status, so I can add this folder now to the index.

For example, I have a folder with node_modules. I want the folder to be in all my commits (I know that most of the people prefer to .gitignore the node_modules folder). But when I move to other commit, or checkut other branch, I want that git will not touch the node_modules folder.

Is it possible?

Enrico Campidoglio
  • 56,676
  • 12
  • 126
  • 154
Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117

4 Answers4

39

You could use sparse checkout to exclude the committed contents of the node_modules directory from the working tree. As the documentation says:

"Sparse checkout" allows populating the working directory sparsely. It uses the skip-worktree bit to tell Git whether a file in the working directory is worth looking at.

Here's how you use it. First, you enable the sparseCheckout option:

git config core.sparseCheckout true

Then, you add the node_modules path as a negation in the .git/info/sparse-checkout file:

echo -e "/*\n!node_modules" >> .git/info/sparse-checkout

This will create a file called sparse-checkout containing:

/*
!node_modules

which effectively means ignore the node_modules directory when reading a commit's tree into the working directory.

If you later want to include the node_modules directory again (i.e. remove the skip-worktree bit from its files) you have to modify the sparse-checkout file to only contain /* – that is "include all paths" – and update your working directory using git read-tree:

echo "/*" > .git/info/sparse-checkout
git read-tree -mu HEAD

You can then disable sparse checkout altogether by setting its configuration variable to false:

git config core.sparseCheckout false

Note that sparse checkout was first introduced in Git 1.7.0.

Enrico Campidoglio
  • 56,676
  • 12
  • 126
  • 154
  • Thank you! Just to confirm. if one day, I will remove the `node_modules` from `sparse-checkout` file, Can I normally go back to the past, and see what it was contain in the past? (I read the link you send, but I didn't understand what is it mean `skip-worktree bit`... – Aminadav Glickshtein Nov 26 '15 at 10:03
  • Yes, you can. I updated my answer to include how to re-introduce the `node_modules` directory and disable sparse checkout. – Enrico Campidoglio Nov 26 '15 at 10:24
  • Very interesting. I will have to check it out (not git checkout), I need to test it :) – Aminadav Glickshtein Nov 26 '15 at 10:33
  • As a point of clarification, this will work just the same on a single-file name or names as it does on directory names – Christopher Hunter Nov 27 '17 at 19:38
  • For the `echo` commands, maybe single-quotes should be used? I'm not sure whether to blame ZSH, Ember, or some combination, but when I execute even `echo "/*\n!node_modules"` my shell expansion results in `echo "/*\nnode_modules/.bin/ember -v"`. – ken Nov 01 '21 at 20:17
2

To enable sparse-checkout and checkout everything except directory or file named unwanted:

git sparse-checkout set --no-cone '/*' '!unwanted'

To disable sparse-checkout and checkout everything:

git sparse-checkout disable

Source: documentation "INTERNALS — FULL PATTERN SET"

Gabriel Devillers
  • 3,155
  • 2
  • 30
  • 53
0

I checked out the entire code from the branch I want to checkout

# assume we want the `components` folder on my-branch to follow us

# first checkout your code to (my-new-branch) for ex.
git checkout -b my-new-branch

# now i'm on my-new-branch (but it doesn't have the components from my-branch :| )

# delete ./components
rm -rf ./components 

# replace it with the one on my-branch :)
git checkout my-branch -- ./components 

Good Luck...

Aakash
  • 21,375
  • 7
  • 100
  • 81
  • Branches will be required to constantly updated to any changes in master, this is a hassle. read-tree is more closer to what author asks. – holms Dec 27 '22 at 03:28
0

An alternative to the read-tree sparse checkout is the command git sparse-checkout in cone mode (presented here)

With Git 2.34 (Q4 2021), in cone mode, the sparse-index code path learned to remove ignored files (like build artifacts) outside the sparse cone, allowing the entire directory outside the sparse cone to be removed, which is especially useful when the sparse patterns change.

See commit 716f68e (10 Aug 2021) by Junio C Hamano (gitster).
See commit 55dfcf9, commit ce7a9f0, commit 77efbb3, commit 02155c8, commit 8a96b9d, commit 5dc1675, commit 72d84ea, commit e27eab4, commit 522d3ce (08 Sep 2021) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit dc89c34, 20 Sep 2021)

sparse-checkout: clear tracked sparse dirs

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

When changing the scope of a sparse-checkout using cone mode, we might have some tracked directories go out of scope.
The current logic removes the tracked files from within those directories, but leaves the ignored files within those directories.
This is a bit unexpected to users who have given input to Git saying they don't need those directories anymore.

This is something that is new to the cone mode pattern type: the user has explicitly said "I want these directories and not those directories." The typical sparse-checkout patterns more generally apply to "I want files with with these patterns" so it is natural to leave ignored files as they are.
This focus on directories in cone mode provides us an opportunity to change the behavior.

Leaving these ignored files in the sparse directories makes it impossible to gain performance benefits in the sparse index.
When we track into these directories, we need to know if the files are ignored or not, which might depend on the tracked .gitignore file(s) within the sparse directory.
This depends on the indexed version of the file, so the sparse directory must be expanded.

We must take special care to look for untracked, non-ignored files in these directories before deleting them.
We do not want to delete any meaningful work that the users were doing in those directories and perhaps forgot to add and commit before switching sparse-checkout definitions.
Since those untracked files might be code files that generated ignored build output, also do not delete any ignored files from these directories in that case.
The users can recover their state by resetting their sparse-checkout definition to include that directory and continue.
Alternatively, they can see the warning that is presented and delete the directory themselves to regain the performance they expect.

By deleting the sparse directories when changing scope (or running 'git sparse-checkout'(man) reapply) we regain these performance benefits as if the repository was in a clean state.

Since these ignored files are frequently build output or helper files from IDEs, the users should not need the files now that the tracked files are removed.
If the tracked files reappear, then they will have newer timestamps than the build artifacts, so the artifacts will need to be regenerated anyway.

Use the sparse-index as a data structure in order to find the sparse directories that can be safely deleted.
Re-expand the index to a full one if it was full before.

git sparse-checkout now includes in its man page:

When changing the sparse-checkout patterns in cone mode, Git will inspect each tracked directory that is not within the sparse-checkout cone to see if it contains any untracked files. If all of those files are ignored due to the .gitignore patterns, then the directory will be deleted.
If any of the untracked files within that directory is not ignored, then no deletions will occur within that directory and a warning message will appear. If these files are important, then reset your sparse-checkout definition so they are included, use git add and git commit to store them, then remove any remaining files manually to ensure Git can behave optimally.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Can you show an example how to use it? – Aminadav Glickshtein Oct 10 '21 at 12:03
  • @AminadavGlickshtein This is still being worked on: https://github.com/git/git/commit/716f68ec33e3506babee03c4df497a7e211220ee#diff-f0e9d5771c607d2b7d8151fe4d3a32142b262fab89c7751195599177b3632350R494 – VonC Oct 10 '21 at 12:18