Aggiornamento del sottomodulo Git


242

Non sono chiaro cosa significhi quanto segue (dalla documentazione di aggiornamento del sottomodulo Git ):

... farà staccare i sottomoduli HEAD, a meno --rebaseche non --mergesia specificato o ...

In che modo --rebase/ --mergecambia le cose?

Il mio caso d'uso principale è avere un sacco di repository centrali, che inserirò tramite sottomoduli in altri repository. Vorrei poter migliorare questi repository centrali, direttamente nella loro posizione originale, o all'interno dei loro repository di incorporamento (quelli che li usano tramite sottomodulo).

  • Dall'interno di questi sottomoduli, posso creare rami / modifiche e usare push / pull proprio come farei nei normali repository, o ci sono cose di cui fare attenzione?
  • Come farei avanzare il commit del sottomodulo referenziato da dire (taggato) da 1.0 a 1.1 (anche se il capo del repository originale è già a 2.0), o scegliere quale commit del ramo viene usato?

Sull'argomento "testa staccata", vedere anche stackoverflow.com/questions/964876/head-and-orighead-in-git e stackoverflow.com/questions/237408/… per un esempio pratico (non relativo al sottomodulo, ma comunque )
VonC,

"non è possibile modificare il contenuto del sottomodulo dall'interno del progetto principale": sì, vero. E ho modificato la mia risposta per far luce su quell'apparente contraddizione (sottomodulo non modificabile, che è ancora possibile modificare dal repository principale del progetto!)
VonC

Risposte:


304

Questa pagina GitPro riassume bene le conseguenze di un aggiornamento del sottomodulo git

Quando viene eseguito git submodule update, verifica la versione specifica del progetto, ma non all'interno di un ramo. Questo si chiama avere una testa staccata - significa che il file HEAD punta direttamente a un commit, non a un riferimento simbolico.
Il problema è che in genere non si desidera lavorare in un ambiente distaccato, perché è facile perdere le modifiche .
Se esegui un aggiornamento iniziale del sottomodulo, esegui il commit in quella directory del sottomodulo senza creare un ramo su cui lavorare, quindi esegui nuovamente git submodule update dal superprogetto senza impegnarti nel frattempo, Git sovrascriverà le modifiche senza dirtelo. Tecnicamente non perderai il lavoro, ma non avrai un ramo che lo punta, quindi sarà un po 'difficile da recuperare.


Nota marzo 2013:

Come menzionato in " ultimo monitoraggio del sottomodulo git ", un sottomodulo ora (git1.8.2) può tracciare un ramo.

# add submodule to track master branch
git submodule add -b master [URL to Git repo];

# update your submodule
git submodule update --remote 
# or (with rebase)
git submodule update --rebase --remote

Vedi " git submodule update --remotevsgit pull ".

La risposta di MindTooth illustra un aggiornamento manuale (senza configurazione locale):

git submodule -q foreach git pull -q origin master

