2012-09-07 37 views
13

Internet hoàn toàn bị phân tán với các câu trả lời sai và không lý tưởng cho câu hỏi này. Điều này là không may bởi vì bạn sẽ nghĩ rằng đây sẽ là một điều phổ biến bạn sẽ muốn làm.Kiểm tra những gì sắp sửa được thực hiện trong một móc trước cam kết

Sự cố: Khi chạy móc pre-commit, kho lưu trữ có thể không sạch. Vì vậy, nếu bạn ngây thơ chạy thử nghiệm của bạn, họ sẽ không được chống lại những gì bạn đang cam kết, nhưng bất cứ điều gì bẩn xảy ra được trong cây làm việc của bạn.

Điều hiển nhiên cần làm là git stash --keep-index --include-untracked ở đầu số pre-commitgit pop khi thoát. Bằng cách đó bạn đang thử nghiệm với chỉ số (thuần), đó là những gì chúng tôi muốn. Không may, điều này tạo ra các dấu xung đột hợp nhất nếu bạn sử dụng git add --patch, (đặc biệt nếu bạn chỉnh sửa khối), vì nội dung của [email protected]{0} có thể không khớp với cây công việc sau khi cam kết.

Một giải pháp phổ biến khác là sao chép kho lưu trữ và chạy thử nghiệm trong một tạm thời mới. Có hai vấn đề với điều đó: Một là chúng tôi chưa cam kết, vì vậy chúng tôi không thể dễ dàng có được một bản sao của kho lưu trữ ở trạng thái chúng tôi sắp cam kết (tôi chắc chắn có một cách để làm điều đó , nhưng tôi không quan tâm vì :). Thứ hai, các bài kiểm tra của tôi có thể nhạy cảm với vị trí của thư mục làm việc hiện tại. Ví dụ vì cấu hình môi trường cục bộ.

Vì vậy: Làm cách nào tôi có thể khôi phục cây công việc của mình về trạng thái trước khi xuất hiện trước git stash --keep-index --include-untracked mà không giới thiệu các dấu xung đột hợp nhất và không sửa đổi sau HEAD sau cam kết?

+0

Các cam kết trước kịch bản nhận được dữ liệu được cam kết như là đầu vào. Tại sao bạn cần phải nhìn vào bất cứ điều gì khác? Có lẽ những gì bạn đang cố gắng làm tốt nhất sẽ được thực hiện trong một cái gì đó khác hơn là một cái móc trước cam kết. Những loại kiểm tra nào bạn muốn làm điều đó yêu cầu truy cập vào kho lưu trữ đầy đủ? –

+0

@WilliamPursell: Bạn có ý nghĩa gì bởi "dữ liệu được cam kết?". Kịch bản trước cam kết chạy trong cây làm việc của tôi (tức là cơ sở của kho lưu trữ nguồn). Vấn đề là nếu bạn thực hiện một số thay đổi đối với kho lưu trữ và chỉ một vài trong số chúng (ví dụ, bạn thêm một số tệp nhưng không phải tệp khác), thì bạn sẽ không thử nghiệm cam kết trước khi nó xảy ra (những gì tôi muốn làm), bạn sẽ kiểm tra những gì bạn có trong thư mục làm việc của mình. – pwaller

+0

Bản vá bạn cam kết có sẵn trên stdin cho móc trước khi cam kết. Bạn đang thử nghiệm điều gì nếu không phải là bản vá đang được cam kết? Mục đích của hook trước khi commit là xác minh patch. –

Trả lời

2

Nếu nhân bản toàn bộ repo quá đắt, có lẽ bạn chỉ cần một bản sao của thư mục làm việc. Tạo một bản sao sẽ đơn giản hơn là cố gắng giải quyết các xung đột. Ví dụ:

#!/bin/sh -e 

trap 'rm -rf $TMPD' 0 
mkdir ${TMPD=$PWD/.tmpdir} 
git ls-tree -r HEAD | while read mod type sha name; do 
    if test "$type" = blob; then 
     mkdir -p $TMPD/$(dirname "$name") 
     git show $sha > $TMPD/"$name"; 
     chmod $mod $TMPD/"$name" 
    fi 
done 
cd $TMPD 
git diff --cached HEAD | patch 
# Run tests here 

