如何使Git忽略文件模式(chmod)更改?

2835

我有一个项目,在开发过程中需要使用 chmod 命令将文件的模式改为777,但是这些修改不应该出现在主仓库中。

Git 会认为 chmod -R 777 . 命令修改了所有文件,并标记它们为已更改。有没有办法让 Git 忽略对文件所做的模式更改?


49
在 Windows 操作系统上使用 Bash on Ubuntu on Windows 环境进行 Git 工作时,这个提示非常有帮助。 - Elazar
10
如果你只是想在特定一次git diff操作中忽略权限更改,而又不希望修改Git配置文件,可以按照Zed的回答这里所述,使用git diff -G.命令。 - user82216
14个回答

4721

尝试:

git config core.fileMode false

来自git-config(1):

core.fileMode
    Tells Git if the executable bit of files in the working tree
    is to be honored.

    Some filesystems lose the executable bit when a file that is
    marked as executable is checked out, or checks out a
    non-executable file with executable bit on. git-clone(1)
    or git-init(1) probe the filesystem to see if it handles the 
    executable bit correctly and this variable is automatically
    set as necessary.

    A repository, however, may be on a filesystem that handles
    the filemode correctly, and this variable is set to true when
    created, but later may be made accessible from another
    environment that loses the filemode (e.g. exporting ext4
    via CIFS mount, visiting a Cygwin created repository with Git
    for Windows or Eclipse). In such a case it may be necessary
    to set this variable to false. See git-update-index(1).

    The default is true (when core.filemode is not specified
    in the config file).

使用-c标志可以为一次性命令设置此选项:

git -c core.fileMode=false diff

在所有的Git存储库中或仅在一个Git存储库中设置-c core.fileMode=false标志,可以避免不必要的麻烦:

# this will set your the flag for your user for all git repos (modifies `$HOME/.gitconfig`)
# WARNING: this will be override by local config, fileMode value is automatically selected with latest version of git.
# This mean that if git detect your current filesystem is compatible it will set local core.fileMode to true when you clone or init a repository.
# Tool like cygwin emulation will be detected as compatible and so your local setting WILL BE SET to true no matter what you set in global setting.
git config --global core.fileMode false

# this will set the flag for one git repo (modifies `$current_git_repo/.git/config`)
git config core.fileMode false
此外,git clonegit init 在仓库配置中明确设置了core.fileModetrue,如在Git global core.fileMode false overridden locally on clone中讨论的那样。
警告:不建议使用core.fileMode,应该谨慎使用。这个设置只涵盖模式的可执行位,而不是读/写位。在许多情况下你可能认为需要这个设置,因为你做了chmod -R 777之类的操作,使得所有文件都可执行。但在大多数项目中,由于安全原因,大多数文件都不需要且不应该被设置为可执行。
解决这种情况的正确方法是分别处理文件夹和文件权限,可以使用类似以下命令的方式:
find . -type d -exec chmod a+rwx {} \; # Make folders traversable and read/write
find . -type f -exec chmod a+rw {} \;  # Make files read/write

如果你这样做,除非在非常罕见的情况下,否则你永远不需要使用core.fileMode


235
如果你执行git config --global core.filemode false,那么你只需要在所有仓库中执行一次即可。 - Greg
22
在我修正大小写之前,这对我没有起作用,应该是fileMode而不是filemode。 - tishma
11
根据文档,Git配置部分和变量名称是不区分大小写的,详见CONFIGURATION FILE部分。因此,如果上述方法对您不起作用,则原因可能不同。 - Greg Hewgill
14
git config 命令会将设置写入正确的配置文件中(对于当前仓库来说是 .git/config,如果使用 --global 则是 ~/.gitconfig)。 - Greg Hewgill
11
没关系。从 git config 中可以看到:"变量名不区分大小写,..." - Greg Hewgill
显示剩余35条评论

326

撤消工作树中的模式更改:

