2010-08-28 14 views
46

Ho due o più progetti (chiamiamoli ProjectFoo e ProjectBar) avendo qualche codice comune che ho messo in un modulo .Git impegnano a modulo comune (branch master)

mia comprensione è che se commetto modifiche a un modulo dall'interno ProjectFoo sarà in una testa indipendente che solo tutti ProjectFoo cloni possono vedere:

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

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

Come avere un codice comune condiviso dal progetto, aggiornato dall'interno di per i progetti che lo utilizzano? In altre parole, l'invio a quel sottomodulo dovrebbe aggiornare tutti i vari repository (repository , non solo cloni) che utilizzano questo stesso sottomodulo.

---- ---- EDIT

Visibilmente mio repository il check-out era incasinato e rotti. Esso dovrebbe avere lavorato fin dall'inizio del genere (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." 

Poi per ottenere quel cambiamento da su altri progetti, come ProjectBar:

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

Would aggiorna all'ultimo codice comune. A git checkout master potrebbe essere richiesto se si trova su una testa staccata.

risposta

60

Risposta breve:

cd ProjectFooBarCommoneSubmodule 
git checkout master 
<Do your editing> 
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:

Git sottomoduli sono un meccanismo di dipendenza, dove il progetto principale (ad esempio A) definisce una revisione specificata in un sottoprogetto (dicono B), che verrà utilizzato nel progetto di costruzione 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 è memorizzato in A (vedere git submodule status) e una modifica di revisione deve essere eseguita e confermata in A, affinché abbia 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. Lo Git book chapter on submodules e lo submodule man page contengono molte informazioni utili sui sottomoduli, come pure l'uso normale e le insidie ​​tipiche. Vale la pena dare un'occhiata.


EDIT: Cercherò di spiegare meglio questo

ho preso la libertà di creare progetti di esempio su my github account. I commit non hanno significato e contengono junk, ma l'installazione dovrebbe andare bene. Si prega di controllare per seguire.

Sia ProjectFoo che ProjectBar condividono 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 si desidera eseguire il fissaggio su ProjectFooBarCommoneSubmodule, è possibile passare alla sottodirectory ad es. ProjectFoo, e scegliere il ramo al posto della revisione:

git checkout master 
<Do your coding and pushing here> 

andare Poi una directory, e controllare lo stato git modulo. Dovrebbe dirti che ora sei fuori sincrono. Ad esempio

git submodule status 

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

Ora si può fare un git add, per impostare il riferimento a questa particolare commit (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/comuni, e fare git fetch origine (questo è un avanzamento rapido merge), fare

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 

Così, 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 ha spiegato meglio

+0

Grazie, ho visto che il capitolo. Purtroppo non ho trovato una risposta chiara alla mia domanda. Tu dici che non esiste un master per l'uso automatico, quindi cosa succede se un sottoprogetto comune, diciamo una libreria, aggiorna? Non è un 'aggiornamento del sottomodulo git' per aggiornare tutti i progetti che si basano su quella libreria? Mi piacerebbe fare lo stesso, ma aggiornare quella libreria direttamente da qualsiasi mio progetto principale. Se questo non è possibile, quale sarebbe l'alternativa? – Wernight

+0

I repository Git non contengono alcuna informazione su chi li ha clonati. Questo è il motivo per cui è impossibile trasferire le modifiche a tutti i cloni. Semplificando le cose, penso che ti aspetti qualcosa di simile ai link simbolici, quindi qualsiasi cosa verrebbe propagata immediatamente, mentre i cloni sono più simili a "tar, gzip, copy, unzip". Probabilmente la chiave è semplicemente pubblicare il numero di revisione modificato in Foo e Bar. Chiunque prelevi le modifiche vedrà il numero di revisione modificato la volta successiva. Qualunque cosa migliore di quella, direi, no. Sarei felice di essere smentito in questo, però. –

+0

I cloni sicuri devono effettuare un aggiornamento o tirare manualmente. La mia domanda è, come? Due progetti, non i cloni, che condividono un codice comune in un sottomodulo Git. C'è qualche altra scelta che ProjectFoo impegna il sottomodulo alla testa staccata, quindi ProjectBar (NON un clone) unisce le modifiche (se ciò è possibile, non so dove sono memorizzate). – Wernight

2

Sul submodule: git push origin HEAD:master

0

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

0

Per unire modificata da testa staccata in maestro, eseguire:

git rebase HEAD master 

maestro poi checkout (uso -f per forza):

git checkout master 

Se hai più sottomoduli da trattare, utilizza: git submodule foreach, ad es.

git submodule foreach git pull origin master -r 
0

Io proprio:

git submodule foreach git push -u origin master