2008-11-10 178 views

回答

283

我發現this scriptthis site,它似乎工作得很好。

  1. 在你的.git目錄複製到你的Web服務器
  2. 在本地複製,修改您的.git/config文件,並添加您的Web服務器作爲遠程:

    [remote "production"] 
        url = [email protected]:/path/to/htdocs/.git 
    
  3. 在服務器,用this file替換.git/hooks/post-update(在下面的答案中)

  4. 添加對文件的再次執行訪問(再次,在服務器上):

    chmod +x .git/hooks/post-update 
    
  5. 現在,只需在當地推到你的Web服務器,它會自動更新工作副本:

    git push production 
    
+123

確保您有一個.htaccess策略來保護.git目錄不被讀取。如果URL可以訪問,那麼感覺像URL跳躍的人可能會有整個源代碼的一天。 – 2010-05-10 21:41:04

+37

或者只是將公共目錄作爲git倉庫的子目錄。那麼你可以有私人文件,你可以肯定不會公開。 – tlrobinson 2010-06-08 19:54:40

+0

我不確定我是否理解這一點。我應該在生產Web服務器上還是在測試Web服務器上創建我的第一個git repo? – 2010-06-23 04:55:01

9

我這樣做的方式是我的部署服務器上有一個裸露的Git存儲庫,我推送更改。然後我登錄到部署服務器,切換到實際的Web服務器文檔目錄,並執行git pull。我沒有使用任何鉤子來自動執行此操作,這看起來更麻煩而不值得。

+0

如果新代碼中存在錯誤,您是否重置每次提交或整個拉? (或者只有1個可能?) – Rudie 2010-09-27 13:19:23

+1

@Rudie:如果您需要回滾部署服務器上的更改,那麼您可以使用`git reset`在* latest *更改中移回(所有提交,而不僅僅是整個提交)。如果您需要回滾一些具體的事情,這不是最新的承諾,那麼你可以使用`git的revert`但也許應該在緊急情況下使用只(`git的revert`創建一個新的提交是撤銷一些以前的承諾的效果)。 – 2010-09-27 18:06:25

1

聽起來像你應該在你的服務器上有兩個副本。一個裸拷貝,你可以推/拉,當你完成後你會推動你的修改,然後你將它克隆到你的web目錄中,並設置一個cronjob來每天更新web目錄中的git pull,或者所以。

1

你可以設想一個git鉤子,當說一個提交被稱爲「穩定」的分支時,它將把這些改變應用到PHP站點。最大的缺點是,如果出現問題,您將無法控制,並且會增加測試的時間 - 但您可以瞭解在合併時將涉及多少工作,請將您的幹線分支插入穩定分支以瞭解可能會碰到多少衝突。除非您僅打算只運行一個站點,否則請務必留意任何特定於站點的文件(例如,配置文件)。

或者,您是否已着眼於將更改推向網站?

有關git掛鉤的信息,請參閱githooks文檔。

12

在本質上,所有你需要做的有以下幾種:

server = $1 
branch = $2 
git push $server $branch 
ssh <username>@$server "cd /path/to/www; git pull" 

我在我的應用程序中有一行叫做deploy的可執行文件。

所以當我想要做一個部署我輸入./deploy myserver mybranch

76

使用下面的更新後文件:

  1. 複製在你的.git目錄到Web服務器
  2. 在本地複製,修改您的.git/config文件,並添加您的網站服務器作爲遠程:與文件

    [remote "production"] 
        url = [email protected]:/path/to/htdocs/.git 
    
  3. 在服務器上,取代的.git /鉤/更新後的下面

  4. 添加執行訪問該文件(再次,在服務器上):

    chmod +x .git/hooks/post-update 
    
  5. 現在,只需在當地推到你的Web服務器,它會自動更新工作副本:

    git push production 
    
#!/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 
+22

你能幫我理解這個更新是什麼嗎? – 2011-05-27 03:30:12

59

經過很多虛假的開始和死衚衕,我終於能夠部署網站代碼,只是「git push remote「感謝this article

