In git, qual è la differenza tra merge --squash e rebase?


363

Sono nuovo di Git e sto cercando di capire la differenza tra una zucca e un rebase. A quanto ho capito, esegui uno squash quando fai un rebase.

Risposte:


360

Entrambi git merge --squashe git rebase --interactivepossono produrre un commit "schiacciato".
Ma servono a scopi diversi.

produrrà un commit schiacciato sul ramo di destinazione, senza contrassegnare alcuna relazione di unione.
(Nota: non produce subito un commit: è necessario un ulteriore git commit -m "squash branch")
Ciò è utile se si desidera eliminare completamente il ramo di origine, passando da (schema preso dalla domanda SO ):

 git checkout stable

      X                   stable
     /                   
a---b---c---d---e---f---g tmp

per:

git merge --squash tmp
git commit -m "squash tmp"

      X-------------------G stable
     /                   
a---b---c---d---e---f---g tmp

e quindi eliminando il tmpramo.


Nota: git mergeha --commitun'opzione , ma non può essere utilizzata con --squash. Non è mai stato possibile utilizzare --commite --squashinsieme.
Da Git 2.22.1 (Q3 2019), questa incompatibilità è resa esplicita:

Vedi commit 1d14d0c (24 maggio 2019) di Vishal Verma ( reloadbrain) .
(Unito da Junio ​​C Hamano - gitster- in commit 33f2790 , 25 lug 2019)

merge: rifiuta --commitcon--squash

In precedenza, quando --squashveniva fornito, ' option_commit' veniva lasciato cadere silenziosamente. Ciò avrebbe potuto sorprendere un utente che ha cercato di ignorare il comportamento senza commit di squash usando --commitesplicitamente.

git/git builtin/merge.c#cmd_merge() ora include:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

ripete alcuni o tutti i tuoi commit su una nuova base, permettendoti di schiacciare (o più recentemente "aggiustare", vedi questa domanda SO ), andando direttamente a:

git checkout tmp
git rebase -i stable

      stable
      X-------------------G tmp
     /                     
a---b

Se scegli di eliminare tutti i commit tmp(ma, al contrario merge --squash, puoi scegliere di rigiocarne alcuni e schiacciarne altri).

Quindi le differenze sono:

  • squashnon tocca il ramo di origine ( tmpqui) e crea un unico commit dove vuoi.
  • rebaseti permette di continuare sullo stesso ramo di origine (ancora tmp) con:
    • una nuova base
    • una storia più pulita

11
Gviene c--d--e--f--gschiacciato insieme?
Wayne Conrad,

8
@Wayne: sì, G in quegli esempi rappresenta i tmpcommit compressi insieme.
VonC

3
@ Th4wn: poiché Git ragiona con le istantanee di un intero progetto, Gnon rappresenterà lo stesso contenuto di g, a causa delle modifiche introdotte da X.
VonC,

1
@VonC: non sono sicuro di quell'ultimo commento. Se hai un git merge --no-ff tempinvece di git merge --squash temp, allora ottieni una cronologia più complessa, ma puoi anche fare cose come git revert e, molto più facilmente. È una storia disordinata, ma onesta e pragmatica, e il ramo principale rimane ancora abbastanza pulito.
nulla101

2
@ naught101 Sono d'accordo. Come spiegato in stackoverflow.com/a/7425751/6309 , tuttavia, si tratta anche di non rompersi git bisecto git blamese usato troppo spesso (come in git pull --no-ff: stackoverflow.com/questions/12798767/… ). Non c'è un approccio in ogni caso, che è il motivo per cui questo articolo ha descritto tre ( stackoverflow.com/questions/9107861/... )
VonC

183

Unisci commit: conserva tutti i commit nel tuo ramo e li interfoglia con i commit sul ramo baseinserisci qui la descrizione dell'immagine

Unisci zucca: mantiene le modifiche ma omette i singoli commit dalla cronologia inserisci qui la descrizione dell'immagine

Rebase: questo sposta l'intero ramo delle caratteristiche per iniziare sulla punta del ramo principale, incorporando efficacemente tutti i nuovi commit nel master

inserisci qui la descrizione dell'immagine

Maggiori informazioni qui


81

Unisci squash unisce un albero (una sequenza di commit) in un singolo commit. Cioè, comprime tutte le modifiche apportate in n commit in un unico commit.

Rebasing è re-basing, ovvero scegliere una nuova base (commit parent) per un albero. Forse il termine mercuriale per questo è più chiaro: lo chiamano trapianto perché è proprio questo: scegliere un nuovo terreno (impegno del genitore, radice) per un albero.

Quando esegui un rebase interattivo, ti viene data la possibilità di schiacciare, scegliere, modificare o saltare i commit che stai per rebase.

Spero fosse chiaro!


7
Quando devo rebase e quando dovrei schiacciare?
Martin Thoma,

31

Cominciamo dal seguente esempio:

inserisci qui la descrizione dell'immagine

Ora abbiamo 3 opzioni per unire le modifiche del ramo della funzione nel ramo principale :

  1. Unisci commit
    manterrà la cronologia di tutti i commit del ramo funzione e li sposta nel ramo master
    Aggiungerà un ulteriore commit fittizio.

  2. Riempi e unisci Aggiungerà
    tutta la cronologia dei commit del ramo delle funzioni nella parte anteriore del ramo principale
    NON aggiungerà un commit fittizio aggiuntivo.

  3. Schiaccia e unisci
    Raggruppa tutti i commit delle diramazioni in un unico commit, quindi aggiungilo nella parte anteriore del branch master
    Aggiungerà un commit fittizio aggiuntivo.

Di seguito puoi trovare come sarà il ramo principale dopo ognuno di essi.

inserisci qui la descrizione dell'immagine

In tutti i casi:
possiamo ELIMINARE in sicurezza il ramo delle funzioni .


1
puoi spiegare cosa è il commit fittizio nella seconda foto ?? Sono un principiante.
Yusuf

1
@Yusuf, è solo un commit extra che contiene gli aggiornamenti di entrambi i rami, è il messaggio di commit predefinito = "Megre branch XYZ in master"
ahmednabil88
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.