2010-10-01 25 views
59

Tôi đang cố gắng thiết lập Git để dàn trang web của mình để tôi có thể git pull để phiên bản hiện tại hoạt động cục bộ và sau đó git push để đẩy các thay đổi đến máy chủ từ xa. Tôi đã thiết lập nó để nó hoạt động theo cách tôi muốn, nhưng sau khi tôi đẩy, tôi phải tự chạy git checkout -f hoặc git reset --hard HEAD trên máy chủ từ xa.Git Post-Receive Hook cho trang web Staging

Tôi đã thử đưa chúng vào một kịch bản lệnh vỏ làm móc hậu nhận trên máy chủ, nhưng nó dường như không có bất kỳ ảnh hưởng nào. Tôi biết rằng tập lệnh đang chạy vì tôi thấy "Thay đổi được đẩy tới máy chủ" sau khi tôi đẩy. Đây là hậu nhận móc:

#!/bin/sh 
git reset --hard HEAD 
echo "Changes pushed to server." 
+0

@VonC: Phần quan trọng nhất trong [câu trả lời của bạn] (http://stackoverflow.com/ các câu hỏi/3838727/git-post-receive-hook-cho-trang web-dàn/3838796 # 3838796) được viết chủ yếu bằng ngôn ngữ 'bash', trong khi downvoter có thể đã khẳng định bản địa của mình;) – takeshin

Trả lời

73

Câu trả lời cho câu hỏi của bạn là ở đây: http://toroid.org/ams/git-website-howto

Nói tóm lại, những gì bạn muốn làm là thêm một "cây công việc tách ra" vào kho trống. Thông thường bạn nghĩ cây công việc của bạn có chứa thư mục .git. Các kho chứa trần không có một cây làm việc theo định nghĩa, nhưng bạn có thể tạo một cây miễn là nó nằm trong một thư mục khác với thư mục rỗng.

Móc hậu nhận chỉ đơn giản là git checkout -f để nhân bản kho lưu trữ HEAD của kho lưu trữ vào thư mục công việc. Apache sử dụng nó như là tài liệu gốc của nó, và bạn đã sẵn sàng. Bất cứ lúc nào bạn đẩy vào kho trống, Apache sẽ ngay lập tức bắt đầu phục vụ nó.

Tôi thường sử dụng tính năng này để tự động đẩy tới máy chủ dàn dựng để xem liệu môi trường "thực sự" có bị thay đổi hay không. Triển khai cho máy chủ trực tiếp là một câu chuyện hoàn toàn khác. :-)

+0

Cảm ơn bạn, tôi vẫn còn mới với Git và khi tôi bắt đầu với dự án này, tôi đã không chắc chắn lý do tại sao nên có một kho trống khi tôi có thể cd vào tài liệu gốc và chỉ git init. Bây giờ tôi nghĩ rằng nó chỉ giữ siêu dữ liệu git ra khỏi gốc tài liệu. Đúng không? – Matt

+0

Ngoài ra, ví dụ trong liên kết ở trên cho thấy cách bắt đầu từ đầu và đẩy tới máy chủ từ một kho lưu trữ cục bộ. Phương pháp tốt nhất để nhận kho lưu trữ trần (bên ngoài gốc tài liệu web) từ phương thức nào hiện có trong đó? – Matt

+0

Matt, kho lưu trữ trần thường được sử dụng trên máy chủ trung tâm của bạn. Nếu bạn chỉ có một bản sao của kho lưu trữ và bạn đang triển khai trực tiếp từ đó, bạn sẽ nhanh chóng chạy vào các vấn đề. Tạo một kho lưu trữ trống trong một thư mục khác với 'git init --bare'. Sau đó, trong bản sao cục bộ của kho lưu trữ, làm 'git origin thêm path_to_central_repo' để đánh dấu repo trung tâm mới là bản gốc. Cuối cùng, 'git push origin master' sẽ đẩy mọi thứ bạn đã thực hiện cho master.Tạo một cây làm việc tách rời từ repo trung tâm và bạn sẽ đặt trang web của bạn với mọi 'push' từ bản sao của bạn. – Paul

15

Cập nhật tháng 3 năm 2015

Như tôi đã đề cập trong "What is this Git warning message when pushing changes to a remote repository?", bạn thực sự có thể đẩy trực tiếp đến một repo phi trần bây giờ (Git 2.3.0+, tháng 2 năm 2015) với:

git config receive.denyCurrentBranch updateInstead 

cập nhật cây làm việc cho phù hợp, nhưng từ chối làm như vậy nếu có bất kỳ thay đổi không bị giam.

