使用Git push部署项目

是否有可能使用git push部署网站? 我有一个预感,它与使用git挂钩来执行git reset --hard在服务器端git reset --hard ,但我怎么去做到这一点呢?

我发现这个脚本在这个网站上 ,它似乎工作得很好。

  1. 将您的.git目录复制到您的Web服务器
  2. 在您的本地副本上,修改.git / config文件并将您的Web服务器添加为远程:

     [remote "production"] url = username@webserver:/path/to/htdocs/.git 
  3. 在服务器上,用这个文件replace.git / hooks / post-update(在下面的答案中)

  4. 添加对文件的执行权限(再次,在服务器上):

     chmod +x .git/hooks/post-update 
  5. 现在,只需在本地推送到您的Web服务器,它应该自动更新工作副本:

     git push production 

使用下面的更新后的文件:

  1. 将您的.git目录复制到您的Web服务器
  2. 在您的本地副本上,修改.git / config文件并将您的Web服务器添加为远程:

     [remote "production"] url = username@webserver:/path/to/htdocs/.git 
  3. 在服务器上,用下面的文件replace.git / hooks / post-update

  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 HEAD@{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 HEAD@{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 

经过许多错误的开始和死胡同,我终于能够部署网站代码只是“git推远程 ”感谢这篇文章 。

作者的更新后脚本只有一行,他的解决scheme不需要.htaccessconfiguration来隐藏Git仓库,就像别人一样。

如果您在Amazon EC2实例上部署此function,则会遇到一些绊脚石;

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

2)如果你不预先configuration你的amazon-private- key.pem的位置,在/ etc / ssh / ssh_config中作为IdentityFile参数,或者在〜/ .ssh / config中使用“ Host] – HostName – IdentityFile – 用户“布局在这里描述…

…但是,如果主机configuration在〜/ .ssh / config和不同于HostName的Git推送将失败。 (这可能是一个Git错误)

不要在服务器上安装git,或在那里复制.git文件夹。 要从git克隆更新服务器,可以使用以下命令:

 git ls-files -z | rsync --files-from - --copy-links -av0 . user@server.com:/var/www/project 

您可能需要删除从项目中删除的文件。

这将复制所有签入的文件。 rsync使用安装在服务器上的ssh。

安装在服务器上的软件越less,他就越安全,pipe理它的configuration和文档就越容易。 也不需要在服务器上保留一个完整的git克隆。 它只会让事情变得更加复杂。

本质上你所要做的就是以下几点:

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

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

所以当我想要进行部署时,input./deploy myserver mybranch

我这样做的方式是我的部署服务器上有一个纯粹的Git存储库,我推送更改。 然后,我login到部署服务器,切换到实际的Web服务器文档目录,并做一个Git拉。 我没有使用任何钩子来自动尝试这样做,这似乎比它的价值更麻烦。

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

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

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公告中提到了以下缺点:

  • 您的服务器将包含一个包含您的项目的整个历史logging的.git目录。 您可能想要确保无法向用户提供服务!
  • 在部署期间,用户可能会偶尔遇到站点处于不一致的状态,其中一些文件位于旧版本,另一些位于新版本,甚至一半是文件。 如果这对于您的项目来说是一个问题,则推送部署可能不适合您。
  • 如果你的项目需要一个“构build”步骤,那么你将不得不明确地设置,也许通过githooks。

但是所有这些都超出了Git的范围,必须由外部代码来处理。 所以从这个意义上来说,这与Git挂钩是最终的解决scheme。

更新:我现在使用关键代理ssh -A ... Lloyd Moore解决scheme。 推到一个主要的回购,然后从它所有的机器并行拉动是更快一些,并需要在这些机器上设置较less。


在这里看不到这个解决scheme 如果git安装在服务器上,只需通过SSH推送。

您需要在本地.git / config中input以下内容

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

但是,嘿,与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' 

(顺便说一句:/path/to/project.git是不同的实际工作目录/path/到/项目)

我们使用capistranopipe理部署。 我们build立capistrano部署在一个临时服务器,然后与我们所有的服务器运行rsync。

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

随着capistrano,我们可以很容易地回滚,以防万一

 cap deploy:rollback cap deploy:start_rsync 

对于部署scheme

在我们的场景中,我们将代码存储在github / bitbucket上,并希望部署到活服务器。 在这种情况下,下面的组合适用于我们(这里是高度优先答案的混合)

  1. 将您的.git目录复制到您的Web服务器
  2. 在你的本地副本git remote add live ssh://user@host: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

笔记

  • 此解决scheme适用于较旧的git版本(使用1.7和1.9进行testing)
  • 你需要确保首先推送到github / bitbucket,所以你将有一个一致的回购现场
  • 如果.git文件夹位于文档根目录中,请确保通过添加到.htaccess ( source )来将其从外部隐藏:

    RedirectMatch 404 /\..*$

Giddyup是语言不可知的只是加水 git挂钩通过git推动自动化部署。 它还允许你有自定义的启动/停止挂钩重新启动Web服务器,预热caching等。

https://github.com/mpalmer/giddyup

检查示例 。

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

你可以设想一个git钩子,当说一个提交说“稳定”的分支,它将拉动变化,并将其应用到PHP网站。 最大的缺点是,如果出现问题,你将不会有太多的控制,这会增加testing的时间 – 但是你可以知道当你合并时把你的主干分支插入到稳定的分支去知道需要多less工作你可能遇到多less冲突。 除非您仅打算只运行一个站点,否则请注意任何特定于站点的文件(例如,configuration文件)。

或者,你有没有考虑推动改变的网站,而不是?

有关git钩子的信息,请参阅githooks文档。

我接受基督徒的解决scheme。

 git archive --prefix=deploy/ master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av username@server.com:/home/user/my_app && rm -rf $TMPDIR/deploy 
  • 将主分支归档为tar
  • 将tar归档文件解压缩到系统临时文件夹中的部署目录中。
  • rsync更改到服务器
  • 从temp文件夹中删除部署目录。

我使用toroid.org的下面的解决scheme,它有一个更简单的钩子脚本。

在服务器上:

 $ 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

作为补充答案,我想提供一个替代scheme。 我使用的是git-ftp,它工作正常。

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

易于使用,只有types:

 git ftp push 

而git会自动上传项目文件。

问候

给定一个环境,您有多个开发人员访问同一个存储库,以下指南可能会有所帮助。

确保您有一个所有开发人员所属的unix组,并将.git存储库的所有权授予该组。

  1. 在服务器存储库的.git / config中设置sharedrepository = true。 (这告诉git允许提交和部署所需的多个用户。

  2. 设置每个用户在他们的bashrc文件的umask是相同的 – 002是一个好的开始

我最终创build了我自己的基本部署工具,它会自动从回购拉下新的更新 – https://github.com/jesalg/SlimJim – 基本上它侦听github post-receive-hook并使用代理来触发更新脚本。

我使用了两个解决scheme来接收挂钩:

部署解决scheme1

 #!/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 

部署解决scheme2

 #!/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 

这两个解决scheme都基于此主题中提供的早期解决scheme。

请注意,BRANCH_REGEX ='^ $ {GIT_BRANCH1}。 $“filter,以匹配”master “或”dev *“string的分支名称 ,并部署工作树(如果推送的分支匹配)。 这使得可以将开发版本和主版本部署到不同的地方。

部署解决scheme1仅删除作为回购的一部分的文件,并被提交删除。 它比Deployment Solution 2更快。

部署解决scheme2的优点是,无论是否将其添加到回购站,它都将删除从服务器端添加的生产目录中的任何新文件。 这将永远是干净的回购。 它比部署解决scheme1慢。