1. Overview
Git comes with the option of trimming a repository’s working tree to only subdirectories or files – a feature called git sparse-checkout. This can come in handy when we only want to track specific files or subdirectories.
Besides git sparse-checkout, there are other ways to retrieve a subset of directories or files from a Git repository. In this tutorial, we’ll discuss different ways of cloning a git repository’s subdirectory.
2. Using git sparse-checkout
Before we proceed, we must state that, at the time of writing this tutorial, git sparse-checkout is experimental. So, there may be some irregularities in its behavior.
To clone a subdirectory using git sparse-checkout, we’ll git clone the directory first:
$ git clone --depth=1 https://github.com/Baeldung/stackify.git
The –depth=1 option ensures that the clone is limited to the most recent commits.
Next, we’ll cd into the local directory:
$ cd stackify
Then, we’ll check out to our desired subdirectory using git sparse-checkout set:
$ git sparse-checkout set tomcat-app
After running git sparse-checkout set, we’ll run ls -F to see the resources in the directory:
$ ls -F
pom.xml README.md tomcat-app/
As shown, our directory contains the tomcat-app subdirectory and its sibling files on checkout, even though we only specified tomcat-app. This happens because git sparse-checkout runs in cone mode by default.
In cone mode, sibling files and children resources are included in the checkout. But we can avoid this by executing the sparse checkout in –no-cone mode.
In –no-cone mode, git sparse-checkout commands read the arguments as patterns. So, if we wanted only the tomcat-app without its sibling files, we’ll pass a matching pattern:
$ git sparse-checkout set --no-cone tomcat-app
Using this new command, we checked out only the tomcat-app subdirectory in the root directory:
$ ls -F
tomcat-app/
However, if we had other resources named tomcat-app anywhere else in the working tree, the command would’ve included them in the sparse checkout. But we can also pass a pattern to limit that outcome:
$ git sparse-checkout set --no-cone tomcat-app/ '!*/tomcat-app'
The ‘!*/tomcat-app’ pattern directs the command to ignore any child resource named tomcat-app in the sibling subdirectories of the tomcat-app subdirectory:
$ ls -F
tomcat-app/
2.1. git sparse-checkout add
Running git sparse-checkout set over a previous git sparse-checkout set command will replace the initial tracked file or directory. So, if we want to add another subdirectory to the working tree, we’ll run git sparse-checkout add followed by the name of the subdirectory:
$ git sparse-checkout add webservices
Now, we have both the tomcat-app and the webservices subdirectories:
$ ls -F
tomcat-app/ webservices/
If we wanted to clone more than one directory or file at the start, we could’ve passed them all to git sparse-checkout set at once.
We can use git sparse-checkout on files, too. However, we may encounter unintended results when using it because the git sparse-checkout command is still experimental.
2.2. Disabling a Sparse Checkout
If we ever want to revert to a fully-tracked repository, we’ll run the disable command:
$ git sparse-checkout disable
With that, we’ll have all the files and repositories in our clone:
$ ls -F
core-java/ core-kotlin/ junit5-example/ logback-example/ pom.xml remote-debugging/ spring-boot-app/ spring-security/ tomcat-app/
core-java-9/ deep-jsf/ log4j2-example/ memory-leaks/ README.md slf4j/ spring-mvc/ thread-pools/ webservices/
3. Using git checkout
To clone a subdirectory or file with git checkout, we’ll start by cloning the repository without a HEAD checkout:
$ git clone --no-checkout --depth=1 https://github.com/Baeldung/stackify.git
Running the command above will recreate the repository’s .git folder locally. However, the local repo’s root directory will have no files or subdirectories. We can confirm this with tree:
$ tree stackify
stackify
0 directories, 0 files
After doing the –no-checkout clone, we’ll cd into the local repo’s main directory:
$ cd stackify
Then, we’ll check out the subdirectory or file we need using git checkout and the branch name:
$ git checkout master -- tomcat-app
Now, we have only the tomcat-app subdirectory:
$ ls -F
tomcat-app/
Using this method to clone a single subdirectory or file from a Git repository means that the other files and subdirectories would be deleted when we commit changes.
So, we’ll use this method when we’re okay with deleting the repo’s other resources. Alternatively, we could use this to get a file or subdirectory and then unlink it from the repository by deleting the .git directory – basically like downloading the file or subdirectory.
Unlike the git checkout method, git sparse-checkout does not delete the other files and subdirectories when we commit changes. Whatever we do to the tracked resource only affects that resource. So, even when we push to the remote repository, only the tracked file in the remote repository is updated.
4. Using git show
If we already have a local repository and we want to download one of its files, we can redirect the output from git show to a local file:
$ git --git-dir ./stackify/.git show master:README.md > /home/baeldung/stackify-README.md
As with the git checkout method, we’ll only use this when we need the files only (without the repo).
5. Conclusion
In this article, we discussed how to clone only the subdirectory of a repository using git clone and git sparse-checkout. We also talked about how to clone resources from a repository when we do not need said resources linked to the repository.