Deploy a project using Git push

后端 未结 19 949
囚心锁ツ
囚心锁ツ 2020-11-22 07:06

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

相关标签:
19条回答
  • 2020-11-22 08:03

    I use two solutions for post-receive hook:

    DEPLOY SOLUTION 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

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

    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.

    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.

    0 讨论(0)
  • 2020-11-22 08:04

    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.

    0 讨论(0)
  • 2020-11-22 08:04

    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.


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

    You'll need the following entry in your local .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:

    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)

    0 讨论(0)
  • 2020-11-22 08:05

    Using the post-update file below:

    1. Copy over your .git directory to your web server
    2. On your local copy, modify your .git/config file and add your web server as a remote:

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

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

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

      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
    
    0 讨论(0)
  • 2020-11-22 08:05

    git config --local receive.denyCurrentBranch updateInstead

    Added in Git 2.3, this could be a good possibility: https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155

    You 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.

    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:

    • 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.

    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.

    0 讨论(0)
  • 2020-11-22 08:05

    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
    • Extracts tar archive into deploy dir in system temp folder.
    • rsync changes into server
    • delete deploy dir from temp folder.
    0 讨论(0)
提交回复
热议问题