Git subtree: l'alternativa al sottomodulo Git

Internet è pieno di articoli sul perché non si debbano usare i sottomoduli Git. Sebbene i sottomoduli siano utili per alcuni casi d'uso, presentano diversi inconvenienti.

Ci sono alternative? La risposta è sì! Esistono (almeno) due strumenti che possono aiutarti a tenere traccia della cronologia delle dipendenze software nel tuo progetto consentendoti di continuare a usare Git:

  • Sottoalbero Git

  • Google repo

In questo post esamineremo Git subtree e mostreremo perché è un miglioramento, anche se non perfetto, rispetto al modulo secondario Git.

Cos'è git subtree e perché dovrei usarlo?

Un git subtree ti consente di annidare un repository all'interno di un altro come sottodirectory. È uno dei tanti modi in cui i progetti Git possono gestire le dipendenze dei progetti.

Diagramma di git subtree prima/dopo

Perché potresti prendere in considerazione un git subtree

  • La gestione di un flusso di lavoro semplice è facile.

  • Sono supportate le versioni precedenti di Git (anche precedenti alla v1.5.2).

  • Il codice del sottoprogetto è disponibile subito dopo il completamento del clone del super progetto.

  • git subtree non richiede agli utenti del tuo repository di apprendere cose nuove. Possono ignorare il fatto che tu stia usando git subtree per gestire le dipendenze.

  • git subtree non aggiunge nuovi file di metadati come fa il modulo secondario Git (ad esempio .gitmodule).

  • Il contenuto del modulo può essere modificato senza avere una copia separata della dipendenza nel repository altrove.

Svantaggi (ma a nostro avviso sono in gran parte accettabili):

  • Devi apprendere una nuova strategia di merge (ad esempio git subtree).

  • Contribuire al codice a monte per i sottoprogetti è leggermente più complicato.

  • La responsabilità di non mischiare il codice del super e del sottoprogetto nei commit spetta a te.

Come usare git subtree

git subtree è disponibile nella versione stock di Git da maggio 2012 – v1.7.11 e successive. La versione installata come homebrew su OSX ha già un sottoalbero correttamente cablato, ma su alcune piattaforme potrebbe essere necessario seguire le istruzioni di installazione.

Ecco un esempio canonico di tracciamento di un plug-in vim usando git subtree.

Il modo rapido e semplice senza tracciamento remoto

Se vuoi solo un paio di battute da tagliare e incollare, leggi questo paragrafo. Per prima cosa aggiungi git subtree in una cartella con prefisso specificata:

git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash

La prassi comune consiste nel non archiviare l'intera cronologia del sottoprogetto nel tuo repository principale, ma se vuoi conservarla, ometti il flag –squash.

Il comando precedente produce il seguente output:

git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git main
warning: no common commits
remote: Counting objects: 338, done.
remote: Compressing objects: 100% (145/145), done.
remote: Total 338 (delta 101), reused 323 (delta 89)
Receiving objects: 100% (338/338), 71.46 KiB, done.
Resolving deltas: 100% (101/101), done.
From https://bitbucket.org/vim-plugins-mirror/vim-surround.git
* branch main -} FETCH_HEAD
Added dir '.vim/bundle/tpope-vim-surround'

Come puoi vedere, registra un commit di merge eseguendo lo squash dell'intera cronologia del repository vim-surround in un valore unico:

1bda0bd [3 minutes ago] (HEAD, stree) Merge commit 'ca1f4da9f0b93346bba9a430c889a95f75dc0a83' as '.vim/bundle/tpope-vim-surround' [Nicola Paolucci]
ca1f4da [3 minutes ago] Squashed '.vim/bundle/tpope-vim-surround/' content from commit 02199ea [Nicola Paolucci]

Se dopo un po' vuoi aggiornare il codice del plugin dal repository upstream, puoi semplicemente fare un pull di git subtree:

git subtree pull --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash

Si tratta di un'operazione molto veloce e indolore, ma i comandi sono leggermente lunghi e difficili da ricordare. Possiamo abbreviarli aggiungendo il sottoprogetto come remoto.

Aggiunta del sottoprogetto come remoto

L'aggiunta del sottoalbero come remoto ci consente di farvi riferimento in forma più breve:

git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git

Ora possiamo aggiungere il sottoalbero (come prima), ma possiamo anche fare riferimento al remoto in forma abbreviata:

git subtree add --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squash

Il comando per aggiornare il sottoprogetto in un secondo momento diventa:

git fetch tpope-vim-surround main
git subtree pull --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squash

Contributo all'upstream

Ora possiamo eseguire liberamente il commit delle nostre correzioni al sottoprogetto nella nostra directory di lavoro locale. Quando è il momento di contribuire al progetto upstream, dobbiamo eseguire un fork del progetto e aggiungerlo come altro remoto:

git remote add durdn-vim-surround ssh://git@bitbucket.org/durdn/vim-surround.git

Ora possiamo usare il comando subtree push come segue:

git subtree push --prefix=.vim/bundle/tpope-vim-surround/ durdn-vim-surround main
git push using: durdn-vim-surround main
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 308 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To ssh://git@bitbucket.org/durdn/vim-surround.git
02199ea..dcacd4b dcacd4b21fe51c9b5824370b3b224c440b3470cb -} main

Dopodiché siamo pronti e possiamo aprire una pull request per il responsabile del pacchetto.

Posso farlo senza usare il comando git subtree?

Sì! git subtree è diverso dalla strategia di merge dei sottoalberi. Puoi comunque utilizzare la strategia di merge anche se per qualche motivo git subtree non è disponibile. Ecco come procederesti.

Aggiungi la dipendenza come semplice git remote:

git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git

Prima di leggere il contenuto della dipendenza nel repository, è importante registrare un merge in modo da poter tenere traccia dell'intera cronologia ad albero del plug-in fino a questo punto:

git merge -s ours --no-commit tpope-vim-surround/main

Quali output:

Automatic merge went well; stopped before committing as requested

Quindi abbiamo letto il contenuto dell'ultimo oggetto ad albero nel repository dei plugin nella nostra directory di lavoro, pronto per il commit

git read-tree --prefix=.vim/bundle/tpope-vim-surround/ -u tpope-vim-surround/main

Ora possiamo eseguire il commit, che sarà un commit di merge che conserverà la cronologia dell'albero che leggiamo:

git ci -m"[subtree] adding tpope-vim-surround"
[stree 779b094] [subtree] adding tpope-vim-surround

Quando vogliamo aggiornare il progetto, possiamo estrarlo utilizzando la strategia di merge di git subtree:

git pull -s subtree tpope-vim-surround main

git subtree è un'ottima alternativa

Dopo aver usato i moduli secondari Git per un po', vedrai che git subtree risolve molti problemi con il modulo secondario Git. Come al solito, con tutto ciò che riguarda Git, c'è una curva di apprendimento per sfruttare al meglio la funzionalità.

Dai un'occhiata a questo articolo sui vantaggi di Git subtree.

Consigliata per te

Blog di Bitbucket

Percorso di apprendimento DevOps

Scopri di più su Git

Trova altre guide e risorse su Git in questo hub.