jacquerie: IMO this is ready for review! Perhaps @omgjlk would like to take a look, given https://github.com/sigmavirus24/github3.py/issues/748#issuecomment-352588562 ?
diff --git a/src/github3/github.py b/src/github3/github.py
index ce22a5fb..3cb9f75c 100644
--- a/src/github3/github.py
+++ b/src/github3/github.py
@@ -1669,6 +1669,87 @@ class GitHub(models.GitHubCore):
             number, url, search.CodeSearchResult, self, params, etag, headers
         )
 
+    def search_commits(self, query, sort=None, order=None, per_page=None,
+                       text_match=False, number=-1, etag=None):
+        """Find commits via the commits search API.
+
+        The query can contain any combination of the following supported
+        qualifiers:
+
+        - ``author`` Matches commits authored by the given username.
+          Example: ``author:defunkt``.
+        - ``committer`` Matches commits committed by the given username.
+          Example: ``committer:defunkt``.
+        - ``author-name`` Matches commits authored by a user with the given
+          name. Example: ``author-name:wanstrath``.
+        - ``committer-name`` Matches commits committed by a user with the given
+          name. Example: ``committer-name:wanstrath``.
+        - ``author-email`` Matches commits authored by a user with the given
+          email. Example: ``author-email:chris@github.com``.
+        - ``committer-email`` Matches commits committed by a user with the
+          given email. Example: ``committer-email:chris@github.com``.
+        - ``author-date`` Matches commits authored within the specified date
+          range. Example: ``author-date:<2016-01-01``.
+        - ``committer-date`` Matches commits committed within the specified
+          date range. Example: ``committer-date:>2016-01-01``.
+        - ``merge`` Matches merge commits when set to to ``true``, excludes
+          them when set to ``false``.
+        - ``hash`` Matches commits with the specified hash. Example:
+          ``hash:124a9a0ee1d8f1e15e833aff432fbb3b02632105``.
+        - ``parent`` Matches commits whose parent has the specified hash.
+          Example: ``parent:124a9a0ee1d8f1e15e833aff432fbb3b02632105``.
+        - ``tree`` Matches commits with the specified tree hash. Example:
+          ``tree:99ca967``.
+        - ``is`` Matches public repositories when set to ``public``, private
+          repositories when set to ``private``.
+        - ``user`` or ``org`` or ``repo`` Limits the search to a specific user,
+          organization, or repository.
+
+        For more information about these qualifiers, see: https://git.io/vb7XQ
+
+        :param str query:
+            (required), a valid query as described above, e.g.,
+            ``css repo:octocat/Spoon-Knife``
+        :param str sort:
+            (optional), how the results should be sorted;
+            options: ``author-date``, ``committer-date``;
+            default: best match
+        :param str order:
+            (optional), the direction of the sorted results,
+            options: ``asc``, ``desc``; default: ``desc``
+        :param int per_page:
+            (optional)
+        :param int number:
+            (optional), number of commits to return.
+            Default: -1, returns all available commits
+        :param str etag:
+            (optional), previous ETag header value
+        :return:
+            generator of commit search results
+        :rtype:
+            :class:`~github3.search.commits.CommitSearchResult`
+        """
+        params = {'q': query}
+        headers = {'Accept': 'application/vnd.github.cloak-preview'}
+
+        if sort in ('author-date', 'committer-date'):
+            params['sort'] = sort
+
+        if sort and order in ('asc', 'desc'):
+            params['order'] = order
+
+        if text_match:
+            headers['Accept'] = ', '.join([
+                headers['Accept'],
+                'application/vnd.github.v3.full.text-match+json'
+            ])
+
+        url = self._build_url('search', 'commits')
+        return structs.SearchIterator(
+            number, url, search.CommitSearchResult,
+            self, params, etag, headers
+        )
+
     def search_issues(self, query, sort=None, order=None, per_page=None,
                       text_match=False, number=-1, etag=None):
         """Find issues by state and keyword.
diff --git a/src/github3/search/__init__.py b/src/github3/search/__init__.py
index 97f776b8..37ea15fa 100644
--- a/src/github3/search/__init__.py
+++ b/src/github3/search/__init__.py
@@ -1,8 +1,14 @@
 from .code import CodeSearchResult
+from .commit import CommitSearchResult
 from .issue import IssueSearchResult
 from .repository import RepositorySearchResult
 from .user import UserSearchResult
 
 
-__all__ = [CodeSearchResult, IssueSearchResult, RepositorySearchResult,
-           UserSearchResult]
+__all__ = (
+    'CodeSearchResult',
+    'CommitSearchResult',
+    'IssueSearchResult',
+    'RepositorySearchResult',
+    'UserSearchResult',
+)
diff --git a/src/github3/search/commit.py b/src/github3/search/commit.py
new file mode 100644
index 00000000..7f694146
--- /dev/null
+++ b/src/github3/search/commit.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+"""Commit search results implementation."""
+from __future__ import unicode_literals
+
+from .. import git
+from .. import models
+from .. import repos
+from .. import users
+
+
+class CommitSearchResult(models.GitHubCore):
+    """A representation of a commit search result from the API.
+
+    This object has the following attributes:
+
+    .. attribute:: author
+
+        A :class:`~github3.users.ShortUser` representing the user who
+        authored the found commit.
+
+    .. attribute:: comments_url
+
+        The URL to retrieve the comments on the found commit from the API.
+
+    .. attribute:: commit
+
+        A :class:`~github3.git.ShortCommit` representing the found commit.
+
+    .. attribute:: committer
+
+        A :class:`~github3.users.ShortUser` representing the user who
+        committed the found commit.
+
+    .. attribute:: html_url
+
+        The URL to view the found commit in a browser.
+
+    .. attribute:: repository
+
+        A :class:`~github3.repos.repo.ShortRepository` representing the
+        repository in which the commit was found.
+
+    .. attribute:: score
+
+        The confidence score assigned to the result.
+
+    .. attribute:: sha
+
+        The SHA1 of the found commit.
+
+    .. attribute:: text_matches
+
+        A list of the text matches in the commit that generated this result.
+
+        .. note::
+
+            To receive these, you must pass ``text_match=True`` to
+            :meth:`~github3.github.GitHub.search_commit`.
+    """
+
+    def _update_attributes(self, data):
+        self._api = data['url']
+        self.author = users.ShortUser(data['author'], self)
+        self.comments_url = data['comments_url']
+        self.commit = git.ShortCommit(data['commit'], self)
+        self.committer = users.ShortUser(data['committer'], self)
+        self.html_url = data['html_url']
+        self.repository = repos.ShortRepository(data['repository'], self)
+        self.score = data['score']
+        self.sha = data['sha']
+        self.text_matches = data.get('text_matches', [])
+
+    def _repr(self):
+        return '<CommitSearchResult [{0}]>'.format(self.sha[:7])

Support for searching commits
Any plans to add support for searching commits?

```
https://developer.github.com/v3/search/#search-commits
```
diff --git a/tests/cassettes/GitHub_search_commits.json b/tests/cassettes/GitHub_search_commits.json
new file mode 100644
index 00000000..39082376
--- /dev/null
+++ b/tests/cassettes/GitHub_search_commits.json
@@ -0,0 +1,1 @@
+{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": ["gzip, deflate"], "Accept": ["application/vnd.github.cloak-preview"], "User-Agent": ["github3.py/1.1.0"], "Accept-Charset": ["utf-8"], "Connection": ["keep-alive"], "Content-Type": ["application/json"]}, "method": "GET", "uri": "https://api.github.com/search/commits?q=css+repo%3Aoctocat%2FSpoon-Knife&per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1ZXW/iRhT9K4jXJtjGhthI0XbVpKttRaKk7HaTaoXG4zEesD3WzDgUrPz33hkbA1EIYLbtS15CMD5n7sfM9bnXRVsyieIxZnkq2wPrrE1TzJIsJpKMORF5LEV7EKJYEPhJkgS+/VW0cx63B+1IykwMDANltDOhMsr9DmANTjImDIYlw0gaf2SMpee/pzQkBvyaUCkM33cwdgPb7xLL8W0U9oKw73nuRT8InDC0EQ5M078I22dtESFY6QhAygIypgGAhlcP/buuJ/0/Y3M4Gs6HV9e94TSjD9P76cMymg27nxePo2vzYXoTPU6/zh6nD73b0cS+Se5nN58ek2H31+nj1cf5wzRIwJJIJvF42/ENp3e7e4y3KkAkleLFOv9agHVG1ILgX5mc9qBxdiEaTTKMchkxrtYNkCSQt65pOedm99x0RpYzsN2B3T833YFpgpEpStQto4i0bssNBhdJgqjaj1UOfk7ZPCKcqM3Yfl45Jslra1jdkdUbWO6g1ztpjYQIgSbKtF84ATdaQi5iIjpYiBZKg1aeKeeC1v31x6vhNdgsOYG7T4q1ohAG6tse8fqhZ9ruhXcR+qhPTKfvhZ6DHN/E2Ol5Ieq79Vk6GFCFDrZHXR4suLbOV8wmNF3HHVZQ567n2l0bCsnmQbzrf/12E+PpF2e4/Lwc3l1ews3oCUnEX251fVHYVUHJBeGYpRKM0LUlN0r6D0+XDlBMeEWiDzxceLMwKbK6MMHNB51ouC9kcczmgH1p63bd26I3alBNQNPJ8QQAKgwmYT+PFf+zcpqKfRVi2xQNKAz1AZVRUQiIMSfBMeZUEDBmnoIdhS7zmiv3BeY0k5SlR0VoCwhEjE9QSpfoaCIAqgKmnzvHuKQBACRP+2vudkRLRGFknD4hvFBh4AQT+gQxPZ7tBRTI5CJTteQLZFxFGB68YxQk6rDpR/HLovZ+ELcEyPtBfD+I/9lBzBDXAuoHyGJkm9jyiB1a9kW/h2zfcd2ud+G6Praw7/oO8XqYEPXgO+jR9Yr2No5Yo5TeBwOev1clmErGF0rbqIeyZZum5XW35cD1/Db+LcafvCX6dv+E09nfw+XH+XA0W4BrlcTb6BvgYpjH8bj65RWpDXfox5Ja9b0YvhfDd1Xy/6gSrYdUE1dNDI4uU3CQA1LLSd3pUdFSQq0FnyHjrYAkoDMl1zKxleUcNBwRLZbGi44qFIzP6uXf7AZ2jikqlj1ScicclD+fKVk5I4vGHApbGPC3EuwYWhDkM/Ca7WtDdhu2RVJAr77mVApWEpQ0NliDgSRibNaYRIOBhAqRk4OE9G5nNYcwVko9zRO/bJ8O0ee7aUs02IiEoJMUOvC3O47dTDVBYaw6O5+jFEfNKVf4wij/01lFk8YmKixQ+DHzG3OoqZAmKAwQFGX/KsenWKUYFX6LkJPwJBMVvibUk5WmedXmKYKaDlpnCSluzLjCG0UVwRilkxzGTY0ZawLIrmrsJ2i5d7yxeyevGYBOTWs49fPTCtWaQ1lYThjg/DZ2eINiTahHFk3TvDm90G7r0XZTtgq+taVPpNwYx9a0P2K+rLqdwljX07JYV8xN/a+q9cq+Tf5q/HdCaPX4UBjFTxmSkapAsIxq25oaW8GNwkcwi+l0OkVEkJ6rJYSfcCpLNNAgjiOYJTW1r1jhQYkkSOpZXajMC6BJihkKGseyJgCyMmVNbSzRm3nOoMVrbJgGb7IlFMbvkqXNa+SaYZM3ZZKGFF5s7Z927i6YWyTFBwHv3MgZiuMz2JWSYgr7FOa+KmMg+kjzqJRoMB/empQzypjAlm0cZU5KfGGUY+SAZDFbnPTGaoNCvasRmHFoH+yO0+1Z8B7h+fvzP+6CgBWjHAAA", "encoding": "utf-8"}, "headers": {"Status": ["200 OK"], "X-RateLimit-Remaining": ["9"], "X-GitHub-Media-Type": ["github.cloak-preview"], "X-Runtime-rack": ["0.066329"], "Content-Security-Policy": ["default-src 'none'"], "X-Content-Type-Options": ["nosniff"], "Access-Control-Expose-Headers": ["ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval"], "Transfer-Encoding": ["chunked"], "X-GitHub-Request-Id": ["BFE0:5172:2C4F2:5A0E2:5B64C901"], "Strict-Transport-Security": ["max-age=31536000; includeSubdomains; preload"], "X-XSS-Protection": ["1; mode=block"], "Server": ["GitHub.com"], "X-RateLimit-Limit": ["10"], "Cache-Control": ["no-cache"], "Date": ["Fri, 03 Aug 2018 21:28:33 GMT"], "Access-Control-Allow-Origin": ["*"], "Referrer-Policy": ["origin-when-cross-origin, strict-origin-when-cross-origin"], "Content-Type": ["application/json; charset=utf-8"], "X-Frame-Options": ["deny"], "Content-Encoding": ["gzip"], "X-RateLimit-Reset": ["1533331773"]}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/search/commits?q=css+repo%3Aoctocat%2FSpoon-Knife&per_page=100"}, "recorded_at": "2018-08-03T21:28:33"}], "recorded_with": "betamax/0.8.1"}
\ No newline at end of file
diff --git a/tests/cassettes/GitHub_search_commits_with_text_match.json b/tests/cassettes/GitHub_search_commits_with_text_match.json
new file mode 100644
index 00000000..1ec94cb5
--- /dev/null
+++ b/tests/cassettes/GitHub_search_commits_with_text_match.json
@@ -0,0 +1,1 @@
+{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": ["gzip, deflate"], "Accept": ["application/vnd.github.cloak-preview, application/vnd.github.v3.full.text-match+json"], "User-Agent": ["github3.py/1.1.0"], "Accept-Charset": ["utf-8"], "Connection": ["keep-alive"], "Content-Type": ["application/json"]}, "method": "GET", "uri": "https://api.github.com/search/commits?q=css+repo%3Aoctocat%2FSpoon-Knife&per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1ZbW/bNhD+K4a/LrEkS7YlA0VXNFnRDUrRzO2aDIVBUZRFWxIFkoprC/nvO1KybAd1Y8vd9iUIECeynof3wjveHcuuZBIlU8yKTHbH1kWXZpileUIkmXIiikSK7jhCiSDwlSQp/Pd32S140h13YylzMTYMlNPejMq4CHqANTjJmTAYlgwjafyZM5Zd/pHRiBjwbUqlMILAwdgN7aBPLCewUTQIo6HnuaNhGDpRZCMcmmYwiroXXREjWOkEQMZCMqUhgPyru+HHvieDvxLTn/hL/+p64M9zeje/nd+t44Xff7+6n1ybd/Ob+H7+eXE/vxt8mMzsm/R2cfPuPvX7v83vr94s7+ZhCpLEMk2m+4rvKH1Y3VO0VQYimRRP1vnXDKw9ohYE/SrndMetvQvWaONhVMiYcbVuiCQBv/VNy7k0+5emM7Gcse2O7eGl6Y5NE4TMUKpemcSk86HaYPCQpIiq/Vj74NeMLWPCidqM3ceNYpJ8bw2rP7EGY8sdDwZnrZESIdBMifaWE1CjI+QqIaKHheigLOwUuVIu7Nxev7nyr0FmyQm8fZatFYUw0ND2iDeMPNN2R94oCtCQmM7QizwHOYGJsTPwIjR0m1g6GlCbDrZHkx4seLb1V8JmNNvaHVZQcTdw7b4NiWQ3ED8OP3+5SfD8k+Ov36/9j69ewcvoAUnEn251/VDYdUIpBOGYZRKE0LmlMCr61w+vHKCY8ZpEBzw8+GFiUmRNYoKXj4poeC9iScKWgH0q637e26M3GlBDQLPZ6QQAKg0mYT9PFf+jUpqK5zLEvigaUBrqAzKjohBgY07CU8SpISDMMgM5Sp3mNVcRCMxpLinLTrLQHhCIGJ+hjK7RyUQAVAlMnzunqKQBACQPz+fcfYtWiNLIOX1AeKXMwAkm9AFsejrbEyiQyVWucskn8LiyMBy8UxSmKtj0Ufw0qb0E4l4B8hKIL4H4nwVijrguoH5CWYxsE1sesSPLHg0HyA4c1+17I9cNsIUDN3CIN8CEqIPvqKPrO7W3ccIaVel9NODxa52CqWR8pWobdShbtmlaXn+/HLhefkh+T/A7b42+3D7gbPHNX79Z+pPFClSrS7ydvgEeRkWSTOtvvlNqwxv6WFKrviTDl2T4UpX8P1WJrodUE1dPDE5OUxDIIWnKSd3pUdFRhVoHPiPGOyFJoc6UXJeJnbzgUMMR0WFZsuqpRMH4oln+h93AwTFFzfJMKXkQDpU/X6iyckFWrTkUtjTgd12wY2hBUMBAa/ZcG3JYsD2SEnr1LaeqYCVBaWuBNRhIYsYWrUk0GEioEAU5qpA+rKzmEMamUs+KNKjap2Pq88O0FRpkRELQWQYd+I87jsNMDUFpbDq7gKMMx+0pN/jSqP7SXkWz1iIqLFAECQtac6ipkCYoDSgoqv5VTs+RSjEq/B4hJ9FZIip8Q6gnK239qsVTBA0dtM4SXNyacYM3ytqCCcpmBYybWjM2BOBd1djP0PrZ8cbhnbxlADo1reE0KM5LVFsOJWE1YYD4ba3wDsWWUI8s2rp5d3qh1daj7bZsNXxvS59JuTOObWh/xnxZdTulsc2nVbKumdvqX2frjXy7/PX47wzT6vGhMMpfciRjlYFgGdW2tRW2hhtlgGAW0+v1ypggPVdLCT8jKis00CCOY5gltZWv3OChEkmR1LO6SIkXQpOUMBS2tmVDAGSVy9rKWKF3/ZxDi9daMA3eZUspjN8ly9rnyC3DLm/GJI0oXGw9P+08nDD3SMrXAu7cyAVKkgvYlZJiCvsU5r7KY1D0kfZWqdAgPtyaVDPKhMCWbW1lTip8aVRj5JDkCVuddWO1Q6HuagRmHNoHu+f0hwO3b6uq9Jucwi5WdZEesrBgTrBsu+/qpHrKpVy9YD2TfasTvV/f91x0c85ywiUMPCD6q0sg6EI4mimzHH8ftKuhUhmQcHekwiwLKdaqW86FNfr6WP38AyuRIHW5HQAA", "encoding": "utf-8"}, "headers": {"Status": ["200 OK"], "X-RateLimit-Remaining": ["8"], "X-GitHub-Media-Type": ["github.cloak-preview; param=full.text-match"], "X-Runtime-rack": ["0.043624"], "Content-Security-Policy": ["default-src 'none'"], "X-Content-Type-Options": ["nosniff"], "Access-Control-Expose-Headers": ["ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval"], "Transfer-Encoding": ["chunked"], "X-GitHub-Request-Id": ["B258:516C:12CE5:2A7F2:5B64C902"], "Strict-Transport-Security": ["max-age=31536000; includeSubdomains; preload"], "X-XSS-Protection": ["1; mode=block"], "Server": ["GitHub.com"], "X-RateLimit-Limit": ["10"], "Cache-Control": ["no-cache"], "Date": ["Fri, 03 Aug 2018 21:28:34 GMT"], "Access-Control-Allow-Origin": ["*"], "Referrer-Policy": ["origin-when-cross-origin, strict-origin-when-cross-origin"], "Content-Type": ["application/json; charset=utf-8"], "X-Frame-Options": ["deny"], "Content-Encoding": ["gzip"], "X-RateLimit-Reset": ["1533331773"]}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/search/commits?q=css+repo%3Aoctocat%2FSpoon-Knife&per_page=100"}, "recorded_at": "2018-08-03T21:28:34"}], "recorded_with": "betamax/0.8.1"}
\ No newline at end of file
diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py
index b88c275f..b827194b 100644
--- a/tests/integration/test_github.py
+++ b/tests/integration/test_github.py
@@ -523,6 +523,27 @@ class TestGitHub(IntegrationHelper):
         assert isinstance(code_result, github3.search.CodeSearchResult)
         assert len(code_result.text_matches) > 0
 
+    def test_search_commits(self):
+        """Test the ability to search for commits."""
+        cassette_name = self.cassette_name('search_commits')
+        with self.recorder.use_cassette(cassette_name):
+            result_iterator = self.gh.search_commits(
+                'css repo:octocat/Spoon-Knife')
+            commit_result = next(result_iterator)
+
+        assert isinstance(commit_result, github3.search.CommitSearchResult)
+
+    def test_search_commits_with_text_match(self):
+        """Test the ability to search for commits  with text matches."""
+        cassette_name = self.cassette_name('search_commits_with_text_match')
+        with self.recorder.use_cassette(cassette_name):
+            result_iterator = self.gh.search_commits(
+                'css repo:octocat/Spoon-Knife', text_match=True)
+            commit_result = next(result_iterator)
+
+        assert isinstance(commit_result, github3.search.CommitSearchResult)
+        assert len(commit_result.text_matches) > 0
+
     def test_search_users(self):
         """Test the ability to use the user search endpoint."""
         cassette_name = self.cassette_name('search_users')
diff --git a/tests/unit/helper.py b/tests/unit/helper.py
index a38bf53e..9a819e98 100644
--- a/tests/unit/helper.py
+++ b/tests/unit/helper.py
@@ -241,6 +241,24 @@ class UnitIteratorHelper(UnitHelper):
         self.get_json_mock.stop()
 
 
+class UnitSearchIteratorHelper(UnitIteratorHelper):
+
+    """Base class for search iterator based unit tests."""
+
+    def patch_get_json(self):
+        """Patch a SearchIterator's _get_json method."""
+        self.get_json_mock = mock.patch.object(
+            github3.structs.SearchIterator, '_get_json'
+        )
+        self.patched_get_json = self.get_json_mock.start()
+        self.patched_get_json.return_value = []
+
+    def setUp(self):
+        """Use UnitIteratorHelper's setUp and patch _get_json."""
+        super(UnitSearchIteratorHelper, self).setUp()
+        self.patch_get_json()
+
+
 class UnitRequiresAuthenticationHelper(UnitHelper):
 
     """Helper for unit tests that demonstrate authentication is required."""
diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py
index c4af3a6f..44e97243 100644
--- a/tests/unit/test_github.py
+++ b/tests/unit/test_github.py
@@ -1295,6 +1295,85 @@ class TestGitHubIterators(helper.UnitIteratorHelper):
         )
 
 
+class TestGitHubSearchIterators(helper.UnitSearchIteratorHelper):
+
+    """Test GitHub methods that return search iterators."""
+
+    described_class = GitHub
+    example_data = None
+
+    def test_search_code(self):
+        """Verify the request to search for code."""
+        i = self.instance.search_code(
+            'addClass in:file language:js repo:jquery/jquery')
+        self.get_next(i)
+
+        self.session.get.assert_called_once_with(
+            url_for('search/code'),
+            params={'per_page': 100,
+                    'q': 'addClass in:file language:js repo:jquery/jquery'},
+            headers={}
+        )
+
+    def test_search_commits(self):
+        """Verify the request to search for commits."""
+        i = self.instance.search_commits(
+            'css repo:octocat/Spoon-Knife')
+        self.get_next(i)
+
+        self.session.get.assert_called_once_with(
+            url_for('search/commits'),
+            params={'per_page': 100,
+                    'q': 'css repo:octocat/Spoon-Knife'},
+            headers={'Accept': 'application/vnd.github.cloak-preview'}
+        )
+
+    def test_search_issues(self):
+        """Verify the request to search for issues."""
+        i = self.instance.search_issues(
+            'windows label:bug language:python state:open',
+            sort='created', order='asc')
+        self.get_next(i)
+
+        self.session.get.assert_called_once_with(
+            url_for('search/issues'),
+            params={'order': 'asc',
+                    'per_page': 100,
+                    'q': 'windows label:bug language:python state:open',
+                    'sort': 'created'},
+            headers={}
+        )
+
+    def test_search_repositories(self):
+        """Verify the request to search for repositories."""
+        i = self.instance.search_repositories(
+            'tetris language:assembly',
+            sort='stars', order='asc')
+        self.get_next(i)
+
+        self.session.get.assert_called_once_with(
+            url_for('search/repositories'),
+            params={'order': 'asc',
+                    'per_page': 100,
+                    'q': 'tetris language:assembly',
+                    'sort': 'stars'},
+            headers={}
+        )
+
+    def test_search_users(self):
+        """Verify the request to search for users."""
+        i = self.instance.search_users(
+            'tom repos:>42 followers:>1000')
+        self.get_next(i)
+
+        self.session.get.assert_called_once_with(
+            url_for('search/users'),
+            params={'per_page': 100,
+                    'q': 'tom repos:>42 followers:>1000'},
+            headers={}
+        )
+
+
 class TestGitHubRequiresAuthentication(
         helper.UnitRequiresAuthenticationHelper):
 

