Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow running Git directly from C:\Program Files\Git\mingw64\bin\git.exe #2506

Merged
merged 2 commits into from
Feb 11, 2020

Conversation

dscho
Copy link
Member

@dscho dscho commented Feb 2, 2020

We still recommend running git.exe via the Git wrapper in /cmd/, just to make sure that the environment variables are set appropriately, such as adding the /usr/bin/ directory to the PATH.

This is relevant e.g. for running the hooks via the Bash.

With this PR, we no longer require that Git be run via the /cmd/git.exe wrapper: it can be run directly from /mingw64/bin/git.exe, configuring the environment variables appropriately itself (using the absence of the MSYSTEM variable as indicator that it should do so).

This addresses #2283

@dscho dscho requested a review from jeffhostetler February 2, 2020 21:07
@jeffhostetler
Copy link

Is there a test that we could add to demonstrate the change? Such as: does the output of git --exec-path (no argument) change?

@jeffhostetler
Copy link

Should we prepend rather than append them to the PATH ??

@jeffhostetler
Copy link

Maybe I'm over analyzing this. But if we're appending $HOME/bin and /usr/bin and /mingXX/ to the PATH, aren't we introducing ambiguity? If I have an official release installed in Program Files and a private version installed in my $HOME, which version of a lib-exec (or maybe just non-builtin) exe gets run when I run a command?

I think a series of tests with before and after output would be helpful here.

@dscho
Copy link
Member Author

dscho commented Feb 4, 2020

Should we prepend rather than append them to the PATH ??

The function name threw you off, right? It appends to the buffer, not to the PATH. The value of getenv("PATH") (if any) is actually appended to the buffer after appending the system bin directories. The idea is that the buffer is initialized with <HOME>/bin/; (HOME is set, which at that point should be the case), then append the system bin directories /mingw64/bin/ and /usr/bin/, and then append the value of getenv("PATH") (if it was set to begin with).

@dscho
Copy link
Member Author

dscho commented Feb 4, 2020

Maybe I'm over analyzing this. But if we're appending $HOME/bin and /usr/bin and /mingXX/ to the PATH, aren't we introducing ambiguity?

We're actually prepending it, by virtue of starting with a completely empty buffer. And then we add ~/bin/, /mingw64/bin/ and /usr/bin/, in this order. After that, we append the original value of PATH.

If I have an official release installed in Program Files and a private version installed in my $HOME, which version of a lib-exec (or maybe just non-builtin) exe gets run when I run a command?

Note that none of this has anything to do with the /mingw64/libexec/git-core/ directory. That is prepended at a totally different point in time, long after this here code.

But your concern is valid: we really need to prepend the components to the PATH (and we do, actually).

I think a series of tests with before and after output would be helpful here.

The biggest problem with adding a test here is that the functionality added in this PR depends highly on the RUNTIME_PREFIX feature: git.exe will figure out its absolute path, then determine where in the MSYS pseudo root it is, depending on its location. For example, if run as C:/Program Files/Git/mingw64/bin/git.exe, it will figure out that it lives in the /mingw64/bin/ directory inside the MSYS pseudo root, and correctly add that, and then <MSYS>/usr/bin to the PATH.

If run as C:/Program Files/Git/mingw64/libexec/git-core/git.exe (which is also a valid scenario), it will detect that it lives in the /mingw64/libexec/git-core/ subdirectory, and again use the correct MSYS pseudo root to figure out where /usr/bin/ is.

If run as D:/a/1/sgit.exe (as would be the case in our CI builds), or as C:/Users/me/Desktop/git/git.exe (a relatively common scenario with contributors), there is zero chance to figure out where the MSYS pseudo root is. That information would have to come from the test suite, via an environment variable, but we do not have any such facility to override the RUNTIME_PREFIX (at least not yet).

What we can do (and what I will do) is to add a simple test that verifies that MSYSTEM has been set.

@jeffhostetler
Copy link

