git subtree în Git

Include un alt depozit Git într-un subdirector al proiectului, cu tot codul copiat în istoric, ca alternativă mai simplă la submodule.

Sintaxă comandă
git subtree add|pull|push|split --prefix=<director> [<depozit> <ramură>]

Ce face git subtree

git subtree copiază conținutul altui depozit (de exemplu o bibliotecă de componente comună) într-un subdirector al proiectului tău și îl salvează în istoric ca orice alt cod. Colegii care clonează proiectul primesc totul direct, fără pași în plus, spre deosebire de git submodule, unde trebuie rulat git submodule update --init.

Cu pull aduci actualizările bibliotecii, iar cu split sau push extragi modificările făcute în subdirector ca să le trimiți înapoi în depozitul original. Opțiunea --squash comprimă istoricul bibliotecii într-un singur commit, ca istoricul proiectului să rămână curat. Comanda vine din directorul contrib/ al lui Git și este inclusă în majoritatea instalărilor (Git for Windows, Homebrew, Apple Git), dar unele distribuții Linux o pun într-un pachet separat.

Opțiuni și argumente

Opțiune / Parametru Descriere
add --prefix=DIR DEPOZIT RAMURĂ Adaugă depozitul în subdirectorul DIR (subdirectorul nu trebuie să existe).
pull --prefix=DIR DEPOZIT RAMURĂ Aduce și integrează modificările noi din depozitul extern.
push --prefix=DIR DEPOZIT RAMURĂ Trimite înapoi în depozitul extern commit-urile care au atins DIR.
split --prefix=DIR [-b RAMURĂ] Creează un istoric separat doar cu subdirectorul DIR (pentru export).
--squash Salvează istoricul extern ca un singur commit comprimat.
-m MESAJ Mesajul commit-ului de îmbinare (la add și pull).

Exemple

Exemplul 1: Adăugarea unei biblioteci de componente într-un subdirector

Biblioteca biblioteca-ui ajunge în vendor/ui/. Cu --squash, istoricul ei apare ca un singur commit.

git init -q -b main biblioteca-ui
cd biblioteca-ui
git config user.name "Ana Popescu" && git config user.email "ana@exemplu.ro"
echo 'buton { color: green; }' > buton.css
git add . && git commit -q -m "Stil buton"
cd ..
git init -q -b main site
cd site
git config user.name "Ana Popescu" && git config user.email "ana@exemplu.ro"
echo '<h1>Magazin Iasi</h1>' > index.html
git add . && git commit -q -m "Pagina principala"
git subtree add --prefix=vendor/ui ../biblioteca-ui main --squash >/dev/null 2>&1
git log --format='%s' --graph
ls vendor/ui

Rezultat

*   Merge commit 'aa97b51cca75d031c7528c13f9dee245c4c65231' as 'vendor/ui'
|\  
| * Squashed 'vendor/ui/' content from commit 0cf1e45
* Pagina principala
buton.css

Exemplul 2: Aducerea actualizărilor din bibliotecă

Biblioteca primește un stil nou; în proiect îl aducem cu subtree pull.

git init -q -b main biblioteca-ui
cd biblioteca-ui
git config user.name "Ana Popescu" && git config user.email "ana@exemplu.ro"
echo 'buton { color: green; }' > buton.css
git add . && git commit -q -m "Stil buton"
cd ..
git init -q -b main site
cd site
git config user.name "Ana Popescu" && git config user.email "ana@exemplu.ro"
git commit -q --allow-empty -m "Start"
git subtree add --prefix=vendor/ui ../biblioteca-ui main --squash >/dev/null 2>&1
cd ../biblioteca-ui
echo 'buton:hover { color: darkgreen; }' >> buton.css
git commit -q -am "Hover buton"
cd ../site
git subtree pull --prefix=vendor/ui ../biblioteca-ui main --squash -m "Actualizare UI" >/dev/null 2>&1
cat vendor/ui/buton.css
git log -1 --format='%s'

Rezultat

buton { color: green; }
buton:hover { color: darkgreen; }
Actualizare UI

Exemplul 3: Trimiterea modificărilor înapoi în bibliotecă

Ai adăugat card.css în vendor/ui/ și vrei ca modificarea să ajungă și în depozitul bibliotecii, pe o ramură nouă.

git subtree push --prefix=vendor/ui git@github.com:firma/biblioteca-ui.git card-nou

Ieșire în terminal

git push using:  git@github.com:firma/biblioteca-ui.git card-nou
To github.com:firma/biblioteca-ui.git
 * [new branch]      48c9e511b9ab15b2c5b0024ad74cf584a47f1d6f -> card-nou

Greșeli frecvente

  • Amestecarea, în același commit, a modificărilor din subdirector cu modificări din restul proiectului: subtree push le separă, dar mesajele devin confuze pentru cei care lucrează doar pe bibliotecă.
  • Folosirea alternativă a lui --squash (uneori cu, alteori fără) pentru același subdirector: Git nu mai găsește corect punctul comun și apar conflicte la pull. Alege o variantă și păstreaz-o.

Comenzi înrudite

  • git submodule: Integrează și sincronizează alte depozite Git ca subproiecte în interiorul depozitului curent.
  • git merge: Îmbină istoricul și modificările dintr-o altă ramură în ramura curentă.
  • git remote: Gestionează lista serverelor și depozitelor la distanță conectate la proiectul local.