pip install -e .[test]
parse_log_pytest
requirements.txt
pytest pytest-xdist betamax betamax_matchers
apt-get update apt-get install -y gcc
3.6
dev-requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
betamax==0.8.1
betamax-matchers==0.4.0
certifi==2021.5.30
charset-normalizer==2.0.12
distlib==0.3.9
execnet==1.9.0
filelock==3.4.1
-e git+https://github.com/sigmavirus24/github3.py.git@37b3cf99960523256d42c2ba512c11c74731123b#egg=github3.py
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
mock==1.0.1
packaging==21.3
platformdirs==2.4.0
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
pytest-xdist==3.0.2
python-dateutil==2.9.0.post0
requests==2.27.1
requests-toolbelt==1.0.0
six==1.17.0
swebench-matterhorn @ file:///swebench_matterhorn
toml==0.10.2
tomli==1.2.3
tox==3.28.0
typing_extensions==4.1.1
uritemplate==4.1.1
urllib3==1.26.20
virtualenv==20.17.1
zipp==3.6.0

name: github3.py
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - betamax==0.8.1
      - betamax-matchers==0.4.0
      - charset-normalizer==2.0.12
      - distlib==0.3.9
      - execnet==1.9.0
      - filelock==3.4.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - mock==1.0.1
      - packaging==21.3
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-xdist==3.0.2
      - python-dateutil==2.9.0.post0
      - requests==2.27.1
      - requests-toolbelt==1.0.0
      - six==1.17.0
      - swebench-matterhorn==0.0.0
      - toml==0.10.2
      - tomli==1.2.3
      - tox==3.28.0
      - typing-extensions==4.1.1
      - uritemplate==4.1.1
      - urllib3==1.26.20
      - virtualenv==20.17.1
      - wheel==0.21.0
      - zipp==3.6.0
