Perché lo staging granulare è importante
Una storia Git ben costruita racconta una narrazione. Ogni commit rappresenta una singola modifica logica: una correzione di bug, un refactoring, una nuova funzionalità. Ma lo sviluppo reale è raramente così ordinato. Correggi un bug, poi noti un errore di battitura lì vicino, poi aggiusti della formattazione, poi inizi un piccolo refactoring -- tutto nello stesso file. Se metti in staging e fai commit dell'intero file in una volta, ottieni un commit che mescola modifiche non correlate. Questo rende la code review più difficile, rende la ricerca di bug con bisect più difficile, e rende la storia dei commit meno utile come documentazione.
Lo staging granulare ti permette di suddividere il tuo lavoro in commit significativi, anche quando le modifiche sono intrecciate all'interno dello stesso file. Invece di fare commit di tutto in una volta, scegli esattamente quali modifiche vanno insieme.
Tre livelli di staging
Staging a livello di file
Il livello più basilare. Metti in staging interi file con git add:
git add src/auth.ts src/utils.ts
Questo è sufficiente quando ogni file contiene una sola modifica logica. Ma non appena un file contiene più modifiche non correlate, lo staging a livello di file è troppo grossolano.
Staging a livello di hunk
Git può suddividere le modifiche di un file in "hunk" -- blocchi contigui di righe modificate separati da codice invariato. Usando git add -p (modalità patch), Git presenta ogni hunk uno alla volta e chiede se metterlo in staging:
git add -p src/auth.ts
Per ogni hunk, scegli y (staging), n (salta), s (dividi in hunk più piccoli), o e (modifica manualmente). Questo è un miglioramento significativo rispetto allo staging a livello di file, ma ha delle limitazioni. Gli hunk sono definiti dalla prossimità: se due modifiche non correlate sono vicine (separate da meno di tre righe di contesto), Git le raggruppa in un singolo hunk. Separarle richiede la modifica manuale del patch, che è tediosa e soggetta a errori.
Staging a livello di riga
Lo staging a livello di riga è l'opzione più precisa. Invece di lavorare con file o hunk, selezioni singole righe da mettere in staging. Vuoi mettere in staging le righe 12 e 15 ma non la riga 14? Puoi farlo. Questo ti dà il controllo completo su cosa va in ogni commit, indipendentemente da quanto sono vicine le modifiche nel file.
Da riga di comando, lo staging a livello di riga significa modificare manualmente i patch con git add -p e l'opzione e. Devi comprendere il formato unified diff, modificare attentamente il patch e sperare di non introdurre errori. Funziona, ma non è qualcosa che la maggior parte degli sviluppatori vuole fare regolarmente.
Staging a livello di riga in GitSquid
GitSquid rende lo staging a livello di riga visuale e diretto. Quando selezioni un file modificato, il visualizzatore di diff mostra ogni riga modificata. Per mettere in staging righe specifiche:
- Clicca su una singola riga per selezionarla.
- Cmd+Click (Ctrl+Click su Windows/Linux) per selezionare più righe individuali.
- Shift+Click per selezionare un intervallo di righe.
Una volta selezionate le righe desiderate, mettile in staging. Solo quelle righe vengono aggiunte all'indice. Il resto rimane come modifiche non in staging nel tuo directory di lavoro, pronto per essere incluso in un commit diverso.
Lo stesso workflow funziona al contrario. Se hai già messo in staging righe che vuoi rimuovere dall'area di staging, puoi selezionarle nel diff in staging e togliere dallo staging solo quelle righe.
Come funziona sotto il cofano
Quando metti in staging singole righe, GitSquid genera un patch lato server che include solo le modifiche selezionate. Questo patch viene poi applicato all'indice usando il meccanismo di patch di Git. Gestendo la generazione del patch lato server anziché manipolando il diff lato client, il risultato è affidabile e corrisponde esattamente a ciò che Git si aspetta. Non ci sono problemi di formattazione o errori di offset che potresti incontrare modificando i patch a mano.
Esempi pratici
Separare una correzione di bug da un refactoring
Stai lavorando a un refactoring e noti un bug. Lo correggi immediatamente perché la correzione è ovvia. Ora il tuo file ha due tipi di modifiche: il refactoring e la correzione del bug. Con lo staging a livello di riga, selezioni solo le righe della correzione del bug, le fai commit con un messaggio chiaro come "fix null check in auth validation", e poi fai commit del refactoring separatamente. Il risultato sono due commit puliti e revisionabili invece di uno confuso.
Separare il codice di debug dal codice di produzione
Hai aggiunto alcune istruzioni console.log durante il debug, proprio accanto alle modifiche reali del codice. Invece di cercare di ricordare quali righe sono di debug e quali sono reali, selezioni visivamente solo le modifiche di produzione, le metti in staging e fai commit. Le righe di debug restano nel tuo directory di lavoro dove puoi continuare a usarle o eliminarle più tardi.
Preparare un commit parziale per la revisione
Hai un grande insieme di modifiche, ma solo parte del lavoro è pronto per la revisione. Lo staging a livello di riga ti permette di fare commit delle porzioni finite mantenendo il codice in corso non committato. La tua pull request resta focalizzata, e il revisore non deve navigare attraverso codice incompleto.
Mantenere i commit atomici
Un commit atomico è quello che contiene una singola modifica logica e completa. Passa i test, non rompe il build e può essere compreso da solo. I commit atomici non sono solo una questione di ordine. Hanno benefici pratici:
- Code review. I revisori possono comprendere ogni commit indipendentemente. Un commit intitolato "fix input validation" che tocca solo la logica di validazione è facile da revisionare. Un commit intitolato "various changes" che tocca validazione, stile e configurazione non lo è.
- Caccia ai bug. Quando qualcosa si rompe,
git bisectpuò individuare il commit esatto che ha introdotto il problema. I commit atomici rendono il risultato significativo: trovi la modifica specifica che ha causato il bug, non un miscuglio di modifiche non correlate. - Revert. Se un commit deve essere revertito, un commit atomico può essere revertito in modo pulito. Un commit misto potrebbe costringerti a revertire modifiche che in realtà volevi mantenere.
- La storia come documentazione. Mesi dopo, quando qualcuno legge la storia dei commit per capire perché un pezzo di codice esiste, i commit atomici con messaggi chiari raccontano una storia utile.
Lo staging a livello di riga è lo strumento che rende i commit atomici pratici. Senza di esso, creare commit puliti dallo sviluppo reale disordinato richiede disciplina e sforzo manuale. Con esso, il processo è semplice come selezionare le righe che vanno insieme.
I migliori commit sono quelli che fanno esattamente una cosa. Lo staging granulare ti dà il controllo per realizzarlo, anche quando il tuo directory di lavoro racconta una storia diversa.