使用Git push部署一个项目。

时间:2022-09-16 20:28:07

Is it possible to deploy a website using git push? I have a hunch it has something to do with using git hooks to perform a git reset --hard on the server side, but how would I go about accomplishing this?

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

19 个解决方案

#1


283  

I found this script on this site and it seems to work quite well.

我在这个网站上找到了这个脚本,它看起来运行得很好。

  1. Copy over your .git directory to your web server
  2. 将.git目录复制到web服务器。
  3. On your local copy, modify your .git/config file and add your web server as a remote:

    在本地副本中,修改.git/config文件,并将您的web服务器添加为远程服务器:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  4. On the server, replace .git/hooks/post-update with this file (in the answer below)

    在服务器上,用这个文件替换.git/hook /更新后的文件(在下面的答案中)

  5. Add execute access to the file (again, on the server):

    添加对文件的执行访问(同样,在服务器上):

    chmod +x .git/hooks/post-update
    
  6. Now, just locally push to your web server and it should automatically update the working copy:

    现在,只要本地推到你的web服务器,它就会自动更新工作副本:

    git push production
    

#2


76  

Using the post-update file below:

使用以下更新后的文件:

  1. Copy over your .git directory to your web server
  2. 将.git目录复制到web服务器。
  3. On your local copy, modify your .git/config file and add your web server as a remote:

    在本地副本中,修改.git/config文件,并将您的web服务器添加为远程服务器:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  4. On the server, replace .git/hooks/post-update with file below

    在服务器上,用下面的文件替换.git/hook /post-update。

  5. Add execute access to the file (again, on the server):

    添加对文件的执行访问(同样,在服务器上):

    chmod +x .git/hooks/post-update
    
  6. Now, just locally push to your web server and it should automatically update the working copy:

    现在,只要本地推到你的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

#3


59  

After many false starts and dead ends, I'm finally able to deploy website code with just "git push remote" thanks to this article.

在许多错误的开始和死胡同之后,我终于可以用“git push remote”来部署网站代码了,这要感谢本文。

The author's post-update script is only one line long and his solution doesn't require .htaccess configuration to hide the Git repo as some others do.

作者的更新后脚本只有一行,而他的解决方案不需要.htaccess配置来隐藏Git repo,就像其他一些操作一样。

A couple of stumbling blocks if you're deploying this on an Amazon EC2 instance;

如果您在Amazon EC2实例上部署这一功能,将会遇到一些障碍;

1) If you use sudo to create the bare destination repository, you have to change the owner of the repo to ec2-user or the push will fail. (Try "chown ec2-user:ec2-user repo.")

1)如果使用sudo创建空目标存储库,则必须将repo的所有者更改为ec2-user,否则push将失败。(试着“乔恩ec2-user:ec2-user回购。”)

2) The push will fail if you don't pre-configure the location of your amazon-private-key.pem, either in /etc/ssh/ssh_config as an IdentityFile parameter or in ~/.ssh/config using the "[Host] - HostName - IdentityFile - User" layout described here...

2)如果您不预先配置amazon-private-key的位置,那么push将会失败。pem在/etc/ssh/ssh_config中作为一个身份文件参数或在~/中。ssh/config使用“[主机]-主机名-身份文件-用户”布局在这里描述…

