DanLevy.net

Scontro: Git Rebase vs. Merge

Una domanda senza tempo...

Hero image for Scontro: Git Rebase vs. Merge

##Deathmatch: Git Rebase vs. (Squash) Merge!

Devo fare il Rebase? O lo Squash Merge?

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?

  1. 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?
  2. 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?

| 💡 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.

Git Tag Releasing from main with 2 feature branches

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).”

  1. Ottieni l’ultima versione: git checkout main && git pull
  2. Crea un nuovo branch: git checkout -b release/hot-newness-and-stuff
  3. 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”)
  4. Elimina i commit desiderati cambiandone il prefisso in drop. Salva e chiudi l’editor.
  5. Risolvi i conflitti di merge, git add . && git rebase --continue (NON eseguire git commit).
  6. Ripeti il passaggio precedente finché non è completato.
  7. Tagga/pusha usando il processo corrente. Esempio git tag -a v1.2.3 -m 'Release v1.2.3' && git push --tags

Pro

Contro

Il modo (Squash) Merge

Modellomentale: “Voglio una release personalizzata, a partire da un punto dato, includendo i branch desiderati.”

  1. Aggiorna: git checkout main && git pull
  2. Crea un nuovo branch: git checkout -b release/hot-newness-and-stuff
  3. Unisci i branch e/o i commit desiderati: git merge --no-ff feature/hot-newness bug/fix-123 (usa il flag --no-ff quando possibile.)
  4. Risolvi eventuali conflitti di merge (se dovessero comparire.)
  5. Tagga/pusha usando il processo corrente. Esempio git tag -a v1.2.3 -m 'Release v1.2.3' && git push --tags

Pro

Contro

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.