Skip to content

Instantly share code, notes, and snippets.

@jasonboukheir
Last active March 29, 2024 18:12
Show Gist options
  • Star 46 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save jasonboukheir/3fdab92ece236744528447a4f7f5de00 to your computer and use it in GitHub Desktop.
Save jasonboukheir/3fdab92ece236744528447a4f7f5de00 to your computer and use it in GitHub Desktop.
git when in unix, git.exe when in wsl
#!/bin/sh
if pwd | grep /mnt/c > /dev/null; then
exec git.exe "$@"
else
exec /usr/bin/git "$@"
fi
@kageurufu
Copy link

kageurufu commented Jan 30, 2020

Instead of if pwd | grep /mnt/c, you could use something like

if [[ "$(pwd -P)/" =~ ^/mnt/./ ]]; then

This avoids the need for grep for matching, and the use of pwd -P means that symlinks from your linux filesystem to the windows filesystem still get run under git.exe.

[frank@GODMODE Source]$ pwd
/home/frank/Source
[frank@GODMODE Source]$ pwd -P
/mnt/c/Users/kageu/Source

@Fleshgrinder
Copy link

Fleshgrinder commented Mar 20, 2020

@kageurufu your syntax would require Bash or another Shell that supports [[ ]] and =~. The fastest way in POSIX should be the following:

