【问题标题】:How to restore the permissions of files and directories within git if they have been modified?git中文件和目录被修改后如何恢复权限?
【发布时间】:2023-03-31 10:13:01
【问题描述】:

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

在不触及文件内容的情况下(只想修改权限)如何将所有文件的权限设置为 git 认为的应有的权限?

【问题讨论】:

标签: git file file-permissions


【解决方案1】:

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

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

【讨论】:

  • 对不起,这是不正确的。 Git 确实会跟踪权限。
  • 大致准确,见git.wiki.kernel.org/index.php/ContentLimitations。设置的确切权限似乎基于服务器和可能的客户端umask 以及配置设置,请参阅stackoverflow.com/a/12735291/125150
  • @不会,不会。不敢相信您的评论获得了如此多的支持。
  • @Will,这大致正确。每the docs...a mode of 100644, which means it’s a normal file. Other options are 100755, which means it’s an executable file; and 120000, which specifies a symbolic link. The mode is taken from normal UNIX modes but is much less flexible — these three modes are the only ones that are valid for files (blobs) in Git (although other modes are used for directories and submodules).
【解决方案2】:

最简单的方法就是将权限改回来。正如@kroger 指出的那样,git 只跟踪可执行位。所以你可能只需要运行chmod -x filename 来修复它(或者+x,如果需要的话。

【讨论】:

  • 这是来自git show 的示例: diff --git a/OpenWatch/src/org/ale/openwatch/fb/FBUtils.java b/OpenWatch/src/org/ale/openwatch/fb /FBUtils.java index cd6fa6a..e5b0935 100644 粗体字表示文件权限。
  • 这对我来说似乎也是最简单的。不幸的是,我遇到了与 Conrado 相同的问题 - 我无法将权限从 100644 更改为 100755。我认为您不应该投反对票。 Git应该被否决。它在如此多不同的层次上以如此多的方式被打破......
【解决方案3】:

试试git config core.fileMode false

来自git config 手册页:

core.fileMode

如果为 false,则忽略索引和工作副本之间的可执行位差异;在 FAT 等损坏的文件系统上很有用。见git-update-index(1)

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

【讨论】:

  • 谢谢,这就是我最终要做的。非常习惯于 cvs 不跟踪权限,所以这行得通。
  • @shovas:我很高兴这有帮助。在 Linux 和 Windows 之间共享存储库时,我遇到了类似的问题。顺便说一句:如果这回答了您的问题,请将回复标记为正确。
  • git checkout origin/master 是否可以将提交给服务器的文件权限设置为我的本地工作副本?因为每当我为 ArangoDB 构建 V8 时,文件权限都会更改,从而拒绝访问整个构建文件夹(即使具有提升的权限;即 Windows 7+)。在继续构建过程之前,我需要修复所有本地文件权限。 core.filemode false 也可以解决这个问题吗?我怀疑 git 在我的 Windows 机器上设置 Linux 权限。构建脚本可能只是保留它们并将相同的权限应用于新创建的文件......
  • 我想知道将filemode 设置为false 是否有任何缺点!
【解决方案4】:

您也可以尝试使用 pre/post checkout hook 来解​​决问题。

见:Customizing Git - Git Hooks

【讨论】:

    【解决方案5】:

    Git 跟踪文件权限并在使用git diff -p 创建补丁时公开权限更改。所以我们只需要:

    1. 创建反向补丁
    2. 仅包括权限更改
    3. 将补丁应用到我们的工作副本

    作为单行:

    git diff -p -R --no-ext-diff --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-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply'
    

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

    git permission-reset
    

    注意,如果您的 shell 是 bash,请确保在 !git 周围使用 ' 而不是 " 引号,否则它将被您运行的最后一个 git 命令替换。

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

    【讨论】:

    • 我在 OS X 中,这不起作用。我已经确定问题出在 git apply 中。它不会应用文件权限更改。
    • 哦,它成功了,我试图从与存储库根目录不同的目录应用。 git apply 只在那里工作。
    • 有什么理由你不会只执行“git diff -p -R”而不是执行 sed 来使其反转吗?
    • @RobQuist 我的本地更改在使用 muhqu 的命令时没有被删除
    • 我收到fatal: unrecognized input
    【解决方案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
    

    在我的情况下需要

    【讨论】:

      【解决方案7】:

      etckeeper tool 可以处理权限并具有:

      etckeeper init -d /mydir
      

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

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

      【讨论】:

      • 它将权限设置为什么?如果它不读取 Git 元数据或调用 Git,它就不会执行 OP 请求的操作。
      【解决方案8】:

      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

      【讨论】:

        【解决方案9】:

        我在 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
        
        

        【讨论】:

          【解决方案10】:

          感谢@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'
          

          【讨论】:

            【解决方案11】:

            我知道这是旧的,但我来自谷歌,但我没有找到答案

            我有一个简单的解决方案如果你没有想要保留的零钱

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

            【讨论】:

              【解决方案12】:

              我遇到了类似的问题,有人将可执行标志添加到服务器上的所有文件中,但是除了权限被破坏的文件之外,我还有本地修改的文件。但是,由于 git 跟踪的唯一权限是可执行标志,因此该管道为我解决了问题:

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

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

              【讨论】:

              • 一般 grep + awk 最好简化为 awk(例如 awk '/modified/{print $3}'),尽管此解决方案无法正确处理文件名中的空格。幸运的是,有一个本地 git 等效项:git ls-files -m -z | xargs -0 chmod a-x.
              猜你喜欢
              • 2011-09-13
              • 1970-01-01
              • 2016-03-20
              • 2012-03-06
              • 2017-01-17
              • 2015-09-29
              • 2013-10-17
              • 2015-02-11
              • 1970-01-01
              相关资源
              最近更新 更多