如果修改了git中的文件和目录的权限,如何恢复?

时间:2010-03-25 16:26:33

标签: git file file-permissions

我有一个git checkout。所有文件权限都与git认为应该是的不同,因此它们都显示为已修改。

不触及文件内容(只想修改权限)如何将所有文件权限设置为git认为应该是什么?

12 个答案:

答案 0 :(得分:496)

使用git diff -p创建补丁时,Git会跟踪文件许可并公开权限更改。所以我们需要的是:

  1. 创建反向补丁
  2. 仅包含权限更改
  3. 将补丁应用于我们的工作副本
  4. 作为一个单行:

    git diff -p -R --no-color \
        | grep -E "^(diff|(old|new) mode)" --color=never  \
        | git apply
    

    您也可以将它作为别名添加到您的git配置...

    git config --global --add alias.permission-reset '!git diff -p -R --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply'
    

    ...您可以通过以下方式调用它:

    git permission-reset
    

    注意,如果你的shell是bash,请务必在'周围使用"而不是!git引号,否则会被最后{{1}替换你运行的命令。

    要求@Mixologic指出,只需在git上使用-R,就不再需要繁琐的git diff命令。

答案 1 :(得分:101)

尝试git config core.fileMode false

注意:core.fileMode 区分大小写

来自git config手册页:

  

core.fileMode

     

如果为false,则忽略索引和工作副本之间的可执行位差异;对像FAT这样的破碎文件系统很有用。请参阅git-update-index(1)

     

默认值为true,但git-clone(1)或git-init(1)将在创建存储库时探测并设置core.fileMode false。

答案 2 :(得分:8)

Git不存储可执行脚本以外的文件权限。请考虑使用git-cache-meta之类的内容来保存文件所有权和权限。

Git只能存储两种模式:755(可执行)和644(不可执行)。如果您的文件是444 git将存储它有644。

答案 3 :(得分:6)

git diff -p \
| grep -E '^(diff|old mode|new mode)' \
| sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
| git apply

在大多数情况下都可以使用,但是如果你有像meld这样的外部差异工具,你必须添加--no-ext-diff

git diff --no-ext-diff -p \
    | grep -E '^(diff|old mode|new mode)' \
    | sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
    | git apply
在我的情况下需要

答案 4 :(得分:0)

您也可以尝试使用前/后结帐钩子来解决这个问题。

请参阅:Customizing Git - Git Hooks

答案 5 :(得分:0)

我在Windows上使用cygwin的git,git apply解决方案对我不起作用。这是我的解决方案,在每个文件上运行chmod以重置其权限。

#!/bin/bash
IFS=$'\n'
for c in `git diff -p |sed -n '/diff --git/{N;s/diff --git//g;s/\n/ /g;s# a/.* b/##g;s/old mode //g;s/\(.*\) 100\(.*\)/chmod \2 \1/g;p}'`
do
        eval $c
done
unset IFS

答案 6 :(得分:0)

感谢@muhqu出色的answer。就我而言,并非所有更改文件的权限都已更改,这阻止了该命令的工作。

$ git diff -p -R --no-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never
diff --git b/file1 a/file1
diff --git b/file2 a/file2
old mode 100755
new mode 100644
$ git diff -p -R --no-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply
warning: file1 has type 100644, expected 100755

然后补丁将停止并且文件将保持不变。

如果有人遇到类似的问题,我可以通过调整命令以仅更改权限已更改的文件来grep来解决此问题:

grep -E "^old mode (100644|100755)" -B1 -A1

或git别名

git config --global --add alias.permission-reset '!git diff -p -R --no-ext-diff --no-color | grep -E "^old mode (100644|100755)" -B1 -A1 --color=never | git apply'

答案 7 :(得分:0)

我知道这很老,但是我来自Google,却没有找到答案

如果您没有要保留的更改,我有一个简单的解决方案:

git config core.fileMode true
git reset --hard HEAD

答案 8 :(得分:0)

我遇到了类似的问题,有人向服务器上的所有文件添加了可执行标志,但是除了权限损坏的文件之外,我还有本地修改过的文件。然而,由于 git 跟踪的唯一权限是可执行标志,这个管道为我解决了这个问题:

git status | grep 'modified:' | awk '{print $3}' | xargs chmod a-x

基本上该命令运行 git status,过滤报告为修饰符的文件,通过 awk 提取它们的路径,并删除可执行标志。

答案 9 :(得分:-1)

最简单的方法是重新更改权限。正如@kroger所说,git只跟踪可执行位。因此,您可能只需要运行chmod -x filename来修复它(或+x,如果需要的话。

答案 10 :(得分:-1)

muhqu's answer中使用的

git diff -p可能不会显示所有差异。

  • 在Cygwin中看到了我没有拥有的文件
  • 如果core.filemodefalse(这是MSysGit的默认设置),
  • 模式更改将被完全忽略

此代码直接读取元数据:

(set -o errexit pipefail nounset;
git ls-tree HEAD -z | while read -r -d $'\0' mask type blob path
do
    if [ "$type" != "blob" ]; then continue; fi;
    case "$mask" in
    #do not touch other bits
    100644) chmod a-x "$path";;
    100755) chmod a+x "$path";;
    *) echo "invalid: $mask $type $blob\t$path" >&2; false;;
    esac
done)

非生产级单线(完全替换面具):

git ls-tree HEAD | perl -ne '/^10(0\d{3}) blob \S+\t(.+)$/ && { system "chmod",$1,$2 || die }'

(" $' \ 0'"转到http://transnum.blogspot.ru/2008/11/bashs-read-built-in-supports-0-as.html

答案 11 :(得分:-2)

etckeeper tool可以处理权限,并使用:

etckeeper init -d /mydir

您可以将其用于/etc以外的其他目的地。

使用您的软件包管理器安装或从上面的链接获取源代码。