Perché git commit non contiene il nome del ramo su cui sono stati creati?

20

Quando lavoro con git in una squadra che usa le branch caratteristiche, lo trovo spesso difficile capire la struttura del ramo nella storia.

Esempio:

Diciamo che c'era un ramo di funzione feature / make-coffee e bugfixing continuato su master in parallelo al ramo della funzione.

La cronologia potrebbe essere simile a questa:

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

problema

A prima vista, trovo difficile capire da che parte si tratta ramo. Di solito ho bisogno di sfogliare diversi commenti su entrambi i lati per ottenere un'idea di quale è quale. Questo diventa più complicato se ci sono più feature branch in parallelo (in particolare se sono per caratteristiche strettamente correlate), o se ci fosse una fusione in entrambe le direzioni tra feature branch e master.

Come contrasto, in Subversion, questo è significativamente più facile perché il il nome del ramo è parte della storia - quindi posso dire subito che a il commit è stato originariamente realizzato in "feature / make-coffee".

Git potrebbe renderlo più facile includendo il nome del ramo corrente nei metadati di commit durante la creazione di un commit (insieme all'autore, data eccetera.). Tuttavia, git non lo fa.

C'è qualche motivo fondamentale per cui ciò non viene fatto? O è solo che nessuno voleva la funzione? Se è il secondo, ci sono altri modi di comprendere lo scopo dei rami storici senza vedere il nome?

    
posta sleske 30.09.2013 - 22:03
fonte

5 risposte

14

Probabilmente perché i nomi dei rami sono significativi solo all'interno di un repository. Se sono nella squadra make-coffee e invio tutte le mie modifiche attraverso un gatekeeper, il mio ramo master potrebbe essere richiamato al ramo make-coffee-gui del gatekeeper, che si unirà al suo ramo make-coffee-backend , prima di rebasing a un make-coffee ramo che viene unito al ramo master centrale.

Anche all'interno di un repository, i nomi delle filiali possono cambiare e cambiare mano a mano che il tuo flusso di lavoro si evolve. master potrebbe cambiare in seguito per essere chiamato development , ad esempio.

Come CodeGnome ha alluso, git ha una strong filosofia di progettazione di non cuocere qualcosa nei dati se non è necessario. Ci si aspetta che gli utenti usino le opzioni in git log e git diff per produrre i dati a loro piacimento dopo il fatto. Vi consiglio di provare un po 'fino a trovare un formato che funzioni meglio per voi. git log --first-parent , ad esempio, non mostrerà i commit da un ramo che viene unito.

    
risposta data 01.10.2013 - 00:06
fonte
5

Tieni traccia della cronologia delle filiali con --no-ff

In Git, un commit ha antenati, ma un "ramo" è in realtà solo l'attuale capo di una linea di sviluppo. In altre parole, un commit è un'istantanea dell'albero di lavoro in un determinato momento e può appartenere a qualsiasi numero di rami contemporaneamente. Questo fa parte di ciò che rende la ramificazione di Git così leggera rispetto ad altri DVCS.

I commit Git non portano informazioni sui rami perché non sono necessari per la cronologia Git. Tuttavia, le fusioni che non sono fast-forward possono certamente portare ulteriori informazioni su quale ramo è stato unito. Puoi assicurarti che la cronologia contenga queste informazioni passando sempre il flag --no-ff alle tue unioni. git-merge (1) dice:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

Generalmente questo crea un messaggio di fusione simile a Merge branch 'foo' , quindi in genere puoi trovare informazioni su "rami antenati" con una linea simile alla seguente:

$ git log --regexp-ignore-case --grep 'merge branch'
    
risposta data 30.09.2013 - 22:47
fonte
3

La risposta più semplice è che i nomi dei rami sono effimeri. Cosa succede se dovessi, ad esempio, rinominare un ramo ( git branch -m <oldname> <newname> )? Cosa accadrebbe a tutti i commit contro quel ramo? O se due persone hanno rami che hanno lo stesso nome su diversi repository locali?

L'unica cosa che ha un significato in git è il checksum del commit stesso. Questa è l'unità di base del monitoraggio.

Le informazioni sono lì, non le chiedi semplicemente, e non sono esattamente lì.

Git memorizza il checksum della testa di ogni ramo in .git/refs/heads . Ad esempio:

.../.git/refs/heads$ ls test 
-rw-rw-r-- 1 michealt michealt   41 Sep 30 11:50 test
.../.git/refs/heads$ cat test 
87111111111111111111111111111111111111d4

(sì, sto sbavando nei miei checksum git, non è speciale, ma sono repository privati che sto guardando nel momento in cui non è necessario che qualcosa trapelasse accidentalmente).

Osservando questo e rintracciando ogni commit che ha questo come genitore, o il genitore dei genitori o il genitore dei genitori ... puoi scoprire in che rami è inserito un dato commit. È solo un grande grafico da rappresentare.

Memorizzando dove specificamente il nome di un ramo (che può cambiare come menzionato sopra) un commit è nel commit stesso è un overhead extra sul commit che non lo aiuta. Memorizza il (i) genitore (i) del commit e il suo bene.

Puoi vedere i rami eseguendo il comando git log con il flag appropriato.

git log --branches --source --pretty=oneline --graph
git log --all --source --pretty=oneline --graph

Ci sono molti modi per scegliere quello che vuoi per questo - guarda git log documentazione - la sezione -all e le poche opzioni che seguono.

*   87111111111111111111111111111111111111d4    test Merge branch 'test1' into test
|\  
| * 42111111111111111111111111111111111111e8    test1 update: add stuff
* |   dd11111111111111111111111111111111111159  test Merge branch 'test3' into test
|\ \  

Che 'test', 'test1' e 'test2' sono i rami a cui sono stati impegnati.

Si noti che la documentazione del log git è enorme ed è abbastanza possibile ottenere quasi tutto ciò che si desidera da esso.

    
risposta data 30.09.2013 - 23:51
fonte
3

Perché git commits non contiene il nome del ramo su cui sono stati creati?

Solo una decisione di progettazione. Se hai bisogno di queste informazioni, puoi aggiungere un hook prepar-commit-msg o commit-msg per applicarlo su un singolo repository.

Dopo il disastro di BitKeeper Linus Torvalds ha sviluppato git per abbinare il processo di sviluppo del kernel di Linux. Lì, fino a quando una patch non viene accettata, viene rivista, modificata, ottimizzata più volte (tutto tramite Mail), firmata (= modifica di un commit), selezionata a mano, errante per i rami di luogotenente, magari spesso ribattezzata, più modifiche, ciliegia -picks e così via fino a quando non sono finalmente unite a monte da Linus.

In un tale flusso di lavoro potrebbe non esserci origine specifica di un commit e spesso un commit viene appena creato in qualche ramo di debug temporaneo in qualche repository privato privato non importante con nomi di rami divertenti, dato che git è distribuito.

Forse questa decisione di progettazione è appena avvenuta per coincidenza, ma corrisponde esattamente al processo di sviluppo del kernel di Linux.

    
risposta data 01.10.2013 - 09:09
fonte
2

Perché in Git i commit come "make coffee" sono considerati parte dei entrambi i rami quando il ramo della funzione viene unito. C'è anche un comando per verificare che:

% git branch --contains @
  feature/make-coffee
  master

Inoltre, i rami sono economici, locali ed eterei; possono essere facilmente aggiunti, rimossi, rinominati, inviati e cancellati dal server.

Git segue il principio secondo cui tutto può essere fatto, motivo per cui puoi facilmente rimuovere un ramo da un server remoto e puoi facilmente riscrivere la cronologia.

Diciamo che ero nel ramo 'master' e ho fatto due commit: 'make coffee' e 'aggiungi latte e zucchero', poi decido di usare un nuovo ramo per quello, quindi resetto 'master' indietro a "origine / master". Non è un problema, tutta la cronologia è ancora pulita: 'fare il caffè' e 'aggiungere latte e zucchero' non fanno parte del master, sono solo feature / make-coffee.

Mercurial è il contrario; non vuole cambiare le cose. Le filiali sono permanenti, la cronologia delle riscritture è disapprovata, non puoi semplicemente eliminare un ramo dal server.

In breve: Git ti consente di fare tutto, Mercurial vuole semplificare le cose (e rende davvero difficile lasciarti fare quello che vuoi).

    
risposta data 18.05.2016 - 21:09
fonte

Leggi altre domande sui tag