Lavorare su un ramo con una dipendenza da un altro ramo in fase di revisione


65

In che modo git aiuta a gestire lo scenario seguente:

Ho un'attività suddivisa in 2 parti: attività backend e attività frontend. Faccio una richiesta pull per unire le modifiche del backend e aspetto che vengano unite (e indirizzo il feedback). Durante l'attesa, non riesco davvero a lavorare sulle modifiche del front-end perché dipende dalle modifiche del back-end e quelle non sono ancora disponibili sul ramo master.

Qual è il modo migliore per inserire le modifiche nel ramo delle modifiche del front-end dal ramo delle modifiche del back-end mentre è ancora in fase di revisione?


14
Di solito, le interfacce del progetto di back-end dovrebbero essere chiaramente definite. Quindi, quando si avvia l'implementazione del front-end, non dovrebbe disturbarti, se la logica del back-end viene comunque rivista, poiché è possibile utilizzare un modello.
Herr Derb,

17
@HerrDerb Oh dolce estate bambina ...
gardenhead,

4
Perché non puoi scriverlo con il tuo codice backend non ancora recensito?
user253751

Il tuo team ha una sorta di tecnica concordata per gestire questa situazione? Altrimenti, forse dovresti essere d'accordo su qualcosa del genere, dal momento che è una situazione abbastanza comune.
Radu Murzea,

Non c'è nessuno. Questo è il motivo per cui ho posto questa domanda. Ho ricevuto ottimi suggerimenti. Proverò i suggerimenti e vedrò come funzionano per me.
sul4bh,

Risposte:


42

Ho questo problema anche a volte. Git è molto flessibile. Ecco un modo per farlo.

Il tuo primo ramo featureAè in attesa di revisione.

Il tuo secondo ramo featureBè in sviluppo e dipende dal codice nel featureAramo.

Unisci il featureAramo nel featureBramo.

Se si apportano modifiche al featureAramo, è necessario unire nuovamente il featureAramo nel featureBramo per incorporare le modifiche.

Dovresti anche assicurarti di unirti featureAper primo al trunk principale, altrimenti quando ti unisci featureBal trunk principale, inavvertitamente ti unirai featureA. Una volta che featureAviene unito al tronco principale, puoi liberarti del featureAramo poiché featureBora dipende solo dal tronco principale.

Lo preferisco quando i rami delle mie funzioni non dipendono l'uno dall'altro, ma a volte lo fanno e devi farlo.


Questo ha senso. Ciò consente di annullare la fusione di featureAinto featureBse necessario?
Sul4bh,

8
Non ci sono operazioni di annullamento, ma come menzionato da @ 9000, potresti creare una nuova filiale e scegliere ciliegia dai commit che desideri featureAse dovessi ricominciare da capo. È bene pensare ai rami Git come usa e getta. Sono economici e facili, puoi sempre creare una nuova filiale. Potresti anche creare un ramo di prova dal tuo featureBramo se volessi giocare con qualcosa di cui non eri sicuro, e poi scartarlo se non ha funzionato, o fonderlo di nuovo nel tuo featureBramo se lo ha fatto.
Matt,

9
La fusione creerà un disordine che sarà difficile (non impossibile) da ripristinare. Reather cherry-pick o rebase (es: cherry-pick tutto nella funzione A alla base della funzione B). Vedi la risposta di 9000.
Pierre.Sassoulas,

1
Questo crea una storia complessa che sarà un problema per molti anni a venire ogni volta che qualcuno vuole capire quale codice è stato modificato per la funzione A e la funzione B
Ian

2
se la funzione A viene aggiornata, la funzione B deve essere riformulata non unita
Lyndon White,

42

Aspetta, salta l'unione

Per questo approccio, che non non desidera unire la vostra feature_ain feature_bpiù volte.