prefix: /opt/conda/envs/github3.py

tests/integration/test_github.py::TestGitHub::test_search_commits tests/integration/test_github.py::TestGitHub::test_search_commits_with_text_match tests/unit/test_github.py::TestGitHubSearchIterators::test_search_commits
tests/integration/test_github.py::TestGitHub::test_activate_membership tests/integration/test_github.py::TestGitHub::test_add_email_addresses tests/integration/test_github.py::TestGitHub::test_all_events tests/integration/test_github.py::TestGitHub::test_all_organizations tests/integration/test_github.py::TestGitHub::test_all_repositories tests/integration/test_github.py::TestGitHub::test_all_users tests/integration/test_github.py::TestGitHub::test_authorize tests/integration/test_github.py::TestGitHub::test_create_gist tests/integration/test_github.py::TestGitHub::test_create_issue tests/integration/test_github.py::TestGitHub::test_create_issue_multiple_assignees tests/integration/test_github.py::TestGitHub::test_create_key tests/integration/test_github.py::TestGitHub::test_create_repository tests/integration/test_github.py::TestGitHub::test_delete_email_addresses tests/integration/test_github.py::TestGitHub::test_emojis tests/integration/test_github.py::TestGitHub::test_emojis_etag tests/integration/test_github.py::TestGitHub::test_feeds tests/integration/test_github.py::TestGitHub::test_followers tests/integration/test_github.py::TestGitHub::test_followers_of tests/integration/test_github.py::TestGitHub::test_gist tests/integration/test_github.py::TestGitHub::test_gitignore_template tests/integration/test_github.py::TestGitHub::test_gitignore_templates tests/integration/test_github.py::TestGitHub::test_is_following tests/integration/test_github.py::TestGitHub::test_is_starred tests/integration/test_github.py::TestGitHub::test_issue tests/integration/test_github.py::TestGitHub::test_key tests/integration/test_github.py::TestGitHub::test_license tests/integration/test_github.py::TestGitHub::test_licenses tests/integration/test_github.py::TestGitHub::test_markdown tests/integration/test_github.py::TestGitHub::test_me tests/integration/test_github.py::TestGitHub::test_meta tests/integration/test_github.py::TestGitHub::test_non_existent_gitignore_template tests/integration/test_github.py::TestGitHub::test_notifications tests/integration/test_github.py::TestGitHub::test_notifications_all tests/integration/test_github.py::TestGitHub::test_octocat tests/integration/test_github.py::TestGitHub::test_organization tests/integration/test_github.py::TestGitHub::test_project tests/integration/test_github.py::TestGitHub::test_project_card tests/integration/test_github.py::TestGitHub::test_project_column tests/integration/test_github.py::TestGitHub::test_public_gists tests/integration/test_github.py::TestGitHub::test_pubsubhubbub tests/integration/test_github.py::TestGitHub::test_pull_request tests/integration/test_github.py::TestGitHub::test_rate_limit tests/integration/test_github.py::TestGitHub::test_repositories tests/integration/test_github.py::TestGitHub::test_repositories_by tests/integration/test_github.py::TestGitHub::test_repository tests/integration/test_github.py::TestGitHub::test_repository_invitations tests/integration/test_github.py::TestGitHub::test_repository_with_id tests/integration/test_github.py::TestGitHub::test_search_code tests/integration/test_github.py::TestGitHub::test_search_code_with_text_match tests/integration/test_github.py::TestGitHub::test_search_issues tests/integration/test_github.py::TestGitHub::test_search_repositories tests/integration/test_github.py::TestGitHub::test_search_repositories_with_text_match tests/integration/test_github.py::TestGitHub::test_search_users tests/integration/test_github.py::TestGitHub::test_search_users_with_text_match tests/integration/test_github.py::TestGitHub::test_star tests/integration/test_github.py::TestGitHub::test_unfollow tests/integration/test_github.py::TestGitHub::test_unstar tests/integration/test_github.py::TestGitHub::test_update_me tests/integration/test_github.py::TestGitHub::test_user tests/integration/test_github.py::TestGitHub::test_user_teams tests/integration/test_github.py::TestGitHub::test_user_with_id tests/integration/test_github.py::TestGitHub::test_zen tests/integration/test_github.py::TestGitHubEnterprise::test_admin_stats tests/integration/test_github.py::TestGitHubStatus::test_api tests/integration/test_github.py::TestGitHubStatus::test_last_message tests/integration/test_github.py::TestGitHubStatus::test_messages tests/integration/test_github.py::TestGitHubStatus::test_status tests/unit/test_github.py::TestGitHub::test_activate_membership tests/unit/test_github.py::TestGitHub::test_add_email_addresses tests/unit/test_github.py::TestGitHub::test_add_email_addresses_with_empty_list tests/unit/test_github.py::TestGitHub::test_authorization tests/unit/test_github.py::TestGitHub::test_authorize tests/unit/test_github.py::TestGitHub::test_authorize_without_scope tests/unit/test_github.py::TestGitHub::test_can_login_without_two_factor_callback tests/unit/test_github.py::TestGitHub::test_check_authorization tests/unit/test_github.py::TestGitHub::test_create_gist tests/unit/test_github.py::TestGitHub::test_create_key tests/unit/test_github.py::TestGitHub::test_create_key_requires_a_key tests/unit/test_github.py::TestGitHub::test_create_key_requires_a_title tests/unit/test_github.py::TestGitHub::test_create_key_with_readonly tests/unit/test_github.py::TestGitHub::test_create_repository tests/unit/test_github.py::TestGitHub::test_delete_email_addresses tests/unit/test_github.py::TestGitHub::test_emojis tests/unit/test_github.py::TestGitHub::test_feeds tests/unit/test_github.py::TestGitHub::test_follow tests/unit/test_github.py::TestGitHub::test_follow_requires_a_username tests/unit/test_github.py::TestGitHub::test_gist tests/unit/test_github.py::TestGitHub::test_gitignore_template tests/unit/test_github.py::TestGitHub::test_gitignore_templates tests/unit/test_github.py::TestGitHub::test_is_following tests/unit/test_github.py::TestGitHub::test_is_starred tests/unit/test_github.py::TestGitHub::test_is_starred_requires_a_repo tests/unit/test_github.py::TestGitHub::test_is_starred_requires_an_owner tests/unit/test_github.py::TestGitHub::test_issue tests/unit/test_github.py::TestGitHub::test_issue_requires_positive_issue_id tests/unit/test_github.py::TestGitHub::test_issue_requires_repository tests/unit/test_github.py::TestGitHub::test_issue_requires_username tests/unit/test_github.py::TestGitHub::test_key tests/unit/test_github.py::TestGitHub::test_key_negative_id tests/unit/test_github.py::TestGitHub::test_license tests/unit/test_github.py::TestGitHub::test_login tests/unit/test_github.py::TestGitHub::test_login_with_token tests/unit/test_github.py::TestGitHub::test_markdown tests/unit/test_github.py::TestGitHub::test_markdown_gfm tests/unit/test_github.py::TestGitHub::test_markdown_raw tests/unit/test_github.py::TestGitHub::test_me tests/unit/test_github.py::TestGitHub::test_meta tests/unit/test_github.py::TestGitHub::test_octocat tests/unit/test_github.py::TestGitHub::test_octocat_response_not_ok tests/unit/test_github.py::TestGitHub::test_organization tests/unit/test_github.py::TestGitHub::test_project tests/unit/test_github.py::TestGitHub::test_project_card tests/unit/test_github.py::TestGitHub::test_project_column tests/unit/test_github.py::TestGitHub::test_pubsubhubbub tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_invalid_username tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_required_callback tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_required_mode tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_required_topic tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_secret tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_topic_no_match tests/unit/test_github.py::TestGitHub::test_pubsubhubbub_valid_username tests/unit/test_github.py::TestGitHub::test_pull_request tests/unit/test_github.py::TestGitHub::test_pull_request_negative_id tests/unit/test_github.py::TestGitHub::test_repository tests/unit/test_github.py::TestGitHub::test_repository_with_id tests/unit/test_github.py::TestGitHub::test_repository_with_id_accepts_a_string tests/unit/test_github.py::TestGitHub::test_repository_with_id_requires_a_positive_id tests/unit/test_github.py::TestGitHub::test_repository_with_invalid_repo tests/unit/test_github.py::TestGitHub::test_repository_with_invalid_user tests/unit/test_github.py::TestGitHub::test_repository_with_invalid_user_and_repo tests/unit/test_github.py::TestGitHub::test_set_client_id tests/unit/test_github.py::TestGitHub::test_set_user_agent tests/unit/test_github.py::TestGitHub::test_set_user_agent_required_user_agent tests/unit/test_github.py::TestGitHub::test_star tests/unit/test_github.py::TestGitHub::test_star_required_repo tests/unit/test_github.py::TestGitHub::test_star_required_username tests/unit/test_github.py::TestGitHub::test_star_required_username_and_repo tests/unit/test_github.py::TestGitHub::test_two_factor_login tests/unit/test_github.py::TestGitHub::test_unfollow tests/unit/test_github.py::TestGitHub::test_unfollow_required_username tests/unit/test_github.py::TestGitHub::test_unstar tests/unit/test_github.py::TestGitHub::test_unstar_requires_repository tests/unit/test_github.py::TestGitHub::test_unstar_requires_username tests/unit/test_github.py::TestGitHub::test_unstar_requires_username_and_repository tests/unit/test_github.py::TestGitHub::test_update_me tests/unit/test_github.py::TestGitHub::test_user tests/unit/test_github.py::TestGitHub::test_user_with_id tests/unit/test_github.py::TestGitHub::test_user_with_id_accepts_a_string tests/unit/test_github.py::TestGitHub::test_user_with_id_requires_a_positive_id tests/unit/test_github.py::TestGitHub::test_zen tests/unit/test_github.py::TestGitHubIterators::test_all_events tests/unit/test_github.py::TestGitHubIterators::test_all_organizations tests/unit/test_github.py::TestGitHubIterators::test_all_organizations_per_page tests/unit/test_github.py::TestGitHubIterators::test_all_organizations_since tests/unit/test_github.py::TestGitHubIterators::test_all_repositories tests/unit/test_github.py::TestGitHubIterators::test_all_repositories_per_page tests/unit/test_github.py::TestGitHubIterators::test_all_repositories_since tests/unit/test_github.py::TestGitHubIterators::test_all_users tests/unit/test_github.py::TestGitHubIterators::test_all_users_per_page tests/unit/test_github.py::TestGitHubIterators::test_all_users_since tests/unit/test_github.py::TestGitHubIterators::test_authorizations tests/unit/test_github.py::TestGitHubIterators::test_emails tests/unit/test_github.py::TestGitHubIterators::test_followed_by tests/unit/test_github.py::TestGitHubIterators::test_followers tests/unit/test_github.py::TestGitHubIterators::test_followers_of tests/unit/test_github.py::TestGitHubIterators::test_followers_require_auth tests/unit/test_github.py::TestGitHubIterators::test_following tests/unit/test_github.py::TestGitHubIterators::test_following_require_auth tests/unit/test_github.py::TestGitHubIterators::test_gists tests/unit/test_github.py::TestGitHubIterators::test_gists_by tests/unit/test_github.py::TestGitHubIterators::test_issues tests/unit/test_github.py::TestGitHubIterators::test_issues_on tests/unit/test_github.py::TestGitHubIterators::test_issues_on_with_params tests/unit/test_github.py::TestGitHubIterators::test_issues_with_params tests/unit/test_github.py::TestGitHubIterators::test_keys tests/unit/test_github.py::TestGitHubIterators::test_licenses tests/unit/test_github.py::TestGitHubIterators::test_notifications tests/unit/test_github.py::TestGitHubIterators::test_notifications_all tests/unit/test_github.py::TestGitHubIterators::test_notifications_participating_in tests/unit/test_github.py::TestGitHubIterators::test_organization_issues tests/unit/test_github.py::TestGitHubIterators::test_organization_issues_with_params tests/unit/test_github.py::TestGitHubIterators::test_organizations tests/unit/test_github.py::TestGitHubIterators::test_organizations_with tests/unit/test_github.py::TestGitHubIterators::test_public_gists tests/unit/test_github.py::TestGitHubIterators::test_public_gists_since tests/unit/test_github.py::TestGitHubIterators::test_repositories_by tests/unit/test_github.py::TestGitHubIterators::test_repositories_by_with_type tests/unit/test_github.py::TestGitHubIterators::test_repository_invitations tests/unit/test_github.py::TestGitHubIterators::test_respositories tests/unit/test_github.py::TestGitHubIterators::test_respositories_accepts_params tests/unit/test_github.py::TestGitHubIterators::test_starred tests/unit/test_github.py::TestGitHubIterators::test_starred_by tests/unit/test_github.py::TestGitHubIterators::test_subscriptions tests/unit/test_github.py::TestGitHubIterators::test_subscriptions_for tests/unit/test_github.py::TestGitHubIterators::test_user_issues tests/unit/test_github.py::TestGitHubIterators::test_user_issues_with_parameters tests/unit/test_github.py::TestGitHubSearchIterators::test_search_code tests/unit/test_github.py::TestGitHubSearchIterators::test_search_issues tests/unit/test_github.py::TestGitHubSearchIterators::test_search_repositories tests/unit/test_github.py::TestGitHubSearchIterators::test_search_users tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_activate_membership tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_add_email_addresses tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_authorization tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_authorizations tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_create_issue tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_create_key tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_create_repository tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_delete_email_addresses tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_emails tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_feeds tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_follow tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_gists tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_is_following tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_is_starred tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_issues tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_key tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_keys tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_me tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_notifications tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_organization_issues tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_organizations tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_pubsubhubbub tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_repositories tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_repository_invitations tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_star tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_starred tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_unfollow tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_unstar tests/unit/test_github.py::TestGitHubRequiresAuthentication::test_user_issues tests/unit/test_github.py::TestGitHubAuthorizations::test_revoke_authorization tests/unit/test_github.py::TestGitHubAuthorizations::test_revoke_authorizations tests/unit/test_github.py::TestGitHubEnterprise::test_admin_stats tests/unit/test_github.py::TestGitHubEnterprise::test_str tests/unit/test_github.py::TestGitHubStatus::test_api tests/unit/test_github.py::TestGitHubStatus::test_last_message tests/unit/test_github.py::TestGitHubStatus::test_messages tests/unit/test_github.py::TestGitHubStatus::test_status
src/github3/search/commit.py src/github3/search/__init__.py src/github3/github.py
src/github3/search/commit.py src/github3/search/__init__.py src/github3/github.py