Um, perhaps I'm just being dense here, but I find all this startup magic way more confusing than I think it needs to be, but I realize there are historical issues here.

Yes, append in the name of the function did throw me, but also the different meanings of the variable "path" in the caller and callee didn't help.

As for testing, would it be helpful to create a tXXXX.sh script that does essentially:

cd $TRASH_DIRECTORY
mkdir foo
mkdir foo/Git/mingw64/bin
mkdir foo/Git/mingw64/libexec/git-core
... and so on ...
cp git.exe foo/Git/mingw64/bin
echo >foo/Git/mingw64/libexec/git-core/git-echo-path <<EOF
    #!/bin/sh
    echo $PATH
EOF
export HOME=foo/home
mkdir foo/home/bin

./foo/Git/mingw64/bin/git echo-path >OUTPUT

And then confirm that the child script was invoked correctly (meaning git.exe found the correct associated git-core directory and was able find the "gitDASHecho-path" ) and that the child script inherited the expected PATH.

Perhaps that's overkill. Perhaps not.

@jeffhostetler
Copy link

I'm going to be away from my keyboard for a while today, so I'm going to go ahead and approve this. I'd like to see some tests and maybe a little more comments about what we're doing, but I don't want to block this for that.

@dscho
Copy link
Member Author

dscho commented Feb 4, 2020

Um, perhaps I'm just being dense here, but I find all this startup magic way more confusing than I think it needs to be, but I realize there are historical issues here.

Yes, you're right, hysterical raisins at play. And the fact that Git is not really portable enough to support Windows, we go out of our way to pretend that we're just implementing POSIX shims in compat/mingw.c.

As for testing, would it be helpful to create a tXXXX.sh script that does essentially:

cd $TRASH_DIRECTORY
mkdir foo
mkdir foo/Git/mingw64/bin
mkdir foo/Git/mingw64/libexec/git-core
... and so on ...
cp git.exe foo/Git/mingw64/bin
echo >foo/Git/mingw64/libexec/git-core/git-echo-path <<EOF
    #!/bin/sh
    echo $PATH
EOF
export HOME=foo/home
mkdir foo/home/bin

./foo/Git/mingw64/bin/git echo-path >OUTPUT

That's a good idea! Originally, I was worried about .dll files: if I only copy git.exe and not, say, zlib1.dll, then Windows looks for that DLL in C:\Windows\system32 directory before it looks at the PATH. Only a DLL in the same directory as the .exe takes precedence. But in practice, that will probably not matter. So I should be able to copy $GIT_EXEC_PATH/git.exe as you indicated.

@jeffhostetler
Copy link

yeah, i forgot about the DLLs, but maybe also copy them into that bin directory too.