Il rifacimento è stato menzionato in altre risposte, ma solo per ripassare le cose master. Quello che vuoi fare nel tuo caso è:

  • Inizia feature_bda feature_a, cioè:

    git checkout feature_a
    git checkout -b feature_b
    
  • Ogni volta che feature_acambia mentre è in attesa di essere unito master, ti rifai feature_b su di esso:

    ... commit something onto feature_a ...
    git checkout feature_b
    git rebase feature_a
    
  • Alla fine, non appena feature_aè stato unito master, si ottiene semplicemente il nuovo mastere si reinserisce feature_asu di esso un'ultima volta:

    git checkout master
    git pull origin master
    git checkout feature_b
    git rebase --onto master feature_a feature_b
    

    Questo rebase finale innesterà tutti i commit che pendono dal feature_acommit (che ora è irrilevante in quanto è stato unito master) direttamente master. feature_bOra il tuo è un ramo semplice e standard che parte proprio da master.

EDIT: ispirato ai commenti, un po 'a testa alta: se hai bisogno di apportare qualche modifica che influisce su entrambe le funzionalità, assicurati di farlo feature_a(e poi rifare come mostrato). Non non farlo in due commit diverse nei due rami, anche se può essere tentati; come feature_afa parte della storia di feature_b, avere il singolo cambiamento in due diversi commit sarà semanticamente sbagliato e probabilmente porterà a conflitti o "resurrezioni" di codice indesiderato, in seguito.


2
Con il rebasing su feature_apiù volte, potresti incorrere in problemi in seguito, quando feature_anel frattempo è stato riformulato. Come risultato della corsa git checkout feature_b; git rebase feature_apotresti avere conflitti o alcuni commit divertenti contenenti commit che ripristinano nuove modifiche di feature_a. Questo di solito è risolvibile usando --interactivee saltando i commit presi dalla vecchia versione dell'altro ramo (ho dovuto farlo più volte di recente).
maaartinus,

@maaartinus, grazie per l'heads-up, non ho riscontrato problemi di questo genere. Come rebasemolti più passaggi individuali di un semplice merge, c'è sicuramente una possibilità visivamente più alta per creare conflitti; d'altra parte mergesarebbe semanticamente abbastanza sbagliato fare in questo caso.
AnoE,

Immagino che mergeavrebbe problemi simili o peggiori (un conflitto non è così grave come entrare in un cambiamento indesiderato). Vedo un ramo come una sequenza di modifiche desiderate precedute da molte modifiche non correlate (logicamente appartenenti a un ramo diverso). Quando eseguo ripetutamente il rebasing con lo stesso ramo, rimuovo sempre le modifiche non correlate poiché so che arriveranno comunque (possibilmente in una forma aggiornata) e funziona bene.
maaartinus,

1
@maaartinus, ho aggiunto un piccolo addendum al riguardo (per apportare costantemente modifiche che devono andare in entrambi i rami solo nel ramo base, non in due diversi commit).
AnoE

Bella tecnica. È così che lo faccio sempre. git rebase --ontoFTW: D
Radu Murzea,

29

Hai già un ramo da cui dipende ogni ramo di ogni funzione e che continua a cambiare. Si chiama master.

Il modo tipico di un ramo di caratteristica di rimanere in sincronia con masterè di rimanere in cima di esso. Quando mastercambia, normalmente si trova git fetch origin master:master && git rebase masternella directory di lavoro della propria filiale.

Puoi fare la stessa cosa con un altro ramo di funzionalità: continua a recuperarlo e riemerlo sopra di esso.

Se, per qualche motivo, dovessi spostare le modifiche in un altro ramo, puoi selezionare i tuoi commit, che non sono mai mescolati con i commit di altri rami.


Ma penso che lo scenario sia che la funzione-b abbia bisogno del codice che si trova nella funzione-a, la ramificazione dal master non sarà molto utile. Dove dovrei iniziare? Devo diramare da feature-a e mantenerli sincronizzati fino a quando feature-a viene reintegrato con master, e quindi passare da master a feature-b?
Sinaesthetic

