2009-05-13 3 views
7

最近、gitの使用を開始し、誰かが大きな(約1.5GBのファイル)をコミットしたときに、いろいろな32ビットOSでgitがクラッシュするという問題がありました。これは既知のバグ(gitがメモリにファイルをmmapsしてしまい、十分な連続スペースが得られない場合には動作しません)のようです。すぐには修正されません。大きなファイルをgitで拒否する

私たちにとって簡単な解決策は、gitが100MBほどの大きなコミットを拒否することですが、私はそれを行う方法を理解できません。

EDIT:この問題は、大きなファイルが誤ってサブミットされた場合に発生します。この場合、プログラム出力が大きくダンプされます。開発者が大量のファイルを誤って提出し、リポジトリを取り戻そうとすると、誰も仕事をすることができない午後になり、すべての地元の支店を修復しなければならないという理由で、偶発的な提出を避けることが目的です持ってる。

+0

大きなファイルの不注意なコミットを防止する予定はありますか? –

答えて

2

問題が発生したのはいつですか?彼らが最初にファイルをコミットしたとき、または他の場所にプッシュされたとき?全員がプッシュするステージングリポジトリがあれば、大きなフアイルの変更されたrefをスキャンする更新フックを実装し、他のパーミッションのチェックなどを行うことができます。

非常ラフと準備例:

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

(それは複数行を取るかもしれませんがちょうど示すことを行く、すべてが、Perlのワンライナーで行うことができます;))

呼び出さ

(refs/heads/master master〜2 masterのように、ref-name、old-rev、new-revです)$ GIT_DIR/hooks/updateが呼び出される方法で、これは追加されたファイルを表示し、が大きすぎます。

私は、あなたがこのようなことを警察に任せれば、それを行うための集中的なポイントが必要だと言います。あなたのチームが互いの変更を交換するだけだと信じているならば、巨大なバイナリファイルを追加することが悪いことを彼らが信じるべきです。

1

あなたのコミッターのツールチェーンを管理しているならば、 "本当の"コミットの前にファイルサイズについて合理的なテストを行うようにgit commitを修正するのが簡単かもしれません。このようなコアの変更はすべてのコミット時にすべてのgitユーザーに負担をかけ、 "1.5GBの変更を行う人を追放する"代替戦略は魅力的なシンプルさを持っているため、このようなテストは決して受け入れられないだろう。私は、あなたが過度のコミットの後にクラッシュしたgitを修復する負担に対して、git - nannygitのローカルフォークを維持する負担を測ることをお勧めします。

私は1.5GBコミットがどのようになったのか不思議です。ビデオファイルは関係していますか?

2

コミットを防止するプリコミットフックを配布できます。中央のリポジトリでは、受け取ったデータを分析して大きなブロブを拒否し、それが参照されないようにする事前受信フックを持つことができます。データは受信されますが、refへの更新を拒否するため、受信したすべての新しいオブジェクトは参照されず、git gcによってピックアップされて削除されます。

私はあなたのためのスクリプトを持っていません。

0
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}