Frage

Wir haben mit git vor kurzem begonnen und hatten ein unangenehmes Problem, wenn jemand eine große (~ 1,5 GB-Datei) begangen, dass dann git verursachten auf verschiedenen 32-Bit-Betriebssysteme zum Absturz bringen. Dies scheint einen bekannten Fehler (git mmaps Dateien in den Speicher, die, wenn sie nicht funktioniert es nicht genug contingous Raum bekommen kann) zu sein, die sich in absehbarer Zeit nicht fest in Gang zu bringen.

Die einfache (für uns) Lösung wäre git zu erhalten alle Commits größer als 100 MB abzulehnen oder so, aber ich kann nicht einen Weg finden, um das zu tun.

EDIT: Das Problem kommt von den versehentlichen Abgabe der großen Datei, in diesem Fall ein großen Dump-Programm ausgegeben. Das Ziel ist, versehentliche Abgabe zu vermeiden, nur weil, wenn ein Entwickler versehentlich eine große Datei nicht einreichen, versucht es dann wieder raus das Repository ein Nachmittag ist, wo niemand jede Arbeit tun kann, und verfügt über alle lokalen Niederlassungen reparieren sie haben.

War es hilfreich?

Lösung

Wann genau trat das Problem auf? Als sie verpflichtet, die Datei ursprünglich oder wenn es wurde an anderer Stelle geschoben? Wenn Sie eine Staging-Repo haben, dass jeder schiebt, könnten Sie ein Update Haken implementieren Ändern Refs, für große Dateien zu scannen, zusammen mit anderen Berechtigungen usw. zu überprüfen.

Sehr notdürftig Beispiel:

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) }';

(geht nur um zu zeigen, kann alles mit einem Perl-Einzeiler getan werden, obwohl es mehr Zeilen dauern kann;))

in der Art und Weise aufgerufen, dass $ GIT_DIR / Haken / update genannt wird (args sind ref-name, old-rev, new-rev, zB "refs / heads / master master ~ 2 Master"), wird dies die Dateien zeigen hinzugefügt und abbrechen, wenn man hinzugefügt wird, dass zu groß ist.

Beachten Sie, dass ich würde sagen, dass wenn Sie diese Art der Sache der Polizei gehen, benötigen Sie einen zentralen Punkt, an dem es zu tun. Wenn Sie Ihrem Team vertrauen nur Änderungen miteinander austauschen, sollten Sie ihnen vertrauen zu lernen, dass das Hinzufügen Riese Binärdateien eine schlechte Sache ist.

Andere Tipps

Sie können einen pre-commit verteilen Haken, den Commits verhindert. Auf zentrale Repositories können Sie einen bereits erhalten Haken haben, die durch die Analyse der empfangenen Daten großen Blobs ablehnt und verhindern, dass sie verwiesen wird. Daten empfangen werden, aber da Sie Updates zu Refs ablehnen, werden alle neuen Objekte empfangen werden unreferenced sein und können abgeholt und abgesetzt von git gc.

ich ein Skript für Sie nicht obwohl haben.

Wenn Sie die Kontrolle über Ihre Committer Werkzeugkette haben, kann es einfach sein git zu modifizieren begehen, so dass es eine Vernünftigkeit Test auf die Dateigröße vor dem ‚echten‘ begehen führt. Da eine solche Änderung im Kern würde belasten alle Git-Benutzer auf jedem Commit, und die alternative Strategie der „jemand verbannen, die eine 1,5 GB Änderung begehen würde“ hat eine ansprechende Einfachheit, vermute ich, ein solcher Test wird nie im Kern akzeptiert werden. Ich schlage vor, Sie die Last der Aufrechterhaltung einer lokalen Gabel von git wiegen - nannygit -. Gegen die Belastung eines abgestürzten git Reparatur nach einer overambitious begehen

Ich muss zugeben, ich bin gespannt, wie ein 1,5 GB commit kam. Sind Videodateien beteiligt?

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}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top