作者的更新後腳本只有一行,他的解決方案不需要.htaccess配置來隱藏Git倉庫,就像其他倉庫一樣。

如果您在Amazon EC2實例上部署此功能,可能會遇到一些絆腳石;

1)如果您使用sudo創建裸露的目標存儲庫,則必須將該存儲庫的所有者更改爲ec2用戶,否則推送將失敗。 (嘗試「CHOWN EC2用戶:EC2用戶回購」)

2)如果你不預先配置亞馬遜私鑰。質子交換膜的位置推送會失敗,無論是在/ etc/ssh/ssh_config中作爲IdentityFile參數或在〜/ .ssh/config中使用「[Host] - HostName - IdentityFile - User」佈局描述here ...

...但是,如果主機已配置在〜/ .ssh/config中,並且與HostName不同,Git推送將失敗。 (這可能是一個Git bug)

21

不要在服務器上安裝git或將.git文件夾複製到那裏。要從git克隆更新服務器,您可以使用以下命令:

git ls-files -z | rsync --files-from - --copy-links -av0 . [email protected]:/var/www/project 

您可能需要刪除從項目中刪除的文件。

這將複製所有簽入的文件。無論如何,rsync使用安裝在服務器上的ssh。

您安裝在服務器上的軟件越少,他就越安全,管理其配置和記錄越容易。也不需要在服務器上保留一個完整的git克隆。它只會讓事情變得更加複雜,以確保一切正常。

0

鑑於您有多個開發人員訪問同一個存儲庫的環境,以下準則可能會有所幫助。