git diff --summary | grep --color 'mode change 100755 => 100644' | cut -d' ' -f7- | xargs -d'\n' chmod +x
git diff --summary | grep --color 'mode change 100644 => 100755' | cut -d' ' -f7- | xargs -d'\n' chmod -x
在mingw-git中。
git diff --summary | grep  'mode change 100755 => 100644' | cut -d' ' -f7- | xargs -e'\n' chmod +x
git diff --summary | grep  'mode change 100644 => 100755' | cut -d' ' -f7- | xargs -e'\n' chmod -x

或在 BSD/macOS 上

git diff --summary | grep --color 'mode change 100644 => 100755' | cut -d' ' -f7- | tr '\n' '\0' | xargs -0 chmod -x
git diff --summary | grep --color 'mode change 100755 => 100644' | cut -d' ' -f7- | tr '\n' '\0' | xargs -0 chmod -x

46
在OS X Lion上,从xargs中省略-d'\n'部分,因为这是不合法的参数(也不需要)。 - Pascal
12
你可以忽略有关“chmod: missing operand after `+x'”错误的任何提示。 - Casey Watson
5
最新的吗?我在mingw中得到了“chmod: too few arguments”的错误提示。 - hammett
8
-d 参数指定了分隔符为换行符,而非任何空白字符。BSD 的 xargs 命令没有该选项,但你可以通过管道将输出传递给 tr '\n' '\0' 命令,然后使用 -0 参数将 NUL 作为分隔符传递给 xargs 命令。 - Mark
13
太棒了,tr命令起作用了!以下是适用于OSX的完整命令:git diff --summary | grep --color 'mode change 100644 => 100755' | cut -d' ' -f7-|tr '\n' '\0'|xargs -0 chmod -x - K.-Michael Aye
显示剩余7条评论

161
如果你想为所有的代码库设置此选项,请使用--global选项。
git config --global core.filemode false
如果这不起作用,你可能正在使用更新版本的Git,请尝试--add选项。
git config --add --global core.filemode false

如果你没有使用 --global 选项,并且你的工作目录不是一个仓库,那么运行它会得到:

error: could not lock config file .git/config: No such file or directory

7
似乎较新版本的GIT使用了 --add,例如 git config --add --global core.filemode false。该命令用于将 core.filemode 设置为 false 并将其添加到全局配置中。 - mgaert
21
如果本地仓库配置中已经有"filemode=true",那么更改全局配置是无效的,因为本地配置会覆盖全局配置。必须针对每个机器上的仓库更改本地配置。 - Rakib
5
请更新这个回答并包含syedrakib的警告!在我发现它之前,一切都感觉疯狂,但在发现它之后,一切都变得非常清晰。 - jerclarke

117
如果
git config --global core.filemode false

如果这对你不起作用,那么请手动操作:

cd into yourLovelyProject folder

进入 .git 文件夹:

cd .git

编辑配置文件:

nano config

将 true 改为 false

[core]
        repositoryformatversion = 0
        filemode = true

->

[core]
        repositoryformatversion = 0
        filemode = false

保存、退出、回到上一个文件夹:

cd ..
重新初始化Git。
git init

你已经完成了!


16
不需要编辑.git/config文件,只需在项目根目录下运行git config core.fileMode false即可。如果您要编辑配置文件,最好将指令完全删除,以便选择全局设置。 - Felix
9
如果git config --global无法工作,这意味着您没有在系统级别上执行此操作的权限。删除 "global" 选项与手动编辑 .git/config 文件完全相同。 - CharlesB
1
@CharlesB 错了 - 回答提供了一种解决方法,通过直接在项目中设置选项,使其成为特定于该项目。这对于您未来创建/检出的其他git项目将不起作用,但对于您正在处理的项目有效。(让我们确保澄清~/.gitconfig~/project/.git/config) - ddavison
2
一旦运行了 git init,我们应该将 filemode 设置回 true 吗? - Jordan
2
"git init" 将 filemode 返回 TRUE! - Geka P

58

Greg Hewgill的回答中提到(使用core.fileMode配置变量),你还可以使用git update-index--chmod=(-|+)x 选项(低级版本的 "git add")来更改索引中的执行权限,如果您使用“git commit”(而不是“git commit -a”),它将从其中获取这些更改。


2
这应该被编辑到Greg Hewgill的回答中,而不是添加为一个单独的答案,从而创建一个至高无上的答案,具有单一明确的表示。 - Greg
6
@Greg:编辑答案需要足够的积分;我认为当时我没有足够的编辑权限。 - Jakub Narębski
1
@Jakub,我认为你现在的声望已经足够了 :) 对于一个示例文件,这个命令会是什么样子? - Alex Hall

50
您可以在全局范围内进行配置: < p > git config --global core.filemode false 如果上述方法对您无效,则可能是因为您的本地配置覆盖了全局配置。
删除您的本地配置以使全局配置生效: < p > git config --unset core.filemode 或者,您可以将本地配置更改为正确的值: < p > git config core.filemode false

5
如果主要答案无法帮助您,请尝试此方法。如果您想在不修改本地配置的情况下检查其内容,请使用命令git config -l(列出当前配置 - 包括本地和全局)。 - Krzysztof Bociurko
删除本地配置是导致全局无法正常工作的原因。谢谢! - Greadimar

26
如果您已经使用过chmod命令,请检查文件的差异,它显示先前文件模式和当前文件模式,例如:
新模式:755
旧模式:644
使用以下命令设置所有文件的旧模式: sudo chmod 644 . 现在在配置文件中使用命令或手动将core.fileMode设置为false。
git config core.fileMode false

然后使用chmod命令更改所有文件的权限,例如

sudo chmod 755 .

再次将core.fileMode设置为true。

git config core.fileMode true

为了最佳实践,请不要始终将 core.fileMode 设置为 false。


你是说整个项目(开发、暂存和生产环境)都应该设置为755权限吗? - Daniel
1
为了最佳实践,请勿始终将core.fileMode保持为false。一些文件系统(例如FAT)不支持文件权限,因此操作系统将报告默认值(在我的系统上为766)。在这种情况下,本地配置中绝对需要使用core.filemode,除非您想用不必要和无意的权限更改使提交历史膨胀。 - KevinOrr
另外,为什么您要费心将权限更改回去呢?如果您设置 core.filemode=false,那么git将忽略执行位的更改,无需更改本地权限。除非您已经将权限更改添加到索引中,否则您需要在关闭 core.filemode 后执行 git add 步骤。 - KevinOrr
我在想如果我有这种情况(带有修改后的权限),然后我使用 git config core.fileMode false,会发生什么。在设置之后,某些文件将不会被视为已修改(只有权限更改的文件),而其他一些文件则由于代码更改等其他更改而仍然被视为已修改。如果我提交这些文件,那么修改后的权限是否也会作为其一部分被提交? - Raja Ehtesham
@RajaEhtesham 不是的,虽然你可能已经想到了。唯一提交的是你为提交而暂存的内容(即你使用git add添加的文件和在运行git status时看到的更改)。 - KevinOrr
显示剩余2条评论

22

通过在~/.gitconfig文件中定义以下别名,您可以轻松地在每个git命令中暂时禁用filemode:

通过在~/.gitconfig文件中定义以下别名,您可以轻松地在每个git命令中暂时禁用filemode:

[alias]
nfm = "!f(){ git -c core.fileMode=false $@; };f"

当这个alias作为git命令的前缀时,文件模式的更改不会显示在本来会显示它们的命令中。例如:

git nfm status

为什么不使用预提交钩子而不是易被遗忘的参数呢? - FredTheWebGuy

14
如果你想在配置文件中递归地(包括子模块)将filemode设置为false: find -name config | xargs sed -i -e 's/filemode = true/filemode = false/'

6
如果配置文件中没有那一行,这将无法生效。如果你想更改子模块的设置,尝试使用以下命令:git submodule foreach git config core.fileMode false - courtlandj

6

简单解决方案:

在项目文件夹中运行此简单命令(它不会删除您的原始更改)......它只会删除更改,这些更改是在您更改项目文件夹权限时进行的。

命令如下:

git config core.fileMode false

为什么所有这些不必要的文件都被修改了:因为您使用以下命令更改了项目文件夹权限:sudo chmod -R 777 ./yourProjectFolder

当您检查未更改的内容时,会发现像下面这样,使用git diff filename

old mode 100644
new mode 100755

这个答案复制了Greg Hewgill在10年前的回答。 - bfontaine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接