为什么'git status'会运行过滤器?

sta*_*fry 5 git

我需要将git repo克隆到现有目录中($HOME用于管理dotfiles).我正在做一个裸克隆并重新配置它,因为我需要克隆到现有的不干净的工作目录中.它工作,但我发现git status尝试在首次使用时运行过滤器.为什么会这样做,我该如何预防呢?

试试这个:

# create a test repo
mkdir test && cd test
git init
echo hello > hello.txt
git add .
git commit -m 1
echo 'hello.txt filter=foo diff=bar' > .gitattributes
git add .
git commit -m 2

# clone it bare and configure it
mkdir ../test2 && cd ../test2
git clone --bare ../test .git
git config core.bare false
git config core.logallrefupdates true
git reset
git checkout .
git config filter.foo.clean foo
git config filter.foo.smudge foo
git config diff.bar.textconv bar
Run Code Online (Sandbox Code Playgroud)

这个borks

$ git status
error: cannot run foo: No such file or directory
error: cannot fork to run external filter 'foo'
error: external filter 'foo' failed
On branch master
nothing to commit, working tree clean
Run Code Online (Sandbox Code Playgroud)

事实并非如此

$ git status
On branch master
nothing to commit, working tree clean
Run Code Online (Sandbox Code Playgroud)

此外,最初git status快速连续多次(即git status; git status; git status)可能产生多次失败.有时.

据我所知,通过大量阅读可以确认过滤器只应在检入和退出文件时运行.

那么为什么要git status运行呢?

tor*_*rek 5

过滤器只在签入/签出期间运行的想法是一个善意的谎言。它的目的是使过滤器更易于解释。

然而,事实上,过滤器在索引和工作树之间移动文件时会运行(而且,在足够现代的 Git 版本中,当使用and和 and 中的--path=选项请求时:其中一些是直接从存储库到标准输出的转换,或者标准输入到存储库)。这主要相当于签入/签出时间。但由于索引的缓存方面,也有特殊的分配。git showgit cat-filegit hash-objectgit status

出于性能原因,Git 想知道工作树中的任何文件是否相对于索引中的版本可能是“脏的”。Git 假定通常具有一秒分辨率的stat1可用于此目的:如果文件的时间- 工作树条目 -保存在索引条目中的时间,则索引条目是是最新的并且是“干净的”:在应用干净的过滤器等之后,索引中的内容与工作树中的内容相匹配。st_mtimest_mtimest_mtime

如果工作树条目的时间戳保存的索引条目新,则文件肯定已被修改:索引条目可能已过期。不能保证它是过时的,因为工作树文件可能已经以最终没有更改的方式进行了修改。但显然有必要运行干净的过滤器(以及任何 CR/LF 线结束hackery)。

如果两个时间戳相同,则工作树条目是不确定的。(Git 称其为“非常干净”,尽管“非常脏”也同样准确。)

在所有这些情况下,git status将在工作树文件上运行干净的过滤器(以及任何输入到 Git 方向的 CR/LF 修改)以计算新的哈希。如果新的哈希与索引哈希匹配,Git 可以并且将更新索引条目以将文件标记为“实际上是干净的”。现在,下次您做某事时,Git 将不必运行清洁过滤器。

除非,也就是说,您在st_mtimestat 字段的分辨率内执行所有操作。在这种情况下,索引条目会变得“非常干净”,Git 必须再试一次。这就是你在这里观察到的。

(顺便说一下,它git status运行两个差异:一个从HEAD索引,一个从索引到工作树。正是第二个差异从索引的缓存方面受益匪浅。索引现在还可以存储有关未缓存的信息文件和目录也是如此!)


1有些stat调用提供亚秒级精度,但由于各种原因,索引/缓存条目通常只存储 1 秒分辨率时间戳。

对于(多)更多相关信息,请参阅racy-git.txt技术文件的文件