確保您有一個所有開發人員都屬於的unix組,並將該.git存儲庫的所有權交給該組。

  1. 在服務器存儲庫的.git/config中設置sharedrepository = true。 (這告訴混帳允許這是需要提交和部署多個用戶

  2. 集他們的.bashrc文件中的每個用戶的umask是相同的 - 002是一個良好的開端

5

更新:我現在使用勞埃德摩爾解決方案與關鍵代理ssh -A ...。推入主倉庫,然後從所有機器並行拖出,這會更快一些,並且需要更少的設置。


在這裏沒有看到這個解決方案。只要通過ssh推送,如果git安裝在服務器上。

你需要在你本地的.git/config中

[remote "amazon"] 
    url = amazon:/path/to/project.git 
    fetch = +refs/heads/*:refs/remotes/amazon/* 

以下條目但是,嘿,什麼與amazon:?在本地的〜/ .ssh/config中,您需要添加以下條目:

Host amazon 
    Hostname <YOUR_IP> 
    User <USER> 
    IdentityFile ~/.ssh/amazon-private-key 

現在你可以調用

git push amazon master 
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull' 

(BTW:/path/to/project.git是不同的到實際的工作目錄/路徑/到/項目)

0

我最終創建了我自己的基本部署工具,它會自動從回購拉下新的更新 - https://github.com/jesalg/SlimJim - 基本上它聽取github post-receive-hook和使用代理來觸發更新腳本。

4

我們使用capistrano來管理部署。 我們將capistrano構建爲在臨時服務器上部署,然後使用我們的所有服務器運行rsync。

cap deploy 
cap deploy:start_rsync (when the staging is ok) 

隨着Capistrano的,我們可以在錯誤

cap deploy:rollback 
cap deploy:start_rsync 
1

我拿上Christians解決方案的情況下輕鬆回滾。

git archive --prefix=deploy/ master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av [email protected]:/home/user/my_app && rm -rf $TMPDIR/deploy 
  • 檔案館主分支成焦油
  • 提取tar歸檔到系統臨時文件夾部署目錄。
  • 將rsync更改爲服務器
  • 從temp文件夾中刪除部署目錄。
1

我正在使用以下解決方案toroid.org,它具有更簡單的掛鉤腳本。

在服務器上

$ mkdir website.git && cd website.git 
$ git init --bare 
Initialized empty Git repository in /home/ams/website.git/ 

,並在服務器上安裝掛鉤:

$ mkdir /var/www/www.example.org 
$ cat > hooks/post-receive 
#!/bin/sh 
GIT_WORK_TREE=/var/www/www.example.org git checkout -f 
GIT_WORK_TREE=/var/www/www git clean -f -d # clean directory from removed files 

$ chmod +x hooks/post-receive 

您的客戶端上:

$ mkdir website && cd website 
$ git init 
Initialized empty Git repository in /home/ams/website/.git/ 
$ echo 'Hello, world!' > index.html 
$ git add index.html 
$ git commit -q -m "The humble beginnings of my web site." 

$ git remote add web ssh://server.example.org/home/ams/website.git 
$ git push web +master:refs/heads/master 

然後發佈,只需要輸入

$ git push web 

沒有在網站上充分說明:http://toroid.org/ams/git-website-howto

7

receive.denyCurrentBranch updateInstead在Git的2.3增加是可能的。

將其設置在服務器存儲庫上,並且如果它乾淨,它也會更新工作樹。

2.4的進一步改進與push-to-checkout hook and handling of unborn branches

使用範例:

git init server 
cd server 
touch a 
git add . 
git commit -m 0 
git config --local receive.denyCurrentBranch updateInstead 

cd .. 
git clone server local 
cd local 
touch b 
git add . 
git commit -m 1 
git push origin master:master 

cd ../server 
ls 

輸出:

a 
b 

這確實具有以下缺點提到on the GitHub announcement

  • 您的服務器中將包含整個歷史.git目錄你的項目。您可能想要確保它不能提供給用戶!
  • 在部署過程中,用戶可能會偶爾遇到站點處於不一致狀態,其中一些文件位於舊版本,其他文件位於新版本,甚至一半爲文件。如果這對於您的項目來說是一個問題,則推送部署可能不適合您。
  • 如果你的項目需要一個「構建」步驟,那麼你將不得不明確地設置,也許通過githooks。

但所有這些點都超出了Git的範圍,必須由外部代碼來處理。所以從這個意義上說,這與Git鉤子一起是最終的解決方案。

1

作爲補充答案,我想提供一個替代方案。我使用的是git-ftp,它工作正常。

https://github.com/git-ftp/git-ftp

易於使用,唯一類型:

git ftp push 

和git會自動上傳項目文件。

問候

4

對於部署方案

在我們的場景中,我們要存儲在GitHub上/到位桶的代碼,並要部署到Live服務器。 在這種情況下,下列組合爲我們工作(也就是這裏的高度upvoted答案的混音)

  1. 在你.git目錄複製到你的Web服務器
  2. 在您的本地副本git remote add live ssh://[email protected]:port/folder
  3. 在遠程:git config receive.denyCurrentBranch ignore
  4. 在遠程:nano .git/hooks/post-receive並添加以下內容:

    #!/bin/sh GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f

  5. 在遙控:chmod +x .git/hooks/post-receive

  6. 現在你可以用git push live

注推動有

  • 此解決方案與舊版本的Git(1.7和1.9測試)
  • 您需要確保先推送到github/bitbucket,這樣您才能擁有一致的回購直播
  • 如果您.git文件夾是文件根目錄中確保你從外面隱藏它通過增加.htaccesssource):

    RedirectMatch 404 /\..*$

0

我用了兩個解決方案後收到鉤:

部署的解決方案1 ​​

#!/bin/bash 
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed) 
# DEPLOY SOLUTION 1 

    export GIT_DIR=/git/repo-bare.git 
    export GIT_BRANCH1=master 
    export GIT_TARGET1=/var/www/html 
    export GIT_BRANCH2=dev 
    export GIT_TARGET2=/var/www/dev 
    echo "GIT DIR: $GIT_DIR/" 
    echo "GIT TARGET1: $GIT_TARGET1/" 
    echo "GIT BRANCH1: $GIT_BRANCH1/" 
    echo "GIT TARGET2: $GIT_TARGET2/" 
    echo "GIT BRANCH2: $GIT_BRANCH2/" 
    echo "" 

    cd $GIT_DIR/ 

while read oldrev newrev refname 
do 
    branch=$(git rev-parse --abbrev-ref $refname) 
    BRANCH_REGEX='^${GIT_BRANCH1}.*$' 
    if [[ $branch =~ $BRANCH_REGEX ]] ; then 
     export GIT_WORK_TREE=$GIT_TARGET1/. 
     echo "Checking out branch: $branch"; 
     echo "Checking out to workdir: $GIT_WORK_TREE"; 

     git checkout -f $branch 
    fi 

    BRANCH_REGEX='^${GIT_BRANCH2}.*$' 
    if [[ $branch =~ $BRANCH_REGEX ]] ; then 
     export GIT_WORK_TREE=$GIT_TARGET2/. 
     echo "Checking out branch: $branch"; 
     echo "Checking out to workdir: $GIT_WORK_TREE"; 

     git checkout -f $branch 
    fi 
done 

部署的解決方案2

#!/bin/bash 
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed) 
# DEPLOY SOLUTION 2 

    export GIT_DIR=/git/repo-bare.git 
    export GIT_BRANCH1=master 
    export GIT_TARGET1=/var/www/html 
    export GIT_BRANCH2=dev 
    export GIT_TARGET2=/var/www/dev 
    export GIT_TEMP_DIR1=/tmp/deploy1 
    export GIT_TEMP_DIR2=/tmp/deploy2 
    echo "GIT DIR: $GIT_DIR/" 
    echo "GIT TARGET1: $GIT_TARGET1/" 
    echo "GIT BRANCH1: $GIT_BRANCH1/" 
    echo "GIT TARGET2: $GIT_TARGET2/" 
    echo "GIT BRANCH2: $GIT_BRANCH2/" 
    echo "GIT TEMP DIR1: $GIT_TEMP_DIR1/" 
    echo "GIT TEMP DIR2: $GIT_TEMP_DIR2/" 
    echo "" 

    cd $GIT_DIR/ 

while read oldrev newrev refname 
do 
    branch=$(git rev-parse --abbrev-ref $refname) 
    BRANCH_REGEX='^${GIT_BRANCH1}.*$' 
    if [[ $branch =~ $BRANCH_REGEX ]] ; then 
     export GIT_WORK_TREE=$GIT_TARGET1/. 
     echo "Checking out branch: $branch"; 
     echo "Checking out to workdir: $GIT_WORK_TREE"; 

     # DEPLOY SOLUTION 2: 
     cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR1; 
     export GIT_WORK_TREE=$GIT_TEMP_DIR1/. 
     git checkout -f $branch 
     export GIT_WORK_TREE=$GIT_TARGET1/. 
     rsync $GIT_TEMP_DIR1/. -v -q --delete --delete-after -av $GIT_TARGET1/. 
     rm -rf $GIT_TEMP_DIR1 
    fi 

    BRANCH_REGEX='^${GIT_BRANCH2}.*$' 
    if [[ $branch =~ $BRANCH_REGEX ]] ; then 
     export GIT_WORK_TREE=$GIT_TARGET2/. 
     echo "Checking out branch: $branch"; 
     echo "Checking out to workdir: $GIT_WORK_TREE"; 

     # DEPLOY SOLUTION 2: 
     cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR2; 
     export GIT_WORK_TREE=$GIT_TEMP_DIR2/. 
     git checkout -f $branch 
     export GIT_WORK_TREE=$GIT_TARGET2/. 
     rsync $GIT_TEMP_DIR2/. -v -q --delete --delete-after -av $GIT_TARGET2/. 
     rm -rf $GIT_TEMP_DIR2 
    fi 
done 

這兩種解決方案都基於在此線程可用的早期解決方案。請注意, BRANCH_REGEX ='^ $ {GIT_BRANCH1}。 $' 用於匹配「master」或「dev *」字符串的分支名稱的過濾器,並在推送的分支匹配時部署工作樹。 這使得可以將dev版本和主版本部署到不同的地方。

部署解決方案1僅刪除文件,這些文件是回購的一部分,並被提交刪除。它比部署解決方案2更快。

部署解決方案2的優點是,它將刪除從服務器端添加的生產目錄中的任何新文件,而不管它是否添加到回購站。這將永遠是乾淨的回購協議。它比Deployment Solution 1慢。