Perché git dello squash si impegna per le richieste pull?

159

Perché ogni serio repo di Github faccio richieste per farmi schiacciare i miei commit in un singolo commit?

Pensavo che il log git fosse lì in modo da poter ispezionare tutta la cronologia e vedere esattamente quali cambiamenti sono accaduti, ma lo schiacciamento lo estrae dalla cronologia e lo trasforma in un unico commit. Qual è il punto?

Questo sembra anche andare contro il "mantra presto e commetti spesso" mantra.

    
posta hamstar 18.11.2014 - 23:41
fonte

5 risposte

140

Per avere una cronologia chiara e concisa che documenta in modo chiaro e semplice le modifiche apportate e i motivi per cui.

Ad esempio un tipico log git 'unsquashed' per me potrebbe essere simile al seguente:

7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
787g8fgf78... hotfix for #5849564648
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Che casino!

Considerando che un log git più attentamente gestito e unito con un po 'di attenzione aggiuntiva sui messaggi per questo potrebbe apparire come:

7hgf8978g9... 8483948393 Added new slideshow feature
787g8fgf78... 5849564648 Hotfix for android display issue
9080gf6567... 6589685988 Implemented pop-up to select language

Penso che tu possa vedere lo schiacciamento dei commit in generale e lo stesso principio si applica alle richieste di pull - Readability of the History. Potresti anche aggiungere a un log di commit che ha già centinaia o addirittura migliaia di commit e questo contribuirà a mantenere la storia crescente breve e concisa.

Vuoi impegnarti presto e spesso. È una buona pratica per molte ragioni. Trovo che questo mi porti spesso a commettere "wip" (work-in-progress) o "part A done" o "typo, minor fix" dove sto usando git per aiutarmi a lavorare e darmi punti di lavoro che Posso tornare indietro se il codice seguente non sta funzionando mentre procedo per far funzionare le cose. Tuttavia non ho bisogno o voglio quella cronologia come parte della cronologia git finale, quindi potrei schiacciare i miei commit, ma vedi le note seguenti su cosa significhi su un ramo di sviluppo rispetto a master.

Se ci sono pietre miliari importanti che rappresentano fasi di lavoro distinte, è ancora ok avere più di un commit per feature / task / bug. Tuttavia, questo spesso può evidenziare il fatto che il ticket in fase di sviluppo è "troppo grande" e deve essere suddiviso in parti più piccole che possono essere indipendenti, ad esempio:

8754390gf87... Implement feature switches

sembra "1 pezzo di lavoro". O esistono o non lo fanno! Non sembra avere senso scoppiare. Tuttavia, l'esperienza mi ha dimostrato che (a seconda delle dimensioni e della complessità dell'organizzazione) un percorso più granulare potrebbe essere:

fgfd7897899... Add field to database, add indexes and a trigger for the dw group
9458947548g... Add 'backend' code in controller for when id is passed in url.
6256ac24426... Add 'backend' code to make field available for views.
402c476edf6... Add feature to UI

Piccoli pezzi significano revisioni più semplici del codice, test dell'unità più semplice, migliore opportunità per qa, migliore allineamento al Principio di Responsabilità Unica, ecc.

Per la praticità del momento in cui fare effettivamente questi squash, ci sono fondamentalmente due fasi distinte che hanno il loro flusso di lavoro

  • il tuo sviluppo, ad es. richieste di pull
  • il tuo lavoro è stato aggiunto al ramo principale, ad es. Master

Durante il tuo sviluppo ti impegni "presto e spesso" e con rapidi messaggi "usa e getta". A volte potresti desiderare di schiacciare qui, ad es. lo schiacciamento nel messaggio wipe e todo commette. È ok, all'interno del ramo, mantenere più commit che rappresentano passaggi distinti che hai fatto nello sviluppo. La maggior parte delle zucche che scegli di fare dovrebbero essere all'interno di questi rami di funzionalità, mentre sono in fase di sviluppo e prima di fondersi con il master.
Quando si aggiunge al ramo principale che si desidera che i commit siano concisi e formattati correttamente in base alla cronologia mainline esistente. Ciò potrebbe includere l'ID del sistema Ticket Tracker, ad es. JIRA come mostrato negli esempi. Lo squashing non si applica qui a meno che non si desideri eseguire il rollup di diversi commit distinti sul master. Normalmente non lo fai.

L'utilizzo di --no-ff durante l'unione con il master utilizzerà un commit per l'unione e conserverà anche la cronologia (nel ramo). Alcune organizzazioni considerano questa una best practice. Vedi di più sul link Vedrai anche l'effetto pratico in git log dove un --no-ff commit sarà l'ultimo commit , all'inizio dell'HEAD (quando appena fatto), mentre senza --no-ff potrebbe essere più in basso nella cronologia, a seconda delle date e di altri commit.

    
risposta data 19.11.2014 - 01:26
fonte
21

