注意:从Git 2.12(2017年第一季度)开始,您可以使用不区分大小写的选项列出分支,这样更容易发现。
请参见
提交3bb16a8(2016年12月4日),作者为
Nguyễn Thái Ngọc Duy(pclouds
)。
(由Junio C Hamano -- gitster
--在提交73e494f中合并,2016年12月19日)
、、:增加
--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
注意:"
git for-each-ref
"(及其相关命令)的"
--ignore-case
"选项之前无法正常工作,已在 Git 2.19(2018年第三季度)中修复。
查看
提交 639ab5e(2018年7月2日)由
Aleksandr Makarov (deviance
)完成。
查看
提交 e674eb2,
提交 ee0f3e2(2018年7月2日)由
Jeff King (peff
)完成。
(由Junio C Hamano -- gitster
--合并于提交 4301330,2018年7月24日)
ref-filter
: 使用 --ignore-case
避免后端过滤
当使用 --ignore-case
的 for-each-ref
时,我们期望 match_name_as_path()
进行大小写不敏感的匹配。
但是,在我们到达那里之前,还有一个额外的过滤层。自从 commit cfe004a(ref-filter
: limit traversal to prefix, 2017-05-22, Git v2.14.0)以来,我们将前缀提供给 ref 后端,以便它可以优化 ref 迭代。
我们没有机制告诉后端我们正在进行大小写不敏感的匹配。由于打包后端依赖于对引用列表的排序二分搜索,因此在短时间内也不太可能会有这样的机制。
让我们暂时放弃这种情况。额外的过滤是我们无法做到的优化。我们仍然会通过 match_name_as_path()
中的过滤器提供正确的答案。
请注意,自Git 2.23(2019年第三季度)起,“
git for-each-ref
”支持多个模式的优化已经完成。
请参见
提交 b31e268(由
Taylor Blau (ttaylorr
)于2019年6月26日提交)。
(由Junio C Hamano -- gitster
--于2019年7月19日合并至提交b4b8c35)
ref-filter.c
: find disjoint pattern prefixes
Since cfe004a (ref-filter
: limit traversal to prefix, 2017-05-22, Git v2.14.0-rc0), the ref-filter
code has sought to limit the traversals to a prefix of the given patterns.
That code stopped short of handling more than one pattern, because it means invoking 'for_each_ref_in' multiple times.
If we're not careful about which patterns overlap, we will output the same refs multiple times.
For instance, consider the set of patterns 'refs/heads/a/*',
'refs/heads/a/b/c', and 'refs/tags/v1.0.0'. If we naïvely ran:
for_each_ref_in("refs/heads/a
we would see 'refs/heads/a/b/c
' (and everything underneath it) twice.
Instead, we want to partition the patterns into disjoint sets, where we
know that no ref will be matched by any two patterns in different sets.
In the above, these are:
{'refs/heads/a/*', 'refs/heads/a/b/c'}
, and
{'refs/tags/v1.0.0'}
Given one of these disjoint sets, what is a suitable pattern to pass to
'for_each_ref_in
'?
One approach is to compute the longest common prefix over all elements in that disjoint set, and let the caller cull out the refs they didn't want.
Computing the longest prefix means that in most cases, we won't match too many things the caller would like to ignore.
The longest common prefixes of the above are:
{'refs/heads/a/*', 'refs/heads/a/b/c'} -> refs/heads/a/*
{'refs/tags/v1.0.0'} -> refs/tags/v1.0.0
We instead invoke:
for_each_ref_in("refs/heads/a
Which provides us with the refs we were looking for with a minimal amount of extra cruft, but never a duplicate of the ref we asked for.
Implemented here is an algorithm which accomplishes the above, which
works as follows:
Lexicographically sort the given list of patterns.
Initialize 'prefix' to the empty string, where our goal is to
build each element in the above set of longest common prefixes.
Consider each pattern in the given set, and emit 'prefix' if it
reaches the end of a pattern, or touches a wildcard character. The
end of a string is treated as if it precedes a wildcard. (Note that
there is some room for future work to detect that, e.g., 'a?b' and
'abc' are disjoint).
Otherwise, recurse on step (3)
with the slice of the list
corresponding to our current prefix (i.e., the subset of patterns
that have our prefix as a literal string prefix.)
This algorithm is 'O(kn + n log(n))
', where 'k
' is max(len(pattern))
for
each pattern in the list, and 'n
' is len(patterns)
.
By discovering this set of interesting patterns, we reduce the runtime
of multi-pattern 'git for-each-ref
' (and other ref traversals) from
O(N)
to O(n log(N))
, where 'N
' is the total number of packed references.
Running 'git for-each-ref refs/tags/a refs/tags/b' on a repository with
10,000,000 refs in 'refs/tags/huge-N', my best-of-five times drop from:
real 0m5.805s
user 0m5.188s
sys 0m0.468s
to:
real 0m0.001s
user 0m0.000s
sys 0m0.000s
On linux.git
, the times to dig out two of the latest -rc
tags drops from
0.002s to 0.001s, so the change on repositories with fewer tags is much
less noticeable.
"
git branch
"和其他 "
for-each-ref
" 变体接受多个
--sort=<key>
选项,按优先级递增排序,但在处理 "
--ignore-case
" 和参考名称的决定性因素时出现了一些故障,在 Git 2.27(2020年第二季度)中已得到修复。
查看
提交 7c5045f,
提交 76f9e56(2020年5月3日)由
Jeff King (peff
)。
(由Junio C Hamano -- gitster
--在提交6de1630中合并,2020年5月8日)
ref-filter
: apply --ignore-case
to all sorting keys
Signed-off-by: Jeff King
All of the ref-filter
users (for-each-ref
, branch
, and tag
) take an --ignore-case
option which makes filtering and sorting case-insensitive.
However, this option was applied only to the first element of the ref_sorting
list.
So:
git for-each-ref --ignore-case --sort=refname
would do what you expect, but:
git for-each-ref --ignore-case --sort=refname --sort=taggername
would sort the primary key (taggername) case-insensitively, but sort the refname case-sensitively. We have two options here:
teach callers to set ignore_case on the whole list
replace the ref_sorting list with a struct that contains both the list of sorting keys, as well as options that apply to all keys
I went with the first one here, as it gives more flexibility if we later want to let the users set the flag per-key (presumably through some special syntax when defining the key; for now it's all or nothing through --ignore-case
).
The new test covers this by sorting on both tagger and subject case-insensitively, which should compare "a
" and "A
" identically, but still sort them before "b
" and "B
".
We'll break ties by sorting on the refname to give ourselves a stable output (this is actually supposed to be done automatically, but there's another bug which will be fixed in the next commit).
git remote --verbose show origin | grep "tracked"
- jub0bsAbc
和abc
,它们是不同的分支,而Windows(和一些MacOS)文件系统通常是不区分大小写的,所以Abc
和abc
是同一个分支 。这肯定会导致您看到的问题。解决方法是确保没有人在服务器上创建仅在大小写方面有所不同的两个不同的分支。 - torek:)
- jub0bsgit remote
中,我得到了minorRelease/Something
。 - ShlomiTC