Dopo tre mesi di sviluppo, è stata rilasciata la versione 2.41 del sistema distribuito di gestione delle versioni Git. Git è uno dei sistemi di controllo versione più popolari, affidabili e ad alte prestazioni, che fornisce strumenti flessibili per lo sviluppo non lineare basati su ramificazioni e fusioni. Per garantire l'integrità della cronologia e la resistenza alle modifiche retroattive, si utilizza l'hashing implicito dell'intera cronologia precedente in ogni commit, ed è possibile la verifica tramite firme digitali degli sviluppatori per singoli tag e commit.
Rispetto alla versione precedente, nella nuova versione sono stati inclusi 542 cambiamenti, frutto della collaborazione di 95 sviluppatori, 29 dei quali hanno partecipato per la prima volta allo sviluppo. Le principali novità:
- È stato migliorato il trattamento degli oggetti irraggiungibili (unreachable), per i quali non ci sono riferimenti nel repository (non sono referenziati da branche o tag). Gli oggetti irraggiungibili vengono rimossi dal garbage collector, ma prima di essere rimossi rimangono nel repository per un certo periodo di tempo per evitare condizioni di competizione. Per monitorare il periodo di esistenza degli oggetti irraggiungibili, è necessaria l'associazione di etichette temporali a tali oggetti, il che impedisce di conservarli in un unico pacchetto file, dove tutti gli oggetti condividono lo stesso timestamp. In precedenza, ogni oggetto irraggiungibile veniva salvato in un file separato, il che causava problemi in presenza di un alto numero di nuovi oggetti irraggiungibili che non erano ancora soggetti a cancellazione. Nella nuova versione, per il confezionamento degli oggetti irraggiungibili viene utilizzato per impostazione predefinita il meccanismo dei "cruft packs", che consente di conservare tutti gli oggetti irraggiungibili in un unico pacchetto file, e i dati sui tempi di modifica di ciascun oggetto vengono riportati in una tabella separata, conservata in un file con estensione ".mtimes" e collegata tramite un file indice con estensione ".idx".

- È stata abilitata per impostazione predefinita la registrazione su disco dell'indice inverso (revindex) per i pacchetti file. Durante i test nel repository torvalds/linux, l'applicazione dell'indice inverso ha consentito di accelerare operazioni intensive come "git push" di 1,49 volte, mentre operazioni semplici, come il calcolo della dimensione di un oggetto con "git cat-file —batch='%{objectsize:disk}'", sono state accelerate di 77 volte. I file ".rev" con l'indice inverso verranno salvati all'interno del repository nella directory ".git/objects/pack".
Ricordiamo che Git memorizza tutti i dati sotto forma di oggetti, che sono collocati in file separati. Per migliorare l'efficienza del lavoro con il repository, gli oggetti vengono ulteriormente collocati in file pack, nei quali le informazioni sono presentate sotto forma di flusso di oggetti che si susseguono (un formato simile è utilizzato durante il trasferimento di oggetti con i comandi git fetch e git push). Per ogni file pack viene creato un file indice (.idx), che consente di determinare molto rapidamente l'offset nel file pack in base all'identificatore dell'oggetto per cui è memorizzato quest'oggetto.
L'indice inverso incluso nella nuova versione mira a ottimizzare il processo di determinazione dell'identificativo dell'oggetto in base alle informazioni sulla posizione dell'oggetto nel pacchetto file. In precedenza, tale trasformazione avveniva al volo durante l'analisi del pacchetto file e veniva conservata solo in memoria, il che non consentiva il riutilizzo di tali indici e costringeva a generare un indice ogni volta. L'operazione di costruzione dell'indice si riduce a costruire un array di coppie "oggetto-posizione" e ordinarlo per posizione, il che può richiedere molto tempo per pacchetti file di grandi dimensioni.
Ad esempio, l'operazione di visualizzazione del contenuto degli oggetti, in cui viene utilizzato un indice diretto, è stata eseguita 62 volte più velocemente rispetto all'operazione di visualizzazione delle dimensioni degli oggetti, per la quale i dati di collegamento tra posizione e oggetto non erano indicizzati. Dopo l'uso dell'indice inverso, le operazioni indicate hanno cominciato a richiedere all'incirca lo stesso tempo. Gli indici inversi consentono anche di accelerare le operazioni di invio degli oggetti durante l'esecuzione dei comandi fetch e push grazie alla trasmissione diretta dei dati già pronti dal disco.

