Nel flusso di lavoro fondamentale di Git, sviluppi una nuova funzione in un ramo argomento dedicato, quindi uniscilo in un ramo di produzione una volta terminato. Questo fa git si fondono
uno strumento integrale per combinare i rami. Tuttavia, non è l'unico che Git offre.
In alternativa allo scenario di cui sopra, è possibile combinare i rami con il git rebase
comando. Invece di legare i rami con un commit di unione, ribasamento sposta l'intero ramo della funzione sulla punta di maestro
come mostrato di seguito.
Questo ha lo stesso scopo di git si fondono
, integrare i commit da diversi rami. Ma ci sono due motivi per cui potremmo desiderare di optare per un rebase su un'unione:
In questo tutorial, esploreremo questi due casi di utilizzo comune di git rebase
. Sfortunatamente, i benefici di git rebase
venire a un trade-off. Se utilizzato in modo errato, può essere una delle operazioni più pericolose che è possibile eseguire in un repository Git. Quindi, daremo anche uno sguardo attento ai pericoli della ribasatura.
Questo tutorial presume che tu abbia familiarità con i comandi Git di base e i flussi di lavoro di collaborazione. Dovresti essere comodo mettere in scena e commettere istantanee, sviluppare funzionalità in rami isolati, unire rami e spingere / tirare rami da / verso repository remoti.
Il primo caso d'uso che esploreremo riguarda una storia di progetto divergente. Considera un repository in cui il tuo ramo di produzione si è spostato mentre stavi sviluppando una funzionalità:
Per rebase il caratteristica
ramo sul maestro
ramo, dovresti eseguire i seguenti comandi:
git checkout feature git rebase master
Questo trapianta il caratteristica
ramo dalla sua posizione attuale alla punta del maestro
ramo:
Ci sono due scenari in cui vorresti farlo. Innanzitutto, se la funzione si basa sul nuovo commit in maestro
, ora avrebbe accesso a loro. In secondo luogo, se la funzionalità fosse completa, ora verrebbe configurata per l'unione rapida in avanti maestro
. In entrambi i casi, i risultati di rebasing in una cronologia lineare, mentre git si fondono
comporterebbe inutili commit di unione.
Ad esempio, considera cosa accadrebbe se integri il commit upstream con un'unione anziché un rebase:
git checkout feature git merge master
Questo ci avrebbe dato un ulteriore commit di merge in caratteristica
ramo. Inoltre, ciò accadrebbe ogni volta che volessi incorporare i commit upstream nella tua funzione. Alla fine, la cronologia del tuo progetto sarebbe piena di commit di fusione senza significato.
Questo stesso vantaggio può essere visto quando si fonde nella direzione opposta. Senza un rebase, integrando il finito caratteristica
ramo in maestro
richiede un merge commit. Sebbene si tratti di un commit merge significativo (nel senso che rappresenta una funzionalità completata), la cronologia risultante è piena di fork:
Quando esegui il rebase prima della fusione, Git è in grado di avanzare rapidamente maestro
alla punta di caratteristica
. Troverai una storia lineare di come il tuo progetto è progredito nel log git
uscita: il commit in caratteristica
sono ordinatamente raggruppati in cima ai commit in maestro
. Questo non è necessariamente il caso quando i rami sono legati insieme con un commit di unione.
Quando corri git rebase
, Git prende ogni commit nel ramo e li sposta, uno alla volta, sulla nuova base. Se uno di questi commuta altera la stessa linea (e) di codice che l'upstream commette, provocherà un conflitto.
Il git si fondono
comando ti consente di risolvere tutti i conflitti del ramo alla fine dell'unione, che è uno degli scopi principali di un commit di unione. Tuttavia, funziona un po 'diversamente quando si ridefinisce. I conflitti vengono risolti in base al commit. Quindi se git rebase
trova un conflitto, interromperà la procedura di rebase e visualizzerà un messaggio di avviso:
Fusione automatica readme.txt CONFLICT (contenuto): Unisci conflitto in readme.txt Impossibile unire le modifiche ... Dopo aver risolto questo problema, eseguire "git rebase --continue". Se preferisci saltare questa patch, lancia "git rebase --skip". Per controllare il ramo originale e smettere di rebasare, esegui "git rebase --abort".
Visivamente, questa è la storia del tuo progetto quando git rebase
incontra un conflitto:
I conflitti possono essere controllati eseguendo stato git
. L'output sembra molto simile a un conflitto di unione:
Percorsi non raggruppati: (utilizzare "git reset HEAD... "per togliere il palco) (usa" git add ... "per contrassegnare la risoluzione) entrambi modificati: readme.txt nessuna modifica aggiunta al commit (utilizzare" git add "e / o" git commit -a ")
Per risolvere il conflitto, apri il file in conflitto (readme.txt nell'esempio precedente), trova le linee interessate e modificale manualmente sul risultato desiderato. Quindi, comunica a Git che il conflitto viene risolto mettendo in scena il file:
git aggiungi readme.txt
Si noti che questo è esattamente lo stesso modo in cui si segna a git si fondono
conflitto come risolto. Ma ricorda che sei nel mezzo di un rebase - non vuoi dimenticare il resto dei commit che devono essere spostati. L'ultimo passo è dire a Git di finire con il rebasing --Continua
opzione:
git rebase --continue
Questo sposterà il resto dei commit, uno alla volta, e se sorgono altri conflitti, dovrai ripetere questo processo da capo.
Se non vuoi risolvere il conflitto, puoi optare per il --Salta
o --abortire
bandiere. Quest'ultimo è particolarmente utile se non hai idea di cosa sta succedendo e vuoi solo tornare in sicurezza.
# Ignora il commit che ha causato il conflitto git rebase --skip # Interrompe l'intero rebase e torna alla scheda di disegno git rebase --abort
Finora, abbiamo solo usato git rebase
spostare rami, ma è molto più potente di quello. Passando il -io
flag, è possibile iniziare una sessione di rebasing interattiva. Il rebasing interattivo consente di definire con precisione come ogni commit verrà spostato nella nuova base. Questo ti dà l'opportunità di ripulire la cronologia di una funzione prima di condividerla con altri sviluppatori.
Ad esempio, diciamo che hai finito di lavorare sul tuo caratteristica
filiale e tu sei pronto per integrarlo maestro
. Per iniziare una sessione di rebasing interattiva, eseguire il seguente comando:
git checkout feature git rebase -i master
Questo aprirà un editor contenente tutti i commit in caratteristica
che stanno per essere spostati:
selezionare 5c43c2b [Descrizione per il commit più vecchio] selezionare b8f3240 [Descrizione per il secondo commit più vecchio] selezionare c069f4a [Descrizione per il commit più recente]
Questo elenco definisce ciò che il caratteristica
il ramo avrà l'aspetto dopo il rebase. Ogni riga rappresenta un commit e il raccogliere
comando prima che ogni hash del commit definisca cosa gli succederà durante il rebase. Si noti che i commit sono elencati dal più vecchio al più recente. Modificando questo elenco, ottieni il controllo completo sulla cronologia del tuo progetto.
Se si desidera modificare l'ordine dei commit, è sufficiente riordinare le righe. Se vuoi cambiare il messaggio di un commit, usa il esprimere con altre parole
comando. Se si desidera combinare due commit, modificare il raccogliere
comando a schiacciare
. Questo farà rotolare tutte le modifiche in quel commit in quella sopra. Ad esempio, se hai schiacciato il secondo commit nell'elenco precedente, il caratteristica
ramo sarebbe simile al seguente dopo aver salvato e chiuso l'editor:
Il modificare
il comando è particolarmente potente. Quando raggiunge il commit specificato, Git interromperà la procedura di rebase, proprio come quando incontra un conflitto. Questo ti dà l'opportunità di modificare il contenuto del commit con git commit --amend
o addirittura aggiungere più commit con lo standard aggiungi git
/Git commit
comandi. Ogni nuovo commit che aggiungi farà parte del nuovo ramo.
Il rebasing interattivo può avere un impatto profondo sul flusso di lavoro dello sviluppo. Invece di preoccuparti di suddividere le tue modifiche in commit incapsulati, puoi concentrarti sulla scrittura del tuo codice. Se si finisce per commettere ciò che dovrebbe essere una singola modifica in quattro snapshot separati, allora non si tratta di un problema: riscrivere la cronologia con git rebase -i
e li schiaccia tutti in un unico impegno significativo.
Ora che hai una comprensione git rebase
, possiamo parlare di quando non usarlo. Internamente, il rebasing non sposta effettivamente i commit in un nuovo ramo. Invece, crea nuovi commit che contengono le modifiche desiderate. Con questa idea, il rebasing è meglio visualizzato come segue:
Dopo il rebase, il commit in caratteristica
avrà diversi hash di commit. Ciò significa che non abbiamo semplicemente riposizionato un ramo: abbiamo letteralmente riscritto la cronologia del nostro progetto. Questo è un effetto collaterale molto importante di git rebase
.
Quando lavori da solo su un progetto, riscrivere la cronologia non è un grosso problema. Tuttavia, non appena inizi a lavorare in un ambiente collaborativo, può diventare molto pericoloso. Se riscrivi le commit che altri sviluppatori stanno utilizzando (ad es., Commette su maestro
ramo), sembrerà come se quei commissari scomparissero la prossima volta che provano a tirare dentro il tuo lavoro. Ciò si traduce in uno scenario di confusione difficile da recuperare.
Con questa idea, non dovresti mai rebase i commit che sono stati spinti in un repository pubblico a meno che tu non sia sicuro che nessuno abbia basato il loro lavoro su di loro.
Questo tutorial ha introdotto i due casi d'uso più comuni di git rebase
. Abbiamo parlato molto di come spostare le filiali in giro, ma teniamo presente che la ridefinizione riguarda davvero il controllo della cronologia del progetto. Il potere di riscrivere i commit dopo il fatto ti libera di concentrarti sulle attività di sviluppo invece di suddividere il tuo lavoro in istantanee isolate.
Tieni presente che il rebasing è un'aggiunta completamente opzionale alla tua casella degli strumenti Git. Puoi sempre fare tutto il necessario con plain old git si fondono
comandi. In effetti, questo è più sicuro in quanto evita la possibilità di riscrivere la storia pubblica. Tuttavia, se comprendi i rischi, git rebase
può essere un modo molto più semplice per integrare i rami rispetto alla fusione dei commit.