Risoluzione delle Storie Divergenti: Strategie Git Merge vs. Rebase
Confronta git merge e git rebase per rami divergenti, gestione dei conflitti, storia condivisa e scelta di un flusso di lavoro sicuro per il team.
Risoluzione delle Storie Divergenti: Strategie Git Merge vs. Rebase
Git merge e rebase aiutano entrambi quando il tuo ramo diverge da un altro ramo. La differenza sta in come preservano la storia, e scegliere quello sbagliato può rendere la collaborazione più difficile del necessario.
Non hai bisogno di una storia perfetta per ogni modifica. Hai bisogno di una strategia che il tuo team comprenda e che mantenga stabili i rami condivisi.
Cosa Significa Storia Divergente
Una storia divergente si verifica quando due rami hanno commit diversi dopo un punto di partenza comune. Ad esempio, hai creato feature/log-cleanup da main lunedì. Martedì, qualcuno ha unito una correzione di sicurezza in main. Ora il tuo ramo e main hanno ciascuno commit che l'altro non ha.
Puoi vedere questo con:
git log --oneline --graph --decorate --all
Potresti anche vedere Git dirti che il tuo ramo e il ramo remoto sono divergenti. Ciò significa che entrambi i lati hanno commit unici. Git ha bisogno che tu decida come combinarli.
I due strumenti normali sono merge e rebase:
git merge main
o:
git rebase main
Entrambi possono produrre lo stesso contenuto finale del file. La storia apparirà diversa.
Come Funziona Git Merge
Merge combina le storie senza riscrivere i commit esistenti. Se il tuo ramo e main sono entrambi avanzati, Git crea un commit di merge che lega insieme le due linee di lavoro.
Un flusso tipico appare così:
git switch feature/log-cleanup
git fetch origin
git merge origin/main
Se non ci sono conflitti, Git crea un commit di merge o esegue un fast-forward quando possibile. Se ci sono conflitti, Git si ferma e ti chiede di risolverli.
Merge è utile quando vuoi preservare la vera forma della collaborazione. Mostra che il lavoro è avvenuto in parallelo ed è stato combinato successivamente. Questo può essere utile per rami di lunga durata, rami di rilascio e rami di funzionalità condivisi.
Il compromesso è che i merge frequenti possono aggiungere rumore. Un ramo con molti commit "merge main in feature" può essere più difficile da scansionare. Ciò non significa che sia sbagliato, ma può rendere la storia meno ordinata.
Usa merge quando:
- Il ramo è condiviso con altri sviluppatori.
- Vuoi evitare di riscrivere la cronologia dei commit.
- Il tuo team apprezza una registrazione esatta dei punti di integrazione.
- Stai aggiornando un ramo di rilascio o un ramo protetto.
Per un ramo già inviato e utilizzato da altri, merge è di solito l'impostazione predefinita più sicura.
Come Funziona Git Rebase
Rebase sposta i commit del tuo ramo in modo che appaiano sopra un nuovo commit base. Invece di mostrare due linee divergenti unite da un commit di merge, la cronologia del ramo diventa lineare.
Un flusso tipico appare così:
git switch feature/log-cleanup
git fetch origin
git rebase origin/main
Git riproduce i tuoi commit uno alla volta sopra l'ultimo main. Se appare un conflitto, Git si ferma al commit che non può essere riprodotto. Dopo aver risolto il conflitto, continua con:
git add <file-risolti>
git rebase --continue
Se il rebase diventa confuso, puoi uscire:
git rebase --abort
Rebase è utile per rami locali e privati perché mantiene la storia facile da leggere. I revisori possono vedere i tuoi commit come se fossero stati costruiti sull'ultimo main dall'inizio.
Usa rebase quando:
- Il ramo è tuo e non condiviso.
- Vuoi una cronologia dei commit pulita e lineare.
- Stai preparando un ramo prima di aprire una pull request.
- Il tuo team preferisce esplicitamente rami di funzionalità rebasati.
La regola principale è semplice: non eseguire rebase su commit pubblici a meno che il tuo team non se lo aspetti. Rebase riscrive gli hash dei commit. Se qualcun altro ha basato il lavoro sui tuoi vecchi commit, la tua riscrittura può creare confusione per loro.
Per ulteriori strumenti quotidiani di cronologia Git, vedi esplorare la cronologia del progetto.
Gestione dei Conflitti Durante Merge o Rebase
I conflitti si verificano quando Git non può combinare automaticamente le modifiche. Sono comuni in file molto modificati come manifesti di distribuzione, file di blocco delle dipendenze e file di configurazione condivisi.
Inizia controllando lo stato:
git status
Apri i file in conflitto e cerca i marcatori di conflitto:
<<<<<<< HEAD
versione del ramo corrente
=======
versione in arrivo
>>>>>>> nome-ramo
Il tuo compito è sostituire il blocco marcato con il contenuto finale che desideri effettivamente. Non mantenere i marcatori.
Dopo la modifica, metti in stage il file:
git add percorso/del/file
Per un merge, termina con:
git commit
Per un rebase, continua con:
git rebase --continue
Esegui test o almeno il comando di validazione pertinente dopo aver risolto i conflitti. Un file può essere sintatticamente pulito ma logicamente sbagliato. Ad esempio, due modifiche YAML di Kubernetes possono unirsi senza conflitto pur definendo porte duplicate o etichette non corrispondenti.
Scelta di una Strategia di Team
La strategia migliore è quella che crea una cronologia prevedibile per il tuo progetto. Molti team usano rebase per rami di funzionalità privati e commit di merge per le pull request. Altri comprimono tutto il lavoro di una funzionalità in un unico commit. Alcuni team di infrastruttura preferiscono i commit di merge perché mostrano esattamente quando i rami sono stati integrati.
Scegli una regola e documentala. Una politica semplice potrebbe essere:
- Esegui rebase sul tuo ramo di funzionalità prima della revisione.
- Non eseguire mai rebase su
main, rami di rilascio o rami condivisi. - Usa commit di merge per le pull request approvate.
- Usa squash merge per piccole correzioni con un unico scopo.
Ciò previene dibattiti sullo stile di Git durante il lavoro urgente. Rende anche più semplice l'automazione perché CI, note di rilascio e strumenti di distribuzione possono fare affidamento su una cronologia coerente.
Quando Chiedere Aiuto
Chiedi prima di eseguire force-push dopo un rebase su un ramo che altri potrebbero utilizzare. Chiedi anche quando un conflitto tocca impostazioni di sicurezza, migrazioni del database, file di distribuzione di produzione o file di blocco generati che non capisci.
Se un merge o rebase diventa intricato, fermati e ispeziona lo stato con git status. Di solito puoi annullare e tornare allo stato precedente con git merge --abort o git rebase --abort. Questo è meglio che provare comandi casuali finché l'albero di lavoro non sembra pulito.
Merge e rebase risolvono lo stesso problema generale, ma raccontano storie diverse. Merge preserva come il lavoro è stato messo insieme. Rebase crea una linea di commit più pulita. Usa ciascuno dove si adatta, e la tua cronologia Git rimarrà utile invece di diventare una fonte di rischio.