Permettimi di rispondere ai tuoi punti in modo diretto e chiaro:
Our issue is with long-term sidebranches -- the kind where you've got a few people working a sidebranch that splits from master, we develop for a few months, and when we reach a milestone we sync the two up.
Di solito non vuoi lasciare i tuoi rami in sincronia per mesi.
Il tuo ramo di funzionalità è derivato da qualcosa che dipende dal tuo flusso di lavoro; chiamiamolo master
per semplicità. Ora, ogni volta che ti impegni a dominare, puoi e dovresti git checkout long_running_feature ; git rebase master
. Ciò significa che i tuoi rami sono, per impostazione, sempre sincronizzati.
git rebase
è anche la cosa giusta da fare qui. Non è un hack o qualcosa di strano o pericoloso, ma completamente naturale. Si perde un po 'di informazioni, che è il "compleanno" del ramo della funzione, ma il gioco è fatto. Se qualcuno lo trova importante, potrebbe essere fornito salvandolo da qualche altra parte (nel tuo sistema di ticket o, se il bisogno è grande, in git tag
...).
Now, IMHO, the natural way to handle this is, squash the sidebranch into a single commit.
No, non lo vuoi assolutamente, vuoi un commit di fusione. Un merge commit è anche un "commit singolo". In qualche modo, non inserisce tutto il singolo ramo che commette "dentro" il master. È un singolo commit con due genitori: il master
head e il branch head al momento dell'unione.
Assicurati di specificare l'opzione --no-ff
, ovviamente; la fusione senza --no-ff
dovrebbe, nel tuo scenario, essere severamente vietata. Sfortunatamente --no-ff
non è il valore predefinito; ma credo che ci sia un'opzione che puoi impostare che lo rende così. Vedi git help merge
per cosa --no-ff
fa (in breve: attiva il comportamento che ho descritto nel paragrafo precedente), è fondamentale.
we're not retroactively dumping months of parallel development into master's history.
Assolutamente no - non si sta mai scaricando qualcosa "nella cronologia" di qualche ramo, specialmente non con un commit di unione.
And if anybody needs better resolution for the sidebranch's history, well, of course it's all still there -- it's just not in master, it's in the sidebranch.
Con un commit di unione, è ancora lì. Non nel master, ma nel sidebranch, chiaramente visibile come uno dei genitori del commit di unione, e mantenuto per l'eternità, come dovrebbe essere.
Vedi cosa ho fatto? Tutte le cose che descrivi per il tuo commit di squash sono proprio lì con il merge --no-ff
commit.
Here's the problem: I work exclusively with the command line, but the rest of my team uses GUIS.
(Nota a margine: lavoro quasi esclusivamente anche con la riga di comando (beh, questa è una bugia, di solito uso emacs magit, ma questa è un'altra storia - se non sono in un posto conveniente con la mia configurazione individuale di emacs, io preferisci la riga di comando), ma per favore fai un favore a te stesso e prova almeno git gui
una volta. È così molto più efficiente per il prelievo di linee, hunk ecc. per aggiungere / annullare aggiunte.)
And I've discovered the GUIS don't have a reasonable option to display history from other branches.
Questo perché ciò che stai cercando di fare è totalmente contro lo spirito di git
. git
costruisce dal nucleo su un "grafo aciclico diretto", il che significa che molte informazioni sono nella relazione genitore-figlio di commit. E, per le unioni, ciò significa che la vera unione si impegna con due genitori e un bambino. Le GUI dei tuoi colleghi andranno bene non appena usi no-ff
merge commit.
So if you reach a squash commit, saying "this development squashed from branch XYZ", it's a huge pain to go see what's in XYZ.
Sì, ma questo non è un problema della GUI, ma del commit dello squash. Usare una zucca significa lasciare pendere la testa del ramo della caratteristica e creare un nuovo commit in master
. Questo rompe la struttura su due livelli, creando un grande casino.
So they want these big, long development-sidebranches merged in, always with a merge commit.
E hanno assolutamente ragione. Ma non sono "uniti in ", sono semplicemente uniti. Un'unione è una cosa veramente bilanciata, non ha un lato preferito che viene unito "nell'altro" ( git checkout A ; git merge B
è esattamente uguale a git checkout B ; git merge A
tranne che per piccole differenze visive come i rami scambiati in git log
ecc. ).
They don't want any history that isn't immediately accessible from the master branch.
Che è completamente corretto. In un momento in cui non ci sono caratteristiche non divise, avresti un singolo ramo master
con una ricca storia che incapsula tutte le linee di commit delle caratteristiche che c'erano, tornando al git init
commit dall'inizio del tempo (nota che io in particolare evitato di usare il termine "rami" nell'ultima parte di quel paragrafo perché la cronologia in quel momento non è più "rami", sebbene il grafico di commit sia piuttosto ramoso).
I hate that idea;
Quindi ti trovi un po 'di dolore, dal momento che stai lavorando contro lo strumento che stai utilizzando. L'approccio git
è molto elegante e potente, specialmente nell'area di branching / merging; se lo fai bene (come accennato in precedenza, specialmente con --no-ff
) è a passi da gigante superiour ad altri approcci (ad esempio, il disordine di sovversione di avere strutture di directory parallele per i rami).
it means an endless, unnavigable tangle of parallel development history.
Senza fine, parallelo - sì.
Unnavigable, tangle - no.
But I'm not seeing what alternative we have.
Perché non funziona proprio come l'inventore di git
, i tuoi colleghi e il resto del mondo lo fanno, ogni giorno?
Do we have any option here besides constantly merging sidebranches into master with merge-commits? Or, is there a reason that constantly using merge-commits is not as bad as I fear?
Nessuna altra opzione; non così male.