...HOWEVER if Host is configured in ~/.ssh/config and different than HostName the Git push will fail. (That's probably a Git bug)

…但是,如果在~/中配置了主机。ssh/config和不同的主机名,Git推送将失败。(这可能是一个Git错误)

#4


21  

dont install git on a server or copy the .git folder there. to update a server from a git clone you can use following command:

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

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

you might have to delete files which got removed from the project.

您可能必须删除从项目中删除的文件。

this copies all the checked in files. rsync uses ssh which is installed on a server anyways.

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

the less software you have installed on a server the more secure he is and the easier it is to manage it's configuration and document it. there is also no need to keep a complete git clone on the server. it only makes it more complex to secure everything properly.

在服务器上安装的软件越少,他就越安全,越容易管理它的配置并记录它。也不需要在服务器上保留一个完整的git克隆。它只会使它更复杂,以确保一切正常。

#5


12  

In essence all you need to do are the following:

实际上,你所需要做的就是:

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

I have those lines in my application as an executable called deploy.

在我的应用程序中,我将这些行作为可执行文件部署。

so when I want to do a deploy I type ./deploy myserver mybranch.

因此,当我想要执行部署I类型。/部署myserver mybranch。

#6


9  

The way I do it is I have a bare Git repository on my deployment server where I push changes. Then I log in to the deployment server, change to the actual web server docs directory, and do a git pull. I don't use any hooks to try to do this automatically, that seems like more trouble than it's worth.

我的做法是,在我的部署服务器上有一个裸Git存储库,在那里我推动更改。然后我登录到部署服务器,更改到实际的web服务器文档目录,并执行git拖动。我不使用任何挂钩来尝试自动完成,这似乎比它的价值更麻烦。

#7


7  

receive.denyCurrentBranch updateInstead added in Git 2.3 is a possibility.

在Git 2.3中添加的denycurrentbranch updateInstead是一种可能。

Set it on the server repository, and it also updates the working tree if it is clean.

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

There have been further improvements in 2.4 with the push-to-checkout hook and handling of unborn branches.

在2.4中有进一步的改进,用推到付款钩和处理未出生的分支。

Sample usage:

示例用法:

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

Output:

输出:

a
b

This does have the following shortcomings mentioned on the GitHub announcement:

在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!
  • 您的服务器将包含一个包含整个项目历史的.git目录。您可能想要额外确保它不能为用户服务!
  • 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.
  • 在部署期间,用户可能随时会遇到不一致状态的站点,在旧版本中有一些文件,在新版本中有一些文件,甚至是半书面文件。如果这对您的项目来说是一个问题,那么pushto -deploy可能并不适合您。
  • If your project needs a "build" step, then you will have to set that up explicitly, perhaps via githooks.
  • 如果您的项目需要一个“构建”步骤,那么您将不得不显式地设置它,可能是通过githooks。

But all of those points are out of the scope of Git and must be taken care of by external code. So in that sense, this, together with Git hooks, are the ultimate solution.

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

#8


5  

Update: I'm now using Lloyd Moore solution with the key agent ssh -A .... Pushing to a main repo and then pulling from it in parallel from all your machines is a bit faster and requires less setup on those machines.

更新:我现在用劳埃德·摩尔的解决方案的关键ssh代理——....推到一个主要的repo,然后与所有的机器并行地拉出它,速度更快,在这些机器上的设置也更少。


Not seeing this solution here. just push via ssh if git is installed on the server.

没有看到这个解。如果git安装在服务器上,只需通过ssh进行推送。

You'll need the following entry in your local .git/config

您需要在本地的.git/config中使用以下条目。

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

But hey, whats that with amazon:? In your local ~/.ssh/config you'll need to add the following entry:

但是,嘿,跟亚马逊有什么关系?在你的地方~ /。ssh/config需要添加以下条目:

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

now you can call

现在你可以叫

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

(BTW: /path/to/project.git is different to the actual working directory /path/to/project)

(顺便说一句:/ /项目/路径。git与实际的工作目录/path/to/项目不同

#9


4  

We use capistrano for managing deploy. We build capistrano to deploy on a staging server, and then running a rsync with all of ours server.

我们使用capistrano管理部署。我们构建capistrano在一个临时服务器上部署,然后运行与我们所有服务器的rsync。

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

With capistrano, we can made easy rollback in case of bug

使用capistrano,我们可以轻松地回滚,以防止出现bug。

cap deploy:rollback
cap deploy:start_rsync

#10


4  

For Deployment Scenario

In our scenario we're storing the code on github/bitbucket and want to deploy to live servers. In this case the following combination works for us (that is a remix of the highly upvoted answers here):

在我们的场景中,我们将代码存储在github/bitbucket上,并希望将其部署到服务器上。在这种情况下,下面的组合对我们来说是有效的(这是一个高度向上的答案的混合):

  1. Copy over your .git directory to your web server
  2. 将.git目录复制到web服务器。
  3. On your local copy git remote add live ssh://user@host:port/folder
  4. 在本地复制git远程添加live ssh://user@host:port/folder。
  5. On remote: git config receive.denyCurrentBranch ignore
  6. 远程:git配置接收。denycurrentbranch忽略。
  7. On remote: nano .git/hooks/post-receive and add this content:

    远程:nano .git/hook /post-receive并添加以下内容:

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

    # !/ bin/shgit_work_tree =/var/www/vhosts/example.org git checkout -f。

  8. On remote: chmod +x .git/hooks/post-receive

    远程:chmod +x .git/hook /post-receive。

  9. Now you can push there with git push live
  10. 现在你可以用git push live推进。

Notes

  • This solution works with older git versions (tested with 1.7 and 1.9)
  • 这个解决方案适用于较老的git版本(测试1.7和1.9)
  • You need to make sure pushing to github/bitbucket first, so you'll have a consistent repo on live
  • 首先,你需要确保把它推到github/bitbucket上,这样你就可以在live上有一个一致的repo。
  • If your .git folder is within document root make sure you hide it from the outside by adding to .htaccess (source):

    如果您的.git文件夹在文档根目录中,请确保通过添加.htaccess(源)将其隐藏到外部。

    RedirectMatch 404 /\..*$

    RedirectMatch / \ . . * 404

#11


2  

Giddyup are language-agnostic just-add-water git hooks to automate deployment via git push. It also allows you to have custom start/stop hooks for restarting web server, warming up cache etc.

Giddyup是一种与语言无关的新添加的git钩子,可以通过git推送实现自动化部署。它还允许您为重新启动web服务器、预热缓存等设置自定义启动/停止挂钩。

https://github.com/mpalmer/giddyup

https://github.com/mpalmer/giddyup

Check out examples.

查看示例。

#12


1  

Sounds like you should have two copies on your server. A bare copy, that you can push/pull from, which your would push your changes when you're done, and then you would clone this into you web directory and set up a cronjob to update git pull from your web directory every day or so.

听起来你的服务器上应该有两份拷贝。一个简单的拷贝,你可以推/拉,当你完成的时候,你会推动你的改变,然后你会把这个复制到你的web目录中,并建立一个cronjob,每天更新git从你的web目录中获取。

#13


1  

You could conceivably set up a git hook that when say a commit is made to say the "stable" branch it will pull the changes and apply them to the PHP site. The big downside is you won't have much control if something goes wrong and it will add time to your testing - but you can get an idea of how much work will be involved when you merge say your trunk branch into the stable branch to know how many conflicts you may run into. It will be important to keep an eye on any files that are site specific (eg. configuration files) unless you solely intend to only run the one site.

可以想象,您可以设置一个git钩子,当表示commit时表示“稳定”分支时,它将拉出更改并将其应用到PHP站点。你最大的缺点是不会有多大控制如果发生错误,它会将时间添加到您的测试——但是你可以了解多少工作将涉及当你说你的主干分支合并到稳定的部门知道你可能会遇到许多冲突。重要的是要注意任何特定于站点的文件。配置文件)除非你只打算运行一个站点。

Alternatively have you looked into pushing the change to the site instead?

或者,你是否考虑过将更改推到站点?

For information on git hooks see the githooks documentation.

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

#14


1  

My take on Christians solution.

我对基督徒的看法。

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
  • Archives the master branch into tar
  • 将主分支归档为tar。
  • Extracts tar archive into deploy dir in system temp folder.
  • 在system temp文件夹中提取tar存档文件到deploy dir。
  • rsync changes into server
  • rsync更改为服务器
  • delete deploy dir from temp folder.
  • 从temp文件夹中删除deploy dir。

#15


1  

I am using the following solution by toroid.org, which has a simpler hook script.

我使用了toroid.org的解决方案,它有一个简单的钩子脚本。

on the server:

在服务器上:

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

and install the hook on the server:

并在服务器上安装钩子:

$ 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

on your client:

你的客户:

$ 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

then to publish, just type

然后发布,只是键入。

$ git push web

There is a full description on the website: http://toroid.org/ams/git-website-howto

网站上有完整的描述:http://toroid.org/ams/git-website-howto。

#16


1  

As complementary answer I would like to offer an alternative. I'm using git-ftp and it works fine.

作为补充回答,我想提供另一种选择。我使用的是git-ftp,它运行良好。

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

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

Easy to use, only type:

易于使用,只有类型:

git ftp push

and git will automatically upload project files.

git将自动上传项目文件。

Regards

问候

#17


0  

Given an environment where you have multiple developers accessing the same repository the following guidelines may help.

在有多个开发人员访问同一个存储库的环境中,下面的指南可能会有所帮助。

Ensure that you have a unix group that all devs belong to and give ownership of the .git repository to that group.

确保您有一个所有devs都属于的unix组,并将.git存储库的所有权授予该组。

  1. In the .git/config of the server repository set sharedrepository = true. (This tells git to allow multiple users which is needed for commits and deployment.

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

  2. set the umask of each user in their bashrc files to be the same - 002 is a good start

    在他们的bashrc文件中设置每个用户的umask是相同的- 002是一个好的开始。

#18


0  

I ended up creating my own rudimentary deployment tool which would automatically pull down new updates from the repo - https://github.com/jesalg/SlimJim - Basically it listens to the github post-receive-hook and uses a proxy to trigger an update script.

最后,我创建了自己的基本部署工具,它可以自动从repo - https://github.com/jesalg/SlimJim中获取新的更新——基本上,它监听了github的post-receive-hook,并使用一个代理来触发一个更新脚本。

#19


0  

I use two solutions for post-receive hook:

我使用两种解决方案:

DEPLOY SOLUTION 1

部署解决方案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

DEPLOY SOLUTION 2

部署解决方案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

Both solutions are based on earlier solutions available in this thread.

这两个解决方案都基于此线程中可用的早期解决方案。

Note, the BRANCH_REGEX='^${GIT_BRANCH1}.$' filters for the branch names matching "master" or "dev*" string, and deploys the work tree, if the pushed branch matches. This makes possible to deploy a dev version and master version to different places.

注意,BRANCH_REGEX = ' ^ $ { GIT_BRANCH1 }。如果被推的分支匹配,则为匹配“master”或“dev*”字符串的分支名称提供$“过滤器”,并部署工作树。这使得可以将开发版本和主版本部署到不同的地方。

DEPLOY SOLUTION 1 removes only files, which are part of the repo, and was removed by a commit. It is faster than Deployment Solution 2.

部署解决方案1只删除文件,它是repo的一部分,并被提交删除。它比部署解决方案2更快。

DEPLOY SOLUTION 2 has the advantage, that it will remove any new files from the production directory, which was added on server side, no matter if it was added to the repo or not. It will be always clean dupe of the repo. It is slower than Deployment Solution 1.

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

#1


283  

I found this script on this site and it seems to work quite well.

我在这个网站上找到了这个脚本,它看起来运行得很好。

  1. Copy over your .git directory to your web server
  2. 将.git目录复制到web服务器。
  3. On your local copy, modify your .git/config file and add your web server as a remote:

    在本地副本中,修改.git/config文件,并将您的web服务器添加为远程服务器:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  4. On the server, replace .git/hooks/post-update with this file (in the answer below)

    在服务器上,用这个文件替换.git/hook /更新后的文件(在下面的答案中)

  5. Add execute access to the file (again, on the server):

    添加对文件的执行访问(同样,在服务器上):

    chmod +x .git/hooks/post-update
    
  6. Now, just locally push to your web server and it should automatically update the working copy:

    现在,只要本地推到你的web服务器,它就会自动更新工作副本:

    git push production
    

#2


76  

Using the post-update file below:

使用以下更新后的文件:

  1. Copy over your .git directory to your web server
  2. 将.git目录复制到web服务器。
  3. On your local copy, modify your .git/config file and add your web server as a remote:

    在本地副本中,修改.git/config文件,并将您的web服务器添加为远程服务器:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  4. On the server, replace .git/hooks/post-update with file below

    在服务器上,用下面的文件替换.git/hook /post-update。

  5. Add execute access to the file (again, on the server):

    添加对文件的执行访问(同样,在服务器上):

    chmod +x .git/hooks/post-update
    
  6. Now, just locally push to your web server and it should automatically update the working copy:

    现在,只要本地推到你的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

#3


59  

After many false starts and dead ends, I'm finally able to deploy website code with just "git push remote" thanks to this article.

在许多错误的开始和死胡同之后,我终于可以用“git push remote”来部署网站代码了,这要感谢本文。

The author's post-update script is only one line long and his solution doesn't require .htaccess configuration to hide the Git repo as some others do.

作者的更新后脚本只有一行,而他的解决方案不需要.htaccess配置来隐藏Git repo,就像其他一些操作一样。

A couple of stumbling blocks if you're deploying this on an Amazon EC2 instance;

如果您在Amazon EC2实例上部署这一功能,将会遇到一些障碍;

1) If you use sudo to create the bare destination repository, you have to change the owner of the repo to ec2-user or the push will fail. (Try "chown ec2-user:ec2-user repo.")

1)如果使用sudo创建空目标存储库,则必须将repo的所有者更改为ec2-user,否则push将失败。(试着“乔恩ec2-user:ec2-user回购。”)