Điều đó sẽ cho phép bạn tránh bất kỳ móc hậu sau khi nhận.


(Original câu trả lời: Tháng 10 năm 2010)

Các GitFAQ khuyến cáo cho non-bare repo sau bản cập nhật này móc:
(nó có thể cung cấp cho bạn đầu mối nhiều như những gì đang thực sự xảy ra trong việc thực hiện móc. Lưu ý đây là một cái móc hậu cập nhật, không phải là một hậu nhận)

#!/bin/sh 
# 
# This hook does two things: 
# 
# 1. update the "info" files that allow the list of references to be 
#  queries over dumb transports such as http 
# 
# 2. if this repository looks like it is a non-bare repository, and 
#  the checked-out branch is pushed to, then update the working copy. 
#  This makes "push" function somewhat similarly to darcs and bzr. 
# 
# To enable this hook, make this file executable by "chmod +x post-update". 

git-update-server-info 

is_bare=$(git-config --get --bool core.bare) 

if [ -z "$is_bare" ] 
then 
    # for compatibility's sake, guess 
    git_dir_full=$(cd $GIT_DIR; pwd) 
    case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac 
fi 

update_wc() { 
    ref=$1 
    echo "Push to checked out branch $ref" >&2 
    if [ ! -f $GIT_DIR/logs/HEAD ] 
    then 
     echo "E:push to non-bare repository requires a HEAD reflog" >&2 
     exit 1 
    fi 
    if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null) 
    then 
     wc_dirty=0 
    else 
     echo "W:unstaged changes found in working copy" >&2 
     wc_dirty=1 
     desc="working copy" 
    fi 
    if git diff-index --cached [email protected]{1} >/dev/null 
    then 
     index_dirty=0 
    else 
     echo "W:uncommitted, staged changes found" >&2 
     index_dirty=1 
     if [ -n "$desc" ] 
     then 
      desc="$desc and index" 
     else 
      desc="index" 
     fi 
    fi 
    if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ] 
    then 
     new=$(git rev-parse HEAD) 
     echo "W:stashing dirty $desc - see git-stash(1)" >&2 
     (trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT 
     git-update-ref --no-deref HEAD [email protected]{1} 
     cd $GIT_WORK_TREE 
     git stash save "dirty $desc before update to $new"; 
     git-symbolic-ref HEAD "$ref" 
     ) 
    fi 

    # eye candy - show the WC updates :) 
    echo "Updating working copy" >&2 
    (cd $GIT_WORK_TREE 
    git-diff-index -R --name-status HEAD >&2 
    git-reset --hard HEAD) 
} 

if [ "$is_bare" = "false" ] 
then 
    active_branch=`git-symbolic-ref HEAD` 
    export GIT_DIR=$(cd $GIT_DIR; pwd) 
    GIT_WORK_TREE=${GIT_WORK_TREE-..} 
    for ref 
    do 
     if [ "$ref" = "$active_branch" ] 
     then 
      update_wc $ref 
     fi 
    done 
fi 

để làm việc này, bạn vẫn sẽ cần phải đặc biệt cho phép đẩy thay đổi đối với chi nhánh hiện tại bằng cách sử dụng một trong hai trên e của các thiết lập cấu hình:

git config receive.denyCurrentBranch ignore 

hoặc

git config receive.denyCurrentBranch warn 
+4

+1: Kịch bản có vẻ cồng kềnh hoặc tiết lộ, nhưng đó là cách đó vì một lý do chính đáng; không giống như cách tiếp cận cùn của việc sử dụng một 'git reset --hard' hoặc' git checkout -f' đơn giản, nó sẽ giữ lại bất kỳ thay đổi không được cam kết nào trong một stash. –

+0

Kịch bản này hoàn toàn fubar và nó không làm gì cả. Tôi quản lý để sửa chữa nó (hy vọng một cách chính xác), xem câu trả lời của tôi ... – Tronic

+0

Với Git 2.3 bạn không cần móc này nữa bạn có thể làm 'git config receive.denyCurrentBranch updateInstead'. Xem https://github.com/blog/1957-git-2-3-has-been-released. – Aurelien

1

Tôi chỉ đoán, nhưng điều này có thể là một số vấn đề về quyền (đường dẫn đầy đủ cần thiết? cd?).Kiểm tra những gì đang thực sự xảy ra trong các tệp nhật ký.

Tuy nhiên việc xuất bản tệp qua git luôn là một nhiệm vụ của quá trình xuất bản. Bạn thường cần sao chép một số tệp, xóa các tệp khác, thiết lập, quyền cập nhật, tạo tài liệu, v.v.