(I'm thinking about a MSVC=1 build that will complain differently....)

@dscho
Copy link
Member Author

dscho commented Feb 4, 2020

yeah, i forgot about the DLLs, but maybe also copy them into that bin directory too.

The biggest problem with that will be that I don't know which DLLs are required in that test...

But $GIT_EXEC_PATH should be in the $PATH (and if not, I can make it so, in the scope of this test).

(I'm thinking about a MSVC=1 build that will complain differently....)

It should not complain differently, because as part of the build, the DLLs are copied into what will become $GIT_EXEC_PATH in the test script.

dscho added 2 commits February 5, 2020 13:01
Git for Windows wants to add `git.exe` to the users' `PATH`, without
cluttering the latter with unnecessary executables such as `wish.exe`.
To that end, it invented the concept of its "Git wrapper", i.e. a tiny
executable located in `C:\Program Files\Git\cmd\git.exe` (originally a
CMD script) whose sole purpose is to set up a couple of environment
variables and then spawn the _actual_ `git.exe` (which nowadays lives in
`C:\Program Files\Git\mingw64\bin\git.exe` for 64-bit, and the obvious
equivalent for 32-bit installations).

Currently, the following environment variables are set unless already
initialized:

- `MSYSTEM`, to make sure that the MSYS2 Bash and the MSYS2 Perl
  interpreter behave as expected, and

- `PLINK_PROTOCOL`, to force PuTTY's `plink.exe` to use the SSH
  protocol instead of Telnet,

- `PATH`, to make sure that the `bin` folder in the user's home
  directory, as well as the `/mingw64/bin` and the `/usr/bin`
  directories are included. The trick here is that the `/mingw64/bin/`
  and `/usr/bin/` directories are relative to the top-level installation
  directory of Git for Windows (which the included Bash interprets as
  `/`, i.e. as the MSYS pseudo root directory).

Using the absence of `MSYSTEM` as a tell-tale, we can detect in
`git.exe` whether these environment variables have been initialized
properly. Therefore we can call `C:\Program Files\Git\mingw64\bin\git`
in-place after this change, without having to call Git through the Git
wrapper.

Obviously, above-mentioned directories must be _prepended_ to the `PATH`
variable, otherwise we risk picking up executables from unrelated Git
installations. We do that by constructing the new `PATH` value from
scratch, appending `$HOME/bin` (if `HOME` is set), then the MSYS2 system
directories, and then appending the original `PATH`.

Side note: this modification of the `PATH` variable is independent of
the modification necessary to reach the executables and scripts in
`/mingw64/libexec/git-core/`, i.e. the `GIT_EXEC_PATH`. That
modification is still performed by Git, elsewhere, long after making the
changes described above.

While we _still_ cannot simply hard-link `mingw64\bin\git.exe` to `cmd`
(because the former depends on a couple of `.dll` files that are only in
`mingw64\bin`, i.e. calling `...\cmd\git.exe` would fail to load due to
missing dependencies), at least we can now avoid that extra process of
running the Git wrapper (which then has to wait for the spawned
`git.exe` to finish) by calling `...\mingw64\bin\git.exe` directly, via
its absolute path.

Testing this is in Git's test suite tricky: we set up a "new" MSYS
pseudo-root and copy the `git.exe` file into the appropriate location,
then verify that `MSYSTEM` is set properly, and also that the `PATH` is
modified so that scripts can be found in `$HOME/bin`, `/mingw64/bin/`
and `/usr/bin/`.

This addresses git-for-windows#2283

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Originally, we refrained from adding a regression test in 7b6c649
(system_path(): Add prefix computation at runtime if RUNTIME_PREFIX set,
2008-08-10), and in 226c0dd (exec_cmd: RUNTIME_PREFIX on some POSIX
systems, 2018-04-10).

The reason was that it was deemed too tricky to test.

Turns out that it is not tricky to test at all: we simply create a
pseudo-root, copy the `git` executable into the `git/` subdirectory of
that pseudo-root, then copy a script into the `libexec/git-core/`
directory and expect that to be picked up.

As long as the trash directory is in a location where binaries can be
executed, this works.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho
Copy link
Member Author

dscho commented Feb 5, 2020

@jeffhostetler just to make sure: do you want me to add any more information to the commit message?

@jeffhostetler
Copy link

jeffhostetler commented Feb 5, 2020 via email

@dscho dscho merged commit fae73c7 into git-for-windows:master Feb 11, 2020
@dscho dscho deleted the issue-2283 branch February 11, 2020 18:57
@dscho dscho added this to the Next release milestone Feb 11, 2020
git-for-windows-ci pushed a commit that referenced this pull request Feb 11, 2020
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Feb 11, 2020
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Feb 11, 2020
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Oct 11, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Oct 20, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Oct 20, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Oct 21, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 21, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 21, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Oct 23, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Oct 30, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 1, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 6, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Nov 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Nov 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Nov 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Nov 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit that referenced this pull request Nov 22, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
dscho added a commit to dscho/git that referenced this pull request Nov 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
git-for-windows-ci pushed a commit that referenced this pull request Nov 25, 2024
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants