使用Git保留文件权限
我想按照我的Web服务器的版本控制中所描述的版本控制我的Web服务器 ,通过在/var/www directory
创build一个git repo。 我希望能够将我们的开发服务器上的网页内容推送到github上,然后把它放到我们的生产服务器上,然后在游泳池中度过余下的时间。
显然我的计划中的一个扭曲是,Git不会尊重文件许可(我还没有尝试过,现在只是阅读它。)我猜这是有道理的,因为不同的盒子可能有不同的用户/组设置。 但是,如果我想强制传播权限,知道我的服务器configuration相同,我有任何选项? 还是有更简单的方法来处理我想要做的?
在SO问题中提到的git-cache-meta
“ git – 如何恢复文件权限git认为文件应该是? ”(和git FAQ )是更直接的方法。
这个想法是在.git_cache_meta
文件中存储文件和目录的权限。
这是一个单独的文件,没有直接在Git仓库中进行版本化。
这就是为什么它的用法是:
$ git bundle create mybundle.bdl master; git-cache-meta --store $ scp mybundle.bdl .git_cache_meta machine2: #then on machine2: $ git init; git pull mybundle.bdl master; git-cache-meta --apply
那么你:
- 捆绑您的回购并保存关联的文件权限。
- 将这两个文件复制到远程服务器上
- 恢复那里的回购,并申请许可
Git是为软件开发而创build的版本控制系统,所以从整套模式和权限中只存储可执行位(对于普通文件)和符号链接位。 如果你想存储完整的权限,你需要第三方工具,如git-cache-meta
( 由VonC提到 )或者Metastore (由etckeeper使用 )。 或者你可以使用IsiSetup ,IIRC使用git作为后端。
请参阅Git Wiki上的接口,前端和工具页面。
这是相当晚,但可能会帮助其他人。 我通过将两个git钩子添加到我的仓库来做你想做的事情。
的.git /钩/预提交:
#!/bin/bash # # A hook script called by "git commit" with no arguments. The hook should # exit with non-zero status after issuing an appropriate message if it wants # to stop the commit. SELF_DIR=`git rev-parse --show-toplevel` DATABASE=$SELF_DIR/.permissions # Clear the permissions database file > $DATABASE echo -n "Backing-up file permissions..." IFS_OLD=$IFS; IFS=$'\n' for FILE in `git ls-files` do # Save the permissions of all the files in the index echo $FILE";"`stat -c "%a;%U;%G" $FILE` >> $DATABASE done IFS=$IFS_OLD # Add the permissions database file to the index git add $DATABASE echo "OK"
git的/钩/结账后:
#!/bin/bash SELF_DIR=`git rev-parse --show-toplevel` DATABASE=$SELF_DIR/.permissions echo -n "Restoring file permissions..." IFS_OLD=$IFS; IFS=$'\n' while read -r LINE || [[ -n "$LINE" ]]; do FILE=`echo $LINE | cut -d ";" -f 1` PERMISSIONS=`echo $LINE | cut -d ";" -f 2` USER=`echo $LINE | cut -d ";" -f 3` GROUP=`echo $LINE | cut -d ";" -f 4` # Set the file permissions chmod $PERMISSIONS $FILE # Set the file owner and groups chown $USER:$GROUP $FILE done < $DATABASE IFS=$IFS_OLD echo "OK" exit 0
第一个钩子在你“提交”的时候被调用,并且将读取版本库中所有文件的所有权和权限,并将它们存储在一个名为.permissions的版本库的根目录下的文件中,然后将.permissions文件添加到提交中。
第二个钩子在你“checkout”时被调用,并且会遍历.permissions文件中的文件列表并且恢复这些文件的所有权和权限。
- 您可能需要使用sudo进行提交和结帐。
- 确保预先提交和结束后脚本具有执行权限。
如果你现在正在进行这项工作,我今天刚刚通过了,可以总结一下。 如果你还没有尝试,这里的一些细节可能会有所帮助。
我认为@Omid Ariyan的方法是最好的方法。 添加预先提交和后结帐脚本。 不要忘了按照Omid的方式命名它们,不要忘记使它们可执行。 如果你忘记了其中的任何一个,它们都没有任何作用,而且你一遍又一遍地运行“git commit”,想知道为什么什么也没有发生。另外,如果你剪切并粘贴出Web浏览器,注意引号和刻度不是改变。
如果你运行一次pre-commit脚本(通过运行git commit),那么将创build文件.permissions。 您可以将其添加到存储库,我认为没有必要在预先提交脚本的末尾重复添加它。 但它并没有伤害,我想(希望)。
在Omid的脚本中,有一些关于目录名和文件名中是否存在空格的小问题。 这里的空间是一个问题,我在IFS修复中遇到了一些麻烦。 为了logging,这个预先提交的脚本确实为我工作:
#!/bin/bash SELF_DIR=`git rev-parse --show-toplevel` DATABASE=$SELF_DIR/.permissions # Clear the permissions database file > $DATABASE echo -n "Backing-up file permissions..." IFSold=$IFS IFS=$'\n' for FILE in `git ls-files` do # Save the permissions of all the files in the index echo $FILE";"`stat -c "%a;%U;%G" $FILE` >> $DATABASE done IFS=${IFSold} # Add the permissions database file to the index git add $DATABASE echo "OK"
现在,我们从中得到什么?
.permissions文件位于git仓库的顶层。 它每个文件有一行,这是我的例子的顶部:
$ cat .permissions .gitignore;660;pauljohn;pauljohn 05.WhatToReport/05.WhatToReport.doc;664;pauljohn;pauljohn 05.WhatToReport/05.WhatToReport.pdf;664;pauljohn;pauljohn
正如你所看到的,我们有
filepath;perms;owner;group
在关于这种方法的评论中,其中一个海报抱怨说,它只能使用相同的用户名,这在技术上是正确的,但修复它却很容易。 注意后结帐脚本有2个动作片断,
# Set the file permissions chmod $PERMISSIONS $FILE # Set the file owner and groups chown $USER:$GROUP $FILE
所以我只保留第一个,这就是我所需要的。 我在Web服务器上的用户名确实不同,但更重要的是,除非您是root用户,否则不能运行chown。 可以运行“chgrp”,但是。 很明显,如何使用它。
在这篇文章的第一个答案中,被广泛接受的是,使用git-cache-meta,这个脚本和前/后钩子脚本在做同样的工作(parsinggit ls-files
输出git ls-files
)。 这些脚本对我来说更容易理解,git-cache-meta代码相当复杂。 可以将git-cache-meta保留在path中,并编写使用它的预提交和后结帐脚本。
文件名中的空格是Omid的脚本的问题。 在post-checkout脚本中,如果看到类似这样的错误,就会知道文件名中有空格
$ git checkout -- upload.sh Restoring file permissions...chmod: cannot access '04.StartingValuesInLISREL/Open': No such file or directory chmod: cannot access 'Notebook.onetoc2': No such file or directory chown: cannot access '04.StartingValuesInLISREL/Open': No such file or directory chown: cannot access 'Notebook.onetoc2': No such file or directory
我正在检查解决scheme。 这是似乎工作的东西,但我只在一个案件testing
#!/bin/bash SELF_DIR=`git rev-parse --show-toplevel` DATABASE=$SELF_DIR/.permissions echo -n "Restoring file permissions..." IFSold=${IFS} IFS=$ while read -r LINE || [[ -n "$LINE" ]]; do FILE=`echo $LINE | cut -d ";" -f 1` PERMISSIONS=`echo $LINE | cut -d ";" -f 2` USER=`echo $LINE | cut -d ";" -f 3` GROUP=`echo $LINE | cut -d ";" -f 4` # Set the file permissions chmod $PERMISSIONS $FILE # Set the file owner and groups chown $USER:$GROUP $FILE done < $DATABASE IFS=${IFSold} echo "OK" exit 0
由于权限信息是一次一行,所以我将IFS设置为$,所以只有换行符被视为新事物。
我读过这样设置IFS环境variables是非常重要的! 你可以看到为什么一个shell会话可能会变得糟糕,如果你离开$作为唯一的分隔符。
在pre-commit / post-checkout中,一个选项是使用“mtree”(FreeBSD)或者“fmtree”(Ubuntu)工具,它们“根据规范比较文件层次结构,创build文件层次结构规范,规范。”
默认设置是标志,gid,链接,模式,链接,大小,时间,types和uid。 这可以用-k开关来适应特定的目的。