Git fetch a branch once with a normal name, and once with capital letter
@torek
is right that it's caused by the difference of Linux
and Windows
. Linux
is case-sensitive, while Windows
is not. You can use ls-remote
to show the branches in the server.
git ls-remote --heads origin
And I think in your case, the output should include the two branches with only the case of S
different.
ref/heads/minorRelease/Something
ref/heads/minorRelease/something
You can delete the remote branch if you find one of them is actually duplicated. And then do fetch
again. It should be fine now.
git push origin :minorRelease/Something
git fetch
Note: with Git 2.12 (Q1 2017) this will become easier to spot, as you can list branch with a case insensitive option.
See commit 3bb16a8 (04 Dec 2016) by Nguyễn Thái Ngọc Duy (pclouds
).
(Merged by Junio C Hamano -- gitster
-- in commit 73e494f, 19 Dec 2016)
tag
,branch
,for-each-ref
: add--ignore-case
for sorting and filtering.
This options makes sorting ignore case, which is great when you have branches namedbug-12-do-something
,Bug-12-do-some-more
andBUG-12-do-what
and want to group them together.
Sorting externally may not be an option because we lose coloring and column layout from git-branch and git-tag.The same could be said for filtering, but it's probably less important because you can always go with the ugly pattern
[bB][uU][gG]-*
if you're desperate.You can't have case-sensitive filtering and case-insensitive sorting (or the other way around) with this though. For
branch
andtag
, that should be no problem.for-each-ref
, as a plumbing, might want finer control.
But we can always add--{filter,sort}-ignore-case
when there is a need for it.
git branch --ignore-case --list
Note: The "--ignore-case
" option of "git for-each-ref
" (and its friends)
did not work correctly, which has been fixed in Git 2.19 (Q3 2018).
See commit 639ab5e (02 Jul 2018) by Aleksandr Makarov (deviance
).
See commit e674eb2, commit ee0f3e2 (02 Jul 2018) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
-- in commit 4301330, 24 Jul 2018)
ref-filter
: avoid backend filtering with--ignore-case
When
for-each-ref
is used with--ignore-case
, we expectmatch_name_as_path()
to do a case-insensitive match.
But there's an extra layer of filtering that happens before we even get there. Since commit cfe004a (ref-filter
: limit traversal to prefix, 2017-05-22, Git v2.14.0), we feed the prefix to the ref backend so that it can optimize the ref iteration.There's no mechanism for us to tell the backend we're matching case-insensitively. Nor is there likely to be one anytime soon, since the packed backend relies on binary-searching the sorted list of refs.
Let's just punt on this case. The extra filtering is an optimization that we simply can't do. We'll still give the correct answer via the filtering inmatch_name_as_path(
).
Note that, with Git 2.23 (Q3 2019), "git for-each-ref
" with multiple patterns have been optimized.
See commit b31e268 (26 Jun 2019) by Taylor Blau (ttaylorr
).
(Merged by Junio C Hamano -- gitster
-- in commit b4b8c35, 19 Jul 2019)
ref-filter.c
: find disjoint pattern prefixesSince cfe004a (
ref-filter
: limit traversal to prefix, 2017-05-22, Git v2.14.0-rc0), theref-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/*", ...); for_each_ref_in("refs/heads/a/b/c", ...); for_each_ref_in("refs/tags/v1.0.0", ...);
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/*", ...); for_each_ref_in("refs/tags/v1.0.0", ...);
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
' ismax(len(pattern))
for each pattern in the list, and 'n
' islen(patterns)
.By discovering this set of interesting patterns, we reduce the runtime of multi-pattern '
git for-each-ref
' (and other ref traversals) fromO(N)
toO(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
" and other "for-each-ref
" variants accepted multiple --sort=<key>
options in the increasing order of precedence, but it had a few breakages around "--ignore-case
" handling, and tie-breaking with the refname, which have been fixed with Git 2.27 (Q2 2020).
See commit 7c5045f, commit 76f9e56 (03 May 2020) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
-- in commit 6de1630, 08 May 2020)
ref-filter
: apply--ignore-case
to all sorting keysSigned-off-by: Jeff King
All of the
ref-filter
users (for-each-ref
,branch
, andtag
) 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).