Git 的 `.gitattributes` 过滤器不更新工作树中的内容

Git's `.gitattributes` filter not updating content in the worktree

我想使用 .gitattributes 过滤器来更新 git add 上的文件(实际上,提交之前的任何内容都可以)。

然而,尽管过滤器是 运行,但工作树中的内容保持不变。

我制作了一个最小的回购作为展示:

foo.txt

Foo
<start>
<stop>
Bar

update-toc

#!/usr/bin/env python3

import re
import sys

def parse(lines):
    start = -1
    stop = -1
    for i, line in enumerate(lines):
        if re.match('<start>', line):
            start = i
            continue
        if re.match('<stop>', line):
            stop = i
            continue
    return start, stop

print('STARTING FILTER', file=sys.stderr)
lines = sys.stdin.readlines()
start, stop = parse(lines)
if start != -1 and stop != -1:
    new_lines = lines[:start + 1] + ['baz\n'] + lines[stop:]
else:
    new_lines = lines
sys.stdout.write(''.join(new_lines))
print('ENDING FILTER', file=sys.stderr)
sys.stderr.write(''.join(new_lines))

.gitattributes

*.txt   filter=update-toc

.git/config

[filter "update-toc"]
        smudge = ./update-toc
        clean = ./update-toc
        required

在这个 repo 上,如果我 运行 以下命令我可以看到过滤器 运行 成功但内容本身没有更新:

$ git add --renormalize foo.txt
STARTING FILTER
ENDING FILTER
Foo
<start>
baz
<stop>
Bar

$ cat foo.txt
Foo
<start>
<stop>
Bar

各种编辑和提交不会改变 foo.txt 除了我自己的修改。

如果我删除 foo.txt 然后检查它 (git checkout) 然后我将检索过滤后的版本。

$ rm foo.txt
$ git checkout foo.txt
$ cat foo.txt
Foo
<start>
baz
<stop>
Bar

有没有办法修改工作树内容或自动检查它(也许将过滤器与 Git 挂钩结合起来)?

无论好坏,这都是清洁过滤器意味着的工作方式。它永远不会改变工作树副本中的内容:它仅适用于 Git 将在其压缩器中看到的字节流。1

由于 , the reliable way to update the working tree copy is to do that separately. In theory, if you can get the name of the working tree object—which you can using the long-running protocol—you could first filter the file, then update it in place (perhaps asynchronously), but this introduces a lot of potential races, and as the documentation notes,该文件此时甚至可能不存在于该路径名中(对于 clean 过滤器通常不会出现这种情况,但可能存在一些不明显的极端情况)。

(在这一点上,即使没有涂抹过滤器,从索引中检查文件也能正常工作,因为文件的 index 副本包含添加的行。)


1压缩器进行zlib压缩,生成一个新的内部blob对象;它还同时计算哈希 ID。生成的散列 ID 要么是某个现有对象的散列 ID(在这种情况下,新的 blob 是一个副本,为了支持现有对象而被丢弃)或者是一个新对象(在这种情况下,新的 blob 被添加到存储库中对象数据库)。新 blob 的哈希 ID 现在有效并替换索引中的旧哈希 ID(如果文件之前在索引中),或者成为索引中新条目的哈希 ID(如果文件是索引的新文件)现在。