Пошук уроків, статей та іншого контенту
Оптимізуємо клонування, пошук і отримання змін у великих Git-репозиторіях за допомогою shallow clone та partial clone.
Великий Git-репозиторій може містити:
десятки або сотні тисяч комітів;
довгу історію гілок;
великі бінарні файли;
багато файлів, які не потрібні для поточної задачі.
Звичайне клонування завантажує всю історію та всі необхідні об’єкти. Це збільшує:
час клонування;
обсяг мережевого трафіку;
розмір каталогу .git;
час виконання операцій із репозиторієм.
Git має два механізми для зменшення обсягу даних:
shallow clone — обмеження глибини історії;
partial clone — відкладене завантаження окремих об’єктів, наприклад вмісту файлів.
Їх можна використовувати окремо або разом.
Shallow clone — це клонування лише частини історії репозиторію. Найчастіше завантажують останній коміт або останні кілька комітів.
git clone --depth=1 https://github.com/git/git.git git-shallowПараметр --depth=1 означає, що Git завантажить лише найновіший коміт вибраної гілки.
Для клонування певної гілки це можна записати явно:
git clone \
--depth=20 \
--branch=main \
--single-branch \
https://github.com/git/git.git \
git-shallowУ результаті локальний репозиторій міститиме:
файли з поточного стану гілки main;
останні 20 комітів цієї гілки;
не повну історію всіх гілок.
Виконайте команду всередині клонованого репозиторію:
cd git-shallow
git log --onelineКількість комітів буде обмеженою. Git також позначає найстаріший доступний коміт як неповний — його називають shallow boundary.
Перевірити такі межі можна командою:
git rev-list --boundary HEADКоміти, перед якими виводиться символ -, є межами доступної історії.
Shallow clone добре підходить для:
CI/CD, де потрібно зібрати лише поточний стан проєкту;
одноразового аналізу останньої версії;
швидкого запуску локального середовища;
контейнерів і тимчасових робочих каталогів;
автоматизованих скриптів, яким не потрібна історія.
Наприклад, у CI зазвичай достатньо:
git clone --depth=1 --single-branch --branch=main "$REPOSITORY_URL" projectОбмежена історія не є незворотною. За потреби можна завантажити додаткові коміти.
git fetch --deepen=50 origin mainЦя команда додасть ще 50 комітів до вже доступної історії гілки main.
Інший варіант — завантажити історію до конкретної дати:
git fetch --shallow-since="2025-01-01" origin mainЩоб отримати повну історію:
git fetch --unshallowПісля цього локальний репозиторій перестане бути shallow-репозиторієм.
Перевірити це можна так:
git rev-parse --is-shallow-repositoryРезультат:
trueозначає, що історія ще обмежена, а false — що доступна повна історія.
Shallow clone зменшує обсяг даних, але обмежує деякі операції.
Якщо потрібного коміту немає серед завантажених, команда не зможе його знайти:
git log --all --oneline -- src/config.jsЦе не означає, що файл або коміт ніколи не існували. Потрібна частина історії може бути відсутня локально.
У такому випадку спочатку розширте історію:
git fetch --deepen=100 origin main
git log --all --oneline -- src/config.jsДля порівняння гілок Git може потребувати спільного предка. Якщо цей предок розташований за межами shallow-історії, команди на кшталт merge або diff можуть дати неповний або несподіваний результат.
Перед аналізом повної історії гілок краще отримати її:
git fetch --unshallowОперації rebase, cherry-pick і складні злиття можуть вимагати комітів, яких немає в shallow clone. Якщо Git повідомляє, що не може знайти потрібний об’єкт або спільного предка, розширте історію.
Partial clone дозволяє отримати лише частину об’єктів репозиторію, а решту завантажувати за потреби.
Найпоширеніший фільтр:
git clone \
--filter=blob:none \
--no-checkout \
https://github.com/git/git.git \
git-partialФільтр blob:none означає, що Git не завантажує вміст файлів одразу. Об’єкти типу blob містять саме вміст файлів.
Метадані комітів і структура дерев завантажуються, але великі файли можуть бути отримані лише тоді, коли вони знадобляться локальній операції.
Після клонування можна перейти до потрібної гілки:
cd git-partial
git checkout mainПід час checkout Git завантажить blob-об’єкти, необхідні для побудови робочого дерева.
Partial clone зберігає інформацію про сервер, який може надати відсутні об’єкти. Такий сервер називається promisor remote.
Якщо команда потребує відсутній blob, Git автоматично звертається до віддаленого репозиторію. Наприклад, під час:
переходу на гілку;
читання файлу;
пошуку вмісту;
побудови diff.
Тому partial clone економить початковий трафік, але подальші команди можуть виконувати додаткові мережеві запити.
Два підходи можна поєднати:
git clone \
--depth=1 \
--filter=blob:none \
--single-branch \
--branch=main \
https://github.com/git/git.git \
git-smallТакий репозиторій має:
лише останній коміт гілки main;
відсутню більшість blob-об’єктів;
мінімальний початковий обсяг завантаження.
Це корисно для автоматизованих середовищ, де потрібен лише поточний стан проєкту.
Пошук потрібно виконувати з урахуванням того, яка інформація вже є локально.
Пошук комітів, які змінювали файл:
git log --all --oneline -- src/config.jsПошук комітів за текстом повідомлення:
git log --all --oneline --grep="authentication"У shallow clone ці команди переглядають лише завантажену частину історії.
Якщо результат неповний:
git fetch --deepen=200 origin main
git log --all --oneline --grep="authentication"Для пошуку тексту в робочому дереві використовуйте:
git grep -n "TODO"Пошук лише у файлах із певним розширенням:
git grep -n "timeout" -- "*.js" "*.ts"У partial clone Git може автоматично завантажити відсутні blob-об’єкти, якщо команда звертається до файлів, яких ще немає локально.
Тому пошук у всьому великому історичному наборі файлів може породити значний мережевий трафік. Якщо потрібен лише поточний стан, не запускайте пошук по всій історії без необхідності.
Для shallow або partial clone звичайне отримання змін працює так само:
git fetch origin mainПісля цього можна оновити локальну гілку:
git merge --ff-only origin/mainАбо, якщо локальна гілка просто має відповідати віддаленій:
git reset --hard origin/maingit fetch у shallow-репозиторії намагається зберегти обмежену глибину. Якщо потрібні старіші коміти, використовуйте --deepen або --unshallow.
Для partial clone команда fetch також зберігає налаштований фільтр:
git fetch origin mainВідсутні об’єкти завантажуються окремо, коли їх потребує конкретна операція.
Наведений сценарій створює невеликий робочий клон, перевіряє його властивості, розширює історію та виконує пошук.
#!/usr/bin/env bash
set -euo pipefail
REPOSITORY_URL="https://github.com/git/git.git"
DIRECTORY="git-work"
rm -rf "$DIRECTORY"
# Завантажуємо лише останній коміт основної гілки без зайвих blob-об'єктів
git clone \
--depth=1 \
--filter=blob:none \
--single-branch \
--branch=main \
"$REPOSITORY_URL" \
"$DIRECTORY"
cd "$DIRECTORY"
echo "Стан shallow-репозиторію:"
git rev-parse --is-shallow-repository
echo "Кількість доступних комітів:"
git rev-list --count HEAD
echo "Пошук слова у поточній версії:"
git grep -n "TODO" || true
# Додаємо ще 50 комітів для аналізу недавньої історії
git fetch --deepen=50 origin main
echo "Коміти, які змінювали файл README.md:"
git log --oneline -- README.mdКоманда || true після git grep потрібна лише для прикладу: git grep повертає ненульовий код завершення, якщо збігів не знайдено. Це не повинно зупиняти демонстраційний скрипт.
Використовуйте shallow clone, якщо:
потрібен поточний стан і кілька останніх комітів;
історія не використовується;
потрібно прискорити CI;
важливо зменшити кількість комітів.
Використовуйте partial clone, якщо:
історія потрібна, але не всі файли;
репозиторій містить великі файли;
потрібно працювати з метаданими комітів без повного завантаження вмісту;
Git-сервер підтримує фільтроване клонування.
Використовуйте обидва механізми, якщо потрібно мінімізувати початкове клонування та працювати лише з останнім станом гілки.
--depth=1git clone --depth=1 "$URL"
git log --allТакий git log не покаже всю історію. Для цього потрібно розширити або повністю завантажити її:
git fetch --unshallowУ shallow clone коміт може бути недоступним, навіть якщо файл існує в поточній версії. Спочатку визначте, що саме потрібно:
поточний вміст файлу — достатньо git grep або перегляду робочого дерева;
історія змін — потрібно розширити shallow clone;
повний аналіз гілок — найімовірніше, потрібен повний клон.
Пошук по великій кількості історичних версій може спричинити завантаження багатьох blob-об’єктів. Це нівелює перевагу partial clone.
Спочатку обмежте пошук:
git log --since="2026-01-01" --all --oneline -- src/А вже потім, якщо потрібно, розширюйте історію або завантажуйте додаткові об’єкти.
Фільтроване клонування залежить від підтримки Git-сервера та його протоколу. Якщо сервер не підтримує --filter, клонування може завершитися помилкою або фільтр не дасть очікуваного результату.
У такій ситуації використовуйте shallow clone або звичайне клонування.
Обмежена історія може не містити спільного предка гілок. Перед важливим merge, rebase або cherry-pick перевірте, чи є потрібна історія локально. За потреби:
git fetch --unshallow--depth=N створює shallow clone з обмеженою історією.
--single-branch не завантажує непотрібні гілки.
git fetch --deepen=N додає частину старої історії.
git fetch --unshallow перетворює shallow clone на повний.
--filter=blob:none створює partial clone з відкладеним завантаженням вмісту файлів.
Shallow clone обмежує історію, а partial clone обмежує набір об’єктів.
Ці підходи можна комбінувати для швидкого початкового клонування.
Під час пошуку потрібно пам’ятати, що відсутня історія або blob-об’єкти можуть бути завантажені пізніше або вимагати додаткового fetch.