2015-03-16 12 views
7

Tôi gặp sự cố khi tạo móc pre-receive trên nhánh git remote, làm những gì tôi muốn.Git: móc nhận trước chỉ cho phép hợp nhất và không trực tiếp commit vào master

Có vấn đề gì?

Không cho phép cam kết trực tiếp với nhánh chính. Chỉ được phép hợp nhất vào nhánh chính.

Giải pháp

Giải pháp của tôi cho đến bây giờ là để kiểm tra, nếu có sự thay đổi trong việc đẩy mạnh từ một người sử dụng, nơi các bậc thầy bị ảnh hưởng. Nhưng vấn đề là tôi không thể phân biệt được nếu thay đổi là cam kết trực tiếp hoặc hợp nhất.

#!/bin/sh 
while read oldrefid newrefid refname 
do 
if [ "$refname" = "refs/heads/master" ]; then 
     echo $(git merge-base $oldrefid $newrefid) 
     echo "---- Direct commit to master branch is not allowed ----" 
     echo "Changes only with a merge from another branch" 
     exit 1 
fi 
done 

Có ai có ý tưởng hay không, cách kiểm tra xem sự thay đổi có hợp nhất không?

Cảm ơn bạn!

Trả lời

4

Những gì bạn nhận được trong móc trước là đầu và mũi mới của nhánh, vì vậy bạn sẽ phải kiểm tra danh sách các cam kết đã được thêm vào và xem có bất kỳ commit nào không được hợp nhất hay không :

nonmerges=$(git rev-list --no-merges --first-parent $oldrefid..$newrefid | wc -l) 
[ "$nonmerges" -eq 0 ] && exit 0 