@Sinaesthetic: si può di corso base feature-bsu feature-a, e fare un tempo rebase in volta come feature-asta cambiando. Questo è un modo tipico per rendere osservabile un grande cambiamento: suddividerlo in part-A(basato su master), part-B(basato su part-A) e altro se necessario. Quindi fai una richiesta pull per ogni parte e i revisori hanno più tempo a guardare pezzi più piccoli, raggruppati logicamente.
9000,

importerà se cambio la parte b con la parte a contro la parte b con il master in termini di PR? Voglio solo assicurarmi che le mie modifiche non mostrino le modifiche della parte A come modifiche nella parte b. Inoltre, se unisco contro rebase, che effetto avrà sulla PR della parte b? Ogni volta che penso di capire gli effetti, ottengo alcuni risultati diversi lol
Sinaesthetic

5

In questo caso in cui l'attività front-end ha una dipendenza critica dal codice back-end e si desidera iniziare a lavorare sul front-end prima che il back-end sia finalizzato e accettato sul master, semplicemente inizierei l'attività front-end come un ramo di funzionalità che viene fuori dal ramo backend, anziché ramificare il frontend sul master.

Un ramo di funzionalità che dura abbastanza a lungo deve fondersi in cambiamenti dal master occasionalmente (per assicurarsi di riconciliare qualsiasi unione o conflitto semantico come parte del lavoro di sviluppo sul ramo di funzionalità, piuttosto che come parte di "review, qa, merge- "master"). Quindi lo fai sul tuo ramo front-end e quando il lavoro di back-end è stato accettato come master, otterrai automaticamente le modifiche minori al back-end come parte della sua revisione / accettazione, lungo lo stesso percorso che avresti ottenere eventuali altre modifiche al codice sul master.

Se si scopre che il ramo back-end ha bisogno di molto più lavoro e continua a cambiare per un periodo di tempo prima di essere unito al master (ad esempio se si riscontrano problemi importanti durante la revisione), allora probabilmente si vorrebbe fare fusioni periodiche direttamente dal ramo backend al ramo frontend (in modo da non continuare a basare tutto il tuo lavoro frontend su codice backend obsoleto). Questo è facile se sei l'unico sviluppatore a fare entrambe le funzionalità (dal momento che sai se tu stesso apporti modifiche importanti), ma anche se entrambe le funzionalità finiscono per essere lavorate in parallelo da diversi sviluppatori, dovrebbe andare bene; devi solo rimanere in comunicazione (cosa che dovresti comunque fare, se stai lavorando su compiti in parallelo in cui uno ha una dipendenza critica dall'altro).

Se si scopre che l'intero ramo di backend deve essere abbandonato e non verrà mai unito (sembra che questo sarebbe un affare piuttosto importante che accadrebbe raramente), allora o scegli con cura i tuoi impegni in un nuovo ramo che esce dal master senza il lavoro di backend oppure si applicano commit inversi che rimuovono tutto il codice di backend nel ramo frontend. Ma come posso vedere, sarebbe più probabile mettere in pausa il lavoro del frontend fino a quando non capiresti cosa avrebbe sostituito il backend che stai buttando, e poi decidere cosa fare.


2

Non vedo il problema qui.

Lo hai già fatto ogni volta con il tuo masterramo, che continua a cambiare mentre le funzionalità vengono sviluppate e poi unite.

Quindi, nel tuo esempio concreto, devi prima creare il feature_xxx_backendramo e sviluppare le modifiche al back-end. Al termine, il ramo deve essere riesaminato e verrà unito in masteruna volta completata la revisione.

Quindi, è sufficiente avviare un altro ramo, feature_yyy_frontend. Probabilmente vorrai diramare direttamente feature_xxx_backend, in modo da avere quelle modifiche già nel tuo branc. quindi semplicemente sviluppare la funzionalità di frontend come fosse il ramo master.

Quando il feature_xxx_backendramo cambia, ad esempio perché durante la revisione ci sono cose che devono essere affrontate, è sufficiente apportare queste modifiche e unirle nel feature_yyy_frontendramo. Quindi continua sul ramo frontend.

