2009-05-13 9 views
7

में बड़ी फ़ाइलों को अस्वीकार करना हमने हाल ही में गिट का उपयोग करना शुरू कर दिया है और जब कोई बड़ी (~ 1.5 जीबी फ़ाइल) करता है तो उसमें एक ग़लत समस्या होती है, जिसके बाद विभिन्न 32 बिट ओएस पर गड़बड़ हो जाती है। ऐसा लगता है कि यह एक ज्ञात बग (गिट mmaps फ़ाइलों को स्मृति में, जो काम नहीं करता है अगर यह पर्याप्त आकस्मिक जगह नहीं मिल सकता है), जो जल्द ही किसी भी समय तय नहीं किया जा रहा है।गिट

आसान (हमारे लिए) समाधान 100 एमबी से भी कम किसी भी काम को अस्वीकार करने के लिए गिट प्राप्त करना होगा, लेकिन मैं ऐसा करने का कोई तरीका नहीं समझ सकता।

संपादित करें: समस्या बड़ी फ़ाइल की आकस्मिक जमा करने से होती है, इस मामले में प्रोग्राम आउटपुट का एक बड़ा डंप। इसका उद्देश्य आकस्मिक सबमिशन से बचने के लिए है, सिर्फ इसलिए कि यदि कोई डेवलपर गलती से बड़ी फाइल जमा करता है, तो उसे वापस निकालने का प्रयास करना दोपहर है, जहां कोई भी कोई काम नहीं कर सकता है, और उन्हें सभी स्थानीय शाखाओं को ठीक करना होगा की है।

+0

क्या बड़ी फ़ाइलों के अनजान कामों को रोकने का इरादा है? –

उत्तर

2

समस्या ठीक होने पर क्या हुआ? जब उन्होंने फ़ाइल को मूल रूप से किया था या जब इसे कहीं और धक्का दिया गया था? यदि आपके पास एक स्टेजिंग रेपो है जो हर कोई धक्का देता है, तो आप अन्य अनुमतियों आदि के साथ-साथ बड़ी फ़ाइलों के लिए बदलती रेफ को स्कैन करने के लिए एक अपडेट हुक लागू कर सकते हैं।

बहुत किसी न किसी और के लिए तैयार उदाहरण:

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

(बस पता चलता है, सब कुछ, एक पर्ल एक लाइनर के साथ किया जा सकता है, हालांकि यह कई पंक्तियों ले सकता है चला जाता है;))

कहा जाता है जिस तरह से $ GIT_DIR/हुक/अपडेट कहा जाता है (तर्क रीफ-नाम, पुरानी-rev, new-rev; उदाहरण के लिए "refs/head/master master ~ 2 master") यह फाइलों को दिखाएगा और रद्द कर देगा यदि कोई जोड़ा गया है कि बहुत बड़ा है।

ध्यान दें कि मैं कहूंगा कि अगर आप इस तरह की चीज पुलिस को जा रहे हैं, तो आपको इसे केंद्रीकृत बिंदु की आवश्यकता है। यदि आप एक दूसरे के साथ परिवर्तनों का आदान-प्रदान करने के लिए अपनी टीम पर भरोसा करते हैं, तो आपको उन पर भरोसा करना चाहिए कि विशाल बाइनरी फाइलें जोड़ना एक बुरी बात है।

1

यदि आपके पास अपने कमिटर्स टूलचैन पर नियंत्रण है, तो यह गिट प्रतिबद्धता को संशोधित करने के लिए सीधा हो सकता है ताकि यह "असली" प्रतिबद्धता से पहले फ़ाइल आकार पर एक तर्कसंगतता परीक्षण कर सके। चूंकि कोर में इस तरह के बदलाव से सभी गिट उपयोगकर्ताओं को हर प्रतिबद्धता पर बोझ आएगा, और "जीबीजी परिवर्तन करने वाले किसी भी व्यक्ति को खत्म करने" की वैकल्पिक रणनीति एक आकर्षक सादगी है, मुझे संदेह है कि इस तरह के परीक्षण को कोर में कभी स्वीकार नहीं किया जाएगा। मेरा सुझाव है कि आप गठबंधन के स्थानीय कांटा को बनाए रखने का बोझ उठाएं - नानीगिट - एक विनाशकारी प्रतिबद्धता के बाद एक दुर्घटनाग्रस्त गिट की मरम्मत के बोझ के खिलाफ।

मुझे स्वीकार करना होगा कि मैं 1.5 जीबी प्रतिबद्धता के बारे में उत्सुक हूं। क्या वीडियो फाइलें शामिल हैं?

2

आप एक प्री-प्रतिबद्ध हुक वितरित कर सकते हैं जो काम करता है। केंद्रीय भंडारों पर आप एक पूर्व-प्राप्त हुक प्राप्त कर सकते हैं जो प्राप्त डेटा का विश्लेषण करके बड़े संदर्भों को अस्वीकार कर देता है और इसे संदर्भित होने से रोकता है। डेटा प्राप्त होगा, लेकिन चूंकि आप रेफरी के अपडेट को अस्वीकार करते हैं, इसलिए प्राप्त सभी नई वस्तुओं को बिना संदर्भित किया जाएगा और इसे गिट जीसी द्वारा उठाया जा सकता है।

हालांकि मेरे पास आपके लिए कोई स्क्रिप्ट नहीं है।

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}