Scontro: Git Rebase vs. Merge
Una domanda senza tempo...
##Deathmatch: Git Rebase vs. (Squash) Merge!
Devo fare il Rebase? O lo Squash Merge?
- È una preferenza personale?
- Risposta: No quando è coinvolto uno o più team! Entrambe le scelte influenzeranno l’usabilità dell’altra!
Perché questo argomento suscita fervore religioso?
Alcuni ingegneri usano la conoscenza di git (e del terminale) come segnale del loro livello di abilità relativo. Qualsiasi pratica legata alla nostra identità/ego può diventare impossibile da analizzare in modo imparziale, figuriamoci da modificare.
Altri fattori includono probabilmente la familiarità e il bias di sopravvivenza, che possono ulteriormente offuscare la nostra valutazione e le nostre ipotesi.
Domanda chiave: Qual è lo scopo di un commit git?
- Committi presto e spesso? Adotti una mentalità da “punto di controllo” o backup?
- Dove tutto viene registrato, anche i falsi inizi e gli esperimenti? (es.
git commit -am "Updated deps" && git push, ripeti regolarmente) - Forse per te i messaggi dei commit sono meno importanti del codice?
- Dove tutto viene registrato, anche i falsi inizi e gli esperimenti? (es.
- Oppure i tuoi commit sono un lavoro d’arte curato e scolpito?
- Forse ogni commit è un’unità di lavoro autonoma, atomica? (es.
git add package.json && git commit -m "Updated deps") - O semplicemente non sopporti i log dei commit “disordinati”?
- Le tue revisioni PR spesso comportano una revisione commit per commit?
- Forse ogni commit è un’unità di lavoro autonoma, atomica? (es.
| 💡 Quali altri modelli mentali definiscono il tuo modo di vedere i commit? Fammi sapere @justsml!
Stai pensando a git in modo che fornisca il massimo valore a te, al tuo team e alla tua organizzazione?
Dato che esistono mentalità molto diverse riguardo alla strategia dei commit, non sorprende che ci sia tanta confusione sul modo “giusto” di usare git.
Scenario: Creare un tag di rilascio revisionato
Confrontiamo il processo di creazione di un tag di rilascio escludendo alcuni commit recenti su main.
Il modo Rebase
Modello mentale: “Voglio creare una versione alternativa di una cronologia esistente. (ad es. ho commesso un errore 16 merge fa e potrei aver bisogno di un controllo fine‑grained per correggerlo. Inoltre, potrei rimanere bloccato in un ciclo apparentemente infinito di conflitti e --continue).”
- Ottieni l’ultima versione:
git checkout main&&git pull - Crea un nuovo branch:
git checkout -b release/hot-newness-and-stuff - Avvia il rebase interattivo includendo il riferimento git da cui vuoi tornare indietro.
git rebase -i HEAD~6(Nota:HEAD~6è la forma abbreviata di “git ref” per “6 commit fa”) - Elimina i commit desiderati cambiandone il prefisso in
drop. Salva e chiudi l’editor. - Risolvi i conflitti di merge,
git add .&&git rebase --continue(NON eseguiregit commit). - Ripeti il passaggio precedente finché non è completato.
- Tagga/pusha usando il processo corrente. Esempio
git tag -a v1.2.3 -m 'Release v1.2.3'&&git push --tags
Pro
- 🔌 Potere assoluto. Puoi riscrivere la cronologia.
Contro
- 😰 Potere assoluto. Puoi riscrivere la cronologia. (Ok, è sia un pro che un contro…)
- 🔂 Potresti finire in un ciclo apparentemente infinito di conflitti e
—-continue. (A volte anche congit rerere) - 🙀 Rompe funzionalità chiave di collaborazione: commenti PR persi o orfani. Scortese.
- 🖇️ I permalink possono diventare meno permanenti.
Il modo (Squash) Merge
Modellomentale: “Voglio una release personalizzata, a partire da un punto dato, includendo i branch desiderati.”
- Aggiorna:
git checkout main&&git pull - Crea un nuovo branch:
git checkout -b release/hot-newness-and-stuff - Unisci i branch e/o i commit desiderati:
git merge --no-ff feature/hot-newness bug/fix-123(usa il flag--no-ffquando possibile.) - Risolvi eventuali conflitti di merge (se dovessero comparire.)
- Tagga/pusha usando il processo corrente. Esempio
git tag -a v1.2.3 -m 'Release v1.2.3'&&git push --tags
Pro
- 💪 Meno passaggi, meno conflitti complessivi, e sfrutta la conoscenza dei comandi git già esistente.
- 🚀 Ti permette di pensare a livello di PR/branch, ignorando la granularità dei singoli commit (a meno che non sia necessario.)
- 🦺 Non distruttivo. Puoi tornare indietro e/o creare nuovi branch in qualsiasi momento.
- 🎥 Mantiene i commit e i messaggi esistenti intatti, riducendo il rumore di “blame”.
Contro
- 🔏 Più difficile modificare i messaggi dei commit.
- 🤐 Più difficile nascondere il tuo lavoro.
Conclusione
Alla fine, un processo più semplice con meno rischi dovrebbe prevalere.
Anche se i Rebasers hanno davvero dei modi per risolvere (o evitare) i loro problemi, il fatto rimane: alla fine ti servirà una cintura nera di git fu. (ad es. Anche un umile git push può incontrare complessità aggiuntiva: era git push --force o git push --force-with-lease? Perché occuparsi di tutto ciò?)
C’è un altro motivo per cui rebasing per creare una cronologia rivista sarà sempre svantaggiato rispetto a git merge .... Un git merge permette al CLI di git di applicare algoritmi avanzati per evitare conflitti analizzando l’HEAD di ciascun branch.
Questo può risultare più intelligente perché ogni merge considera solo lo stato più recente di ciascun branch desiderato, mentre il rebase deve riprodurre (o scartare) la cronologia dei commit nella sequenza specificata. Questo limita la capacità di git di ottimizzare il merge poiché confronta solo 2 commit alla volta.
In definitiva, il rebase fa sì che a volte ti ritrovi a rivivere commit e conflitti obsoleti – anche se sai che sono stati rimossi o risolti.
Riepilogo
-
💃 Risposta: SQUASH MERGE le tue PR su
main.- La cronologia del tuo branch sarà disponibile se necessaria, e
mainrimarrà relativamente “pulita”.
- La cronologia del tuo branch sarà disponibile se necessaria, e
-
🔤 Committa sempre!
- In più del 95 % dei progetti aziendali la mentalità del “backup” è preferibile a quella dell’“arte scolpita”. Col tempo, il significato dei tuoi messaggi di commit svanirà molto più rapidamente del codice la cui logica e i test manterranno la loro rilevanza.
-
Puoi usare il separatore speciale “—” con
git checkoutper rimanere nel branch corrente mentre copi i file specificati: -
git checkout feature/half-a-feature **--** <percorso della cartella o del file> -
Assicurati di aver committato prima tutte le modifiche che vuoi conservare, poiché questo sovrascriverà eventuali modifiche locali.