Una volta completata la revisione del ramo back-end, viene unita master. A questo punto, sarebbe saggio rifare il feature_yyy_frontendramo su master, in modo che i revisori debbano solo rivedere le nuove modifiche a cui contribuisce questo ramo mastere non è necessario rivedere le modifiche apportate per il back-end (che sono già state approvate ).

Questo può essere fatto anche quando hai due, tre o più rami dipendenti. Se hai due rami di funzionalità su cui contare, crea semplicemente un ramo derivato in cui entrambe le funzioni sono state unite. Ramo da lì, sviluppa la terza funzione, unisci entrambi i rami di funzionalità lungo la strada quando ognuno di essi cambia. Quando entrambe le funzionalità sono terminate e vengono unite nel ramo derivato, si rifanno su quello o se si uniscono nel master, si rifanno al master.

Il rebasing (come suggerito sopra) è davvero potente e aiuta a tenere un registro pulito delle modifiche, rendendo le recensioni molto più facili.


2

Come menzionato Polygnome, puoi effettivamente unire il tuo ramo frontend con il tuo ramo backend invece che con i master. Anche con l'attuale configurazione del ramo che hai ora, puoi semplicemente fare:

git checkout frontend
git merge backend

o semplicemente

git merge backend frontend

Tieni presente, tuttavia, che se le modifiche al back-end non vengono accettate ed è necessario ulteriore lavoro, dovrai evitare gli aggiornamenti dal back-end al front-end per evitare conflitti. Una volta che le modifiche sono state accettate nel master, puoi modificare il frontend sul master per eliminare i commit di unione back-end.

Tecnicamente potresti anche fare tutto con rebase, ma ciò rovinerà la cronologia di commit del tuo ramo frontend. Da dove vengo, questa è considerata una cattiva pratica. YMMV


"Strano che nessuno abbia menzionato che puoi effettivamente unire il tuo ramo frontend con il tuo ramo backend invece che con i master:" Questo è già stato menzionato, ad esempio nella mia risposta.
Polygnome,

Il frontend @Polygnome non deve essere ramificato direttamente dal backend. Entrambi possono essere ramificati anche dal master, ma puoi comunque unirli. Quindi la tua risposta non lo menziona in realtà.
Joris Meys,

In realtà, la mia risposta non suggerisce che ti dirigi direttamente dal backend, ma solo che è probabilmente la strada da percorrere (dal momento che unisci quelle modifiche nel ramo frontend comunque).
Polygnome,

@Polygnome poi ho frainteso la tua risposta. Aggiornato appositamente per te :-)
Joris Meys,

Non so chi abbia votato in negativo, ma per favore dimmi dove sbaglio, così posso imparare anche qualcosa.
Joris Meys,

1

La maggior parte delle risposte qui descrivono correttamente il processo di fusione delle modifiche dal secondo ramo al primo, ma non affrontano come minimizzare la quantità di conflitti che potrebbe essere necessario risolvere.

Ogni volta che hai due serie di grandi cambiamenti che vuoi rivedere individualmente (come featureAe featureB), crea un PR che NON è pensato per essere unito, ma per raccogliere feedback in anticipo su un PoC di featureA.

Le persone saranno in grado di esaminarlo rapidamente (è solo un PoC) e l'obiettivo è convalidare il design o l'approccio generale.

Quindi, puoi continuare a lavorare sulla funzione A, creare una richiesta pull per esso e diramare e lavorare sulla funzione B.

La grande differenza è che ora puoi aspettarti featureAdi non cambiare radicalmente: il design e l'approccio sono già stati validati. La revisione del codice e le modifiche richieste possono essere impercettibili e locali piuttosto che "guai, è necessario un approccio diverso". Ciò ridurrà al minimo la quantità di lavoro che è necessario eseguire in seguito per unire featureBil featureAcodice, indipendentemente dal metodo scelto.

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.