Repository: pypa/pip

Issue:
TypeError when installing from git and git version contains a letter
### Description

I am trying to install a dependency from a git source and get an exception because the git version cannot be parsed

Going through the code (I have pip version 23.2.1 installed), it seems the issue is with my git version that contains an alphabetical patch version…

```bash
$ git version
git version 2.37.GIT
```

In `git.py:100` the match produces 3 groups with the last one being `None` because of the way the `GIT_VERSION_REGEX` is built. That in turns create a problem in `git.py:104` because `tuple(int(c) for c in match.groups())` doesn't work with the `None` value.

### Expected behavior

I would expect pip to accept the major and minor git version as they are and go on without a numeric patch version. But I can't tell why it is checking the version numbers.

### pip version

23.2.1

### Python version

3.9.9

### OS

Debian 11.5

### How to Reproduce

I can't share the code but what I do is simply `pip install "my_package @ git+https://my_gitlab/my_repo"`

### Output

This is the full stacktrace :

```
ERROR: Exception:
Traceback (most recent call last):
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/cli/base_command.py", line 180, in exc_logging_wrapper
    status = run_func(*args)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/cli/req_command.py", line 248, in wrapper
    return func(self, options, args)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/commands/install.py", line 377, in run
    requirement_set = resolver.resolve(
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 73, in resolve
    collected = self.factory.collect_root_requirements(root_reqs)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 491, in collect_root_requirements
    req = self._make_requirement_from_install_req(
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 453, in _make_requirement_from_install_req
    cand = self._make_candidate_from_link(
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 206, in _make_candidate_from_link
    self._link_candidate_cache[link] = LinkCandidate(
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 293, in __init__
    super().__init__(
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 156, in __init__
    self.dist = self._prepare()
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 225, in _prepare
    dist = self._prepare_distribution()
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 304, in _prepare_distribution
    return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/operations/prepare.py", line 538, in prepare_linked_requirement
    return self._prepare_linked_requirement(req, parallel_builds)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/operations/prepare.py", line 609, in _prepare_linked_requirement
    local_file = unpack_url(
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/operations/prepare.py", line 155, in unpack_url
    unpack_vcs_link(link, location, verbosity=verbosity)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/operations/prepare.py", line 78, in unpack_vcs_link
    vcs_backend.unpack(location, url=hide_url(link.url), verbosity=verbosity)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/vcs/versioncontrol.py", line 608, in unpack
    self.obtain(location, url=url, verbosity=verbosity)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/vcs/versioncontrol.py", line 521, in obtain
    self.fetch_new(dest, url, rev_options, verbosity=verbosity)
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/vcs/git.py", line 272, in fetch_new
    if self.get_git_version() >= (2, 17):
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/vcs/git.py", line 104, in get_git_version
    return tuple(int(c) for c in match.groups())
  File "/home/lcottereau/my_project/env/lib/python3.9/site-packages/pip/_internal/vcs/git.py", line 104, in <genexpr>
    return tuple(int(c) for c in match.groups())
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
```

### Code of Conduct

- [X] I agree to follow the [PSF Code of Conduct](https://www.python.org/psf/conduct/).

Discussion:

Patch:
diff --git a/news/12280.bugfix.rst b/news/12280.bugfix.rst
new file mode 100644
index 000000000..77de283d3
--- /dev/null
+++ b/news/12280.bugfix.rst
@@ -0,0 +1,1 @@
+Fix crash when the git version number contains something else than digits and dots.
diff --git a/src/pip/_internal/vcs/git.py b/src/pip/_internal/vcs/git.py
index 8d1d49937..8c242cf89 100644
--- a/src/pip/_internal/vcs/git.py
+++ b/src/pip/_internal/vcs/git.py
@@ -101,7 +101,7 @@ class Git(VersionControl):
         if not match:
             logger.warning("Can't parse git version: %s", version)
             return ()
-        return tuple(int(c) for c in match.groups())
+        return (int(match.group(1)), int(match.group(2)))
 
     @classmethod
     def get_current_branch(cls, location: str) -> Optional[str]:


Test patch:
diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py
index 3ecc69abf..fb6c3ea31 100644
--- a/tests/unit/test_vcs.py
+++ b/tests/unit/test_vcs.py
@@ -598,6 +598,21 @@ def test_get_git_version() -> None:
     assert git_version >= (1, 0, 0)
 
 
+@pytest.mark.parametrize(
+    ("version", "expected"),
+    [
+        ("git version 2.17", (2, 17)),
+        ("git version 2.18.1", (2, 18)),
+        ("git version 2.35.GIT", (2, 35)),  # gh:12280
+        ("oh my git version 2.37.GIT", ()),  #  invalid version
+        ("git version 2.GIT", ()),  # invalid version
+    ],
+)
+def test_get_git_version_parser(version: str, expected: Tuple[int, int]) -> None:
+    with mock.patch("pip._internal.vcs.git.Git.run_command", return_value=version):
+        assert Git().get_git_version() == expected
+
+
 @pytest.mark.parametrize(
     "use_interactive,is_atty,expected",
     [