#!/bin/sh
case "$(pwd -P)" in
    /mnt/?/*) exec /mnt/c/Program\ Files/Git/cmd/git.exe "$@" ;;
    *) exec /usr/bin/git "$@" ;;
esac

A Bash solution with a regular expression would look as follows:

#!/usr/bin/env bash
if [[ "$(pwd -P)" =~ ^/mnt/./ ]]
    then exec /mnt/c/Program\ Files/Git/cmd/git.exe "$@"
    else exec /usr/bin/git "$@"
fi

@jonpugh
Copy link

jonpugh commented May 14, 2020

YES!!
THANK YOU!

@Goopher
Copy link

Goopher commented May 18, 2020

I'm not thát familiar with linux, but where do we put this script?

@mariobadr
Copy link

From the reddit post you should: 'Add this script to your "/usr/local/bin" directory and name it "git"'

@LiamThursfield
Copy link

Thanks - this works except for one issue!

When trying to pull / commit to private repos I get

ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights

I thought it was issues with my ssh key at first, but removing the git.exe config above, cloning and pulling the repo works fine (with the same ssh key) except it is just incredibly slow.

Anyone had any similar issues?

@tobiasdiez
Copy link

With this change, VS code stopped recognizing the git folder (if under WSL). The reason is perhaps that git rev-parse --show-toplevel still points to the folder in normal Windows format, e.g. returns D:/Programming/.... instead of /mnt/d/Programming/.... Any ideas to fix this?

@jameslan
Copy link

jameslan commented Aug 3, 2020

Thanks - this works except for one issue!

When trying to pull / commit to private repos I get

ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights

I thought it was issues with my ssh key at first, but removing the git.exe config above, cloning and pulling the repo works fine (with the same ssh key) except it is just incredibly slow.

Anyone had any similar issues?

Are you able to git pull on Windows prompt?

@2-X
Copy link

2-X commented Aug 4, 2020

Thanks - this works except for one issue!
When trying to pull / commit to private repos I get

ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights

I thought it was issues with my ssh key at first, but removing the git.exe config above, cloning and pulling the repo works fine (with the same ssh key) except it is just incredibly slow.
Anyone had any similar issues?

Are you able to git pull on Windows prompt?

I had the same issue. The reason is because you're trying to use SSH to pull git, but since you are now using git.exe, it uses the SSH credentials stored at /mnt/c/Users/YOURNAME/.ssh instead of the ones at ~/.ssh. To fix this I just did ssh-keygen there and added that ssh key to my github account too.

@2-X
Copy link

2-X commented Aug 4, 2020

Also I changed the script to

#!/bin/sh

if pwd | grep /mnt/c; then
    exec /mnt/c/"Program Files"/Git/cmd/git.exe "$@"
else
    exec /usr/bin/git "$@"
fi

to fix sudo git <command> not being able to find git.exe

@LiamThursfield-NexusPoint

Thanks - this works except for one issue!
When trying to pull / commit to private repos I get

ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights

I thought it was issues with my ssh key at first, but removing the git.exe config above, cloning and pulling the repo works fine (with the same ssh key) except it is just incredibly slow.
Anyone had any similar issues?

Are you able to git pull on Windows prompt?

I had the same issue. The reason is because you're trying to use SSH to pull git, but since you are now using git.exe, it uses the SSH credentials stored at /mnt/c/Users/YOURNAME/.ssh instead of the ones at ~/.ssh. To fix this I just did ssh-keygen there and added that ssh key to my github account too.

Ahh, that makes sense! Thanks for that, I'll give it a try later

@akainth015
Copy link

I had the same issue. The reason is because you're trying to use SSH to pull git, but since you are now using git.exe, it uses the SSH credentials stored at /mnt/c/Users/YOURNAME/.ssh instead of the ones at ~/.ssh. To fix this I just did ssh-keygen there and added that ssh key to my github account too.

You can do it a bit more easily; just cp -r ~/.ssh/ /mnt/c/Users/YOURNAME/ does the trick. Whether you choose to copy the known_hosts file over is up to you.

@roopjm
Copy link

roopjm commented Sep 28, 2020

Has anyone had issues running this with bash-git-prompt?

I just got this working this morning, and love the speed it adds, however I do miss the git-prompt.

@Nilpo
Copy link

Nilpo commented Nov 24, 2020

#!/bin/sh

if pwd | grep /mnt/c; then
exec /mnt/c/"Program Files"/Git/cmd/git.exe "$@"
else
exec /usr/bin/git "$@"
fi

Adding a wildcard to the if condition makes it work on any Windows volumes.

#!/bin/sh

if pwd | grep /mnt/*; then
    exec /mnt/c/"Program Files"/Git/cmd/git.exe "$@"
else
    exec /usr/bin/git "$@"
fi

@medeirosinacio
Copy link

#!/bin/sh
if pwd | grep /mnt/c; then
exec /mnt/c/"Program Files"/Git/cmd/git.exe "$@"
else
exec /usr/bin/git "$@"
fi

Adding a wildcard to the if condition makes it work on any Windows volumes.

#!/bin/sh

if pwd | grep /mnt/*; then
    exec /mnt/c/"Program Files"/Git/cmd/git.exe "$@"
else
    exec /usr/bin/git "$@"
fi

this solves well, but to use zsh, reading the branch on the continuous command line is slow. I think he is still using the Linux binary for reading.

➜ agenda git:(test) ✗

@grandemk
Copy link

grandemk commented Nov 25, 2020

With this change, VS code stopped recognizing the git folder (if under WSL). The reason is perhaps that git rev-parse --show-toplevel still points to the folder in normal Windows format, e.g. returns D:/Programming/.... instead of /mnt/d/Programming/.... Any ideas to fix this?

Here is a version that works with visual code.
It transform the windows paths to wsl path with a sed ([A-E] being the name of the windows volumes you have, so you might have to adjust this.
(Well it transforms the first occurence of A: in /mnt/A in every git command, so it comes with some risk ^^, but I've never had a problem with it yet)

#!/bin/sh
  
GIT_WINDOWS="/mnt/c/Program Files/Git/cmd/git.exe"
GIT_LINUX="/usr/bin/git"

case "$(pwd -P)" in
  /mnt/?/*) exec "$GIT_WINDOWS" "$@" | sed "s#\([A-E]\):#/mnt/\L\1#" ;;
  *) exec "$GIT_LINUX" "$@" ;;
esac

@arkiaconsulting
Copy link

Thanks @grandemk, works like a charm on VSCode !

However, in the terminal, sed is removing colors. Any idea how to keep the colors ?

@grandemk
Copy link

grandemk commented Jul 3, 2021

It's not sed removing color but git not coloring the text because it's not being outputed directly to a terminal.
I think modifying the git command like this should solve it: "$GIT_WINDOWS" -c color.ui=always "$@".
(It might be a bit more complicated than that if some commands of git do not support the -c flag)

Note that what I propose is a big hack, you will most likely encounter a problem at some point with a A: becoming /mnt/A in the code you are diffing (especially in C++ with the A::method syntax.)

@mdentremont
Copy link

mdentremont commented Nov 26, 2021

@grandemk Your versions were super helpful! With this tweak things seem to be happy thus far (after a short amount of play time):

GIT_WINDOWS="/mnt/c/Program Files/Git/cmd/git.exe"
GIT_LINUX="/usr/bin/git"

case "$(pwd -P)" in
/mnt/?/*)
  case "$@" in
  # Needed to fix prompt, but it breaks things like paging, colours, etc
  rev-parse*)
    # running linux git for rev-parse seems faster, even without translating paths
    exec "$GIT_LINUX" "$@"
    ;;
  *)
    exec "$GIT_WINDOWS" "$@"
    ;;
  esac
  ;;
*)
  exec "$GIT_LINUX" "$@"
  ;;
esac

@guanxiongsun
Copy link

Can anyone tell me which file should I modify to enable these changes? Thank you so much.

@davidkopp
Copy link

davidkopp commented Jan 23, 2022

@sunguanxiong You can place the file with the name git e.g. into the directory /usr/local/bin so it's in your path and can be found by your shell.

@DanKaplanSES
Copy link

DanKaplanSES commented Feb 2, 2022

@medeirosinacio I think this is the relevant file for oh-my-zsh.. It runs git like this: GIT_OPTIONAL_LOCKS=0 command git "$@" The problem is, I can't figure out what command does, but that's where I'm guessing the issue lies.

UPDATE: actually, I said that without trying it myself. Using @mdentremont's solution worked fine on my oh-my-zsh install.

@MMI
Copy link

MMI commented Mar 4, 2022

First, thanks for all this. You've saved my relationship with zsh and wsl2... however, I did a little measurement and I'm thinking that all this is a bandaid on something that should be avoided.

I have a small firmware project (think a collection of C code that builds with make). If I build using Linux (WSL2 on ext4) then it takes about 26 seconds. The same build on in /mnt/c/path/to/code/on/c/drive takes around 1:30... roughly 3x slower. The same build under Windows build takes 40seconds. The build under Windows, pointing at the WSL2 disk (via \\wsl.localhost\Ubuntu\...) was so incredibly slow that I gave up waiting for it (after 10 minutes!)

The take-away here is that Linux stuff should only point at ext4 (or whatever) and Windows stuff should only look at NTFS. Mixing things is just creates a bunch of annoying problems to solve.

Happy that WSL exists but still waiting for it to be The Answer(tm)

@grumpyjacek
Copy link

@grandemk Your versions were super helpful! With this tweak things seem to be happy thus far (after a short amount of play time):

GIT_WINDOWS="/mnt/c/Program Files/Git/cmd/git.exe"
GIT_LINUX="/usr/bin/git"

case "$(pwd -P)" in
/mnt/?/*)
  case "$@" in
  # Needed to fix prompt, but it breaks things like paging, colours, etc
  rev-parse*)
    # running linux git for rev-parse seems faster, even without translating paths
    exec "$GIT_LINUX" "$@"
    ;;
  *)
    exec "$GIT_WINDOWS" "$@"
    ;;
  esac
  ;;
*)
  exec "$GIT_LINUX" "$@"
  ;;
esac

Hi! Can anyone help me - where exactly this code should go to? To which file? I'm totaly new to Linux/WSL2 and can't faind myself around it :(

@roopjm
Copy link

roopjm commented Sep 28, 2022

It's really helpful in your bashrc file! Which is the file that loads all kinds of settings when bash is first initialized for any instance.

@grumpyjacek
Copy link

@roopjm thank you, I did, but it doesn't seem to work :(
image

@Fleshgrinder
Copy link

Fleshgrinder commented Sep 28, 2022

Having this code in the Bash startup script is not going to be very useful, since you are only going to be able to use it if you are invoking git from within an interactive login shell. What you really want is to overload the git executable that is found in the PATH.

PATH works exactly the same way on Linux as it does on Windows. It contains a list of directories that is searched for executables whenever you enter the name of a program in your terminal. The default path on Linux is something like /usr/local/bin:/usr/bin. What you can see here is that /usr/local/bin is searched before /usr/bin, as such we can place stuff in there to overload other executables.

To know where your current git is installed use command -v git, which should give you /usr/bin/git. Meaning, we can use /usr/local/bin to overload it. So, let us do exactly that.

cat >/tmp/git <<'GIT'
#!/usr/bin/env bash
set -e
if [[ $(pwd -P) =~ ^/mnt/./ ]]
    then exec /mnt/c/Program\ Files/Git/cmd/git.exe "$@"
    else exec /usr/bin/git "$@"
fi
GIT
sudo install /tmp/git /usr/local/bin

That is all, no matter from where you invoke git it will be using your overloaded version going forward. Whenever you really want to us the original just use /usr/bin/git.

You can do exactly the same with many other programs that read things from disk. For instance https://github.com/sharkdp/bat is really awesome, and available cross-platform. Just brew install bat on Linux and choco install bat on Windows and create an overload with exactly the same logic as in the git overload (obviously replacing the paths to the executables), and enjoy a massive speed up.

@MarounMaroun
Copy link

Just use it as an alias. I use fish, I added:

alias git "git.exe"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment