diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py index c1faee3947d..fdd7de908a9 100644 --- a/src/pip/_internal/utils/misc.py +++ b/src/pip/_internal/utils/misc.py @@ -653,6 +653,7 @@ def call_subprocess( show_stdout=True, # type: bool cwd=None, # type: Optional[str] on_returncode='raise', # type: str + returncodes=None, # type: Optional[Iterable[int]] command_desc=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] unset_environ=None, # type: Optional[Iterable[str]] @@ -661,9 +662,13 @@ def call_subprocess( # type: (...) -> Optional[Text] """ Args: + returncodes: an iterable of integer return codes that are acceptable, + in addition to 0. Defaults to None, which means []. unset_environ: an iterable of environment variable names to unset prior to calling subprocess.Popen(). """ + if returncodes is None: + returncodes = [] if unset_environ is None: unset_environ = [] # This function's handling of subprocess output is confusing and I @@ -740,7 +745,7 @@ def call_subprocess( spinner.finish("error") else: spinner.finish("done") - if proc.returncode: + if proc.returncode and proc.returncode not in returncodes: if on_returncode == 'raise': if (logger.getEffectiveLevel() > std_logging.DEBUG and not show_stdout): diff --git a/src/pip/_internal/vcs/__init__.py b/src/pip/_internal/vcs/__init__.py index 7fc53526123..a432c3868e8 100644 --- a/src/pip/_internal/vcs/__init__.py +++ b/src/pip/_internal/vcs/__init__.py @@ -17,7 +17,7 @@ if MYPY_CHECK_RUNNING: from typing import ( # noqa: F401 - Dict, Optional, Tuple, List, Type, Any, Mapping, Text + Any, Dict, Iterable, List, Mapping, Optional, Text, Tuple, Type ) from pip._internal.utils.ui import SpinnerInterface # noqa: F401 @@ -467,6 +467,7 @@ def run_command( show_stdout=True, # type: bool cwd=None, # type: Optional[str] on_returncode='raise', # type: str + returncodes=None, # type: Optional[Iterable[int]] command_desc=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] spinner=None # type: Optional[SpinnerInterface] @@ -480,8 +481,10 @@ def run_command( cmd = [self.name] + cmd try: return call_subprocess(cmd, show_stdout, cwd, - on_returncode, - command_desc, extra_environ, + on_returncode=on_returncode, + returncodes=returncodes, + command_desc=command_desc, + extra_environ=extra_environ, unset_environ=self.unset_environ, spinner=spinner) except OSError as e: diff --git a/src/pip/_internal/vcs/git.py b/src/pip/_internal/vcs/git.py index dc80a0532ef..e32bba8c1c4 100644 --- a/src/pip/_internal/vcs/git.py +++ b/src/pip/_internal/vcs/git.py @@ -84,14 +84,18 @@ def get_current_branch(self, location): Return the current branch, or None if HEAD isn't at a branch (e.g. detached HEAD). """ - args = ['rev-parse', '--abbrev-ref', 'HEAD'] - output = self.run_command(args, show_stdout=False, cwd=location) - branch = output.strip() + # The -q causes the command to exit with status code 1 instead of + # 128 if "HEAD" is not a symbolic ref but a detached HEAD. + args = ['symbolic-ref', '-q', 'HEAD'] + output = self.run_command( + args, returncodes=(1, ), show_stdout=False, cwd=location, + ) + ref = output.strip() - if branch == 'HEAD': - return None + if ref.startswith('refs/heads/'): + return ref[len('refs/heads/'):] - return branch + return None def export(self, location): """Export the Git repository at the url to the destination location"""