Để có giải pháp phức tạp, tập lệnh xây dựng có thể tốt hơn bất kỳ móc git nào. Công cụ này có thể xử lý những nhiệm vụ rất tốt:

(Tôi nhận ra đây không phải là câu trả lời bạn đang mong đợi, nhưng nó quá dài để đăng dưới dạng nhận xét)

11

Tôi gặp vấn đề tương tự. Trong một bài trả lời liên kết này: http://toroid.org/ams/git-website-howto - Các lệnh sau đây đã thực hiện nó:

sudo chmod +x hooks/post-receive 

Chúng tôi bỏ lỡ một phép sudo đầu tiên cấu hình các công cụ.

6

Phiên bản cố định của tập lệnh VonC, hoạt động đối với tôi (hoàn toàn không có bảo đảm).

#!/bin/sh 
# 
# This hook does two things: 
# 
# 1. update the "info" files that allow the list of references to be 
#  queries over dumb transports such as http 
# 
# 2. if this repository looks like it is a non-bare repository, and 
#  the checked-out branch is pushed to, then update the working copy. 
#  This makes "push" function somewhat similarly to darcs and bzr. 
# 
# To enable this hook, make this file executable by "chmod +x post-update". 

set -e 

git update-server-info 

is_bare=$(git config --get --bool core.bare) 

if [ -z "${is_bare}" ] 
then 
    # for compatibility's sake, guess 
    git_dir_full=$(cd $GIT_DIR; pwd) 
    case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac 
fi 

update_wc() { 
    ref=$1 
    echo "Push to checked out branch $ref" >&2 
    if [ ! -f ${GIT_DIR}/logs/HEAD ] 
    then 
     echo "E:push to non-bare repository requires a HEAD reflog" >&2 
     exit 1 
    fi 
    if (cd ${GIT_WORK_TREE}; git diff-files -q --exit-code >/dev/null) 
    then 
     wc_dirty=0 
    else 
     echo "W:unstaged changes found in working copy" >&2 
     wc_dirty=1 
     desc="working copy" 
    fi 
    if git diff-index --cached [email protected]{1} >/dev/null 
    then 
     index_dirty=0 
    else 
     echo "W:uncommitted, staged changes found" >&2 
     index_dirty=1 
     if [ -n "$desc" ] 
     then 
      desc="$desc and index" 
     else 
      desc="index" 
     fi 
    fi 
    if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ] 
    then 
     new=$(git rev-parse HEAD) 
     echo "W:stashing dirty $desc - see git-stash(1)" >&2 
     (trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT 
     git update-ref --no-deref HEAD [email protected]{1} 
     cd ${GIT_WORK_TREE} 
     git stash save "dirty $desc before update to $new"; 
     git symbolic-ref HEAD "$ref" 
     ) 
    fi 

    # eye candy - show the WC updates :) 
    echo "Updating working copy" >&2 
    (cd ${GIT_WORK_TREE} 
    git diff-index -R --name-status HEAD >&2 
    git reset --hard HEAD 
    # need to touch some files or restart the application? do that here: 
    # touch *.wsgi 
    ) 

} 

if [ x"${is_bare}" = x"false" ] 
then 
    active_branch=$(git symbolic-ref HEAD) 
    export GIT_DIR=$(cd ${GIT_DIR}; pwd) 
    GIT_WORK_TREE="${GIT_DIR}/.." 
    for ref in $(cat) 
    do 
     if [ x"$ref" = x"${active_branch}" ] 
     then 
      update_wc $ref 
     fi 
    done 
fi 
+1

+1 Phản hồi thú vị. Tôi sẽ phải kiểm tra nó. – VonC

6

kịch bản đơn giản để cài đặt triển khai git này:

Chuẩn bị hậu nhận móc:

echo '#!/bin/sh'  > .git/hooks/post-receive 
echo 'git checkout -f' >> .git/hooks/post-receive 
echo 'git reset --hard' >> .git/hooks/post-receive 
chmod +x .git/hooks/post-receive 

Cho phép đẩy vào kho lưu trữ này, mặc dù nó không phải là trần:

git config receive.denycurrentbranch false 
+1

Bạn cũng có thể sử dụng worktree bên ngoài: 'git config core.worktree/path/to/workdir'. Bạn có thể chuyển kho trống thành một với worktree cho rằng ('git config core.bare false') –

+0

Tại sao bạn cần' git reset --hard' BTW? –

+3

Bạn cũng có thể thêm 'git diff -R --cached --name-status' trước khi thanh toán để có được danh sách tốt đẹp về những tập tin đang được cập nhật ở phía đẩy. –

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