- È stata aggiunta al protocollo "credential helper", utilizzato per la trasmissione delle credenziali durante le chiamate a repository con accesso limitato, la supporto per la trasmissione degli header WWW-Authenticate tra il gestore delle credenziali e il servizio in cui avviene l'autenticazione. Il supporto per l'header WWW-Authenticate consente di trasmettere parametri scope OAuth per una suddivisione più granulare dell'accesso degli utenti ai repository e per delimitare le aree disponibili per le richieste.
- È stata aggiunta al comando for-each-ref l'opzione di formattazione "%(ahead-behind:)", che consente di ottenere rapidamente informazioni sul numero di commit presenti o assenti in un determinato ramo rispetto a un altro ramo (di quanto un ramo è in ritardo o in anticipo rispetto all'altro a livello di commit). In precedenza, per ottenere tali informazioni, era necessario eseguire due comandi separati: "git rev-list —count main..my-feature" per ottenere il numero di commit unici per il ramo e "git rev-list —count my-feature..main" per ottenere il numero di commit assenti. Ora tali calcoli possono essere ridotti a un solo comando, semplificando la scrittura dei gestori e riducendo il tempo di esecuzione. Ad esempio, per mostrare i rami non uniti e valutare il ritardo o l'anticipo rispetto al ramo principale, è possibile utilizzare una riga di comando: $ git for-each-ref —no-merged=origin/HEAD \ —format='%(refname:short) %(ahead-behind:origin/HEAD)' \ refs/heads/tb/ | column -t tb/cruft-extra-tips 2 96 tb/for-each-ref—exclude 16 96 tb/roaring-bitmaps 47 3 invece di utilizzare lo script precedentemente utilizzato, che viene eseguito 17 volte più lentamente: $ git for-each-ref —format='%(refname:short)' —no-merged=origin/HEAD \ refs/heads/tb | while read ref do ahead="$(git rev-list --count origin/HEAD..$ref)" behind="$(git rev-list --count $ref..origin/HEAD)" printf "%s %d %d\n" "$ref" "$ahead" "$behind" done | column -t tb/cruft-extra-tips 2 96 tb/for-each-ref—exclude 16 96 tb/roaring-bitmaps 47 3
- Nel comando «git fetch» è stata aggiunta l'opzione «—porcelain», che produce un'uscita nel formato « », meno leggibile ma più comoda per essere analizzata negli script.
- È stata aggiunta l'impostazione «fetch.hideRefs», che consente di accelerare le operazioni di «git fetch» nascondendo parte dei riferimenti nel repository locale durante il controllo dell'invio da parte del server dell'intero insieme di oggetti. Ciò consente di risparmiare tempo limitando il controllo solo a server, da cui vengono estratti i dati direttamente. Ad esempio, durante il test su un sistema con repository contenenti un gran numero di riferimenti esterni tracciati, escludere tutti i riferimenti eccetto quelli indirizzati a $remote ha permesso di ridurre il tempo di esecuzione dell'operazione «git fetch» da 20 minuti a 30 secondi. $ git -c fetch.hideRefs=refs -c fetch.hideRefs=!refs\/remotes\/ $remote \ fetch $remote server $remote, riducendo il tempo di esecuzione dell'operazione «git fetch» da 20 minuti a 30 secondi. $ git -c fetch.hideRefs=refs -c fetch.hideRefs=!refs/remotes/$remote \ fetch $remote
- Nel comando «git fsck» è stata implementata la possibilità di controllare danneggiamenti, corrispondenza delle somme di controllo e correttezza dei valori nelle mappe di disponibilità e negli indici inversi.
- Nel comando «git clone —local» è stata implementata l'uscita di errore quando si tenta di copiare da un repository che contiene collegamenti simbolici all'interno di $GIT_DIR.
Fonte: opennet.ru


