Limitazione della dimensione del file nel repository git

Attualmente sto pensando di cambiare il mio VCS (da sovversione) a git. È ansible limitare la dimensione del file all’interno di un commit in un repository git? Per es. Sovversione c’è un hook: http://www.davidgrant.ca/limit_size_of_subversion_commits_with_this_hook

Dalla mia esperienza, le persone, specialmente quelle inesperte, a volte tendono a commettere file che non dovrebbero entrare in un VCS (ad esempio immagini di grandi file system).

Mentre stavo lottando per un po ‘, anche con la descrizione, e penso che questo sia rilevante anche per gli altri, ho pensato di pubblicare un’implementazione su come ciò che J16 SDiZ ha descritto potrebbe essere implementato.

Quindi, il mio punto di vista sul hook di update lato server che impedisce di inviare file troppo grandi:

 #!/bin/bash # Script to limit the size of a push to git repository. # Git repo has issues with big pushes, and we shouldn't have a real need for those # # eis/02.02.2012 # --- Safety check, should not be run from command line if [ -z "$GIT_DIR" ]; then echo "Don't run this script from the command line." >&2 echo " (if you want, you could supply GIT_DIR then run" >&2 echo " $0   )" >&2 exit 1 fi # Test that tab replacement works, issue in some Solaris envs at least testvariable=`echo -e "\t" | sed 's/\s//'` if [ "$testvariable" != "" ]; then echo "Environment check failed - please contact git hosting." >&2 exit 1 fi # File size limit is meant to be configured through 'hooks.filesizelimit' setting filesizelimit=$(git config hooks.filesizelimit) # If we haven't configured a file size limit, use default value of about 100M if [ -z "$filesizelimit" ]; then filesizelimit=100000000 fi # Reference to incoming checkin can be found at $3 refname=$3 # With this command, we can find information about the file coming in that has biggest size # We also normalize the line for excess whitespace biggest_checkin_normalized=$(git ls-tree --full-tree -r -l $refname | sort -k 4 -n -r | head -1 | sed 's/^ *//;s/ *$//;s/\s\{1,\}/ /g' ) # Based on that, we can find what we are interested about filesize=`echo $biggest_checkin_normalized | cut -d ' ' -f4,4` # Actual comparison # To cancel a push, we exit with status code 1 # It is also a good idea to print out some info about the cause of rejection if [ $filesize -gt $filesizelimit ]; then # To be more user-friendly, we also look up the name of the offending file filename=`echo $biggest_checkin_normalized | cut -d ' ' -f5,5` echo "Error: Too large push attempted." >&2 echo >&2 echo "File size limit is $filesizelimit, and you tried to push file named $filename of size $filesize." >&2 echo "Contact configuration team if you really need to do this." >&2 exit 1 fi exit 0 

Le risposte di eis e J-16 SDiZ soffrono di un grave problema. Stanno controllando solo lo stato del finale commit $ 3 o $ newrev. Devono inoltre verificare che cosa viene inviato negli altri commit tra $ 2 (o $ oldrev) e $ 3 (o $ newrev) nel hook di udpate.

J-16 SDiZ è più vicino alla risposta giusta.

Il grande difetto è che qualcuno il cui server dipartimentale ha installato questo hook di aggiornamento per proteggerlo scoprirà nel modo più duro che:

Dopo aver usato git rm per rimuovere accidentalmente il file di grandi dimensioni, la struttura attuale o l’ultimo commit andranno a posto, e verrà inserita tutta la catena di commit, incluso il grande file che è stato eliminato, creando un grasso gonfiato e infelice storia che nessuno vuole

Per soluzione è sia per controllare ogni commit da $ oldrev a $ newrev, o per specificare l’intero intervallo $ oldrev .. $ newrev. Assicurati che non stai controllando solo $ newrev da solo, o questo fallirà con una grossa spazzatura nella tua storia git, spinto a condividere con gli altri, e poi difficile o imansible da rimuovere dopo.

se usi la gitolite puoi anche provare VREF. C’è un VREF già fornito di default (il codice è in gitolite / src / VREF / MAX_NEWBIN_SIZE). Si chiama MAX_NEWBIN_SIZE. Funziona così:

 repo name RW+ = username - VREF/MAX_NEWBIN_SIZE/1000 = usernames 

Dove 1000 è la soglia di esempio in byte.

Questo VREF funziona come un hook di aggiornamento e rifiuterà il tuo push se un file che stai per spingere è maggiore della soglia.

È ansible utilizzare un hook , hook pre-commit (sul client) o hook di update (sul server). Fai un git ls-files --cached (per pre-commit) o git ls-tree --full-tree -r -l $3 (per l’aggiornamento) e agisci di conseguenza.

git ls-tree -l darebbe qualcosa come questo:

 100644 blob 97293e358a9870ac4ddf1daf44b10e10e8273d57 3301 file1 100644 blob 02937b0e158ff8d3895c6e93ebf0cbc37d81cac1 507 file2 

Prendi la quarta colonna, ed è la dimensione. Usa git ls-tree --full-tree -r -l HEAD | sort -k 4 -n -r | head -1 git ls-tree --full-tree -r -l HEAD | sort -k 4 -n -r | head -1 git ls-tree --full-tree -r -l HEAD | sort -k 4 -n -r | head -1 per ottenere il file più grande. cut per estrarre, if [ a -lt b ] per controllare le dimensioni, ecc.

Scusa, penso che se sei un programmatore, dovresti essere in grado di farlo da solo.

Sì, Git ha anche gli ami ( git ganci ). Ma dipende dal stream di lavoro che userete.

Se hai utenti inesperti, è molto più sicuro tirare, quindi lasciarli spingere. In questo modo, puoi assicurarti che non rovinino il repository principale.

Un altro modo è la versione a .gitignore , che impedirà a qualsiasi file con una certa estensione di apparire nello stato.
Puoi ancora avere degli hook (su downstream o upstream, come suggerito dalle altre risposte), ma almeno tutto il repository downstream può includere quel .gitignore per evitare di aggiungere .exe , .dll , .iso , …

Questo sarà un caso molto raro da quello che ho visto quando qualcuno lo controlla, diciamo un 200Mb o anche più file di dimensioni.

Mentre puoi evitare che ciò accada usando ganci lato server (non sono sicuro dei ganci lato client dal momento che devi fare affidamento sulla persona che ha i ganci installati) come in SVN, devi tenerne conto anche in Git , è molto più facile rimuovere un tale file / commit dal repository. Non hai avuto un tale lusso in SVN, almeno non è un modo semplice.

Sto usando gitolite e il hook di aggiornamento era già in uso – invece di usare il hook di aggiornamento, ho usato il hook di pre-ricezione. La sceneggiatura pubblicata da Chriki ha funzionato favolosamente con l’eccezione che i dati sono passati tramite stdin, quindi ho apportato una modifica alla linea:

 - refname=$3 + read ab refname 

(potrebbe esserci un modo più elegante per farlo ma funziona)