是否可以使用git push部署一个网站?我有一种预感,它与使用git挂钩来执行git重置有关——在服务器端很难,但我该如何完成这一点呢?


当前回答

对于post-receive hook,我使用了两种解决方案:

部署方案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*”字符串的分支名称,如果推送的分支匹配,则部署工作树。 这使得将开发版本和主版本部署到不同的位置成为可能。

DEPLOY SOLUTION 1仅删除文件,这些文件是repo的一部分,并由提交删除。比部署方案2快。

DEPLOY SOLUTION 2的优势在于,它将从生产目录中删除添加到服务器端的任何新文件,无论这些文件是否添加到repo。它将永远是回购的干净的欺骗。比部署方案1慢。

其他回答

git配置——local receive.denyCurrentBranch updateInstead

在Git 2.3中添加了一个很好的可能性:https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155

您在服务器存储库上设置它,如果工作树是干净的,它也会更新工作树。

在2.4中有进一步的改进,包括push-to-checkout钩子和未出生分支的处理。

示例用法:

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

这确实有以下GitHub公告中提到的缺点:

Your server will contain a .git directory containing the entire history of your project. You probably want to make extra sure that it cannot be served to users! During deploys, it will be possible for users momentarily to encounter the site in an inconsistent state, with some files at the old version and others at the new version, or even half-written files. If this is a problem for your project, push-to-deploy is probably not for you. If your project needs a "build" step, then you will have to set that up explicitly, perhaps via githooks.

但是所有这些点都超出了Git的范围,必须由外部代码来处理。因此,从这个意义上说,这和Git钩子一起是最终的解决方案。

我最终创建了我自己的基本部署工具,它会自动从repo - https://github.com/jesalg/SlimJim -下拉新的更新,基本上它会监听github的接收后钩子,并使用代理来触发更新脚本。

在经历了许多错误的开始和死胡同之后,多亏了这篇文章,我终于能够使用“git push remote”部署网站代码。

作者的更新后脚本只有一行长,并且他的解决方案不像其他一些解决方案那样需要.htaccess配置来隐藏Git回购。

如果您在Amazon EC2实例上部署它,则会遇到几个绊脚石;

1)如果使用sudo创建裸目标存储库,必须将repo的所有者更改为ec2-user,否则推送将失败。(尝试“chown ec2-user:ec2-user repo”)

2)如果你没有预先配置你的amazon-private-key的位置,推送会失败。可以在/etc/ssh/ssh_config中作为IdentityFile参数,也可以在~/。ssh/config使用“[主机]- HostName - IdentityFile - User”布局在这里描述…

...但是,如果在~/中配置了Host。ssh/config和不同于HostName的Git推送将失败。(这可能是Git的bug)

听起来你应该在你的服务器上有两个副本。一个裸拷贝,你可以推/拉,当你完成时,你会推你的改变,然后你会把这个克隆到你的web目录,并设置一个cronjob来每天从你的web目录更新git pull。

我们使用capistrano来管理部署。 我们构建capistrano以部署在登台服务器上,然后与我们所有的服务器运行rsync。

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

使用capistrano,我们可以在出现bug时轻松回滚

cap deploy:rollback
cap deploy:start_rsync