Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork939
usesys.platform == "cygwin"
to figure out when we are using cygwin#2027
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Conversation
only this PR or#2026 should be merged |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Pull Request Overview
This PR simplifies the detection of Cygwin Git by replacing the former multi-step logic with a concise check that relies on sys.platform.
- Removed deprecated functions and caching logic for Cygwin detection.
- Updated the Git command interface to directly use sys.platform and the Git executable's existence.
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
git/util.py | Removed the py_where and _is_cygwin_git functions along with unused imports. |
git/cmd.py | Updated the is_cygwin method to use a simplified sys.platform check. |
Uh oh!
There was an error while loading.Please reload this page.
sys.platform == "cygwin"
to figure out when we are using cygwin
EliahKagan left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is preliminary and I'll try to say a little more in a forthcoming review of#2026, which I hope to do tomorrow.
I think we'll probably want to prefer the approach in#2026 over this, at least in the short term. There is a deliberate and long-standing (though not always perfectly applied) distinction throughout the code of GitPython between whether the platform is Cygwin (i.e. whether thepython
interpreter running the code of GitPython is a Cygwin program) and whether thegit
executable that GitPython calls is a Cygwin program.
This appears to be relevant to the treatment of absolute paths in some operations that involve cloning to an absolute path or adding a submodule. Most use ofis_cygwin_git
is throughGit.is_cygwin
, and searching forGit.is_cygwin
reveals uses where it looks like this distinction can matter.
GitPython uses whatevergit
executable it is configured to use via environment variables orrefresh
or, if it is not configured to use a particulargit
executable, whatever executable it finds in a path search. In either case, this executable need not be built for the same target as GitPython.
I admittedly would not recommend most such mismatches betweenpython
andgit
if they can be avoided. I also think we should be willing to run the risk of breaking things in what I believe to be the unusual case of using Cygwingit
from outside Cygwin, if doing so is necessary in order to avoid or fix breakages when Cygwin is not used--especially for bugs that affect users on Unix-like operating systems that aren't related to Windows. This is one of the reasons I anticipate that the approach in#2026 is probably okay.
But distinguishing Cygwinpython
using Cygwingit
from Cygwinpython
using Git for Windowsgit
seems like it is at least partially working. It's also fairly easy to produce the situation of Cygwinpython
using Git for Windowsgit
. This can plausibly occur intentionally or by accident. Most Cygwin environments preserve WindowsPATH
entries, allowing them to appear after Cygwin-specificbin
directories. If GitPython is used in Cygwinpython
, on a system where Cygwingit
is not installed but Git for Windowsis installed, thenusually the non-Cygwingit
will be found in thePATH
, and GitPython will use it.
Thanks for the thorough review! Neither the value of |
EliahKagan commentedMay 28, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I've looked into this further. Keeping |
ifnotis_win: | |
returnFalse |
Where:
Line 28 ine6e23ed
is_win= (os.name=='nt') |
I believe that, even at that time and even in Python 2,os.name
on Cygwin evaluated to"posix"
as it does today. Thus, the scenario whereis_cygwin_git
would returnTrue
was when the Python interpreter was anative Windows executable andgit
was a Cygwin executable! This makes sense, since the title of that PR was "Support Cygwin's Git on Windows".
At that time, AppVeyor was used for CI. The.appveyor.yml
file from that time confirms that this is what was going on--the original purpose ofis_cygwin_git
was to allownative Windows Python programs to use GitPython with either Git for Windows or Cygwingit
. In relevant part:
Lines 2 to 38 incc77e6b
environment: | |
GIT_DAEMON_PATH:"C:\\Program Files\\Git\\mingw64\\libexec\\git-core" | |
CYGWIN_GIT_PATH:"C:\\cygwin\\bin;%GIT_DAEMON_PATH%" | |
CYGWIN64_GIT_PATH:"C:\\cygwin64\\bin;%GIT_DAEMON_PATH%" | |
matrix: | |
## MINGW | |
# | |
-PYTHON:"C:\\Python27" | |
PYTHON_VERSION:"2.7" | |
GIT_PATH:"%GIT_DAEMON_PATH%" | |
-PYTHON:"C:\\Python34-x64" | |
PYTHON_VERSION:"3.4" | |
GIT_PATH:"%GIT_DAEMON_PATH%" | |
-PYTHON:"C:\\Python35-x64" | |
PYTHON_VERSION:"3.5" | |
GIT_PATH:"%GIT_DAEMON_PATH%" | |
-PYTHON:"C:\\Miniconda35-x64" | |
PYTHON_VERSION:"3.5" | |
IS_CONDA:"yes" | |
GIT_PATH:"%GIT_DAEMON_PATH%" | |
## Cygwin | |
# | |
-PYTHON:"C:\\Miniconda-x64" | |
PYTHON_VERSION:"2.7" | |
IS_CONDA:"yes" | |
IS_CYGWIN:"yes" | |
GIT_PATH:"%CYGWIN_GIT_PATH%" | |
-PYTHON:"C:\\Python35-x64" | |
PYTHON_VERSION:"3.5" | |
GIT_PATH:"%CYGWIN64_GIT_PATH%" | |
IS_CYGWIN:"yes" | |
install: | |
-set PATH=%PYTHON%;%PYTHON%\Scripts;%GIT_PATH%;%PATH% |
The second wasRe-enable Cygwin CI and get most tests passing #1455 in 2022, which included this very significant change tois_cygwin_git
in96fae83:
def is_cygwin_git(git_executable: Union[None, PathLike]) -> bool:- if not is_win:+ if is_win:+ # is_win seems to be true only for Windows-native pythons+ # cygwin has os.name = posix, I think return False
Much as#533 was guided by testing on AppVeyor set up so that Cygwingit
was being called only from native Windows builds of Python,#1455 was guided by testing on GitHub Actions set up so that Cygwingit
was being called only from Cygwin builds of Python.
I cannot tell from the history whether this distinction was recognized at the time! It may be that this change was made based on the belief thatis_cygwin_git
had already been intended to returnFalse
except in Cygwin builds of Python, I am not sure. But it may be that it was intentional. It would make sense if, over time, it has become rarer and rarer to use anything butGit for Windows forgit
on Windows, except when operating entirely within some other specific environment.
An important question is whether, since#1455, there is anything in GitPython that actually works because of the ability to identify a non-Cygwingit
executable from Cygwin. Operations with such an executable seem either to work onmain
, in the original#2026 (cffa264), and here...or not to work in any of the three. An example of something that should in principle work if GitPython on Cygwin supports non-Cygwingit
, but that fails and fails the same way in all three, is:
(.venv) ✔ ~/repos-cygwin/GitPython [main|⚑ 1]09:27 $ GIT_PYTHON_GIT_EXECUTABLE=/cygdrive/c/Users/ek/scoop/shims/git python3.9 -c 'import git; r1 = git.Repo.clone_from("https://github.com/EliahKagan/trivial.git", "trivial"); r2 = r1.clone("trivial-clone", bare=True); print(r2.git_dir)'Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/ek/repos-cygwin/GitPython/git/repo/base.py", line 1482, in clone return self._clone( File "/home/ek/repos-cygwin/GitPython/git/repo/base.py", line 1414, in _clone finalize_process(proc, stderr=stderr) File "/home/ek/repos-cygwin/GitPython/git/util.py", line 504, in finalize_process proc.wait(**kwargs) File "/home/ek/repos-cygwin/GitPython/git/cmd.py", line 834, in wait raise GitCommandError(remove_password_if_present(self.args), status, errstr)git.exc.GitCommandError: Cmd('/cygdrive/c/Users/ek/scoop/shims/git') failed due to: exit code(128) cmdline: /cygdrive/c/Users/ek/scoop/shims/git clone -v --bare -- /home/ek/repos-cygwin/GitPython/trivial/.git trivial-clone stderr: 'fatal: repository '/home/ek/repos-cygwin/GitPython/trivial/.git' does not exist'
What happens there is that adecygpath
operation is either not being done or not being done correctly in at least one place where it would need to happen to support Git for Windowsgit
from Cygwin. I am not sure if this has ever worked.
So that's admittedly a reason to prefer this PR: it's not clear under what circumstances, if any,is_cygwin_git
has done any better than this, since#1455.
But I think this examination of the history also shows that the original#2026 (up tocffa264) is safe and strictly improves correctness. Thesys.platform == "win32"
condition onmain
descends from theis_win
check. (sys.platform == "win32"
always has the same value asos.name == "nt"
, at least in Python 3 and I think since well before that.) When I introducedthe TODO comment in42e10c0 (#1859), I was worried that doing the check even when the platform doesn't seem to be Cygwin might've been intentional, and that checking ifgit
seems to be a Cygwin executable only whensys.platform == "cygwin"
might somehow break something. I think looking at the history confirms that this is not the case.
But another reason to start slow is MSYS2
Somewhat confusingly, Cygwin is not the only platform in whichsys.platform
is"cygwin"
.
We don't test MSYS2 on CI, though maybe we should. I don't know how often, if at all, people use GitPython in a Python interpreter that targets MSYS2. (This should not be confused with other environments that MSYS2 supplies, such as MINGW64, which is actually a native Windows target rather than a Cygwin-like target. I am talking about the MSYSenvironment of MSYS2, which is a non-Cygwin but Cygwin-like target.)
In MSYS2,sys.platform
is"cygwin"
:
ek@Glub MSYS ~$ python -c 'import sys; print(sys.platform)'cygwin
Butuname
does not reportCYGWIN
:
ek@Glub MSYS ~$ unameMSYS_NT-10.0-19045
The facilities within GitPython that do Cygwin-related things, such ascygpath
anddecygpath
, and their helpers, ingit/util.py
--which are used in more places whengit
is detected to be a Cygwin build--don't look like they will always work on MSYS2. While a MSYS2 does have/proc/cygdrive
, it does not have/cygdrive
; a path like/cygdrive/c
in Cygwin is just/c
is MSYS2. There may be other relevant differences.
As things stand now, where MSYS2git
run from MSYS2 is not considered to be a Cygwingit
, MSYS2 does seem to work pretty well, though maybe not perfectly. I say that based onthis test run; see#1988 (comment) for context. It may be good to look into that further before doing anything that would cause MSYS2 to be treated more like Cygwin.
This also applies tothestrings
approach pushed to#2026 aftercffa264--strings
will turn upcygwin
in MSYS2git
as well:
ek@Glub MSYS ~$ strings /usr/bin/git | grep -F cygwincygwin_conv_pathcygwin_internal__imp_cygwin_internal__imp_cygwin_conv_path
So this is part of why I'd be interested to integratecffa264 first.
The current logic for detecting cygwin is:
sys.platform == "win32"
, then it's not cygwinuname
executable in the same folder as the git executable, and if so, does the output of that command include"CYGWIN"
? if so, then it's cygwinIn thepython 3.7 docs for sys.platform, Cygwin systems have
sys.platform == "cygwin"
. Since Python 3.7 is the oldest version still supported by GitPython, it stands to reason that we can rely on that being true for all supported Python versions.The logic I propose is:
sys.platform == 'cygwin'
, then it's cygwin gitThis is simple enough for a single expression, so I replaced the body of the
is_cygwin
function with that expression and removedis_cygwin_git
and friends completely.I don't know if there's such a thing as
sys.platform == 'cygwin'
and thegit
not being cygwingit
, but if there is, I don't think the existing code deals with that anyway, so this seems to return the same result and would fail in the same way.