Git si impegna al sottomodulo comune (ramo principale)

Ho due o più progetti (chiamiamoli ProjectFoo e ProjectBar ) con un codice comune che inserisco in un sottomodulo .

La mia comprensione è che se applico le modifiche a un sottomodulo all’interno di ProjectFoo , sarà in una testa distaccata che solo tutti i cloni di ProjectFoo possono vedere:

(master) $ cd ProjectFooBarCommoneSubmodule/ (master) $ git commit -am "Common code fix." (56f21fb0...) $ git push Everything up-to-date 

Questo è probabilmente perché il ramo master non è cambiato. Potrei probabilmente fare qualcosa come git checkout master && git merge Everything up-to-date ma sembra piuttosto brutto. Può essere una git reset --hard master farebbe lo stesso, ma sembra ancora più brutto.

Come avere un codice comune condiviso per progetto, aggiornato da quei progetti che lo utilizzano? In altre parole, il commit su quel sottomodulo dovrebbe aggiornare tutti i vari repository ( repository, non solo cloni ) che usano questo stesso sottomodulo.

—- MODIFICARE —-

Visibilmente il mio repository è stato incasinato e rotto. Dovrebbe funzionare sin dall’inizio come in questo (su ProjectFoo in questo esempio):

 (master) $ cd ProjectFooBarCommoneSubmodule/ (master) $ git commit -am "Common code fix." (master) $ git push .... fbfdd71..0acce63 master -> master (master) $ cd .. (master) $ git add ProjectFooBarCommoneSubmodule (master) $ git commit -m "Submodule update." 

Quindi per ottenere quel cambiamento da altri progetti, come ProjectBar :

 (master) $ cd ProjectFooBarCommoneSubmodule/ (master) $ git pull 

Aggiornarsi all’ultimo codice comune. Potrebbe essere necessario un git checkout master se è su una testa staccata.

Risposta breve:

 cd ProjectFooBarCommoneSubmodule git checkout master  git commit --all -m "Lots of fixes" git push submodule_origin master cd .. git add ProjectFooBarCommoneSubmodule git commit -m "Bumped up the revision of ProjectFooBarCommoneSubmodule" git push origin master 

Quello più lungo:

I sottomoduli Git sono un meccanismo di dipendenza, in cui il progetto principale (ad esempio A) definisce una revisione specificata in un sottoprogetto (ad esempio B), che verrà utilizzato nella costruzione del progetto A. Affinché lo strumento sia utile, il comportamento deve essere prevedibile dal punto di vista di A: s. Le dipendenze non possono cambiare, a meno che qualcuno non decida di incorporare la modifica al progetto A. Potrebbero accadere tutti i tipi di cose brutte, le modifiche del progetto B sono automaticamente importate, di cui gli errori di compilazione sono probabilmente i migliori, in quanto A noterebbe immediatamente i guasti. Questo è il motivo per cui B: s testa è tenuta in stato di distacco.

Lo stato di B è archiviato in A (controlla lo git submodule status ) e una modifica di revisione deve essere eseguita e commessa in A, in modo che possa avere alcun effetto. Questo è ciò che accade nell’esempio sopra, A cambia il numero di revisione memorizzato nel repository e riporta la versione a quella più recente. Il processo dovrà essere ripetuto anche nell’altro repository principale, quindi non utilizzare l’opzione “use master” automatica AFAIK.

BTW. Il capitolo del libro Git sui sottomoduli e la pagina man del sottomodulo contengono molte informazioni utili sui sottomoduli, come pure l’uso normale e le insidie ​​tipiche. Vale la pena dare un’occhiata.


EDIT: cercherò di spiegarlo meglio

Mi sono preso la libertà di creare progetti di esempio sul mio account github . I commit non hanno significato e contengono junk, ma l’installazione dovrebbe andare bene. Si prega di controllare per seguire.

ProjectFoo e ProjectBar condividono entrambi il codice nel sottomodulo comune.

ProjectFooBarCommoneSubmodule: master è 6850e4e4c1fac49de398

In ProjectFoo:

 git submodule status 

-6850e4e4c1fac49de39890703f21486ca04b87a0 comune

In ProjectBar:

 git submodule status 

-6850e4e4c1fac49de39890703f21486ca04b87a0 comune

Quindi entrambi puntano alla stessa revisione, giusto? Il trucco qui è vedere che ProjectFoo e ProjectBar puntano alla revisione (6850e4e4c1fac49de39890703f21486ca04b87a0) non al ramo (master), sebbene siano la stessa cosa. Il primo è un capo distaccato e l’altro un ramo nominato.

Se vuoi fare un po ‘di correzione su ProjectFooBarCommoneSubmodule, puoi andare nella sottodirectory ad es. ProjectFoo e scegliere il ramo al posto della revisione :

 git checkout master  

Quindi vai su una directory e controlla lo stato del sottotitolo git. Dovrebbe dirti che ora sei fuori sincrono. Per esempio

 git submodule status 

+ e24bd2bf45d52171a63b67ac05cd4be0ac965f60 comune (heads / master-1-ge24bd2b)

Ora puoi fare un git add, per impostare il riferimento a questo commit particolare (ge24bd …), fare un commit, e dopo questo il riferimento al sottomodulo punta a questa revisione, che capita anche di essere master su ProjectFooBarCommoneSubmodule.

Ora è necessario aggiornare anche il riferimento in ProjectBar. Vai a ProjectBar / common, ed esegui git fetch origin (questa è una forward forward merge), do

 git checkout master cd .. git add common git commit -m "Bumped up the revision" git push origin master # to publish the revision bump to everybody else 

Quindi, come con qualsiasi repository git, non è necessario lavorare su una testa staccata. Puoi lavorare su master o creare un ramo con nome. Ad ogni modo, assicurati che upstream contenga le modifiche a ProjectFooBarCommoneSubmodule, altrimenti interromperai sia ProjectFoo che ProjectBar, se fanno riferimento a qualcosa che non esiste. Spero che questo l’abbia spiegato meglio

Sul submodule : git push origin HEAD:master

Se vuoi impegnare e spingere tutti i sottomoduli in una sola volta, fai: git submodule foreach 'git commit -a' ; git submodule foreach 'git push --all' ; git commit -a && \ git push --all --recurse-submodules=on-demand git submodule foreach 'git commit -a' ; git submodule foreach 'git push --all' ; git commit -a && \ git push --all --recurse-submodules=on-demand

Per unire le modifiche da HEAD distaccato a master, eseguire:

 git rebase HEAD master 

poi checkout master (usa -f per forza):

 git checkout master 

Se hai diversi sottomoduli da trattare, usa: git submodule foreach , es

 git submodule foreach git pull origin master -r 

Io faccio solo:

git submodule foreach git push -u origin master

Avviso:

 git submodule foreach 'git commit -a' 

fallirà se uno dei sottomoduli non contatterà di impegnarsi.

Per sbarazzarsi di questo, devi forzare il risultato del comando a 0.

 git submodule foreach "git commit -am 'your comment' || echo ' '" 

Usando l’echo pipe si forza l’intero comando a ritornare con 0 e si continua ad eseguire il comando commit sugli altri sottomoduli