Điều này sẽ hủy bỏ trạng thái của cây như sau cam kết $ TMPD, vì vậy bạn có thể chạy thử nghiệm ở đó. Bạn sẽ nhận được một thư mục tạm thời trong một thời trang an toàn hơn là được thực hiện ở đây, nhưng để cho sự khác biệt cuối cùng để làm việc (hoặc để đơn giản hóa kịch bản và cd trước đó), nó phải là một con của thư mục làm việc.

-1

Tôi cuối cùng đã tìm được giải pháp mà tôi đang tìm kiếm. Chỉ trạng thái của chỉ mục trước khi commit được kiểm tra, và nó để lại chỉ mục và cây làm việc chính xác như trước khi commit.

Nếu bạn gặp bất kỳ sự cố nào hoặc cách nào tốt hơn, vui lòng trả lời, dưới dạng nhận xét hoặc câu trả lời của riêng bạn.

Điều này giả định rằng không có gì khác sẽ cố gắng cất giấu hoặc sửa đổi kho lưu trữ git hoặc cây đang hoạt động trong khi đang chạy. Điều này đi kèm với không có bảo hành, có thể là sai và ném mã của bạn vào gió. SỬ DỤNG CẨN THẬN.

# pre-commit.sh 
REPO_PATH=$PWD 
git stash save -q --keep-index --include-untracked # ([email protected]{1}) 
git stash save -q         # ([email protected]{0}) 

# Our state at this point: 
# * clean worktree 
# * [email protected]{0} contains what is to be committed 
# * [email protected]{1} contains everything, including dirt 

# Now reintroduce the changes to be committed so that they can be tested 
git stash apply [email protected]{0} -q 

git_unstash() { 
    G="git --work-tree \"$REPO_PATH\" --git-dir \"$REPO_PATH/.git\"" 
    eval "$G" reset -q --hard    # Clean worktree again 
    eval "$G" stash pop -q [email protected]{1}  # Put worktree to original dirty state 
    eval "$G" reset -q [email protected]{0} .  # Restore index, ready for commit 
    eval "$G" stash drop -q [email protected]{0}  # Clean up final remaining stash 
} 
trap git_unstash EXIT 

... tests against what is being committed go here ... 
+0

Như đã đề cập trong các ý kiến ​​trong bài viết sau, điều này sẽ không hoạt động chính xác nếu sửa đổi một cam kết, hoặc nếu bạn không có một cây làm việc bẩn. http: // codeinthehole.com/writing/tips-for-using-a-git-pre-commit-hook/ – pwaller

2

Nếu bạn có thể đủ khả năng để sử dụng thư mục tạm thời (. Tức là tạo một bản sao hoàn chỉnh của thanh toán hiện tại), bạn có thể sử dụng một thư mục tạm thời như sau:

tmpdir=$(mktemp -d) # Or put it wherever you like 
git archive HEAD | tar -xf - -C "$tmpdir" 
git diff --staged | patch -p1 -d "$tmpdir" 
cd "$tmpdir" 
... 

này về cơ bản là William Pursell của giải pháp nhưng tận dụng lợi thế của git archive làm cho mã đơn giản hơn và tôi mong đợi sẽ nhanh hơn.

Ngoài ra, bởi cd'ing đầu tiên:

cd somewhere 
git -C path/to/repo archive HEAD | tar -xf - 
git -C path/to/repo diff --staged | patch -p1 
... 

git -C đòi hỏi Git 1.8.5.

+0

Tôi đã bỏ phiếu cho bạn nhưng không thỏa mãn "ở lại trong $ PWD khi kiểm tra", điều này là cần thiết đối với một số hệ thống, chẳng hạn như đi thư viện. – pwaller

+0

Bên cạnh những lo ngại của pwaller, tôi tin rằng giải pháp này không hoạt động nếu bạn đang thực hiện 'git commit -a', bởi vì kịch bản của bạn giả định rằng chúng tôi chỉ cam kết các tệp được dàn dựng. – TanguyP

1

git write-tree hữu ích trong các móc pre-commit. Nó viết một cái cây vào repo của chỉ số (cây này sẽ được tái sử dụng nếu và khi các cam kết được hoàn thành.)

Khi cây được ghi vào repo, bạn có thể sử dụng git archive | tar -x viết cây vào một thư mục tạm thời .

ví dụ .:

#!/bin/bash 

TMPDIR=$(mktemp -d) 
TREE=$(git write-tree) 
git archive $TREE | tar -x -C $TMPDIR 

# Run tests in $TMPDIR 

RESULT=$? 
rm -rf "$TMPDIR" 
exit $RESULT