1

I'm using MSYS2/git with a proper installation of git for windows SDK Install git inside MSYS2 proper

The git.exe is in /mingw64/bin directory (which is added to $PATH), but other packages that git needs (specifically like sh.exe and less.exe) are in /usr/bin directory which I don't want to put in $PATH to avoid polluting my environment with other executables like mkdir and dir,...

Currently, some git commands need those packages like git config -l which needs less and any git command that'll open the EDITOR will need sh.exe.

What I want to achieve is adding less and sh to the PATH without adding the whole directory.


I tried adding them using methods HERE and HERE. Most of them allowed me to use sh and less directly from the terminal, but none of them made the dependent git commands work.

For example, creating a symlink of less and sh in the /mingw64/bin directory will make the command prompt recognize these executables, but using git config -l will give no output at all unless the directory of less was added to $PATH.

However, other methods (creating scripts and shortcuts,..) will make git complain "Unable to spawn sh/less", altgough cmd and powershell would recognize less and sh.


Why would the executable work from the terminal, but not with git? Especially the symlink case where git didn't complain about missing EXEs but still didn't function properly?

NadAlaba
  • 292
  • 3
  • 15

2 Answers2

1

It sounds like you want to run Git for Windows outside of MSYS2 and you want to avoid putting all of the MSYS2's /usr/bin directory on your PATH. It's also probably a good idea to avoid putting /mingw64/bin on your PATH too.

I suggest making a wrapper program for git itself. It would know where git.exe is located, and know what directories to put on the PATH before running git.exe. It would simply modify the PATH and then pass all its arguments on to the correct git.exe. Since you're probably using a shell like the Windows Command Prompt that doesn't recognize Bash shell scripts, you'll probably just have to make a statically-linked native Windows executable that uses the Win32 API to do this. Then put that in its own directory, and add that directory to your PATH.

Here is some code that should work for you. However, you will have to edit MSYS2_DIR to point to the directory where you installed MSYS2, and you will have to edit the target string too. (Most MSYS2 users have git installed with pacman and it lives in /usr/bin, so I didn't want to hardcode something different into this code.)

#include <windows.h>
#include <stdio.h>

#define MSYS2_DIR "C:/msys64"

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nShowCmd)
{
  const char * target = MSYS2_DIR "/usr/bin/git.exe";

  BOOL success = SetEnvironmentVariable(
    "PATH", MSYS2_DIR "/mingw64/bin;" MSYS2_DIR "/usr/bin/");
  if (!success)
  {
    DWORD error = GetLastError();
    fprintf(stderr, "Failed to set PATH: error %ld.\n", error);
    return 1;
  }

  PROCESS_INFORMATION info;

  STARTUPINFOA startup_info = {
    sizeof(startup_info),
    .hStdInput = GetStdHandle(STD_INPUT_HANDLE),
    .hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE),
    .hStdError = GetStdHandle(STD_ERROR_HANDLE),
  };

  success = CreateProcessA(target, GetCommandLine(),
    NULL, NULL, 1, 0, NULL, NULL, &startup_info, &info);
  if (!success)
  {
    DWORD error = GetLastError();
    fprintf(stderr, "Failed to start git: error %ld.\n", error);
    return 1;
  }

  DWORD result = WaitForSingleObject(info.hProcess, INFINITE);
  if (result)
  {
    fprintf(stderr, "Unexpected wait result: 0x%lx\n", result);
    return 1;
  }

  DWORD code;
  success = GetExitCodeProcess(info.hProcess, &code);
  if (!success)
  {
    fprintf(stderr, "Failed to get child exit code.\n");
    return 1;
  }
  return code;
}

You can compile this using either the 32-bit or 64-bit MinGW toolchains that MSYS2 provides. Just run gcc wrapper.c -o git. This should create a native Windows executable with no dependencies on any MSYS2 DLLs.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • Thanks for the help, I'm probably going with the wrapper exe and a an example of that code in C++ would be very appreciated since I've never worked with Win32 API, but still seems the right way to go – NadAlaba Apr 30 '19 at 04:26
  • I developed the code and added it to my answer; check it out! – David Grayson Apr 30 '19 at 06:20
  • I changed the `target` path of git as you said, and added `#define pathAdditional "path/toMy/EDITOR"` then appended `pathAdditional` to the `SetEnvironmentVariable` value, because I'm using a short path in git to open my editor. i.e, `core.editor = Code --wait`. After that all features of git are tested and working. Thank you so much! – NadAlaba May 01 '19 at 12:11
1

My trick for this kind of problems is to replace "git.exe" with "git.bat" which does something like set PATH=my\extra\dir;%PATH followed by pass-all-args call to git.exe __git.exe %*. After creating such a BAT file I just place it in the same place as git.exe, rename git.exe to __git.exe and it's done. Whenever I write "git checkout foo" it actually calls the BAT file with "checkout foo" params and the BAT handles temporarily extending the PATH variable, or whatever else preparations I'd like to have.

Of course, it will not work for external programs that would like to call git.exe directly. If the external program calls git.exe it will fail. If it calls git without extension, it will succeed, as it will hit the BAT file (provided the BAT itself is on the PATH).

In case when the git.exe cannot be 'hid' behind a BAT file (which case I also stumbled upon already), I used a similar solution -- I used .gitrc file and put my fixups there. You can see an example of a more complex gitrc here, basically it's just a shell script like bashrc/etc. However, strangely, I cannot find any mention on the internet regarding what provides running the gitrc.. I thought it's git itself, but I can't find any supporting reference. Odd.

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
  • This is simple and it worked from the command line, thanks. However, as you said it wouldn't work if external programs called git.exe, and I have some git extensions that do call git.exe. – NadAlaba May 01 '19 at 12:06