Repository navigation
gh search code --web returns zero matches and error #11029
Description
Activity
- addedgh-searchrelating to the gh search commandrelating to the gh search command
on Jun 18, 2025 Thank you for taking the time to raise this problem, @onnimonni! 🙇 Totally makes sense.
Digging into the underlying code, I see the following comment that was added in #6945 as part of #7376 when
gh search codewas added:cli/pkg/cmd/search/code/code.go
Lines 104 to 114 in d9d0e14
func codeRun(opts *CodeOptions) error { io := opts.IO if opts.WebMode { // FIXME: convert legacy `filename` and `extension` ES qualifiers to Blackbird's `path` qualifier // when opening web search, otherwise the Blackbird search UI will complain. url := opts.Searcher.URL(opts.Query) if io.IsStdoutTTY() { fmt.Fprintf(io.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(url)) } return opts.Browser.Browse(url) } Technical details
The
Querytype is used for searching via the API as formatting the web search URLs, however 1) it does not have thepathqualifier and 2) it doesn't have a mechanism for translating certain qualifiers:Lines 28 to 93 in d9d0e14
type Qualifiers struct { Archived *bool Assignee string Author string AuthorDate string AuthorEmail string AuthorName string Base string Closed string Commenter string Comments string Committer string CommitterDate string CommitterEmail string CommitterName string Created string Draft *bool Extension string Filename string Followers string Fork string Forks string GoodFirstIssues string Hash string Head string HelpWantedIssues string In []string Interactions string Involves string Is []string Label []string Language string License []string Mentions string Merge *bool Merged string Milestone string No []string Parent string Project string Pushed string Reactions string Repo []string Review string ReviewRequested string ReviewedBy string Size string Stars string State string Status string Team string TeamReviewRequested string Topic []string Topics string Tree string Type string Updated string User []string } func (q Query) String() string { qualifiers := formatQualifiers(q.Qualifiers) keywords := formatKeywords(q.Keywords) all := append(keywords, qualifiers...) return strings.TrimSpace(strings.Join(all, " ")) } Lines 140 to 149 in d9d0e14
func formatQualifiers(qs Qualifiers) []string { var all []string for k, vs := range qs.Map() { for _, v := range vs { all = append(all, fmt.Sprintf("%s:%s", k, quote(v))) } } sort.Strings(all) return all } I would prefer avoiding a
gh search codespecific workaround as it would be brittle and there might be similar situations with other searches and qualifiers.My initial thought might be to enhance the
URLmethod used to transform certain qualifiers before they are formatted:Lines 243 to 256 in d9d0e14
func (s searcher) URL(query Query) string { path := fmt.Sprintf("https://%s/search", s.host) qs := url.Values{} qs.Set("type", query.Kind) qs.Set("q", query.String()) if query.Order != "" { qs.Set(orderKey, query.Order) } if query.Sort != "" { qs.Set(sortKey, query.Sort) } url := fmt.Sprintf("%s?%s", path, qs.Encode()) return url } It appears the
URLmethod is used exclusively for web search URLs, so the function documentation should be updated to reflect its exclusive use and that certain qualifiers are translated:https://github.com/search?q=repo%3Acli%2Fcli+%22Searcher.URL%28%22&type=code
- addedpriority-2Affects more than a few users but doesn't prevent core functionsAffects more than a few users but doesn't prevent core functionsand removedneeds-triageneeds to be reviewedneeds to be reviewed
on Jun 18, 2025 Acceptance Criteria
-
When user runs
gh search code --extension <EXT>such asgh search code --extension nix karabiner-elements
Then the GitHub API returns results that match files with that extension such as:Showing 30 of 828 results nix-darwin/nix-darwin modules/services/karabiner-elements/default.nix cfg = config.services.karabiner-elements; options.services.karabiner-elements = { enable = mkEnableOption "Karabiner-Elements"; Enzime/dotfiles-nix overlays/karabiner-elements.nix karabiner-elements = super.karabiner-elements.overrideAttrs (old: { rgomezcasas/dotfiles nix/_homebrew.nix "karabiner-elements" ahmedelgabri/dotfiles nix/modules/shared/karabiner.nix "karabiner-elements" eikster-dk/nixcfg modules/hosts/karabiner-elements/darwin.nix "karabiner-elements"
-
When user runs
gh search code --web --extension <EXT>such asgh search code --web --extension nix karabiner-elements
Then web browser is opened to GitHub global search withpath:*.nixsearch qualifier instead ofextension:nix -
When user runs
gh search code --filename <FILENAME>such asgh search code --filename default.nix karabiner-elements
Then the GitHub API returns results that match files with that filename such as:Showing 30 of 169 results nix-darwin/nix-darwin modules/services/karabiner-elements/default.nix cfg = config.services.karabiner-elements; options.services.karabiner-elements = { enable = mkEnableOption "Karabiner-Elements"; tiiuae/nixpkgs-spectrum pkgs/os-specific/darwin/karabiner-elements/default.nix pname = "karabiner-elements"; url = "https://github.com/pqrs-org/Karabiner-Elements/releases/download/v${version}/Karabiner-Elements-${version}.dmg"; abayomi185/nix-dotfiles modules/darwin/apps/karabiner-elements/default.nix services.karabiner-elements = {
-
When user runs
gh search code --web --filename <FILENAME>such asgh search code --filename default.nix karabiner-elements --web
Then web browser is opened to GitHub gloabl search withpath:**/default.nixsearch qualifier instead offilename:default.nix
Reacted by @YoungTae-
@andyfeller Hi 👋 I was checking out the amazing progress on
ghand thought I would contribute!I was taking a look at this issue and had a couple questions for you.
-
Do we need to worry about any GHES versions that do not support the
pathqualifier? From the docs I was unable to figure out what web search each GHES version was using. -
As far as implementation, what are your thoughts around introducing a
--pathflag instead of trying to convert the--filenameand--extensionflag values into a validpathqualifier string? I am envisioning that the--pathflag would only be compatible with the--webflag and result in an error if not accompanied by it. If the--filenameor--extensionflags were used with the--webflag it would output an error saying to use the--pathflag instead. The thought process here is that this new--pathflag would be more powerful and reflect the web search better than any sort of conversion we can do using the--filenameand--extensionflag values. Additionally, it sets up nicely to deprecate the--filenameand--extensionflags in the future if the search API does eventually get around to matching the web search. Perhaps this would constitute a breaking change but it would only impact use cases where the--webflag is being used so maybe that is a bit of a gray area.
Looking forward to your thoughts. I am happy to implement whichever direction you feel is best.
Reacted by Andy Feller, Kynan Ware, Melissa Xie, Onni Hakala and Babak K. ShandizReacted by William Martin, Onni Hakala and Babak K. Shandiz-
Thank you so much, @samcoe, as I'd love a chance to work with you again! ❤
Do we need to worry about any GHES versions that do not support the path qualifier? From the docs I was unable to figure out what web search each GHES version was using.
Very insightful question!
GHES code search appears to be the same as GitHub.com legacy code search. This means that
path:is available but it is only a directory path within the repo without support for wildcards or other pattern matching.Whereas GitHub.com has Blackbird, too. This allows more complex
pathsearches that use regex to match files or directories. For example,repo:cli/cli path:**/*_test.go "fmt.Fprintf"finds all Go tests incli/clithat print to files.So,
path:is technically available everywhere; its just a question of what you can do based on whether the host is GHES or GitHub.com and whether you're using it for API or web searches.What are your thoughts around introducing a
--pathflag instead of trying to convert the--filenameand--extensionflag values into a validpathqualifier string?I am envisioning that the --path flag would only be compatible with the --web flag and result in an error if not accompanied by it. If the --filename or --extension flags were used with the --web flag it would output an error saying to use the --path flag instead.
The thought process here is that this new --path flag would be more powerful and reflect the web search better than any sort of conversion we can do using the --filename and --extension flag values. Additionally, it sets up nicely to deprecate the --filename and --extension flags in the future if the search API does eventually get around to matching the web search. Perhaps this would constitute a breaking change but it would only impact use cases where the --web flag is being used so maybe that is a bit of a gray area.
🤔 Let me see if I understand how this proposal would affect users' experience.
Scenario 1
-
User wants to find repositories with
go.modfiles usinggithub.com/cli/go-gh/v2module -
They would retrieve this via the REST Search code endpoint or GraphQL search query would look like:
filename:go.mod "github.com/cli/go-gh/v2"gh search code --filename go.mod "github.com/cli/go-gh/v2" -
If they want to view it on the web and re-run it using
--web, they would receive an error stating--filenamecan't be used with--weband to use--pathinstead -
The user doesn't understand why this error happened and looks at the command's help docs and is directed to the legacy code search documentation:
›$ gh search code --help Search within code in GitHub repositories. The search syntax is documented at: <https://docs.github.com/search-github/searching-on-github/searching-code>
Maybe we have a special note in the docs that say, "If you're using --web on github.com or ghe.com, then use --path flag with this other search documentation syntax"
-
The legacy code search documentation talks about
path:search qualifier and how it is only a static directory path
In this scenario, I fear the user is confused having to navigate between API and web search documentation to come up with 2 different incantations of
gh search codeto get what they ultimately want.Scenario 2
-
Let's see which
clirepositories have our standardlint.ymlworkflow setup$ gh search code org:cli path:.github/workflows filename:lint.yml Working... Showing 3 of 3 results cli/cli .github/workflows/lint.yml cli/go-gh .github/workflows/lint.yml cli/oauth .github/workflows/lint.yml
-
I want to view it on the web, so re-run it with
--webwhich results in a error and suggestion to use--path -
Viewing this on the web would require the following query:
org:cli path:.github/workflows/lint.yml
-
So, path: is technically available everywhere; its just a question of what you can do based on whether the host is GHES or GitHub.com and whether you're using it for API or web searches.
Ok I got it I think. I will limit the implementation to just
github.comand not modify any invocations targeting GHES for now.Scenario 1
In this scenario, I fear the user is confused having to navigate between API and web search documentation to come up with 2 different incantations of gh search code to get what they ultimately want.I agree it is not ideal and a bit confusing for sure if the user is not aware of the correct
pathqualifier syntax to use. As you suggested we could mitigate it by linking to the correct search documentation syntax in the error message but the user would still need to figure out the correct syntax again.Scenario 2
gh search code org:cli path:.github/workflows filename:lint.ymlThis scenario is not exactly correct based on my proposal. I am envisioning that in this scenario
ghwould error out saying that the--pathflag is only available when using the--webflag. As you said, there is apathqualifier in the API but it has different functionality than the web search so my thought was that it would be confusing to have a flag that works differently based on targeting the API or web and that an error might be a nicer user experience.Having thought through this a bit more and running through your scenarios it is pretty clear that because we are trying to target two different search implementations with different features,
ghwill likely need to do some conversion/magic behind the scenes to hide this fact from the user and reduce confusion. I think your original acceptance criteria is looking like the simplest and best option. If you are comfortable with going that route, let me know and I will begin implementing.@andyfeller In your acceptance criteria:
When user runs gh search code --web --filename ...
Then web browser is opened ... with path:**/default.nix search qualifier instead of filename:default.nixThis is not quite the actual behaviour at present: the web browser is opened with
path:default.nixrather thanpath:**/default.nix. A subtle, but important difference if the file is in a subdirectory.I think the latter (i.e. your acceptance criteria) would be correct behaviour. But there may be nuance that I am missing here. What do you and @samcoe think?
Describe the bug
Same query for
gh search codeshould probably work both in terminal and web?This works and returns examples:
But when adding
--webit doesn't show any results becauseextensiondoesn't work in web:Affected version
Steps to reproduce the behavior
Expected vs actual behavior
If the web search query would not use
extension:nixbutpath:*.nixit would work correctly.