Question

Nous avons récemment commencé à utiliser git et avait un problème méchant quand quelqu'un a commis un grand (~ fichier 1.5GB), qui a causé alors git crash sur divers systèmes d'exploitation 32bits. Cela semble être un bug connu (fichiers de mmaps git en mémoire, ce qui ne fonctionne pas si elle ne peut pas obtenir assez d'espace contingous), ce qui ne va pas se fixe dans un proche avenir.

Le facile (pour nous) solution serait d'obtenir git de rejeter toute commits de plus de 100 Mo ou plus, mais je ne peux pas trouver un moyen de le faire.

EDIT: Le problème vient de la soumission accidentelle de gros fichier, dans ce cas, une grande décharge de la production du programme. Le but est d'éviter la soumission accidentelle, juste parce que si un développeur ne présente accidentellement un fichier volumineux, en essayant de puis récupérer le dépôt est un après-midi où personne ne peut faire un travail, et doit réparer toutes les branches locales qu'ils ont.

Était-ce utile?

La solution

Quand exactement le problème se produit? Quand ils ont commis le fichier à l'origine ou quand il a été repoussée ailleurs? Si vous avez une prise en pension de mise en scène que tout le monde pousse, vous pourriez mettre en œuvre un crochet de mise à jour pour analyser l'évolution refs pour les gros fichiers, ainsi que d'autres autorisations, etc vérifier.

très exemple rustre:

git --no-pager log --pretty=oneline --name-status $2..$3 -- | \
  perl -MGit -lne 'if (/^[0-9a-f]{40}/) { ($rev, $message) = split(/\s+/, $_, 2) }
     else { ($action, $file) = split(/\s+/, $_, 2); next unless $action eq "A"; 
       $filesize = Git::command_oneline("cat-file", "-s", "$rev:$file");
       print "$rev added $file ($filesize bytes)"; die "$file too big" if ($filesize > 1024*1024*1024) }';

(va juste pour montrer, tout peut être fait avec un Perl one-liner, bien qu'il puisse prendre plusieurs lignes;))

Appelé de la manière que $ GIT_DIR / crochets / mise à jour est appelé (args sont ref-name, old-rev, nouveau-rev, par exemple "refs / heads / maître maître ~ 2 maître"), cela affichera les fichiers ajoutés et interrompra si l'on ajoute c'est trop grand.

Notez que je dirais que si vous allez à la police ce genre de chose, vous avez besoin d'un point central auquel de le faire. Si vous faites confiance à votre équipe pour simplement échanger des changements entre eux, vous devriez leur faire confiance pour apprendre que l'ajout de fichiers binaires géant est une mauvaise chose.

Autres conseils

Vous pouvez distribuer un crochet pre-commit qui empêche commits. Sur les dépôts centraux, vous pouvez avoir un crochet pré-réception qui rejette les grands blobs en analysant les données reçues et l'empêcher d'être référencé. Les données seront reçues, mais puisque vous rejetez mises à jour de refs, tous les nouveaux objets reçus seront et peut être non référencé ramassés et déposés par git gc.

Je n'ai pas un script pour vous bien.

Si vous avez le contrôle sur votre committers de la toolchain, il peut être simple de modifier git commit afin qu'il effectue un test de caractère raisonnable sur la taille du fichier avant la validation « réel ». Étant donné qu'un tel changement dans le noyau se charge tous les utilisateurs git à chaque livraison, et la stratégie alternative de « bannir toute personne qui engagerait un changement de 1.5GB » a une simplicité séduisante, je soupçonne un tel test ne sera jamais accepté dans le noyau. Je vous suggère de peser la charge de maintenir une fourchette locale de git - nannygit -., La charge de la réparation d'un git écrasé suite à un trop ambitieux commettras

Je dois admettre que je suis curieux de savoir comment un 1,5 Go commit est venu à être. Sont des fichiers vidéo impliqués?

Here is my solution. I must admit it doesn't look like others I have seen, but to me it makes the most sense. It only checks the inbound commit. It does detect when a new file is too large, or an existing file becomes too big. It is a pre-receive hook. Since tags are size 0, it does not check them.

    #!/usr/bin/env bash
#
# This script is run after receive-pack has accepted a pack and the
# repository has been updated.  It is passed arguments in through stdin
# in the form
#  <oldrev> <newrev> <refname>
# For example:
#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#
# see contrib/hooks/ for an sample, or uncomment the next line (on debian)
#

set -e

let max=1024*1024
count=0
echo "Checking file sizes..."
while read oldrev newrev refname
do
#   echo $oldrev $newrev $refname
    # skip the size check for tag refs
    if [[ ${refname} =~ ^refs/tags/* ]]
    then
        continue
    fi

    if [[ ${newrev} =~ ^[0]+$ ]]
    then
        continue
    fi

    # find all refs we don't care about and exclude them from diff
    if [[ ! ${oldrev} =~ ^[0]+$ ]]
    then
        excludes=^${oldrev}
    else
        excludes=( $(git for-each-ref --format '^%(refname:short)' refs/heads/) )
    fi
#   echo "excludes " ${excludes}
    commits=$(git rev-list $newrev "${excludes[@]}")
    for commit in ${commits};
    do
#       echo "commit " ${commit}
        # get a list of the file changes in this commit
        rawdiff=$(git diff-tree --no-commit-id ${commit})
        while read oldmode newmode oldsha newsha code fname
        do
#           echo "reading " ${oldmode} ${newmode} ${oldsha} ${newsha} ${code} ${fname}
            # if diff-tree returns anything, new sha is not all 0's, and it is a file (blob)
            if [[ "${newsha}" != "" ]] && [[ ! ${newsha} =~ ^[0]+$ ]] && [[ $(git cat-file -t ${newsha}) == "blob" ]]
            then
                echo -n "${fname} "
                newsize=$(git cat-file -s ${newsha})
                if (( ${newsize} > ${max} ))
                then
                    echo " size ${newsize}B > ${max}B"
                    let "count+=1"
                else
                    echo "ok"
                fi
            fi
        done <<< "${rawdiff}"
    done
done

exit ${count}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top