为了在提交时自动使.sh
文件可执行,我做了一个干净的过滤器,并对其结果感到困惑。
首先,我跑git config filter.executable.clean 'chmod +x %f'
.这会将以下节添加到我的测试存储库的.git/config
文件中:
[filter "executable"]
clean = chmod +x %f
接下来,我创建了一个.gitattributes
文件:
*.sh filter=executable
让我们看看它是如何表现的。当然,新创建的.sh
文件是不可执行的:
$ touch foo.sh
$ ls -l foo.sh
-rw-r--r-- foo.sh
如果我们add
它,我们的干净过滤器应该运行。但这会导致我们的工作目录中有一个可执行文件,在我们的暂存区域中有一个不可执行的文件,以及一个脏的工作副本!
$ git add foo.sh
$ ls -l foo.sh # As expected
-rwxr-xr-x foo.sh
$ git ls-files -s foo.sh # Confusing
100644 foo.sh
$ git status # Confusing
Changes to be committed:
new file: foo.sh
Changes not staged for commit:
modified: foo.sh
再次运行git add
会在暂存区域中生成可执行文件和干净的工作副本:
$ git add foo.sh
$ git ls-files -s foo.sh
10755 foo.sh
$ git status
Changes to be committed:
new file: foo.sh
这是怎么回事?
Git 的过滤器必须从 STDIN 获取输入并将其输出发送到 STDOUT:
签出时,当指定
smudge
命令时,该命令将从其标准输入提供给 blob 对象,其标准输出用于更新工作树文件。同样,clean
命令用于在检入时转换工作树文件的内容。
上面显示的筛选器不会以这种方式运行。它忽略 STDIN,并且不向 STDOUT 发送任何输出,因此第一个git add
命令不会捕获其效果。暂存文件不可执行。
但是,筛选器确实运行。这会产生在工作副本中的文件上添加执行位的副作用。git status
看到文件的权限已更改。
第二个git add
捕获可执行位,但不直接因为我们的过滤器。它只是暂存它在工作副本中看到的权限更改。
我不知道有什么方法可以通过 STDIN 和 STDOUT 修改文件的权限。在干净和污迹过滤器中修改文件权限可能非常困难。