Github(PRO) pills - clone a specific folder with sparse

is a bit like the discovery of hot water… exists but not used. For the record, it’s part of those pearls that I circumvented with extreme methods. One of those options that have been on github for a long time. That’s why after the umpteenth request by mail request is the case to sign as you do. In full KISS philosophy: simple, clear. When I forget it I will have the notes to remind me that it already exists.

To understand we take a repo . git that contains subdirectories and let’s make a practical example of how to download one of the folders present individually

EXAMPLE1: repo is https://github.com/aicsx/dots.git and I just want to clone .vim/colors/. Let’s go!

❯ git clone --filter=blob:none --no-checkout https://github.com/aicsx/dots.git && cd dots
Clone in 'dots' in corso...
remote: Enumerating objects: 30, done.
remote: Counting objects: 100% (30/30), done.
remote: Compressing objects: 100% (23/23), done.
Ricezione degli oggetti: 100% (30/30), 4.13 KiB | 4.13 MiB/s, fatto.
Risoluzione dei delta: 100% (5/5), fatto.
remote: Total 30 (delta 5), reused 24 (delta 3), pack-reused 0 (from 0)

dots on  main [✘] 
❯ git sparse-checkout set --cone

dots on  main [✘] 
❯ git checkout main
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 1 (delta 0), pack-reused 0 (from 0)
Ricezione degli oggetti: 100% (3/3), 2.16 KiB | 2.16 MiB/s, fatto.
Si è già su 'main'
Il tuo branch è aggiornato rispetto a 'origin/main'.

dots on  main 
❯ git sparse-checkout set .vim/colors/
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 1 (delta 0), pack-reused 0 (from 0)
Ricezione degli oggetti: 100% (1/1), 3.34 KiB | 3.34 MiB/s, fatto.


You can use a simple bash script for this! save clone-subdir.sh

NOTE: Required Git ≥ 2.25 (support for sparse-checkout –cone)

~$ vim clone_subdir.sh 
#!/bin/bash

# Check that two arguments are provided
if [ "$#" -ne 2 ]; then
    echo "Usage: $0 <repository-url> \"<subdirectory>\""
    exit 1
fi

REPO_URL="$1"
SUBDIR="$2"
REPO_NAME=$(basename "$REPO_URL" .git)

# Clone the repository in sparse mode
git clone --filter=blob:none --no-checkout "$REPO_URL" "$REPO_NAME"
cd "$REPO_NAME" || exit 1

# Initialize sparse-checkout
git sparse-checkout init --cone
git sparse-checkout set "$SUBDIR"

# Checkout the specified subdirectory
git checkout

echo "Subdirectory \"$SUBDIR\" has been cloned into ./$REPO_NAME/$SUBDIR"

:wq #save and exit

Usage example:

~$ ./clone_subdir.sh https://github.com/user/project.git "path/to/subdirectory"

as I mentioned there is an older version. Not necessarily old is worse. In my use case I prefer it because it avoids cloning some basic parts of the base url. That’s why I share it with you.

#!/bin/bash

# Check parameters
if [ "$#" -ne 2 ]; then
    echo "Usage: $0 <repository-url> \"<subdirectory>\""
    exit 1
fi

REPO_URL="$1"
SUBDIR="$2"
REPO_NAME=$(basename "$REPO_URL" .git)

# Clone the repository without checkout
git clone --no-checkout "$REPO_URL" "$REPO_NAME"
cd "$REPO_NAME" || exit 1

# Enable sparse checkout manually (for older Git versions)
git config core.sparseCheckout true

# Define the subdirectory to checkout
echo "$SUBDIR/" > .git/info/sparse-checkout

# Perform the checkout
git checkout

# Initialize and update any submodules inside the subdirectory
if [ -f .gitmodules ]; then
    # Filter submodules located within the specified subdirectory
    SUBMODULES=$(git config --file .gitmodules --get-regexp path | awk -v sub="$SUBDIR/" '$2 ~ "^"sub {print $2}')
    
    if [ -n "$SUBMODULES" ]; then
        git submodule init
        for sm in $SUBMODULES; do
            git submodule update --depth 1 "$sm"
        done
    fi
fi

echo "Subdirectory \"$SUBDIR\" has been cloned into ./$REPO_NAME/$SUBDIR"

USAGE EXAMPLE:

~$ ./clone_subdir_compat.sh https://github.com/user/project.git "src/components"

What this version supports:

✅ Older Git versions (≥ 1.7.0)
✅ Manual sparse-checkout using .git/info/sparse-checkout
✅ Submodules located inside the subdirectory
✅ Only checks out the selected path

That’s it!


(END)