Deathmatch: Git Rebase vs. Merge
Una domanda senza tempo...
Deathmatch: Git Rebase vs. (Squash) Merge!
Dovrei fare il rebase? O lo squash merge?
- È una questione di preferenza personale?
- Risposta: Non quando sono coinvolti uno o più team! Entrambe le scelte avranno un impatto sull’usabilità dell’altro!
Perché questo argomento evoca un fervore religioso?
Alcuni ingegneri usano la conoscenza di git (e del terminale) come segnale del loro livello di abilità relativo. E qualsiasi pratica legata alla nostra identità/ego può essere impossibile da analizzare con imparzialità, figuriamoci da cambiare.
Altri fattori probabilmente includono la familiarità e il bias del sopravvissuto, che possono ulteriormente offuscare la nostra valutazione e le nostre ipotesi.
Domanda chiave: qual è lo scopo di un commit git?
- Fai commit presto e spesso? Con una mentalità da “checkpoint” o backup?
- Dove tutto viene registrato, anche i falsi inizi e gli esperimenti? (es.
git commit -am "Updated deps" && git push, da ripetere regolarmente) - Forse i messaggi di commit sono meno importanti del codice per te?
- Dove tutto viene registrato, anche i falsi inizi e gli esperimenti? (es.
- Oppure i tuoi commit sono un’opera d’arte accuratamente curata e scolpita?
- Forse ogni commit è un’unità di lavoro atomica e autosufficiente? (es.
git add package.json && git commit -m "Updated deps") - O semplicemente non sopporti i log di commit “disordinati”?
- Le tue revisioni PR coinvolgono spesso una revisione commit per commit?
- Forse ogni commit è un’unità di lavoro atomica e autosufficiente? (es.
| 💡 Quali altri modelli mentali definiscono il modo in cui vedi i commit? Fatemelo sapere @justsml!
Stai pensando a git in un modo che sta fornendo il massimo valore a te, al tuo team e alla tua organizzazione?
Dato che esistono mentalità molto diverse riguardo alla strategia di commit, non c’è da stupirsi se c’è così 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. (es. Ho fatto un errore 16 merge fa, e potrei aver bisogno di un controllo granulare per correggerlo. Inoltre, potrei rimanere bloccato in un ciclo apparentemente infinito di conflitti e --continue.)”
- Ottieni gli ultimi aggiornamenti:
git checkout main&&git pull - Crea un nuovo branch:
git checkout -b release/hot-newness-and-stuff - Avvia il rebase interattivo e includi il riferimento git per il punto nel tempo a cui vuoi tornare.
git rebase -i HEAD~6(Nota:HEAD~6è una scorciatoia per ‘6 commit fa’) - Scarta i commit desiderati cambiando il loro prefisso in
drop. Salva e chiudi l’editor. - Risolvi i conflitti di merge,
git add .&&git rebase --continue(NON faregit commit). - Ripeti il passaggio precedente fino al completamento.
- Crea il tag/push usando il processo corrente. Esempio
git tag -a v1.2.3 -m 'Release v1.2.3'&&git push --tags
Pro
- 🔌 Potere assoluto. Puoi cambiare la cronologia.
Contro
- 😰 Potere assoluto. Puoi cambiare la cronologia. (Ok, un pro e un contro…)
- 🔂 Puoi ritrovarti in un ciclo apparentemente infinito di conflitti e
—-continue. (A volte anche congit rerere) - 🙀 Rompe funzionalità chiave di collaborazione: commenti PR persi/orfani. Scortese.
- 🖇️ I permalink possono diventare non così permanenti.
Il modo (Squash) Merge
Modello mentale: “Voglio un rilascio personalizzato, a partire da un dato punto, e includendo i branch desiderati.”
- Ottieni gli ultimi aggiornamenti:
git checkout main&&git pull - Crea un nuovo branch:
git checkout -b release/hot-newness-and-stuff - Merge dei branch e/o commit desiderati:
git merge --no-ff feature/hot-newness bug/fix-123(usa il flag--no-ffdove possibile.) - Risolvi eventuali conflitti di merge (dovessero presentarsi.)
- Crea il tag/push usando il processo corrente. Esempio
git tag -a v1.2.3 -m 'Release v1.2.3'&&git push --tags
Pro
- 💪 Meno procedure, meno conflitti complessivi, e usa la conoscenza esistente dei comandi git.
- 🚀 Ti permette di pensare a un livello più alto di PR/branch, ignorando la granularità a livello di commit (a meno che non sia necessaria.)
- 🦺 Non distruttivo. Puoi tornare indietro e/o creare nuovi branch in qualsiasi momento.
- 🎥 Lascia i commit e i messaggi esistenti come un tutto, il che porta a meno ‘rumore’ nel blame.
Contro
- 🔏 Più difficile cambiare i messaggi di commit.
- 🤐 Più difficile nascondere il tuo lavoro.
Conclusione
Alla fine, un processo più semplice con meno rischi dovrebbe prevalere.
Anche se i Rebaser hanno certamente modi per risolvere (o evitare) i loro problemi, il fatto resta: avrai bisogno di una cintura nera nel kung fu di git. (es. Anche un umile git push può affrontare una complessità extra: era git push --force o git push --force-with-lease? Perché occuparsene affatto?)
C’è un altro motivo per cui il rebasing per creare una cronologia revisionata sarà sempre in svantaggio rispetto a git merge .... Un git merge permette alla CLI git di applicare algoritmi avanzati per evitare conflitti analizzando l’HEAD di ogni branch.
Questo può essere più intelligente perché ogni merge si preoccupa solo dello stato più recente di ogni branch desiderato, mentre il rebasing deve ri-eseguire (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.
Alla fine, il rebasing significa che occasionalmente ti ritroverai a rivivere commit e conflitti obsoleti irrilevanti - anche se sai che sono stati rimossi o risolti da tempo.
Riepilogo
- 💃 Risposta: SQUASH MERGE le tue PR su
main.- La cronologia del tuo branch sarà lì se necessaria, e
mainrimarrà relativamente “pulita.”
- La cronologia del tuo branch sarà lì se necessaria, e
- 🔤 Always Be Committing!
- In oltre il 95% dei progetti aziendali la mentalità da “backup” è preferibile alla mentalità da “opera d’arte scolpita”. Col passare del tempo, il significato dei messaggi di commit svanirà, molto più velocemente del codice la cui logica e i cui test manterranno il loro significato.