2) The push will fail if you don't pre-configure the location of your amazon-private-key.pem, either in /etc/ssh/ssh_config as an IdentityFile parameter or in ~/.ssh/config using the "[Host] - HostName - IdentityFile - User" layout described here...

2)如果您不预先配置amazon-private-key的位置,那么push将会失败。pem在/etc/ssh/ssh_config中作为一个身份文件参数或在~/中。ssh/config使用“[主机]-主机名-身份文件-用户”布局在这里描述…

...HOWEVER if Host is configured in ~/.ssh/config and different than HostName the Git push will fail. (That's probably a Git bug)

…但是,如果在~/中配置了主机。ssh/config和不同的主机名,Git推送将失败。(这可能是一个Git错误)

#4


21  

dont install git on a server or copy the .git folder there. to update a server from a git clone you can use following command:

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

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

you might have to delete files which got removed from the project.

您可能必须删除从项目中删除的文件。

this copies all the checked in files. rsync uses ssh which is installed on a server anyways.

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

the less software you have installed on a server the more secure he is and the easier it is to manage it's configuration and document it. there is also no need to keep a complete git clone on the server. it only makes it more complex to secure everything properly.

在服务器上安装的软件越少,他就越安全,越容易管理它的配置并记录它。也不需要在服务器上保留一个完整的git克隆。它只会使它更复杂,以确保一切正常。

#5


12  

In essence all you need to do are the following:

实际上,你所需要做的就是:

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

I have those lines in my application as an executable called deploy.

在我的应用程序中,我将这些行作为可执行文件部署。

so when I want to do a deploy I type ./deploy myserver mybranch.

因此,当我想要执行部署I类型。/部署myserver mybranch。

#6


9  

The way I do it is I have a bare Git repository on my deployment server where I push changes. Then I log in to the deployment server, change to the actual web server docs directory, and do a git pull. I don't use any hooks to try to do this automatically, that seems like more trouble than it's worth.

我的做法是,在我的部署服务器上有一个裸Git存储库,在那里我推动更改。然后我登录到部署服务器,更改到实际的web服务器文档目录,并执行git拖动。我不使用任何挂钩来尝试自动完成,这似乎比它的价值更麻烦。

#7


7  

receive.denyCurrentBranch updateInstead added in Git 2.3 is a possibility.

在Git 2.3中添加的denycurrentbranch updateInstead是一种可能。

Set it on the server repository, and it also updates the working tree if it is clean.

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

There have been further improvements in 2.4 with the push-to-checkout hook and handling of unborn branches.

在2.4中有进一步的改进,用推到付款钩和处理未出生的分支。

Sample usage:

示例用法:

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

Output:

输出:

a
b

This does have the following shortcomings mentioned on the GitHub announcement:

在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!
  • 您的服务器将包含一个包含整个项目历史的.git目录。您可能想要额外确保它不能为用户服务!
  • 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.
  • 在部署期间,用户可能随时会遇到不一致状态的站点,在旧版本中有一些文件,在新版本中有一些文件,甚至是半书面文件。如果这对您的项目来说是一个问题,那么pushto -deploy可能并不适合您。
  • If your project needs a "build" step, then you will have to set that up explicitly, perhaps via githooks.
  • 如果您的项目需要一个“构建”步骤,那么您将不得不显式地设置它,可能是通过githooks。

But all of those points are out of the scope of Git and must be taken care of by external code. So in that sense, this, together with Git hooks, are the ultimate solution.

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

#8


5  

Update: I'm now using Lloyd Moore solution with the key agent ssh -A .... Pushing to a main repo and then pulling from it in parallel from all your machines is a bit faster and requires less setup on those machines.

更新:我现在用劳埃德·摩尔的解决方案的关键ssh代理——....推到一个主要的repo,然后与所有的机器并行地拉出它,速度更快,在这些机器上的设置也更少。


Not seeing this solution here. just push via ssh if git is installed on the server.

没有看到这个解。如果git安装在服务器上,只需通过ssh进行推送。

You'll need the following entry in your local .git/config

您需要在本地的.git/config中使用以下条目。

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

But hey, whats that with amazon:? In your local ~/.ssh/config you'll need to add the following entry:

但是,嘿,跟亚马逊有什么关系?在你的地方~ /。ssh/config需要添加以下条目:

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

now you can call

现在你可以叫

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

(BTW: /path/to/project.git is different to the actual working directory /path/to/project)

(顺便说一句:/ /项目/路径。git与实际的工作目录/path/to/项目不同

#9


4  

We use capistrano for managing deploy. We build capistrano to deploy on a staging server, and then running a rsync with all of ours server.

我们使用capistrano管理部署。我们构建capistrano在一个临时服务器上部署,然后运行与我们所有服务器的rsync。

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

With capistrano, we can made easy rollback in case of bug

使用capistrano,我们可以轻松地回滚,以防止出现bug。

cap deploy:rollback
cap deploy:start_rsync

#10


4  

For Deployment Scenario

In our scenario we're storing the code on github/bitbucket and want to deploy to live servers. In this case the following combination works for us (that is a remix of the highly upvoted answers here):

在我们的场景中,我们将代码存储在github/bitbucket上,并希望将其部署到服务器上。在这种情况下,下面的组合对我们来说是有效的(这是一个高度向上的答案的混合):

  1. Copy over your .git directory to your web server
  2. 将.git目录复制到web服务器。
  3. On your local copy git remote add live ssh://user@host:port/folder
  4. 在本地复制git远程添加live ssh://user@host:port/folder。
  5. On remote: git config receive.denyCurrentBranch ignore
  6. 远程:git配置接收。denycurrentbranch忽略。
  7. On remote: nano .git/hooks/post-receive and add this content:

    远程:nano .git/hook /post-receive并添加以下内容:

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

    # !/ bin/shgit_work_tree =/var/www/vhosts/example.org git checkout -f。

  8. On remote: chmod +x .git/hooks/post-receive

    远程:chmod +x .git/hook /post-receive。

  9. Now you can push there with git push live
  10. 现在你可以用git push live推进。

Notes

  • This solution works with older git versions (tested with 1.7 and 1.9)
  • 这个解决方案适用于较老的git版本(测试1.7和1.9)
  • You need to make sure pushing to github/bitbucket first, so you'll have a consistent repo on live
  • 首先,你需要确保把它推到github/bitbucket上,这样你就可以在live上有一个一致的repo。
  • If your .git folder is within document root make sure you hide it from the outside by adding to .htaccess (source):

    如果您的.git文件夹在文档根目录中,请确保通过添加.htaccess(源)将其隐藏到外部。

    RedirectMatch 404 /\..*$

    RedirectMatch / \ . . * 404

#11


2  

Giddyup are language-agnostic just-add-water git hooks to automate deployment via git push. It also allows you to have custom start/stop hooks for restarting web server, warming up cache etc.

Giddyup是一种与语言无关的新添加的git钩子,可以通过git推送实现自动化部署。它还允许您为重新启动web服务器、预热缓存等设置自定义启动/停止挂钩。

https://github.com/mpalmer/giddyup

https://github.com/mpalmer/giddyup

Check out examples.

查看示例。

#12


1  

Sounds like you should have two copies on your server. A bare copy, that you can push/pull from, which your would push your changes when you're done, and then you would clone this into you web directory and set up a cronjob to update git pull from your web directory every day or so.

听起来你的服务器上应该有两份拷贝。一个简单的拷贝,你可以推/拉,当你完成的时候,你会推动你的改变,然后你会把这个复制到你的web目录中,并建立一个cronjob,每天更新git从你的web目录中获取。

#13


1  

You could conceivably set up a git hook that when say a commit is made to say the "stable" branch it will pull the changes and apply them to the PHP site. The big downside is you won't have much control if something goes wrong and it will add time to your testing - but you can get an idea of how much work will be involved when you merge say your trunk branch into the stable branch to know how many conflicts you may run into. It will be important to keep an eye on any files that are site specific (eg. configuration files) unless you solely intend to only run the one site.

可以想象,您可以设置一个git钩子,当表示commit时表示“稳定”分支时,它将拉出更改并将其应用到PHP站点。你最大的缺点是不会有多大控制如果发生错误,它会将时间添加到您的测试——但是你可以了解多少工作将涉及当你说你的主干分支合并到稳定的部门知道你可能会遇到许多冲突。重要的是要注意任何特定于站点的文件。配置文件)除非你只打算运行一个站点。

Alternatively have you looked into pushing the change to the site instead?

或者,你是否考虑过将更改推到站点?

For information on git hooks see the githooks documentation.

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

#14


1  

My take on Christians solution.

我对基督徒的看法。

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
  • Archives the master branch into tar
  • 将主分支归档为tar。
  • Extracts tar archive into deploy dir in system temp folder.
  • 在system temp文件夹中提取tar存档文件到deploy dir。
  • rsync changes into server
  • rsync更改为服务器
  • delete deploy dir from temp folder.
  • 从temp文件夹中删除deploy dir。

#15


1  

I am using the following solution by toroid.org, which has a simpler hook script.

我使用了toroid.org的解决方案,它有一个简单的钩子脚本。

on the server:

在服务器上:

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

and install the hook on the server:

并在服务器上安装钩子:

$ 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

on your client:

你的客户:

$ 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

then to publish, just type

然后发布,只是键入。

$ git push web

There is a full description on the website: http://toroid.org/ams/git-website-howto

网站上有完整的描述:http://toroid.org/ams/git-website-howto。

#16


1  

As complementary answer I would like to offer an alternative. I'm using git-ftp and it works fine.

作为补充回答,我想提供另一种选择。我使用的是git-ftp,它运行良好。

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

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

Easy to use, only type:

易于使用,只有类型:

git ftp push

and git will automatically upload project files.

git将自动上传项目文件。

Regards

问候

#17


0  

Given an environment where you have multiple developers accessing the same repository the following guidelines may help.

在有多个开发人员访问同一个存储库的环境中,下面的指南可能会有所帮助。

Ensure that you have a unix group that all devs belong to and give ownership of the .git repository to that group.

确保您有一个所有devs都属于的unix组,并将.git存储库的所有权授予该组。

  1. In the .git/config of the server repository set sharedrepository = true. (This tells git to allow multiple users which is needed for commits and deployment.

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

  2. set the umask of each user in their bashrc files to be the same - 002 is a good start

    在他们的bashrc文件中设置每个用户的umask是相同的- 002是一个好的开始。

#18


0  

I ended up creating my own rudimentary deployment tool which would automatically pull down new updates from the repo - https://github.com/jesalg/SlimJim - Basically it listens to the github post-receive-hook and uses a proxy to trigger an update script.

最后,我创建了自己的基本部署工具,它可以自动从repo - https://github.com/jesalg/SlimJim中获取新的更新——基本上,它监听了github的post-receive-hook,并使用一个代理来触发一个更新脚本。

#19


0  

I use two solutions for post-receive hook:

我使用两种解决方案:

DEPLOY SOLUTION 1

部署解决方案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

DEPLOY SOLUTION 2

部署解决方案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

Both solutions are based on earlier solutions available in this thread.

这两个解决方案都基于此线程中可用的早期解决方案。

Note, the BRANCH_REGEX='^${GIT_BRANCH1}.$' filters for the branch names matching "master" or "dev*" string, and deploys the work tree, if the pushed branch matches. This makes possible to deploy a dev version and master version to different places.

注意,BRANCH_REGEX = ' ^ $ { GIT_BRANCH1 }。如果被推的分支匹配,则为匹配“master”或“dev*”字符串的分支名称提供$“过滤器”,并部署工作树。这使得可以将开发版本和主版本部署到不同的地方。

DEPLOY SOLUTION 1 removes only files, which are part of the repo, and was removed by a commit. It is faster than Deployment Solution 2.

部署解决方案1只删除文件,它是repo的一部分,并被提交删除。它比部署解决方案2更快。

DEPLOY SOLUTION 2 has the advantage, that it will remove any new files from the production directory, which was added on server side, no matter if it was added to the repo or not. It will be always clean dupe of the repo. It is slower than Deployment Solution 1.

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