Perché spesso la persona che trascina un PR si preoccupa dell'effetto netto dei commit "aggiunta funzione X", non dei "modelli base, funzione di correzione bug X, aggiunta funzione Y, errori di battitura fissi nei commenti, parametri di ridimensionamento dei dati regolati, hashmap funziona meglio dell'elenco "... livello di dettaglio

Se ritieni che i tuoi 16 commit siano rappresentati al meglio da 2 commit anziché 1 "Funzione aggiunta X, ri-fattorizzato Z per usare X", allora probabilmente è meglio proporre un pr con 2 commit, ma potrebbe essere meglio proporre 2 pr separati in quel caso (se il repository insiste ancora sui singoli commit pr)

Questo non va contro il mantra "commit early e commit spesso", come nel tuo repository, mentre stai sviluppando hai ancora i dettagli granulari, quindi hai una minima possibilità di perdere il lavoro, e altre persone possono rivedere / tira / proponi i pr contro il tuo lavoro mentre il nuovo pr è in fase di sviluppo.

    
risposta data 19.11.2014 - 00:25
fonte
13

Il motivo principale da ciò che posso vedere è il seguente:

  • L'interfaccia utente GitHub per la fusione delle richieste pull attualmente (ottobre 2015) non consente di modificare la prima riga del messaggio di commit, forzandolo a essere Merge pull request #123 from joebloggs/fix-snafoo
  • L'interfaccia utente di GitHub per la navigazione nella cronologia dei commit attualmente non ti consente di visualizzare la cronologia del ramo dal punto di vista di --first-parent
  • L'interfaccia utente di GitHub per la visualizzazione della colpa su un file al momento non ti consente di visualizzare la colpa del file con il punto di vista di --first-parent (nota che questo problema è stato corretto solo in Git 2.6.2, quindi abbiamo potuto perdona GitHub per non averlo disponibile)

Quindi, quando combini tutte e tre queste situazioni sopra, ottieni una situazione in cui i commit non sincronizzati in fase di unione risultano brutti dall'interfaccia utente di GitHub.

La cronologia con commit compressi sarà simile a

1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... Hotfix for android display issue
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... Implemented pop-up to select language

Mentre senza i commit schiacciati la cronologia sarà simile a

1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... hotfix for #5849564648
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Quando hai un sacco di commit in un tracciamento del PR in cui un cambiamento è entrato può diventare un po 'un incubo se ti limiti a utilizzare l'interfaccia utente di GitHub .

Ad esempio, si trova un puntatore nullo che viene de-referenziato da qualche parte in un file ... quindi si dice "chi ha fatto questo e quando? quali versioni sono interessate?". Poi vai alla vista della colpa nell'interfaccia utente di GitHub e vedi che la linea è stata cambiata in 789fdfffdf ... "oh, ma aspetta un secondo, quella linea stava cambiando il suo rientro per adattarsi al resto del codice ", quindi ora devi navigare nello stato dell'albero per quel file nel commit genitore e rivedere la pagina della colpa ... alla fine trovi il commit ... è un commit di 6 mesi fa ..." oh **** questo potrebbe interessare gli utenti per 6 mesi "tu dici ... ah ma aspetta, quell'impegno era in realtà in una richiesta di pull ed è stato fuso solo ieri e nessuno ha ancora rilasciato una liberatoria ..." Accidenti a voi gente per la fusione dei commit senza distruggere la cronologia "è il grido che di solito può essere ascoltato dopo circa 2 o 3 spedizioni di archeologia in codice tramite l'interfaccia utente di GitHub

Ora consideriamo come funziona se usi la riga di comando di Git (e il super-fantastico 2.6.2 che ha la correzione per git blame --first-parent )

  • Se si stesse usando la riga di comando di Git, si sarebbe in grado di controllare completamente il messaggio di commit di merge e quindi il commit di merge potrebbe avere una bella riga di riepilogo.

Quindi la nostra cronologia dei commit sarà simile a

$ git log
1256556316... #423 Added new slideshow feature
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... #324 Hotfix for android display issue
787g8fgf78... hotfix for #5849564648
f56556316e... #28 Implemented pop-up to select language
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Ma possiamo anche fare

$ git log --first-parent
1256556316... #423 Added new slideshow feature
56556316ad... #324 Hotfix for android display issue
f56556316e... #28 Implemented pop-up to select language

(In altre parole: la Git CLI ti permette di avere la tua torta e di mangiarla anche tu)

Ora, quando rileviamo il problema con il puntatore nullo ... beh, usiamo solo git blame --first-parent -w dodgy-file.c e ci viene immediatamente assegnato il commit esatto in cui il de-riferimento del puntatore nullo è stato introdotto al ramo master ignorando le semplici modifiche dello spazio bianco.

