2011-08-22 52 views
21

Tôi hiện đang nghĩ đến việc thay đổi VCS (từ lật đổ) sang git. Có thể giới hạn kích thước tệp trong một cam kết trong kho lưu trữ git không? Đối với e. g. subversion có một cái móc: http://www.davidgrant.ca/limit_size_of_subversion_commits_with_this_hookGiới hạn kích thước tệp trong kho git

Từ những người có kinh nghiệm của tôi, đặc biệt là những người thiếu kinh nghiệm, đôi khi có xu hướng cam kết các tập tin không nên đi vào VCS (hình ảnh hệ thống tập tin lớn).

Trả lời

2

Vâng, git cũng có móc (git hooks). Nhưng nó phụ thuộc vào dòng chảy công việc thực tế mà bạn sẽ sử dụng.

Nếu bạn có người dùng thiếu kinh nghiệm, sẽ an toàn hơn nhiều để kéo, sau đó để cho họ đẩy. Bằng cách đó, bạn có thể chắc chắn rằng họ sẽ không làm hỏng kho lưu trữ chính.

2

Bạn có thể sử dụng hook, móc pre-commit (trên máy khách) hoặc móc update (trên máy chủ). Hãy thực hiện một số git ls-files --cached (cho tiền cam kết) hoặc git ls-tree --full-tree -r -l $3 (để cập nhật) và hành động tương ứng.

git ls-tree -l sẽ cung cấp cho một cái gì đó như thế này:

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

Grab cột ra, và nó là kích thước. Sử dụng git ls-tree --full-tree -r -l HEAD | sort -k 4 -n -r | head -1 để nhận tệp lớn nhất. cut để trích xuất, if [ a -lt b ] để kiểm tra kích thước, v.v.

Xin lỗi, tôi nghĩ nếu bạn là lập trình viên, bạn sẽ có thể tự mình làm điều này.

+10

Bị bỏ phiếu cho bullsh ** tự mình làm nhận xét. –

+0

@ J-16SDiZ Câu trả lời rất chưa trưởng thành. – nash

0

Cách khác là phiên bản .gitignore, điều này sẽ ngăn bất kỳ tệp nào có tiện ích mở rộng nhất định hiển thị trong trạng thái.
Bạn vẫn có thể có móc cũng như (trên hạ lưu hay thượng nguồn, theo đề nghị của các câu trả lời khác), nhưng ít nhất tất cả các repo hạ lưu có thể bao gồm mà .gitignore để tránh thêm .exe, .dll, .iso ...

+0

Lưu ý: móc không được nhân bản qua bản sao: http://stackoverflow.com/questions/5165239/why-it-is-not-possible-to-git-add-git-hooks-my-hook/5165299#5165299) – VonC

0

này sẽ là một trường hợp rất hiếm từ những gì tôi đã nhìn thấy khi một số kiểm tra trong, nói rằng một tập tin kích thước 200Mb hoặc thậm chí nhiều hơn. Trong khi bạn có thể ngăn chặn điều này xảy ra bằng cách sử dụng móc bên máy chủ (không chắc chắn về móc phía máy khách vì bạn phải dựa vào người có móc cài đặt) giống như cách bạn làm trong SVN, bạn cũng phải đi vào tài khoản trong Git, nó dễ dàng hơn nhiều để loại bỏ một tập tin/cam kết từ kho lưu trữ. Bạn không có một sự sang trọng như vậy trong SVN, ít nhất không phải là một cách dễ dàng.

+0

Thực ra, trong git không khó hơn sao? Một 'git rm' của tập tin không thực sự loại bỏ nó khỏi repo, nó chỉ làm cho nó không xuất hiện trong các bản sửa đổi sau này. Bạn vẫn lãng phí không gian/băng thông cho nó. –

+0

@JosephGarvin - Làm cách nào? 'git rm' là lệnh để xóa một tệp khỏi cam kết hiện tại. Nó không thay đổi lịch sử. Bạn có các lệnh khác như 'git commit --amend' và' git filter-branch' – manojlds

19

Vì tôi đã đấu tranh với nó một thời gian, ngay cả với mô tả, và tôi nghĩ rằng điều này là có liên quan cho những người khác, tôi nghĩ rằng tôi muốn đăng một thực hiện như thế nào J16 SDiZ described có thể được thực hiện.

Vì vậy, quan điểm của tôi trên server-side update móc ngăn ngừa các file quá lớn để được đẩy:

#!/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 <ref> <oldrev> <newrev>)" >&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 
+0

Cách sử dụng? Thực thi tệp này mỗi lần trước khi cam kết? – Gank

+0

@Gank bạn đã đọc câu trả lời tôi đã liên kết chưa? – eis

+0

Có. Nhưng tôi không biết làm thế nào để cấu hình nó trong git. – Gank

0

Tôi đang sử dụng gitolite và móc cập nhật đã được sử dụng - thay vì sử dụng móc cập nhật, Tôi đã sử dụng móc trước khi nhận.Các kịch bản đăng bởi Chriki làm việc vượt bực với ngoại lệ mà các dữ liệu được truyền qua stdin - vì vậy tôi đã thực hiện một sự thay đổi dòng:

- refname=$3 
+ read a b refname 

(có thể có một cách thanh lịch hơn để làm điều đó nhưng nó hoạt động)

4

nếu bạn đang sử dụng gitolite bạn cũng có thể thử VREF. Có một VREF đã được cung cấp theo mặc định (mã này nằm trong gitolite/src/VREF/MAX_NEWBIN_SIZE). Nó được gọi là MAX_NEWBIN_SIZE. Hoạt động như sau:

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

Trường hợp 1000 là ngưỡng ví dụ tính bằng byte.

VREF này hoạt động như một móc cập nhật và nó sẽ từ chối đẩy của bạn nếu một tệp bạn đang đẩy lớn hơn ngưỡng.

6

Câu trả lời bằng eis và J-16 SDiZ gặp phải sự cố nghiêm trọng. Họ chỉ kiểm tra trạng thái của đêm chung kết cam kết $ 3 hoặc $ newrev. Họ cũng cần phải kiểm tra những gì đang được gửi trong các cam kết khác giữa $ 2 (hoặc $ oldrev) và $ 3 (hoặc $ newrev) trong móc udpate.

SD -Z SDiZ gần với câu trả lời đúng hơn.

Các lỗ hổng lớn là ai đó mà phòng ban máy chủ đã móc bản cập nhật này được cài đặt để bảo vệ nó sẽ tìm ra cách cứng mà:

Sau khi sử dụng git rm để loại bỏ các tập tin lớn vô tình được kiểm tra trong, thì cây hiện tại hoặc cam kết cuối cùng chỉ sẽ ổn, và nó sẽ kéo trong toàn bộ chuỗi cam kết, bao gồm cả tệp lớn mà đã bị xóa, tạo ra một lịch sử chất béo không hài lòng bị sưng mà không ai muốn.

Để giải pháp là kiểm tra từng cam kết từ $ oldrev đến $ newrev hoặc để chỉ định toàn bộ phạm vi $ oldrev .. $ newrev. Hãy chắc chắn rằng bạn không chỉ kiểm tra $ newrev một mình, hoặc điều này sẽ thất bại với rác lớn trong lịch sử git của bạn, đẩy ra để chia sẻ với những người khác, và sau đó khó khăn hoặc không thể loại bỏ sau đó.

Các vấn đề liên quan