Repository: VirtusLab/git-machete
Pull request #750 (2022-12-27 20:46:09)

Add support for GitHub Enterprise domains

codecov-commenter: # [Codecov](https://codecov.io/gh/VirtusLab/git-machete/pull/750?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) Report
> Merging [#750](https://codecov.io/gh/VirtusLab/git-machete/pull/750?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) (8263dcf) into [develop](https://codecov.io/gh/VirtusLab/git-machete/commit/4e98f4f104adecd90e4aa3ac31ee2341ff1a13b2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) (4e98f4f) will **increase** coverage by `0.01%`.
> The diff coverage is `83.33%`.

```diff
@@             Coverage Diff             @@
##           develop     #750      +/-   ##
===========================================
+ Coverage    70.99%   71.01%   +0.01%     
===========================================
  Files           10       10              
  Lines         2989     2991       +2     
  Branches       696      696              
===========================================
+ Hits          2122     2124       +2     
  Misses         603      603              
  Partials       264      264              
```


| [Impacted Files](https://codecov.io/gh/VirtusLab/git-machete/pull/750?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) | Coverage Δ | |
|---|---|---|
| [git\_machete/github.py](https://codecov.io/gh/VirtusLab/git-machete/pull/750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab#diff-Z2l0X21hY2hldGUvZ2l0aHViLnB5) | `67.70% <80.00%> (+0.33%)` | :arrow_up: |
| [git\_machete/\_\_init\_\_.py](https://codecov.io/gh/VirtusLab/git-machete/pull/750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab#diff-Z2l0X21hY2hldGUvX19pbml0X18ucHk=) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab)


Patch:
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 3e2072d..b7edbb8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -3,6 +3,8 @@
 ## New in git-machete 3.14.0
 
 - added: `push=no` and `rebase=no` branch qualifiers that control push and rebase behaviour of `git machete traverse`
+- added: `machete.github.domain` config key to support GitHub Enterprise domains
+- added: support for per-domain entries in `~/.github-token` file
 
 ## New in git-machete 3.13.2
 
diff --git a/docs/source/cli_help/config.rst b/docs/source/cli_help/config.rst
index a4470b9..c3d9ebb 100644
--- a/docs/source/cli_help/config.rst
+++ b/docs/source/cli_help/config.rst
@@ -8,7 +8,7 @@ Note: ``config`` is not a command as such, just a help topic (there is no ``git
 
 **Git config keys:**
 
-``machete.github.{remote,organization,repository}``:
+``machete.github.{domain,remote,organization,repository}``:
     When executing ``git machete github <subcommand>`` command, the following will happen:
 
     .. include:: github_config_keys.rst
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 579fd6d..fda8e3d 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -4,7 +4,12 @@
 # list see the documentation:
 # https://www.sphinx-doc.org/en/master/usage/configuration.html
 
-import git_machete
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
+
+import git_machete  # noqa: E402
 
 # -- Path setup --------------------------------------------------------------
 
diff --git a/docs/source/github_api_access.rst b/docs/source/github_api_access.rst
index 1e53040..c72ddc8 100644
--- a/docs/source/github_api_access.rst
+++ b/docs/source/github_api_access.rst
@@ -8,3 +8,17 @@
         2. content of the ``.github-token`` file in the home directory (``~``),
         3. current auth token from the ``gh`` GitHub CLI,
         4. current auth token from the ``hub`` GitHub CLI.
+
+    GitHub Enterprise domains are supported.
+
+    ``GITHUB_TOKEN`` is used indiscriminately for any domain, both github.com and Enterprise.
+
+    ``gh`` and ``hub`` have their own built-in support for Enterprise domains, which is honored by git-machete.
+
+    ``.github-token`` can have multiple per-domain entries in the format:
+
+      .. code-block::
+
+        ghp_mytoken_for_github_com
+        ghp_myothertoken_for_git_example_org git.example.org
+        ghp_yetanothertoken_for_git_example_com git.example.com
diff --git a/docs/source/github_config_keys.rst b/docs/source/github_config_keys.rst
index 107dfb6..2065c17 100644
--- a/docs/source/github_config_keys.rst
+++ b/docs/source/github_config_keys.rst
@@ -3,6 +3,9 @@
     GitHub API server URL will be inferred from ``git remote``.
     You can override this by setting the following git config keys:
 
+        GitHub Enterprise domain
+            E.g. ``machete.github.domain`` = ``git.example.org``
+
         Remote name
             E.g. ``machete.github.remote`` = ``origin``
 
@@ -17,10 +20,11 @@
     .. code-block::
 
         [machete "github"]
+            domain = <domain>
             organization = <organization_name>
             repository = <repo_name>
             remote = <remote_name>
 
 ..
-    Text order in this file is relevant, if you want to change something, find each ``.. include:: status_config_key.rst`` instance
+    Text order in this file is relevant, if you want to change something, find each ``.. include:: github_config_keys.rst`` instance
     and if the instance has ``start-line`` or ``end-line`` options provided, make sure that after changes the output text stays the same.
diff --git a/git_machete/client.py b/git_machete/client.py
index 25bbe61..e8e0241 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -18,7 +18,7 @@ from git_machete.git_operations import (
     AnyBranchName, AnyRevision, ForkPointOverrideData,
     FullCommitHash, GitContext, GitLogEntry, HEAD, BranchPair, LocalBranchShortName, RemoteBranchShortName)
 from git_machete.github import (
-    add_assignees_to_pull_request, add_reviewers_to_pull_request,
+    DEFAULT_GITHUB_DOMAIN, add_assignees_to_pull_request, add_reviewers_to_pull_request,
     create_pull_request, checkout_pr_refs, derive_pull_request_by_head, derive_pull_requests,
     get_github_token_possible_providers, get_parsed_github_remote_url, get_pull_request_by_number_or_none, GitHubPullRequest,
     is_github_remote_url, RemoteAndOrganizationAndRepository, set_base_of_pull_request, set_milestone_of_pull_request)
@@ -399,7 +399,7 @@ class MacheteClient:
             )]
         else:
             c = DISCOVER_DEFAULT_FRESH_BRANCH_COUNT
-            stale, fresh = non_root_fixed_branches_by_last_checkout_timestamps[:-c],\
+            stale, fresh = non_root_fixed_branches_by_last_checkout_timestamps[:-c], \
                 non_root_fixed_branches_by_last_checkout_timestamps[-c:]
             stale_non_root_fixed_branches = [LocalBranchShortName.of(branch) for (timestamp, branch) in stale]
             if stale:
@@ -1179,9 +1179,9 @@ class MacheteClient:
         if use_overrides:
             overridden_fp_hash = self.__get_overridden_fork_point(branch)
             if overridden_fp_hash:
-                if upstream and self.__git.is_ancestor_or_equal(upstream.full_name(),
-                                                                branch.full_name()) and not self.__git.is_ancestor_or_equal(
-                        upstream.full_name(), overridden_fp_hash.full_name()):
+                if upstream and \
+                        self.__git.is_ancestor_or_equal(upstream.full_name(), branch.full_name()) and \
+                        not self.__git.is_ancestor_or_equal(upstream.full_name(), overridden_fp_hash.full_name()):
                     # We need to handle the case when branch is a descendant of upstream,
                     # but the fork point of branch is overridden to a commit that
                     # is NOT a descendant of upstream. In this case it's more
@@ -1459,11 +1459,12 @@ class MacheteClient:
         return result
 
     def sync_annotations_to_github_prs(self) -> None:
-        _, org, repo = self.__derive_remote_and_github_org_and_repo()
-        current_user: Optional[str] = git_machete.github.derive_current_user_login()
+        domain = self.__derive_github_domain()
+        _, org, repo = self.__derive_remote_and_github_org_and_repo(domain)
+        current_user: Optional[str] = git_machete.github.derive_current_user_login(domain)
         debug('Current GitHub user is ' + (current_user or '<none>'))
-        all_prs: List[GitHubPullRequest] = derive_pull_requests(org, repo)
-        self.__sync_annotations_to_definition_file(all_prs, current_user=current_user)
+        all_prs: List[GitHubPullRequest] = derive_pull_requests(domain, org, repo)
+        self.__sync_annotations_to_definition_file(all_prs, current_user)
 
     def __sync_annotations_to_definition_file(self,
                                               prs: List[GitHubPullRequest],
@@ -1970,8 +1971,9 @@ class MacheteClient:
         org: str
         repo: str
         remote: str
-        remote, org, repo = self.__derive_remote_and_github_org_and_repo()
-        current_user: Optional[str] = git_machete.github.derive_current_user_login()
+        domain = self.__derive_github_domain()
+        remote, org, repo = self.__derive_remote_and_github_org_and_repo(domain)
+        current_user: Optional[str] = git_machete.github.derive_current_user_login(domain)
         if not current_user and my_opened_prs:
             msg = ("Could not determine current user name, please check that the GitHub API token provided by one of the: "
                    f"{get_github_token_possible_providers()}is valid.")
@@ -1980,9 +1982,10 @@ class MacheteClient:
                 return
             else:
                 raise MacheteException(msg)
-        all_open_prs: List[GitHubPullRequest] = derive_pull_requests(org, repo)
+        all_open_prs: List[GitHubPullRequest] = derive_pull_requests(domain, org, repo)
         applicable_prs: List[GitHubPullRequest] = self.__get_applicable_pull_requests(pr_nos,
                                                                                       all_opened_prs_from_github=all_open_prs,
+                                                                                      domain=domain,
                                                                                       org=org,
                                                                                       repo=repo,
                                                                                       all=all_opened_prs,
@@ -2000,7 +2003,7 @@ class MacheteClient:
         for pr in sorted(applicable_prs, key=lambda x: x.number):
             if pr.full_repository_name:
                 if '/'.join([remote, pr.head]) not in self.__git.get_remote_branches():
-                    remote_already_added: Optional[str] = self.__get_added_remote_name_or_none(pr.repository_url)
+                    remote_already_added: Optional[str] = self.__get_added_remote_name_or_none(domain, pr.repository_url)
                     if not remote_already_added:
                         remote_from_pr: str = pr.full_repository_name.split('/')[0]
                         if remote_from_pr not in self.__git.get_remotes():
@@ -2068,6 +2071,7 @@ class MacheteClient:
     @staticmethod
     def __get_applicable_pull_requests(prs_list: Optional[List[int]],
                                        all_opened_prs_from_github: List[GitHubPullRequest],
+                                       domain: str,
                                        org: str,
                                        repo: str,
                                        all: bool,
@@ -2082,7 +2086,7 @@ class MacheteClient:
                 if _pr:
                     result.append(_pr)
                 else:
-                    pr_from_github = get_pull_request_by_number_or_none(pr_no, org, repo)
+                    pr_from_github = get_pull_request_by_number_or_none(domain, pr_no, org, repo)
                     if pr_from_github:
                         result.append(pr_from_github)
                     else:
@@ -2110,7 +2114,7 @@ class MacheteClient:
             return result
         return []
 
-    def __get_added_remote_name_or_none(self, remote_url: str) -> Optional[str]:
+    def __get_added_remote_name_or_none(self, github_domain: str, remote_url: str) -> Optional[str]:
         """
         Function to check if remote is added locally by its url,
         because it may happen that remote is already added under a name different from the name of organization on GitHub
@@ -2122,18 +2126,20 @@ class MacheteClient:
         for remote, url in url_for_remote.items():
             url = url if url.endswith('.git') else url + '.git'
             remote_url = remote_url if remote_url.endswith('.git') else remote_url + '.git'
-            if is_github_remote_url(url) and get_parsed_github_remote_url(url, remote) == get_parsed_github_remote_url(remote_url, remote):
+            if is_github_remote_url(github_domain, url) and get_parsed_github_remote_url(github_domain, url, remote) == \
+                    get_parsed_github_remote_url(github_domain, remote_url, remote):
                 return remote
         return None
 
     def retarget_github_pr(self, head: LocalBranchShortName) -> None:
         org: str
         repo: str
-        _, org, repo = self.__derive_remote_and_github_org_and_repo(branch_used_for_tracking_data=head)
+        domain: str = self.__derive_github_domain()
+        _, org, repo = self.__derive_remote_and_github_org_and_repo(domain, branch_used_for_tracking_data=head)
 
         debug(f'organization is {org}, repository is {repo}')
 
-        pr: Optional[GitHubPullRequest] = derive_pull_request_by_head(org, repo, head)
+        pr: Optional[GitHubPullRequest] = derive_pull_request_by_head(domain, org, repo, head)
         if not pr:
             raise MacheteException(f'No PR is opened in `{org}/{repo}` for branch `{head}`')
         debug(f'found {pr}')
@@ -2147,7 +2153,7 @@ class MacheteClient:
                 f' so that `{head}` is a child of `{pr.base}`.')
 
         if pr.base != new_base:
-            set_base_of_pull_request(org, repo, pr.number, base=new_base)
+            set_base_of_pull_request(domain, org, repo, pr.number, base=new_base)
             print(fmt(f'The base branch of PR #{pr.number} has been switched to `{new_base}`'))
         else:
             print(fmt(f'The base branch of PR #{pr.number} is already `{new_base}`'))
@@ -2155,12 +2161,16 @@ class MacheteClient:
         self.__annotations[head] = Annotation(f'PR #{pr.number}')
         self.save_definition_file()
 
+    def __derive_github_domain(self) -> str:
+        return self.__git.get_config_attr_or_none("machete.github.domain") or DEFAULT_GITHUB_DOMAIN
+
     def __derive_remote_and_github_org_and_repo(self,
+                                                domain: str,
                                                 branch_used_for_tracking_data: LocalBranchShortName = None
                                                 ) -> RemoteAndOrganizationAndRepository:
-        remote_and_organization_and_repository_for_custom_url = self.__get_remote_and_organization_and_repository_name_for_custom_url()
-        if all(remote_and_organization_and_repository_for_custom_url):
-            return remote_and_organization_and_repository_for_custom_url
+        remote_and_organization_and_repository_from_config = self.__get_remote_and_organization_and_repository_name_from_config()
+        if all(remote_and_organization_and_repository_from_config):
+            return remote_and_organization_and_repository_from_config
 
         url_for_remote: Dict[str, str] = {
             remote: self.__git.get_url_of_remote(remote) for remote in self.__git.get_remotes()
@@ -2169,16 +2179,17 @@ class MacheteClient:
             raise MacheteException(fmt('No remotes defined for this repository (see `git remote`)'))
 
         remote_and_github_org_and_repo: Dict[str, RemoteAndOrganizationAndRepository] = {
-            remote: get_parsed_github_remote_url(url, remote) for remote, url in url_for_remote.items() if is_github_remote_url(url)
+            remote: get_parsed_github_remote_url(domain, url, remote)
+            for remote, url in url_for_remote.items() if is_github_remote_url(domain, url)
         }
 
         if not remote_and_github_org_and_repo:
             raise MacheteException(
                 fmt('Remotes are defined for this repository, but none of them '
-                    'corresponds to GitHub (see `git remote -v` for details). \n'
-                    'It is possible that you are using custom GitHub URL.\n'
-                    'If that is the case, you can provide repository information explicitly, via these 3 git config keys: '
-                    '`machete.github.{{remote,organization,repository}}`\n'))
+                    'seems to correspond to GitHub (see `git remote -v` for details). \n'
+                    'It is possible that you are using a custom GitHub URL.\n'
+                    'If that is the case, you can provide repository information explicitly via some or all of git config keys: '
+                    '`machete.github.{domain,remote,organization,repository}.`\n'))  # noqa: FS003
 
         if len(remote_and_github_org_and_repo) == 1:
             return remote_and_github_org_and_repo[list(remote_and_github_org_and_repo.keys())[0]]
@@ -2196,10 +2207,10 @@ class MacheteClient:
         raise MacheteException(
             f'Multiple non-origin remotes correspond to GitHub in this repository: '
             f'{", ".join(remote_and_github_org_and_repo.keys())} -> aborting. \n'
-            f'You can also select the repository by providing 3 git config keys: '
-            f'`machete.github.{{remote,organization,repository}}`\n')
+            f'You can also select the repository by providing some or all of git config keys: '
+            '`machete.github.{domain,remote,organization,repository}`.\n')  # noqa: FS003
 
-    def __get_remote_and_organization_and_repository_name_for_custom_url(self) -> RemoteAndOrganizationAndRepository:
+    def __get_remote_and_organization_and_repository_name_from_config(self) -> RemoteAndOrganizationAndRepository:
         return RemoteAndOrganizationAndRepository(remote=self.__git.get_config_attr_or_none("machete.github.remote"),
                                                   organization=self.__git.get_config_attr_or_none("machete.github.organization"),
                                                   repository=self.__git.get_config_attr_or_none("machete.github.repository"))
@@ -2220,7 +2231,8 @@ class MacheteClient:
             raise MacheteException(f'Could not determine base branch for PR. Branch `{head}` is a root branch.')
         org: str
         repo: str
-        remote, org, repo = self.__derive_remote_and_github_org_and_repo(branch_used_for_tracking_data=head)
+        domain = self.__derive_github_domain()
+        remote, org, repo = self.__derive_remote_and_github_org_and_repo(domain, branch_used_for_tracking_data=head)
         print(f"Fetching {remote}...")
         self.__git.fetch_remote(remote)
         if '/'.join([remote, base]) not in self.__git.get_remote_branches():
@@ -2234,7 +2246,7 @@ class MacheteClient:
                 opt_push_untracked=True,
                 opt_yes=False)
 
-        current_user: Optional[str] = git_machete.github.derive_current_user_login()
+        current_user: Optional[str] = git_machete.github.derive_current_user_login(domain)
         debug(f'organization is {org}, repository is {repo}')
         debug('current GitHub user is ' + (current_user or '<none>'))
 
@@ -2247,7 +2259,7 @@ class MacheteClient:
 
         ok_str = '<green><b>OK</b></green>'
         print(fmt(f'Creating a {"draft " if opt_draft else ""}PR from `{head}` to `{base}`... '), end='', flush=True)
-        pr: GitHubPullRequest = create_pull_request(org, repo, head=head, base=base, title=commits[0].subject,
+        pr: GitHubPullRequest = create_pull_request(domain, org, repo, head=head, base=base, title=commits[0].subject,
                                                     description=description, draft=opt_draft)
         print(fmt(f'{ok_str}, see <b>{pr.html_url}</b>'))
 
@@ -2255,12 +2267,12 @@ class MacheteClient:
         milestone: str = utils.slurp_file_or_empty(milestone_path).strip()
         if milestone:
             print(fmt(f'Setting milestone of PR #{pr.number} to {milestone}... '), end='', flush=True)
-            set_milestone_of_pull_request(org, repo, pr.number, milestone=milestone)
+            set_milestone_of_pull_request(domain, org, repo, pr.number, milestone=milestone)
             print(fmt(ok_str))
 
         if current_user:
             print(fmt(f'Adding `{current_user}` as assignee to PR #{pr.number}... '), end='', flush=True)
-            add_assignees_to_pull_request(org, repo, pr.number, [current_user])
+            add_assignees_to_pull_request(domain, org, repo, pr.number, [current_user])
             print(fmt(ok_str))
 
         reviewers_path = self.__git.get_main_git_subpath('info', 'reviewers')
@@ -2271,7 +2283,7 @@ class MacheteClient:
                     f'as reviewer{"s" if len(reviewers) > 1 else ""} to PR #{pr.number}... '),
                 end='', flush=True)
             try:
-                add_reviewers_to_pull_request(org, repo, pr.number, reviewers)
+                add_reviewers_to_pull_request(domain, org, repo, pr.number, reviewers)
             except UnprocessableEntityHTTPError as e:
                 if 'Reviews may only be requested from collaborators.' in e.msg:
                     warn(f"There are some invalid reviewers in {self.__git.get_main_git_subpath('info', 'reviewers')} file.\n"
diff --git a/git_machete/generated_docs.py b/git_machete/generated_docs.py
index d4c1b00..a30a246 100644
--- a/git_machete/generated_docs.py
+++ b/git_machete/generated_docs.py
@@ -136,8 +136,24 @@ long_docs: Dict[str, str] = {
            * current auth token from the `gh` GitHub CLI,
            * current auth token from the `hub` GitHub CLI.
 
+        GitHub Enterprise domains are supported.
+
+        `GITHUB_TOKEN` is used indiscriminately for any domain, both github.com and Enterprise.
+
+        `gh` and `hub` have their own built-in support for Enterprise domains, which is honored by git-machete.
+
+        `.github-token` can have multiple per-domain entries in the format:
+        <dim>
+          ghp_mytoken_for_github_com
+          ghp_myothertoken_for_git_example_org git.example.org
+          ghp_yetanothertoken_for_git_example_com git.example.com
+        </dim>
+
         GitHub API server URL will be inferred from `git remote`.
         You can override this by setting the following git config keys:
+           GitHub Enterprise domain
+              E.g. `machete.github.domain` = `git.example.org`
+
            Remote name
               E.g. `machete.github.remote` = `origin`
 
@@ -150,6 +166,7 @@ long_docs: Dict[str, str] = {
         To do this, run `git config --local --edit` and add the following section:
         <dim>
           [machete "github"]
+              domain = <domain>
               organization = <organization_name>
               repository = <repo_name>
               remote = <remote_name>
@@ -194,8 +211,24 @@ long_docs: Dict[str, str] = {
            * current auth token from the `gh` GitHub CLI,
            * current auth token from the `hub` GitHub CLI.
 
+        GitHub Enterprise domains are supported.
+
+        `GITHUB_TOKEN` is used indiscriminately for any domain, both github.com and Enterprise.
+
+        `gh` and `hub` have their own built-in support for Enterprise domains, which is honored by git-machete.
+
+        `.github-token` can have multiple per-domain entries in the format:
+        <dim>
+          ghp_mytoken_for_github_com
+          ghp_myothertoken_for_git_example_org git.example.org
+          ghp_yetanothertoken_for_git_example_com git.example.com
+        </dim>
+
         GitHub API server URL will be inferred from `git remote`.
         You can override this by setting the following git config keys:
+           GitHub Enterprise domain
+              E.g. `machete.github.domain` = `git.example.org`
+
            Remote name
               E.g. `machete.github.remote` = `origin`
 
@@ -208,6 +241,7 @@ long_docs: Dict[str, str] = {
         To do this, run `git config --local --edit` and add the following section:
         <dim>
           [machete "github"]
+              domain = <domain>
               organization = <organization_name>
               repository = <repo_name>
               remote = <remote_name>
@@ -230,13 +264,16 @@ long_docs: Dict[str, str] = {
         Note: `config` is not a command as such, just a help topic (there is no `git machete config` command).
 
         <b>Git config keys:</b>
-           `machete.github.{remote,organization,repository}`:
+           `machete.github.{domain,remote,organization,repository}`:
  
               When executing `git machete github <subcommand>` command, the following will happen:
 
               GitHub API server URL will be inferred from `git remote`.
               You can override this by setting the following git config keys:
 
+                 GitHub Enterprise domain
+              E.g. `machete.github.domain` = `git.example.org`
+
                  Remote name
               E.g. `machete.github.remote` = `origin`
 
@@ -249,6 +286,7 @@ long_docs: Dict[str, str] = {
               To do this, run `git config --local --edit` and add the following section:
 
               [machete "github"]
+                  domain = <domain>
                   organization = <organization_name>
                   repository = <repo_name>
                   remote = <remote_name>
@@ -505,8 +543,24 @@ long_docs: Dict[str, str] = {
            * current auth token from the `gh` GitHub CLI,
            * current auth token from the `hub` GitHub CLI.
 
+        GitHub Enterprise domains are supported.
+
+        `GITHUB_TOKEN` is used indiscriminately for any domain, both github.com and Enterprise.
+
+        `gh` and `hub` have their own built-in support for Enterprise domains, which is honored by git-machete.
+
+        `.github-token` can have multiple per-domain entries in the format:
+        <dim>
+          ghp_mytoken_for_github_com
+          ghp_myothertoken_for_git_example_org git.example.org
+          ghp_yetanothertoken_for_git_example_com git.example.com
+        </dim>
+
         GitHub API server URL will be inferred from `git remote`.
         You can override this by setting the following git config keys:
+           GitHub Enterprise domain
+              E.g. `machete.github.domain` = `git.example.org`
+
            Remote name
               E.g. `machete.github.remote` = `origin`
 
@@ -519,6 +573,7 @@ long_docs: Dict[str, str] = {
         To do this, run `git config --local --edit` and add the following section:
         <dim>
           [machete "github"]
+              domain = <domain>
               organization = <organization_name>
               repository = <repo_name>
               remote = <remote_name>
diff --git a/git_machete/github.py b/git_machete/github.py
index 9898727..fbf18ee 100644
--- a/git_machete/github.py
+++ b/git_machete/github.py
@@ -1,4 +1,3 @@
-# Deliberately NOT using much more convenient `requests` to avoid external dependencies
 import http
 import json
 import os
@@ -7,6 +6,7 @@ import shutil
 import subprocess
 from pathlib import Path
 from typing import Any, Dict, List, NamedTuple, Optional
+# Deliberately NOT using much more convenient `requests` to avoid external dependencies in production code
 import urllib.request
 import urllib.error
 
@@ -15,17 +15,18 @@ from git_machete.exceptions import MacheteException, UnprocessableEntityHTTPErro
 from git_machete.git_operations import GitContext, LocalBranchShortName
 
 GITHUB_TOKEN_ENV_VAR = 'GITHUB_TOKEN'
+DEFAULT_GITHUB_DOMAIN = "github.com"
 
-# TODO (#137): Support GitHub Enterprise endpoints
-GITHUB_DOMAIN = "github.com"
 
-# GitHub DOES NOT allow trailing `.git` suffix in the repository name (also applies to multiple repetitions e.g. `repo_name.git.git`)
-GITHUB_REMOTE_PATTERNS = [
-    r"^https://.*@github\.com/(.*)/(.*)$",
-    r"^https://github\.com/(.*)/(.*)$",
-    r"^git@github\.com:(.*)/(.*)$",
-    r"^ssh://git@github\.com/(.*)/(.*)$"
-]
+def github_remote_url_patterns(domain: str) -> List[str]:
+    # GitHub DOES NOT allow trailing `.git` suffix in the repository name (also applies to multiple repetitions e.g. `repo_name.git.git`)
+    domain_regex = re.escape(domain)
+    return [
+        f"^https://.*@{domain_regex}/(.*)/(.*)$",
+        f"^https://{domain_regex}/(.*)/(.*)$",
+        f"^git@{domain_regex}:(.*)/(.*)$",
+        f"^ssh://git@{domain_regex}/(.*)/(.*)$"
+    ]
 
 
 class GitHubPullRequest(object):
@@ -74,38 +75,36 @@ class GithubTokenAndTokenProvider(NamedTuple):
     token_provider: str
 
 
-def __get_github_token_and_provider() -> Optional[GithubTokenAndTokenProvider]:
+def __get_github_token_and_provider(domain: str) -> Optional[GithubTokenAndTokenProvider]:
     def get_token_from_gh() -> Optional[GithubTokenAndTokenProvider]:
         # Abort without error if `gh` isn't available
         gh = shutil.which('gh')
         if not gh:
             return None
 
-        # Run via subprocess.run as we're insensitive to return code.
-        #
-        # TODO (#137): `gh` can store auth token for public and enterprise domains,
-        #  specify single domain for lookup.
-        # This is *only* github.com until enterprise support is added.
+        # There is also `gh auth token`, but it's only been added in gh v2.17.0, in Oct 2022.
+        # Let's stick to the older `gh auth status --show-token` for compatibility.
         proc = subprocess.run(
-            [gh, "auth", "status", "--hostname", GITHUB_DOMAIN, "--show-token"],
+            [gh, "auth", "status", "--hostname", domain, "--show-token"],
             stdout=subprocess.PIPE,
             stderr=subprocess.PIPE
         )
+        if proc.returncode != 0:
+            return None
 
-        # gh auth status outputs to stderr in the form:
+        # `gh auth status --show-token` outputs to stderr in the form:
         #
         # {domain}:
         #   ✓ Logged in to {domain} as {username} ({config_path})
         #   ✓ Git operations for {domain} configured to use {protocol} protocol.
-        #   ✓ Token: *******************
+        #   ✓ Token: <token>
         #
-        # with non-zero exit code on failure
-        result = proc.stderr.decode()
-
-        match = re.search(r"Token: (\w+)", result)
+        # with non-zero exit code on failure.
+        stderr = proc.stderr.decode()
+        match = re.search(r"Token: (\w+)", stderr)
         if match:
-            return GithubTokenAndTokenProvider(token=match.groups()[0],
-                                               token_provider='current auth token from the `gh` GitHub CLI')
+            return GithubTokenAndTokenProvider(token=match.group(1),
+                                               token_provider=f'auth token for {domain} from `hub` GitHub CLI')
         return None
 
     def get_token_from_hub() -> Optional[GithubTokenAndTokenProvider]:
@@ -113,17 +112,25 @@ def __get_github_token_and_provider() -> Optional[GithubTokenAndTokenProvider]:
         config_hub_path: str = os.path.join(home_path, ".config", "hub")
         if os.path.isfile(config_hub_path):
             with open(config_hub_path) as config_hub:
-                config_hub_content: str = config_hub.read()
                 # ~/.config/hub is a yaml file, with a structure similar to:
                 #
-                # {domain}:
-                # - user: {username}
+                # {domain1}:
+                # - user: {username1}
+                #   oauth_token: *******************
+                #   protocol: {protocol}
+                #
+                # {domain2}:
+                # - user: {username2}
                 #   oauth_token: *******************
                 #   protocol: {protocol}
-                match = re.search(r"oauth_token: (\w+)", config_hub_content)
-                if match:
-                    return GithubTokenAndTokenProvider(token=match.groups()[0],
-                                                       token_provider='current auth token from the `hub` GitHub CLI')
+                found_host = False
+                for line in config_hub.readlines():
+                    if line.rstrip() == domain + ":":
+                        found_host = True
+                    elif found_host and line.lstrip().startswith("oauth_token:"):
+                        result = re.sub(' *oauth_token: *', '', line).rstrip().replace('"', '')
+                        return GithubTokenAndTokenProvider(token=result,
+                                                           token_provider=f'auth token for {domain} from `hub` GitHub CLI')
         return None
 
     def get_token_from_env() -> Optional[GithubTokenAndTokenProvider]:
@@ -135,12 +142,17 @@ def __get_github_token_and_provider() -> Optional[GithubTokenAndTokenProvider]:
 
     def get_token_from_file_in_home_directory() -> Optional[GithubTokenAndTokenProvider]:
         required_file_name = '.github-token'
+        token_provider = f'auth token for {domain} from `~/.github-token`'
         file_full_path = os.path.expanduser(f'~/{required_file_name}')
 
         if os.path.isfile(file_full_path):
             with open(file_full_path) as file:
-                return GithubTokenAndTokenProvider(token=file.read().strip(),
-                                                   token_provider='content of the `~/.github-token` file')
+                for line in file.readlines():
+                    if line.endswith(" " + domain):
+                        token = line.split(" ")[0]
+                        return GithubTokenAndTokenProvider(token=token, token_provider=token_provider)
+                    elif domain == DEFAULT_GITHUB_DOMAIN and " " not in line.rstrip():
+                        return GithubTokenAndTokenProvider(token=line.rstrip(), token_provider=token_provider)
         return None
 
     return (get_token_from_env() or
@@ -149,13 +161,13 @@ def __get_github_token_and_provider() -> Optional[GithubTokenAndTokenProvider]:
             get_token_from_hub())
 
 
-def __get_github_token() -> Optional[str]:
-    github_token_and_provider = __get_github_token_and_provider()
+def __get_github_token(domain: str) -> Optional[str]:
+    github_token_and_provider = __get_github_token_and_provider(domain)
     return github_token_and_provider.token if github_token_and_provider else None
 
 
-def __get_github_token_provider() -> Optional[str]:
-    github_token_and_provider = __get_github_token_and_provider()
+def __get_github_token_provider(domain: str) -> Optional[str]:
+    github_token_and_provider = __get_github_token_and_provider(domain)
     return github_token_and_provider.token_provider if github_token_and_provider else None
 
 
@@ -172,7 +184,8 @@ def __extract_failure_info_from_422(response: Any) -> str:
     return str(response)
 
 
-def __fire_github_api_request(method: str, path: str, token: Optional[str], request_body: Optional[Dict[str, Any]] = None) -> Any:
+def __fire_github_api_request(domain: str, method: str, path: str,
+                              token: Optional[str], request_body: Optional[Dict[str, Any]] = None) -> Any:
     headers: Dict[str, str] = {
         'Content-type': 'application/json',
         'User-Agent': 'git-machete',
@@ -181,7 +194,7 @@ def __fire_github_api_request(method: str, path: str, token: Optional[str], requ
     if token:
         headers['Authorization'] = 'Bearer ' + token
 
-    host = 'https://api.' + GITHUB_DOMAIN
+    host = 'https://api.' + domain
     url = host + path
     json_body: Optional[str] = json.dumps(request_body) if request_body else None
     http_request = urllib.request.Request(url, headers=headers, data=json_body.encode() if json_body else None, method=method.upper())
@@ -199,26 +212,27 @@ def __fire_github_api_request(method: str, path: str, token: Optional[str], requ
         elif err.code in (http.HTTPStatus.UNAUTHORIZED, http.HTTPStatus.FORBIDDEN):
             first_line = f'GitHub API returned `{err.code}` HTTP status with error message: `{err.reason}`\n'
             if token:
-                raise MacheteException(first_line + f'Make sure that the GitHub API token provided by the {__get_github_token_provider()} '
-                                                    f'is valid and allows for access to `{method.upper()}` `https://{host}{path}`.\n'
+                raise MacheteException(first_line + 'Make sure that the GitHub API token '
+                                                    f'provided by the {__get_github_token_provider(domain)} '
+                                                    f'is valid and allows for access to `{method.upper()}` `{host}{path}`.\n'
                                                     'You can also use a different token provider, available providers can be found '
-                                                    'when running `git machete help github`')
+                                                    'when running `git machete help github`.')
             else:
                 raise MacheteException(
                     first_line + f'You might not have the required permissions for this repository.\n'
-                                 f'Provide a GitHub API token with `repo` access via {__get_github_token_provider()}.\n'
-                                 'Visit `https://github.com/settings/tokens` to generate a new one.\n'
+                                 f'Provide a GitHub API token with `repo` access via {__get_github_token_provider(domain)}.\n'
+                                 f'Visit `https://{domain}/settings/tokens` to generate a new one.\n'
                                  'You can also use a different token provider, available providers can be found '
-                                 'when running `git machete help github`')
+                                 'when running `git machete help github`.')
         elif err.code == http.HTTPStatus.NOT_FOUND:
             raise MacheteException(
                 f'`{method} {url}` request ended up in 404 response from GitHub. A valid GitHub API token is required.\n'
                 f'Provide a GitHub API token with `repo` access via one of the: {get_github_token_possible_providers()} '
-                'Visit `https://github.com/settings/tokens` to generate a new one.')  # TODO (#164): make dedicated exception here
+                f'Visit `https://{domain}/settings/tokens` to generate a new one.')  # TODO (#164): make dedicated exception here
         elif err.code == http.HTTPStatus.TEMPORARY_REDIRECT:
             if err.headers['Location'] is not None:
                 if len(err.headers['Location'].split('/')) >= 5:
-                    current_repo_and_org = get_repo_and_org_names_by_id(err.headers['Location'].split('/')[4])
+                    current_repo_and_org = get_repo_and_org_names_by_id(domain, err.headers['Location'].split('/')[4])
             else:
                 first_line = fmt(f'GitHub API returned `{err.code}` HTTP status with error message: `{err.reason}`\n')
                 raise MacheteException(
@@ -237,7 +251,7 @@ def __fire_github_api_request(method: str, path: str, token: Optional[str], requ
                  f'new repository = `{current_repo_and_org.split("/")[1]}`.\n'
                  'You can update your remote repository via: `git remote set-url <remote_name> <new_repository_url>`.',
                  end='')
-            return __fire_github_api_request(method=method, path=new_path, token=token, request_body=request_body)
+            return __fire_github_api_request(domain=domain, method=method, path=new_path, token=token, request_body=request_body)
         else:
             first_line = fmt(f'GitHub API returned `{err.code}` HTTP status with error message: `{err.reason}`\n')
             raise MacheteException(
@@ -246,8 +260,9 @@ def __fire_github_api_request(method: str, path: str, token: Optional[str], requ
         raise MacheteException(f'Could not connect to {host}: {e}')
 
 
-def create_pull_request(org: str, repo: str, head: str, base: str, title: str, description: str, draft: bool) -> GitHubPullRequest:
-    token: Optional[str] = __get_github_token()
+def create_pull_request(domain: str, org: str, repo: str,
+                        head: str, base: str, title: str, description: str, draft: bool) -> GitHubPullRequest:
+    token: Optional[str] = __get_github_token(domain)
     request_body: Dict[str, Any] = {
         'head': head,
         'base': base,
@@ -255,69 +270,69 @@ def create_pull_request(org: str, repo: str, head: str, base: str, title: str, d
         'body': description,
         'draft': draft
     }
-    pr = __fire_github_api_request('POST', f'/repos/{org}/{repo}/pulls', token, request_body)
+    pr = __fire_github_api_request(domain, 'POST', f'/repos/{org}/{repo}/pulls', token, request_body)
     return __parse_pr_json(pr)
 
 
-def add_assignees_to_pull_request(org: str, repo: str, number: int, assignees: List[str]) -> None:
-    token: Optional[str] = __get_github_token()
+def add_assignees_to_pull_request(domain: str, org: str, repo: str, number: int, assignees: List[str]) -> None:
+    token: Optional[str] = __get_github_token(domain)
     request_body: Dict[str, List[str]] = {
         'assignees': assignees
     }
     # Adding assignees is only available via the Issues API, not PRs API.
-    __fire_github_api_request('POST', f'/repos/{org}/{repo}/issues/{number}/assignees', token, request_body)
+    __fire_github_api_request(domain, 'POST', f'/repos/{org}/{repo}/issues/{number}/assignees', token, request_body)
 
 
-def add_reviewers_to_pull_request(org: str, repo: str, number: int, reviewers: List[str]) -> None:
-    token: Optional[str] = __get_github_token()
+def add_reviewers_to_pull_request(domain: str, org: str, repo: str, number: int, reviewers: List[str]) -> None:
+    token: Optional[str] = __get_github_token(domain)
     request_body: Dict[str, List[str]] = {
         'reviewers': reviewers
     }
-    __fire_github_api_request('POST', f'/repos/{org}/{repo}/pulls/{number}/requested_reviewers', token, request_body)
+    __fire_github_api_request(domain, 'POST', f'/repos/{org}/{repo}/pulls/{number}/requested_reviewers', token, request_body)
 
 
-def set_base_of_pull_request(org: str, repo: str, number: int, base: LocalBranchShortName) -> None:
-    token: Optional[str] = __get_github_token()
+def set_base_of_pull_request(domain: str, org: str, repo: str, number: int, base: LocalBranchShortName) -> None:
+    token: Optional[str] = __get_github_token(domain)
     request_body: Dict[str, str] = {'base': base}
-    __fire_github_api_request('PATCH', f'/repos/{org}/{repo}/pulls/{number}', token, request_body)
+    __fire_github_api_request(domain, 'PATCH', f'/repos/{org}/{repo}/pulls/{number}', token, request_body)
 
 
-def set_milestone_of_pull_request(org: str, repo: str, number: int, milestone: str) -> None:
-    token: Optional[str] = __get_github_token()
+def set_milestone_of_pull_request(domain: str, org: str, repo: str, number: int, milestone: str) -> None:
+    token: Optional[str] = __get_github_token(domain)
     request_body: Dict[str, str] = {'milestone': milestone}
     # Setting milestone is only available via the Issues API, not PRs API.
-    __fire_github_api_request('PATCH', f'/repos/{org}/{repo}/issues/{number}', token, request_body)
+    __fire_github_api_request(domain, 'PATCH', f'/repos/{org}/{repo}/issues/{number}', token, request_body)
 
 
-def derive_pull_request_by_head(org: str, repo: str, head: LocalBranchShortName) -> Optional[GitHubPullRequest]:
-    token: Optional[str] = __get_github_token()
-    prs = __fire_github_api_request('GET', f'/repos/{org}/{repo}/pulls?head={org}:{head}', token)
+def derive_pull_request_by_head(domain: str, org: str, repo: str, head: LocalBranchShortName) -> Optional[GitHubPullRequest]:
+    token: Optional[str] = __get_github_token(domain)
+    prs = __fire_github_api_request(domain, 'GET', f'/repos/{org}/{repo}/pulls?head={org}:{head}', token)
     if len(prs) >= 1:
         return __parse_pr_json(prs[0])
     else:
         return None
 
 
-def derive_pull_requests(org: str, repo: str) -> List[GitHubPullRequest]:
-    token: Optional[str] = __get_github_token()
-    prs = __fire_github_api_request('GET', f'/repos/{org}/{repo}/pulls', token)
+def derive_pull_requests(domain: str, org: str, repo: str) -> List[GitHubPullRequest]:
+    token: Optional[str] = __get_github_token(domain)
+    prs = __fire_github_api_request(domain, 'GET', f'/repos/{org}/{repo}/pulls', token)
     return list(map(__parse_pr_json, prs))
 
 
-def derive_current_user_login() -> Optional[str]:
-    token: Optional[str] = __get_github_token()
+def derive_current_user_login(domain: str) -> Optional[str]:
+    token: Optional[str] = __get_github_token(domain)
     if not token:
         return None
-    user = __fire_github_api_request('GET', '/user', token)
+    user = __fire_github_api_request(domain, 'GET', '/user', token)
     return str(user['login'])  # str() to satisfy mypy
 
 
-def is_github_remote_url(url: str) -> bool:
-    return any((re.match(pattern, url) for pattern in GITHUB_REMOTE_PATTERNS))
+def is_github_remote_url(domain: str, url: str) -> bool:
+    return any((re.match(pattern, url) for pattern in github_remote_url_patterns(domain)))
 
 
-def get_parsed_github_remote_url(url: str, remote: str) -> Optional[RemoteAndOrganizationAndRepository]:
-    for pattern in GITHUB_REMOTE_PATTERNS:
+def get_parsed_github_remote_url(domain: str, url: str, remote: str) -> Optional[RemoteAndOrganizationAndRepository]:
+    for pattern in github_remote_url_patterns(domain):
         match = re.match(pattern, url)
         if match:
             org = match.group(1)
@@ -328,10 +343,10 @@ def get_parsed_github_remote_url(url: str, remote: str) -> Optional[RemoteAndOrg
     return None
 
 
-def get_pull_request_by_number_or_none(number: int, org: str, repo: str) -> Optional[GitHubPullRequest]:
-    token: Optional[str] = __get_github_token()
+def get_pull_request_by_number_or_none(domain: str, number: int, org: str, repo: str) -> Optional[GitHubPullRequest]:
+    token: Optional[str] = __get_github_token(domain)
     try:
-        pr_json: Dict[str, Any] = __fire_github_api_request('GET', f'/repos/{org}/{repo}/pulls/{number}', token)
+        pr_json: Dict[str, Any] = __fire_github_api_request(domain, 'GET', f'/repos/{org}/{repo}/pulls/{number}', token)
         return __parse_pr_json(pr_json)
     except MacheteException:
         return None
@@ -342,9 +357,9 @@ def checkout_pr_refs(git: GitContext, remote: str, pr_number: int, branch: Local
     git.checkout(branch)
 
 
-def get_repo_and_org_names_by_id(repo_id: str) -> str:
-    token: Optional[str] = __get_github_token()
-    repo = __fire_github_api_request('GET', f'/repositories/{repo_id}', token)
+def get_repo_and_org_names_by_id(domain: str, repo_id: str) -> str:
+    token: Optional[str] = __get_github_token(domain)
+    repo = __fire_github_api_request(domain, 'GET', f'/repositories/{repo_id}', token)
     return str(repo['full_name'])
 
 


Test patch:
diff --git a/tests/test_github.py b/tests/test_github.py
index 76e5275..955909d 100644
--- a/tests/test_github.py
+++ b/tests/test_github.py
@@ -1,14 +1,14 @@
 import os
 import subprocess
 from tempfile import mkdtemp
-from typing import Any, Dict, Optional
+from typing import Any, Dict, Optional, List
 from unittest import mock
 
 import pytest
 
 from git_machete.exceptions import MacheteException
 from git_machete.git_operations import LocalBranchShortName
-from git_machete.github import get_parsed_github_remote_url, RemoteAndOrganizationAndRepository
+from git_machete.github import get_parsed_github_remote_url
 from git_machete.options import CommandLineOptions
 
 from .mockers import (GitRepositorySandbox, MockContextManager,
@@ -18,8 +18,6 @@ from .mockers import (GitRepositorySandbox, MockContextManager,
                       mock_should_perform_interactive_slide_out,
                       rewrite_definition_file)
 
-FAKE_GITHUB_REMOTE_PATTERNS = ['(.*)/(.*)']
-
 
 class FakeCommandLineOptions(CommandLineOptions):
     def __init__(self) -> None:
@@ -28,20 +26,24 @@ class FakeCommandLineOptions(CommandLineOptions):
         self.opt_yes: bool = True
 
 
+def mock_github_remote_url_patterns(domain: str) -> List[str]:
+    return ['(.*)/(.*)']
+
+
 def mock_fetch_ref(cls: Any, remote: str, ref: str) -> None:
     branch: LocalBranchShortName = LocalBranchShortName.of(ref[ref.index(':') + 1:])
     git.create_branch(branch, get_current_commit_hash(), switch_head=True)
 
 
-def mock_derive_current_user_login() -> str:
+def mock_derive_current_user_login(domain: str) -> str:
     return "very_complex_user_token"
 
 
-def mock__get_github_token() -> Optional[str]:
+def mock__get_github_token_none(domain: str) -> Optional[str]:
     return None
 
 
-def mock__get_github_token_fake() -> Optional[str]:
+def mock__get_github_token_fake(domain: str) -> Optional[str]:
     return 'token'
 
 
@@ -157,7 +159,7 @@ class TestGithub:
         )
 
     @mock.patch('git_machete.cli.exit_script', mock_exit_script)
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
     @mock.patch('urllib.request.Request', git_api_state_for_test_retarget_pr.new_request())
     @mock.patch('urllib.request.urlopen', MockContextManager)
@@ -193,7 +195,8 @@ class TestGithub:
         launch_command("discover", "-y")
         expected_error_message = (
             "Multiple non-origin remotes correspond to GitHub in this repository: origin_1, origin_2 -> aborting. \n"
-            "You can also select the repository by providing 3 git config keys: `machete.github.{remote,organization,repository}`\n"  # noqa: FS003, E501
+            "You can also select the repository by providing some or all of git config keys: "
+            "`machete.github.{domain,remote,organization,repository}`.\n"  # noqa: FS003
         )
         with pytest.raises(MacheteException) as e:
             launch_command("github", "retarget-pr")
@@ -413,7 +416,7 @@ class TestGithub:
     @mock.patch('git_machete.cli.exit_script', mock_exit_script)
     @mock.patch('git_machete.client.MacheteClient.ask_if', mock_ask_if)
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_create_pr` due to `git fetch` executed by `create-pr` subcommand.
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
     @mock.patch('urllib.error.HTTPError', MockHTTPError)  # need to provide read() method, which does not actually reads error from url
@@ -591,8 +594,8 @@ class TestGithub:
     )
 
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_create_pr` due to `git fetch` executed by `create-pr` subcommand.
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
-    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
+    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token_none)
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
     @mock.patch('git_machete.client.MacheteClient.ask_if', mock_ask_if)
@@ -651,8 +654,8 @@ class TestGithub:
     @mock.patch('git_machete.cli.exit_script', mock_exit_script)
     @mock.patch('git_machete.client.MacheteClient.ask_if', mock_ask_if)
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_create_pr` due to `git fetch` executed by `create-pr` subcommand.
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
-    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
+    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token_none)
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
     @mock.patch('urllib.error.HTTPError', MockHTTPError)  # need to provide read() method, which does not actually reads error from url
@@ -912,10 +915,10 @@ class TestGithub:
     @mock.patch('git_machete.cli.exit_script', mock_exit_script)
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_checkout_prs`
     # due to `git fetch` executed by `checkout-prs` subcommand.
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
-    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token)
+    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token_none)
     @mock.patch('urllib.request.Request', git_api_state_for_test_checkout_prs.new_request())
     @mock.patch('urllib.request.urlopen', MockContextManager)
     def test_github_checkout_prs(self, tmp_path: Any) -> None:
@@ -1105,7 +1108,7 @@ class TestGithub:
         # check against wrong pr number
         repo: str
         org: str
-        _, org, repo = get_parsed_github_remote_url(self.repo_sandbox.remote_path, remote='origin')
+        _, org, repo = get_parsed_github_remote_url(domain='github.com', url=self.repo_sandbox.remote_path, remote='origin')
         expected_error_message = f"PR #100 is not found in repository {org}/{repo}"
         with pytest.raises(MacheteException) as e:
             launch_command('github', 'checkout-prs', '100')
@@ -1208,7 +1211,7 @@ class TestGithub:
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_checkout_prs_freshly_cloned`
     # due to `git fetch` executed by `checkout-prs` subcommand.
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     @mock.patch('urllib.request.urlopen', MockContextManager)
     @mock.patch('urllib.request.Request', git_api_state_for_test_github_checkout_prs_fresh_repo.new_request())
     def test_github_checkout_prs_freshly_cloned(self, tmp_path: Any) -> None:
@@ -1331,7 +1334,7 @@ class TestGithub:
     # need to mock fetch_ref due to underlying `git fetch pull/head` calls
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_checkout_prs_from_fork_with_deleted_repo`
     # due to `git fetch` executed by `checkout-prs` subcommand.
     @mock.patch('urllib.request.urlopen', MockContextManager)
@@ -1442,10 +1445,10 @@ class TestGithub:
     @mock.patch('git_machete.cli.exit_script', mock_exit_script)
     # We need to mock GITHUB_REMOTE_PATTERNS in the tests for `test_github_checkout_prs`
     # due to `git fetch` executed by `checkout-prs` subcommand.
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)  # to hide git outputs in tests
-    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token)
+    @mock.patch('git_machete.github.__get_github_token', mock__get_github_token_none)
     @mock.patch('urllib.request.Request', git_api_state_for_test_github_checkout_prs_of_current_user_and_other_users.new_request())
     @mock.patch('urllib.request.urlopen', MockContextManager)
     @mock.patch('git_machete.github.derive_current_user_login', mock_derive_current_user_login)
@@ -1595,7 +1598,7 @@ class TestGithub:
     @mock.patch('git_machete.utils.run_cmd', mock_run_cmd)
     @mock.patch('git_machete.client.MacheteClient.ask_if', mock_ask_if)
     @mock.patch('git_machete.options.CommandLineOptions', FakeCommandLineOptions)
-    @mock.patch('git_machete.github.GITHUB_REMOTE_PATTERNS', FAKE_GITHUB_REMOTE_PATTERNS)
+    @mock.patch('git_machete.github.github_remote_url_patterns', mock_github_remote_url_patterns)
     @mock.patch('git_machete.github.__get_github_token', mock__get_github_token_fake)
     @mock.patch('urllib.request.urlopen', MockContextManager)
     @mock.patch('urllib.request.Request', git_api_state_for_test_github_sync.new_request())
@@ -1662,6 +1665,6 @@ class TestGithub:
         urls = urls + [url + '.git' for url in urls]
 
         for url in urls:
-            remote_and_organization_and_repository: RemoteAndOrganizationAndRepository = get_parsed_github_remote_url(url, 'origin')
+            remote_and_organization_and_repository = get_parsed_github_remote_url('github.com', url, 'origin')
             assert remote_and_organization_and_repository.organization == organization
             assert remote_and_organization_and_repository.repository == repository