--first-parent hạn chế đầu ra để cam kết từ dòng chính, tức là cam kết đó đã sáp nhập vào (có thể truy cập thông qua thứ hai// ... mẹ thứ ba) đều được bỏ qua.

Có thể biến chứng: hợp nhất nhanh về phía trước (rất khó phân biệt với một loạt các cam kết thông thường).

+0

"hợp nhất nhanh về phía trước (rất khó phân biệt với một loạt các cam kết thông thường)" AFAIK không có cách nào để phân biệt một loạt các cam kết từ quá trình hợp nhất nhanh về phía trước. Nó chỉ đơn giản là một bản cập nhật của chi nhánh chúng tôi hợp nhất vào cam kết trong câu hỏi. –

+0

@Zeeker bạn có thể đoán trước về việc hợp nhất nhanh về phía trước bằng cách kiểm tra xem các cam kết đó có tồn tại trên một nhánh khác hay không. Trong một số trường hợp, điều này có thể là bằng chứng đầy đủ. Tuy nhiên, nó không xa bằng chứng lỗi. –

+0

Tôi thấy nhưng điều đó sẽ được tìm kiếm khá xa. Ít nhất là cục bộ, việc reflog có thể làm cho thông minh trở nên thông minh hơn nhưng rõ ràng không bao gồm bất kỳ điều khiển từ xa nào mà chúng tôi đẩy tới. –

6

Dưới đây là câu trả lời ngắn: nhìn vào giá trị sản xuất bởi:

git rev-list --count --max-parents=1 $oldrefid..$newrefid 

Bạn muốn đây là zero. Đọc tiếp cho lời giải thích (và hãy cẩn thận).


vòng lặp của bạn có đề cương phải:

  • đọc tất cả cập nhật ref;
  • cho những người cập nhật (các) chi nhánh (hoặc các tài liệu tham khảo khác) mà bạn quan tâm, thực hiện một số kiểm tra.

Bí quyết nằm trong việc thực hiện kiểm tra. Hãy xem xét hai mẩu thông tin khác mà bạn nhận được, cụ thể là các ID SHA-1 cũ và mới, và trong các móc này, một (nhưng không phải cả hai) của hai ID SHA-1 này có thể là tất cả 0 s (có nghĩa là ref đang được đã tạo hoặc bị xóa).

Để nhấn mạnh rằng thay đổi không phải là việc tạo hoặc xóa, kiểm tra của bạn phải đảm bảo rằng cả SHA-1 đều là số không. (Nếu bạn sẵn sàng giả định rằng chỉ xóa cần phải được kiểm tra bạn mới có thể kiểm tra xem SHA-1 mới không phải là tất cả không. Nhưng nếu việc tạo ra có thể xảy ra - đó chỉ là trường hợp nếu bằng cách nào đó chi nhánh master bị xóa sau tất cả, ví dụ, bởi ai đó đăng nhập vào máy chủ đang nhận push và xóa thủ công — bạn vẫn sẽ cần đảm bảo rằng SHA-1 cũ không phải là tất cả 0 cho thử nghiệm cuối cùng. Rõ ràng loại xóa này là có thể, câu hỏi là bạn có muốn viết mã để xử lý vụ việc hay không.)

Trong mọi trường hợp, push điển hình nhất chỉ cập nhật tham chiếu. Lưu ý rằng mọi cam kết mới đã được ghi vào kho lưu trữ (chúng sẽ được thu gom rác nếu bạn từ chối việc đẩy), do đó nhiệm vụ của bạn tại thời điểm này là:

  • tìm và xác minh bất kỳ cam kết nào tham chiếu được sử dụng để đặt tên, rằng nó sẽ không còn tên (đây là những cam kết sẽ được loại bỏ bởi một push không nhanh về phía trước); và
  • tìm và xác minh bất kỳ cam kết nào mà tham chiếu sẽ đặt tên ngay bây giờ, không được sử dụng để đặt tên (đây là các cam kết mới sẽ được thêm vào bằng cách nhấn, cho dù nó có tiến nhanh hay không: nhớ rằng đẩy có thể xóa một hoặc nhiều cam kết trong khi thêm một hoặc nhiều lần, cùng một lúc).

Để tìm hai bộ cam kết này, bạn nên sử dụng git rev-list, vì đó chính xác là công việc của nó: để tạo danh sách SHA-1 được chỉ định bởi một số biểu thức. Hai biểu thức mà bạn muốn ở đây là "tất cả các ID cam kết có thể tìm thấy từ một bản sửa đổi, mà chưa thể tìm thấy từ một số ID khác". Trong các điều khoản git rev-list đây là git rev-list $r1 ^$r2, hoặc tương đương, git rev-list $r2..$r1, cho hai phiên bản sửa đổi $r1$r2. Hai revspecs, tất nhiên, chỉ là ID cũ và mới cho đề xuất push.

Thứ tự của hai ID này xác định tập hợp các cam kết git rev-list danh sách nào: các danh sách sẽ bị xóa — bộ này trống cho thao tác chuyển tiếp nhanh — và các cài đặt sẽ được thêm vào.


Trong đặc biệt trường hợp này, mục tiêu của bạn không phải là để tạo ra các danh sách của cam kết bản thân (mặc dù điều đó sẽ làm việc), nhưng đúng hơn, để chọn một cái gì đó từ các danh sách này.

Bạn có thể ngăn chặn việc xóa bỏ cam kết (tức là, để thực thi chuyển tiếp nhanh ngay cả khi người dùng thực hiện cờ hiệu lực push). Trong trường hợp này, chỉ cần xác minh rằng danh sách "cần xóa" là các hậu tố trống. Bạn có thể làm điều đó bằng cách đảm bảo rằng danh sách thực sự trống hoặc — đơn giản hơn trong tập lệnh shell — có số git rev-list đếm chúng cho bạn và kiểm tra xem số kết quả bằng không.

Bạn chắc chắn muốn ngăn các bổ sung không phải là hợp nhất nhưng cho phép bổ sung. Trong trường hợp này, hãy thêm --max-parents=1 (cũng có thể được viết là --no-merges) cho biết git rev-list để chặn các cam kết có hai hoặc nhiều bậc cha mẹ, tức là, hợp nhất. Thêm --count sẽ cho bạn một số cam kết đáp ứng điều này "không phải là hợp nhất vì không hoặc một phụ huynh" hạn chế. Nếu số này bằng không, thì bất kỳ cam kết nào được thêm vào đều phải được hợp nhất.

Do đó:

n=$(git rev-list --count --max-parents=1 $oldrefid..$newrefid) 
if [ $n -gt 0 ]; then 
    echo "disallowed: push adds $n non-merge commit(s)" 1>&2 
    exit 1 
fi 

ví dụ, sẽ đủ để thực thi hạn chế đặc biệt này.


Hầu nhưng không hoàn toàn tương đương, bạn có thể viết git rev-list $r1 --not $r2: sự khác biệt là ảnh hưởng của --not nán lại, do đó nếu bạn đã thêm thêm một phiên bản ID $r3 các --not sẽ áp dụng cho r3. Tức là, git rev-list A ^B C có nghĩa là yes-A, not-B, yes-C nhưng A --not B C có nghĩa là yes-A, not-B, not-C. Lưu ý rằng trong cú pháp rev-list, B..A có nghĩa là A ^B, nghĩa là, chính xác B được đảo ngược.

+0

Cảm ơn bạn! Làm việc, quá! +1 –

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