为什么改了文件权限 git status 也会报告改动?core.fileMode 到底管什么?这篇造十种权限的文件看 git 记成什么、检出后又变成什么,再比较 fileMode 为 true 和 false 时 chmod、add、update-index 的表现。
$ git add -A && git ls-files -s | awk '{print $1, $4}' | sort -k2
100644 data.txt
100644 p600
100644 p611
100644 p640
100644 p644
100644 p664
100755 p700
100755 p711
100755 p744
100755 p755
100755 p775
100755 run.sh
$ stat -f '%Lp %N' p600 p611 p640 p664 p700 p711 p744 p775 | sort -k2
600 p600
611 p611
640 p640
664 p664
700 p700
711 p711
744 p744
775 p775git 对每个文件只记录一个信息:属主有没有可执行位,记成 100755 或 100644。读写位、组和其他人的权限一概不记。
$ git commit -q -m 第一次 && git clone -q . ../l9clone && cd ../l9clone && umask && stat -f "%Lp %N" p600 p611 p640 p664 p700 p711 p744 p775 p644 p755 | sort -k2 0022 644 p600 644 p611 644 p640 644 p644 644 p664 755 p700 755 p711 755 p744 755 p755 755 p775
检出时按 umask 重新生成权限:100644 变成 666 & ~umask(这里是 644),100755 变成 777 & ~umask(755)。所以 600、664 这样的细节无法通过 git 传递。
$ chmod 755 data.txt; git status --short; git diff M data.txt diff --git a/data.txt b/data.txt old mode 100644 new mode 100755 $ git add data.txt; git ls-files -s data.txt; git commit -q -m 改权限; git log -1 --stat --format=%s 100755 587be6b4c3f93f93c489c0111bba5596147a26cb 0 data.txt 改权限 data.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-)
默认情况下 chmod 会被 git 看作改动:git diff 显示 old mode / new mode,可以提交,提交里只有模式变化而没有行数变化。
$ git config core.fileMode false; chmod 644 data.txt; git status --short; echo "[fileMode=false 下 chmod 644 后 status 为空]"; git ls-files -s data.txt [fileMode=false 下 chmod 644 后 status 为空] 100755 587be6b4c3f93f93c489c0111bba5596147a26cb 0 data.txt $ git config core.fileMode true; git status --short M data.txt git init 时会探测文件系统是否保存权限位: $ rm -rf l9probe && git init -q l9probe && git -C l9probe config core.fileMode true
在不保存权限位的文件系统上 git 会自动把 core.fileMode 设成 false,此时磁盘权限的变化被忽略。这台机器上 git init 探测到的是 true。
$ git config core.fileMode false; git add tool.sh; git ls-files -s tool.sh 100644 1a2485251c33a70432394c93fb89330ef214bfc9 0 tool.sh $ git update-index --chmod=+x tool.sh; git ls-files -s tool.sh 100755 1a2485251c33a70432394c93fb89330ef214bfc9 0 tool.sh $ git update-index --chmod=-x tool.sh; git ls-files -s tool.sh 100644 1a2485251c33a70432394c93fb89330ef214bfc9 0 tool.sh $ git config core.fileMode true; git update-index --chmod=+x tool.sh; git ls-files -s tool.sh; git status --short 100755 1a2485251c33a70432394c93fb89330ef214bfc9 0 tool.sh A tool.sh
fileMode=false 时新文件一律记成 100644;要提交可执行脚本,用 git update-index --chmod=+x 手工设置。
$ chmod 644 tool.sh; git status --short; git config core.fileMode false; git status --short; echo "(fileMode=false 时 status 为空)"; git ls-files -s tool.sh M tool.sh (fileMode=false 时 status 为空) 100755 1a2485251c33a70432394c93fb89330ef214bfc9 0 tool.sh $ git config core.fileMode true; git diff --summary mode change 100755 => 100644 tool.sh
false 会隐藏真实的权限丢失:已提交为 100755 的文件在磁盘上失去可执行位,status 看不出来。怀疑权限被破坏时,临时切回 true 再看 git diff --summary。