In entrambi i casi, ciò cambierà i riferimenti dei sottomoduli (il gitlink , una voce speciale nell'indice repo principale ) e sarà necessario aggiungere, eseguire il commit e inviare tali riferimenti dal repository principale.
La prossima volta che clonerai quel repository principale, popolerà i sottomoduli per riflettere quei nuovi riferimenti SHA1.

Il resto di questa risposta descrive in dettaglio la classica funzionalità del sottomodulo (riferimento a un commit fisso , che è il punto centrale dietro l'idea di un sottomodulo).


Per evitare questo problema, crea un ramo quando lavori in una directory di sottomodulo con git checkout -b work o qualcosa di equivalente. Quando esegui l'aggiornamento del sottomodulo una seconda volta, ripristinerai comunque il tuo lavoro, ma almeno hai un puntatore a cui tornare.

Anche cambiare i rami con i sottomoduli può essere complicato. Se si crea un nuovo ramo, aggiungere un sottomodulo lì, e quindi tornare a un ramo senza quel sottomodulo, la directory del sottomodulo rimane comunque come directory non tracciata:


Quindi, per rispondere alle tue domande:

posso creare rami / modifiche e usare push / pull proprio come farei nei normali repository, o ci sono cose di cui fare attenzione?

È possibile creare un ramo e inviare modifiche.

ATTENZIONE (da Git Submodule Tutorial ): pubblicare sempre (push) la modifica del sottomodulo prima di pubblicare (push) la modifica nel superprogramma che la fa riferimento. Se si dimentica di pubblicare la modifica del sottomodulo, gli altri non saranno in grado di clonare il repository.

come avanzerei il commit del sottomodulo referenziato da dire (taggato) da 1.0 a 1.1 (anche se il capo del repository originale è già a 2.0)

La pagina " Comprensione dei sottomoduli " può essere d'aiuto

I sottomoduli Git sono implementati usando due parti mobili:

  • il .gitmodulesfile e
  • un tipo speciale di oggetto ad albero.

Questi insieme triangolano una revisione specifica di un repository specifico che viene estratto in una posizione specifica nel progetto.


Dalla pagina del sottomodulo git

non è possibile modificare il contenuto del sottomodulo dall'interno del progetto principale

100% corretto: non è possibile modificare un sottomodulo, fare riferimento solo a uno dei suoi commit.

Ecco perché, quando modifichi un sottomodulo dall'interno del progetto principale, tu:

  • è necessario eseguire il commit e l'invio all'interno del sottomodulo (al modulo upstream) e
  • quindi passa al progetto principale e esegui nuovamente il commit (affinché quel progetto principale faccia riferimento al nuovo commit del sottomodulo appena creato e inviato)

Un sottomodulo consente di avere uno sviluppo di approccio basato su componenti , in cui il progetto principale fa riferimento solo a commit specifici di altri componenti (qui "altri repository Git dichiarati come sottomoduli").

Un sottomodulo è un marker (commit) in un altro repository Git che non è vincolato dal ciclo di sviluppo del progetto principale: esso (l '"altro" repository Git) può evolversi indipendentemente.
Spetta al progetto principale scegliere dall'altro repository qualsiasi impegno di cui abbia bisogno.

Tuttavia, se desideri, per comodità , modificare uno di quei sottomoduli direttamente dal tuo progetto principale, Git ti consente di farlo, a condizione che tu prima pubblichi quelle modifiche del sottomodulo al suo repository Git originale e quindi esegua il commit del tuo progetto principale facendo riferimento a una nuova versione di detto sottomodulo.

Ma l'idea principale rimane: fare riferimento a componenti specifici che:

  • hanno il loro ciclo di vita
  • hanno il proprio set di tag
  • hanno il loro sviluppo

L'elenco di specifici commit a cui ti riferisci nel tuo progetto principale definisce la tua configurazione (questo è il concetto di Configuration Management, che comprende il semplice sistema di controllo versione )

Se un componente potesse davvero essere sviluppato contemporaneamente al tuo progetto principale (poiché qualsiasi modifica al progetto principale implicherebbe la modifica della sottodirectory e viceversa), non sarebbe più un "sottomodulo", ma un subtree merge (presentato anche nella domanda Trasferimento legacy code base da cvs a repository distribuito ), collegando insieme la cronologia dei due repository Git.

Ciò aiuta a comprendere la vera natura dei sottomoduli Git?


77
Wow. Una spiegazione così lunga per qualcosa che è principalmente così semplice dovrebbe essere sufficiente per spaventare qualsiasi nuovo arrivato a rimanere fedele al proprio svn: gli esterni. ;-)
conny

2
@conny: ma, come dettagliato in " Perché i sottomoduli git sono incompatibili con gli svn esterni? ", i sottomoduli sono fondamentali diversi e non compatibili svn:externals.
VonC,

1
Mi dispiace, per rispondere alla mia domanda, raccolgo il cd nel sottomodulo e eseguo il checkout di uno sha, oppure git pull / fetch andrà bene. Quindi eseguire il commit dell'aggiornamento nel repository locale.
Henrik

2
@hced: puoi anche colpire tutti i sottomoduli contemporaneamente usandogit submodule foreach
Dav Clark il

1
.. ancora non capisco. c'è una spiegazione più semplice sul web da qualche parte?
Eugene,

135

Per aggiornare ciascun sottomodulo, è possibile richiamare il comando seguente (nella radice del repository):

git submodule -q foreach git pull -q origin master

È possibile rimuovere l' opzione -q per seguire l'intero processo.


15
Se corri git submodule update --init --recursivedalla radice, li otterrà tutti ricorsivamente e li inizializzerà se non lo sono già.
Sam Soffes,

10
@SamSoffes Questo ha uno scopo completamente diverso. Sottomoduli Aggiornamento potranno controllare i moduli presso il commit sono attualmente rivolte a (non necessariamente l'ultima commit). La soluzione nella risposta precedente aggiorna il commit di ciascun sottomodulo all'ultima HEAD da origin / master.
indragie

7
Il mio nuovo metodo:git submodule update --rebase --remote
MindTooth,

19

Per affrontare l' opzione --rebasevs --merge.:

Diciamo che hai un super repository A e un sottomodulo B e vuoi fare qualche lavoro nel sottomodulo B. Hai fatto i compiti e sai che dopo aver chiamato

git submodule update

sei in uno stato senza TESTA, quindi qualsiasi impegno che fai a questo punto è difficile tornare a. Quindi, hai iniziato a lavorare su una nuova filiale nel sottomodulo B

cd B
git checkout -b bestIdeaForBEver
<do work>

Nel frattempo, qualcun altro nel progetto A ha deciso che l'ultima e la più grande versione di B è davvero ciò che A merita. Tu, per abitudine, unisci le modifiche più recenti e aggiorna i tuoi sottomoduli.

<in A>
git merge develop
git submodule update

Oh no! Sei di nuovo in uno stato senza testa, probabilmente perché B sta ora indicando lo SHA associato al nuovo suggerimento di B, o qualche altro commit. Se solo tu avessi:

git merge develop
git submodule update --rebase

Fast-forwarded bestIdeaForBEver to b798edfdsf1191f8b140ea325685c4da19a9d437.
Submodule path 'B': rebased into 'b798ecsdf71191f8b140ea325685c4da19a9d437'

Ora l'idea migliore di sempre per B è stata riadattata al nuovo commit e, cosa più importante, sei ancora nel tuo ramo di sviluppo per B, non in uno stato senza testa!

( --mergeUniranno le modifiche da beforeUpdateSHA a afterUpdateSHA nel tuo ramo di lavoro, invece di riassegnare le modifiche a afterUpdateSHA.)


7

Git 1.8.2 presenta una nuova opzione --remote, che abiliterà esattamente questo comportamento. In esecuzione

git submodule update --rebase --remote

recupererà le ultime modifiche dall'upstream in ciascun sottomodulo, le riforme e verificherà l'ultima revisione del sottomodulo. Come dice la documentazione :

--a distanza

Questa opzione è valida solo per il comando di aggiornamento. Invece di utilizzare lo SHA-1 registrato del superprogetto per aggiornare il sottomodulo, utilizzare lo stato del ramo di tracciamento remoto del sottomodulo.

Ciò equivale a funzionare git pullin ogni sottomodulo, che è generalmente esattamente quello che vuoi.

(Questo è stato copiato da questa risposta .)


Se decidi di rispondere a una domanda precedente con risposte ben definite e corrette, l'aggiunta di una nuova risposta a fine giornata potrebbe non farti ottenere alcun credito. Se hai alcune nuove informazioni distintive o sei convinto che le altre risposte siano tutte sbagliate, aggiungi sicuramente una nuova risposta, ma "l'ennesima risposta" fornisce le stesse informazioni di base molto tempo dopo che la domanda è stata generalmente vinta " ti guadagno molto credito. Non c'è spiegazione di ciò che fa - nemmeno un collegamento a documentazione esterna (che non sarebbe sufficiente).
Jonathan Leffler,

2
Non è "ancora un'altra risposta", in quanto NESSUNA altra risposta ha questo comando (dimostrami che ho torto). Altre risposte non hanno funzionato per me, questo commento ha fatto, quindi ho deciso di pubblicarlo come risposta dando credito al proprietario originale. Quindi considera di rimuovere il tuo downvote.
Iulian Onofrei il

C'è un commento di MindTooth del 2015 che dice che è quello che fanno adesso. Non dai alcuna spiegazione di ciò che fa (anche se menzioni MindTooth, ma non esiste una vera spiegazione di ciò che intendi con questo - l'incorporamento di URL, come in questo commento, sarebbe di aiuto). Non dici perché è una buona idea. Non dare alcun avvertimento. A mio avviso, questa non è una risposta utile perché solleva più domande di quante ne risolva.
Jonathan Leffler il

1
Con ciò intendevo dire che funziona invece di non funzionare. Credetemi, se più persone vedessero questa risposta, sarebbero contente, perché funziona . Per cose come questa, la maggior parte delle persone vuole semplicemente conoscere il comando che aggiorna un sottomodulo git, non come è implementato.
Iulian Onofrei il

Ho modificato la risposta per dimostrare che hai torto, inoltre, stackoverflow.com/questions/1979167/git-submodule-update/… !!!
Iulian Onofrei il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.