Ovviamente se stai facendo unioni usando l'interfaccia utente di GitHub allora git log --first-parent è davvero schifoso grazie a GitHub che impone la prima riga del messaggio di commit di fusione:

1256556316... Merge pull request #423 from jrandom/add-slideshows
56556316ad... Merge pull request #324 from ahacker/fix-android-display
f56556316e... Merge pull request #28 from somwhere/select-lang-popup

Quindi, per farla breve:

L'interfaccia utente GitHub (ottobre 2015) presenta una serie di carenze relative al modo in cui unisce le richieste di pull, come presenta la cronologia del commit e come attribuisce le informazioni di biasimo. L'attuale modo migliore per aggirare questi difetti nell'interfaccia utente di GitHub è di richiedere alle persone di reprimere i loro commit prima di unirli.

La Git CLI non ha questi problemi e puoi facilmente scegliere quale vista vuoi vedere in modo che tu possa entrambi scoprire il motivo per cui un particolare cambiamento è stato fatto in quel modo (osservando la cronologia dei commit non soddisfatti) così come vedere i commit effettivamente schiacciati.

Post script

Il motivo finale spesso citato per il commit dello schiacciamento è rendere il backporting più facile ... se si ha solo un commit alla back port (cioè il commit schiacciato), allora è facile scegliere come ...

Bene, se stai guardando la cronologia git con git log --first-parent , puoi semplicemente selezionare i commit di unione. La maggior parte delle persone si confonde Il cherry picking merge perché devi specificare l'opzione -m N ma se hai ottenuto il commit da git log --first-parent allora sai che è il primo genitore che vuoi seguire in questo modo sarà git cherry-pick -m 1 ...

    
risposta data 20.10.2015 - 11:18
fonte
1

Sono d'accordo con i sentimenti espressi in altre risposte in questa discussione su come mostrare una cronologia chiara e concisa delle funzionalità aggiunte e dei bug corretti. Tuttavia, ho voluto affrontare un altro aspetto a cui la tua domanda è sfuggita ma che non ha indicato esplicitamente. Parte dell'aggancio che potresti avere su alcuni dei metodi di lavoro di Git è che git ti permette di riscrivere la storia che sembra strana quando viene introdotto a git dopo aver usato altre forme di controllo del codice sorgente dove tali azioni sono impossibili. Inoltre, questo va anche contro il principio generalmente accettato del controllo del codice sorgente che una volta che qualcosa è stato eseguito / controllato al controllo del codice sorgente, dovresti essere in grado di ripristinare lo stato, indipendentemente dalle modifiche che fai dopo il commit. Come sottintendi nella tua domanda, questa è una di quelle situazioni. Penso che git sia un ottimo sistema di controllo della versione; tuttavia, per comprenderlo è necessario comprendere alcuni dei dettagli di implementazione e le decisioni di progettazione che stanno dietro di esso, e come risultato ha una curva di apprendimento più ripida. Tieni presente che git è stato concepito come un sistema di controllo della versione distribuito e questo aiuterà a spiegare perché i progettisti consentono la riscrittura della cronologia git con il commit di squash come esempio.

    
risposta data 22.11.2014 - 21:21
fonte
0

Vista la prospettiva ... La migliore pratica è quella di avere un singolo commit per ogni singolo problema di <<issue-management-system>> , se possibile.

Potresti avere il numero di commit che vuoi nel tuo branch / repository, ma è la tua cronologia rilevante per quello che stai facendo ora per la TUA prospettiva ... non è STORIA per l'intero TEAM / PROJECT o applicazione dal loro punto di vista per essere mantenuta diversi mesi da adesso ...

Quindi ogni volta che si desidera commettere una correzione di bug o una funzionalità per un repository comune (questo esempio è con il ramo di sviluppo), cosa si potrebbe fare come segue:

how-to rebase il tuo branch di funzionalità per svilupparsi rapidamente

    # set your current branch , make a backup of it , caveat minute precision
    curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr

    # squash all your changes at once 
    git reset $(git merge-base develop $curr_branch)

    # check the modified files to add 
    git status

    # add the modified files dir by dir, or file by file or all as shown
    git add --all 

    # check once again 
    git log --format='%h %ai %an %m%m %s'  | less

    # add the single message of your commit for the stuff you did 
    git commit -m "<<MY-ISSUE-ID>>: add my very important feature"

    # check once again 
    git log --format='%h %ai %an %m%m %s'  | less

    # make a backup once again , use seconds precision if you were too fast ... 
    curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr

    # compare the old backup with the new backup , should not have any differences 
    git diff <<old-backup>>..<<new-backup-branch>>


    # you would have to git push force to your feature branch 
    git push --force 
    
risposta data 10.04.2018 - 11:14
fonte

Leggi altre domande sui tag