注意:使用 Git 2.12(2017 年第一季度)这将变得更容易发现,因为您可以使用不区分大小写的选项列出分支。
请参阅Nguyễn Thái Ngọc Duy ( )的提交 3bb16a8(2016 年 12 月 4 日) 。(由Junio C Hamano 合并——在提交 73e494f中,2016 年 12 月 19 日)pclouds
gitster
tag
, branch
, for-each-ref
: 添加--ignore-case
用于排序和过滤。
此选项使排序忽略大小写,当您有名为 的分支bug-12-do-something
并Bug-12-do-some-more
希望
BUG-12-do-what
将它们组合在一起时,这非常有用。
外部排序可能不是一种选择,因为我们从 git-branch 和 git-tag 中丢失了颜色和列布局。
过滤也可以这样说,但它可能不太重要,因为[bB][uU][gG]-*
如果你绝望,你总是可以使用丑陋的模式。
但是,您不能进行区分大小写的过滤和不区分大小写的排序(或相反)。对于branch
和tag
,应该没问题。for-each-ref
,作为管道,可能需要更好的控制。
但是我们总是可以--{filter,sort}-ignore-case
在需要时添加它。
git branch --ignore-case --list
注意:--ignore-case
“”(及其朋友)的“”选项git for-each-ref
无法正常工作,已在 Git 2.19(2018 年第三季度)中修复。
请参阅Aleksandr Makarov ( ) 的提交 639ab5e(2018 年 7 月 2 日)。
请参阅Jeff King ( ) 的commit e674eb2和commit ee0f3e2(2018 年 7 月 2 日)。(由Junio C Hamano 合并 -- --在提交 4301330中,2018 年 7 月 24 日)deviance
peff
gitster
ref-filter
: 避免后端过滤--ignore-case
当for-each-ref
与 一起使用时--ignore-case
,我们希望match_name_as_path()
进行不区分大小写的匹配。
但是在我们到达那里之前,就会发生额外的过滤层。由于提交 cfe004a ( ref-filter
: limit traversal to prefix, 2017-05-22, Git v2.14.0),我们将前缀提供给 ref 后端,以便它可以优化 ref 迭代。
我们没有机制告诉后端我们不区分大小写匹配。短期内也不可能有一个,因为打包的后端依赖于对已排序的 refs 列表进行二进制搜索。
让我们简单地讨论一下这个案子。额外的过滤是我们根本做不到的优化。我们仍然会通过match_name_as_path(
) 中的过滤给出正确答案。
请注意,在 Git 2.23(2019 年第三季度)中,git for-each-ref
具有多种模式的 " " 已得到优化。
请参阅Taylor Blau ( ) 的提交 b31e268(2019 年 6 月 26 日)。(由Junio C Hamano 合并 -- --在提交 b4b8c35中,2019 年 7 月 19 日)ttaylorr
gitster
ref-filter.c
: 查找不相交的模式前缀
自cfe004a ( ref-filter
: limit traversal to prefix, 2017-05-22, Git v2.14.0-rc0) 以来,ref-filter
代码一直试图将遍历限制为给定模式的前缀。
该代码没有处理多个模式,因为这意味着多次调用“for_each_ref_in”。
如果我们不注意哪些模式重叠,我们将多次输出相同的参考。
例如,考虑模式集“refs/heads/a/*”、“refs/heads/a/b/c”和“refs/tags/v1.0.0”。如果我们天真地跑:
for_each_ref_in("refs/heads/a/*", ...);
for_each_ref_in("refs/heads/a/b/c", ...);
for_each_ref_in("refs/tags/v1.0.0", ...);
我们会看到 ' refs/heads/a/b/c
' (以及它下面的所有内容)两次。
相反,我们希望将模式划分为不相交的集合,我们知道不同集合中的任何两个模式都不会匹配任何 ref。
在上面,这些是:
{'refs/heads/a/*', 'refs/heads/a/b/c'}
, 和
{'refs/tags/v1.0.0'}
给定这些不相交的集合之一,传递给“ for_each_ref_in
”的合适模式是什么?
一种方法是计算该不相交集中所有元素的最长公共前缀,并让调用者剔除他们不想要的引用。
计算最长前缀意味着在大多数情况下,我们不会匹配调用者想要忽略的太多东西。
上述最长的公共前缀是:
{'refs/heads/a/*', 'refs/heads/a/b/c'} -> refs/heads/a/*
{'refs/tags/v1.0.0'} -> refs/tags/v1.0.0
我们改为调用:
for_each_ref_in("refs/heads/a/*", ...);
for_each_ref_in("refs/tags/v1.0.0", ...);
这为我们提供了我们正在寻找的 refs 以及最少量的额外内容,但绝不会与我们要求的 ref 重复。
这里实现的是完成上述操作的算法,其工作原理如下:
按字典顺序对给定的模式列表进行排序。
将 'prefix' 初始化为空字符串,我们的目标是在上述最长公共前缀集中构建每个元素。
考虑给定集中的每个模式,如果它到达模式的末尾或触及通配符,则发出“前缀”。字符串的结尾被视为在通配符之前。(请注意,未来的工作还有一些空间来检测,例如,'a?b' 和 'abc' 是不相交的)。
否则,(3)
使用对应于我们当前前缀的列表切片(即,将我们的前缀作为文字字符串前缀的模式子集)逐步递归。
这个算法是' O(kn + n log(n))
',其中' k
'max(len(pattern))
代表列表中的每个模式,' n
'是len(patterns)
。
通过发现这组有趣的模式,我们将多模式“ git for-each-ref
”(和其他引用遍历)的运行时间从
减少O(N)
到O(n log(N))
,其中“ N
”是打包引用的总数。
在 'refs/tags/huge-N' 中有 10,000,000 个 refs 的存储库上运行 'git for-each-ref refs/tags/a refs/tags/b',我最好的五次来自:
real 0m5.805s
user 0m5.188s
sys 0m0.468s
至:
real 0m0.001s
user 0m0.000s
sys 0m0.000s
在 上linux.git
,挖掘两个最新-rc
标签的时间从 0.002 秒下降到 0.001 秒,因此标签较少的存储库的变化不太明显。
" git branch
" 和其他 " " 变体按优先级递增的顺序for-each-ref
接受多个选项,但它在 " " 处理和与 refname 的平局中存在一些问题,这些问题已在 Git 2.27(2020 年第二季度)中得到修复。--sort=<key>
--ignore-case
请参阅Jeff King ( ) 的提交 7c5045f和提交 76f9e56(2020 年 5 月 3 日)。(由Junio C Hamano 合并 -- --在提交 6de1630中,2020 年 5 月 8 日)peff
gitster
ref-filter
: 适用--ignore-case
于所有排序键
签字人:杰夫·金
所有ref-filter
用户(for-each-ref
、branch
和tag
)都有一个--ignore-case
选项,使过滤和排序不区分大小写。
但是,此选项仅应用于ref_sorting
list的第一个元素。
所以:
git for-each-ref --ignore-case --sort=refname
会做你所期望的,但是:
git for-each-ref --ignore-case --sort=refname --sort=taggername
将对主键(标记名)进行不区分大小写的排序,但对引用名进行区分大小写的排序。我们在这里有两个选择:
我在这里选择了第一个,因为如果我们以后想让用户为每个键设置标志,它会提供更大的灵活性(可能在定义键时通过一些特殊的语法;现在它是 all or nothing through --ignore-case
)。
新的测试通过不区分大小写对标记器和主题进行排序来涵盖这一点,它应该对“ a
”和“ A
”进行相同的比较,但仍将它们排序在“ b
”和“ B
”之前。
我们将通过对 refname 进行排序来打破平局,给自己一个稳定的输出(这实际上应该是自动完成的,但还有另一个错误将在下一次提交中修复)。