Git post-receive hook不会从master中删除已删除的文件

时间:2013-09-29 09:37:05

标签: git git-post-receive

我在服务器上创建了一个裸git repo并设置了this blog的以下post-receive挂钩:

#!/bin/bash

while read oldrev newrev ref
do
  branch=`echo $ref | cut -d/ -f3`

  if [ "master" == "$branch" ]; then
    git --work-tree=/path/to/my/project/live/ checkout -f $branch
    echo 'Changes pushed live.'
  fi

  if [ "develop" == "$branch" ]; then
    git --work-tree=/path/to/my/project/dev/ checkout -f $branch
    echo 'Changes pushed to dev.'
  fi
done

因此,每当我将本地推送到我的服务器时,更改将自动发布在每个分支的文件夹上,而无需手动拉取。

我为dev文件夹设置了正确的权限:

drwxrwsr-x 2 git git 4096 Sep 29 12:10 live/
drwxrwsr-x 2 git git 4096 Sep 29 12:09 dev/

从开发分支推动按预期工作。检查主分支并执行合并时会发生此问题。当我推送主文件时,新文件会被复制到我服务器上的实时文件夹中,但我在本地删除的文件不会被删除。

如何使收件后正确更新实时文件夹?谢谢!

2 个答案:

答案 0 :(得分:4)

我遇到了同样的问题。正在研究rsync将tmp文件夹文件复制到实时文件夹,但后来我想到为什么不在工作树上使用git glean。

我不确定这是不是很糟糕,但它应该只从文件夹中删除未跟踪的文件,并使用.gitignore设置不删除不在您的仓库中的文件。

它似乎完成了我想要的东西,即清除未被推送删除的文件。

#!/bin/sh
while read oldrev newrev refname
do
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)
    if [ "master" == "$branch" ]; then
        GIT_WORK_TREE=/home/store/public_html git checkout -f master
        GIT_WORK_TREE=/home/store/public_html git clean -fd
    fi
    if [ "test" == "$branch" ]; then
        GIT_WORK_TREE=/home/store/test_html git checkout -f test
        GIT_WORK_TREE=/home/store/test_html git clean -fd
    fi
    if [ "dev" == "$branch" ]; then
        GIT_WORK_TREE=/home/store/dev_html git checkout -f dev
        GIT_WORK_TREE=/home/store/dev_html git clean -fd
    fi
done

答案 1 :(得分:3)

问题是git不知道要删除什么(它在工作树中没有索引,跟踪这些事情)。应该可以使用每个工作树的索引来解决这个问题,但我认为将git checkout -f放入一个新的空目录,然后重命名新目录和旧目录以使新版本“go”更简单生活”。这也缩小了竞争条件窗口:现在只有一个短暂的时刻(mv次操作之间) no 版本,而不是稍长的窗口(checkout期间)当旧版本和新版本混合使用时。

注意:如果有一个名为masterdevelop的标记,则您显示的脚本会出错,因为这两个标记的引用名称分别为refs/tags/masterrefs/tags/develop。我建议通过shell函数和case语句修复此问题(如果你关心:-)),以减少非部署情况下的进程产生,例如:

die() {
    echo "$@" >&2
    exit 1
}

# deploy (to given path, $1) the version named by $2
# if the target is /some/path/there we use a temp version
# named /some/path/tmp.<pid> to hold the new one until we
# can swap it out, and $1.old.<pid> while we remove the old.
deploy() {
    local path=$1 branch=$2
    local tmpdir=${path%/*}/tmp.$$        # tune this as needed

    echo "deploying $branch to $path via $tmpdir..."
    trap "rm -rf $tmpdir" 0 1 2 3 15
    mkdir $tmpdir || die "can't create work dir $tempdir"
    git --work-tree=$tmpdir/ checkout -f $branch
    mv $path $path.old.$$ ||
        die "unable to move live version out of the way"
    mv $tmpdir $path ||
        die "unable to set new version live"
    trap - 0 1 2 3 15
    echo "done, cleaning up old version"
    rm -rf $path.old.$$
}

while read oldrev newrev ref; do
    case $ref in
    refs/heads/master) deploy /path/to/my/project/live master;;
    refs/heads/develop) deploy /path/to/my/project/dev develop;;
    esac
done

(注意:完全未经测试)。