An installation instruction for Git Bash / MINGW / MSYS2 on Windows with some notes on solving common problems
This article appeared first on https://www.pascallandau.com/ at Setting up Git Bash / MINGW / MSYS2 on Windows
In this article I'll document my process for setting up Git Bash / MINGW / MSYS2 on Windows including some additional configuration (e.g. installing make
and apply some customizations via .bashrc
).
Table of contents
- Introduction
- How to install and update Git Bash / MINGW / MSYS2 via Git for Windows
- Common issues
- Miscellaneous
Introduction
When I was learning git
I started with the fantastic Git for Windows package, that is maintained in the git-for-windows/git
Github repository and comes with Git Bash, a shell that offers a Unix-terminal like experience. It uses MINGW and MSYS2 under the hood and does not only provide git
but also a bunch of other common Linux utilities like
bash
sed
awk
ls
cp
rm
...
I believe the main "shell" is actually powered by MINGW64 as that's what will be shown by default:
Thus, I will refer to the tool as MINGW shell or Git Bash throughout this article.
I have been using MINGW for almost 10 years now, and it is still my go-to shell for Windows. I could just never warm up to WSL, because the file sharing performance between WSL and native Windows files was (is?) horrible - but that's a different story.
How to install and update Git Bash / MINGW / MSYS2 via Git for Windows
You can find the latest Git for Windows installation package directly at the homepage of https://gitforwindows.org/. Older releases can be found on Github in the Releases section of the git-for-windows/git
repository
Follow the instructions in the How to Install Git Bash on Windows article on git-tower.com to get a guided tour through the setup process.
After the installation is finished, I usually create a desktop icon and assign the shortcut CTRL + ALT + B
(for "bash") so that I can open a new shell session conveniently via keyboard.
Update MINGW
To update Git for Windows, you can simply run
git update-git-for-windows
See also the Git for Windows FAQ under "How do I update Git for Windows upon new releases?"
Git for Windows comes with a tool to check for updates and offer to install them. Whether or
not you enabled auto-updates during installation, you can manually run
git update-git-for-windows
.
You can check the current version via git version
$ git --version
git version 2.37.2.windows.2
How to install make
As per How to add more to Git Bash on Windows: make
:
- Go to ezwinports
- Download file
make-4.3-without-guile-w32-bin.zip
(get the version without guile) - Extract zip
-
Copy the contents to your
Git/mingw64/
directory, merging the folders, but do NOT
overwrite/replace any existing files- navigate to the
Git/mingw64/
directory via
$(cd /; explorer .)
- navigate to the
Test via make version
$ make --version
GNU Make 4.3.1
Built for Windows32
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
PS: There's also an alternative way that I've outlined in Install make
on Windows (MinGW), though the one explained here is easier/faster.
Configuration via .bashrc
The MINGW shell is a bash
shell and can thus be configured via a .bashrc
file located at the home directory of the user. The shell supports the ~
character as an alias for the home directory, i.e. you can use ~/.bashrc
to refer to the full path of the file. This means you can also edit it easily via vi ~/.bashrc
- though I prefer an actual GUI editor like Notepad++. A common workflow for me to open the file is running the following commands in a MINGW shell session
# navigate to to the home directory
cd ~
# open the file explorer
explorer .
My .bashrc
file usually includes the following setup:
# Get bash completion for make targets by parsing make files in the current directory at
# the file "Makefile"
# all files with a ".mk" suffix in the folders ".make" and ".makefile"
# see https://stackoverflow.com/questions/4188324/bash-completion-of-makefile-target
# Notes:
# -h hides filenames
# -s hides error messages
complete -W "\`grep -shoE '^[a-zA-Z0-9_.-]+:([^=]|$)' Makefile .make/*.mk .makefile/*.mk | sed 's/[^a-zA-Z0-9_.-]*$//' | grep -v PHONY\`" make
# Docker login helper
# see https://www.pascallandau.com/blog/structuring-the-docker-setup-for-php-projects/#easy-container-access-via-din-bashrc-helper
function din() {
filter=$1
user=""
if [[ -n "$2" ]];
then
user="--user $2"
fi
shell="bash"
if [[ -n "$3" ]];
then
shell=$3
fi
prefix=""
if [[ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]]; then
prefix="winpty"
fi
${prefix} docker exec -it ${user} $(docker ps --filter name=${filter} -q | head -1) ${shell}
}
Links:
Common issues
The Git for Windows Known Issues page lists common problems with Git Bash and I want to provide some more context (and solutions) to the things that I have encountered.
The role of winpty
: Fixing "The input device is not a TTY"
I encountered the The input device is not a TTY
error while using docker
. To log into a running docker
container or starting a container with a login session, the -i
(Keep STDIN open even if not attached) and -t
(Allocate a pseudo-tty) options must be given:
For interactive processes (like a shell), you must use
-i
-t
together in order to allocate a
tty for the container process.-i
-t
is often written-it
.
But attempting to do so via
docker run --rm -it busybox sh
yields the following error:
$ docker run --rm -it busybox sh
the input device is not a TTY. If you are using mintty, try prefixing the command with 'winpty'
Fortunately, the fix is included in the message: Prefix the command with winpty
. Doing so works as expected:
$ winpty docker run --rm -it busybox sh
/ #
winpty
is according to it's readme
[...] a Windows software package providing an interface similar to a Unix pty-master for
communicating with Windows console programs. The package consists of a library (libwinpty) and
a tool for Cygwin and MSYS for running Windows console programs in a Cygwin/MSYS pty.
So kind of a translator between your "Windows input" and the "command input" to create input that is compatible with a Unix pty (pty=pseudoterminal interface), e.g. for docker
.
According to the Git for Windows Known Issues page, there are a number of other cases where winpty
is required (though I personally didn't encounter them yet):
Some console programs, most notably non-MSYS2 Python, PHP, Node and OpenSSL, interact
correctly with MinTTY only when called throughwinpty
(e.g. the Python console needs to be
started aswinpty python
instead of justpython
).
CAUTION: I've seen people put an alias in their .bashrc
file to always prefix docker
commands automatically with winpty
like so:
alias docker="winpty docker"
However, winpty
seems to break piping and can lead to unexpected results like the error stdout is not a tty
. See the following example:
$ docker run --rm busybox echo "foo" | cat
foo
$ winpty docker run --rm busybox echo "foo" | cat
stdout is not a tty
You might work around this by adding the (undocumented) -Xallow-non-tty
flag like so
$ winpty -Xallow-non-tty docker run --rm busybox echo "foo" | cat
foo
But this doesn't seem to be a catch-all solution and I would recommend against using it as a default - or if you do, only use it when the -it
flag is used as proposed in this answer.
The path conversion issue
Ah. This one has given me lots of headaches over the years. MINGW, MSYS2 and winpty
use automatic conversion of Unix paths to Windows paths, e.g. /foo
gets translated to something like C:/Program Files/Git/foo
where C:/Program Files/Git/
is the installation directory of the Git for Windows installation.
Fixing the path conversion issue for MINGW / MSYS2
First, the behavior is mentioned on the Git for Windows Known Issues page
If you specify command-line options starting with a slash, POSIX-to-Windows path conversion
will kick in converting e.g. "/usr/bin/bash.exe
" to "C:\Program Files\Git\usr\bin\bash.exe
".
When that is not desired -- e.g. "--upload-pack=/opt/git/bin/git-upload-pack
" or "-L/regex/
"
-- you need to set the environment variableMSYS_NO_PATHCONV
temporarily, like so:
MSYS_NO_PATHCONV=1 git blame -L/pathconv/ msys2_path_conv.cc
Alternatively, you can double the first slash to avoid POSIX-to-Windows path conversion, e.g.
"//usr/bin/bash.exe
".
and also documented for MINGW at "Posix path conversion", but it's still brought up regularly, see e.g. GH #3619: "/" is replaced with the directory path of Git installation when using MinGW64 Bash. or SO: How to stop MinGW and MSYS from mangling path names given at the command line
Example
$ docker run --rm busybox ls /foo
ls: C:/Program Files/Git/foo: No such file or directory
As quoted above, it can be solved by either
- adding an additional
/
to the path
$ docker run --rm busybox ls //foo
ls: /foo: No such file or directory
-
prefixing the command with
MSYS_NO_PATHCONV=1
$ MSYS_NO_PATHCONV=1 docker run --rm busybox ls /foo
ls: /foo: No such file or directory
- or exporting the
MSYS_NO_PATHCONV=1
variable as an environment variable to disable the behavior completely
$ export MSYS_NO_PATHCONV=1
$ docker run --rm busybox ls /foo
ls: /foo: No such file or directory
CAUTION: The value of the MSYS_NO_PATHCONV
variable does not matter - we can also set it to 0
, false
or an empty string. It only matters that the variable is defined!
$ MSYS_NO_PATHCONV=0 docker run --rm busybox ls /foo
ls: /foo: No such file or directory
This is particularly important when using the environment variable approach. In order to selectively enable the path conversion again, you must unset the MSYS_NO_PATHCONV
first via env -u MSYS_NO_PATHCONV ...
, e.g.
$ env -u MSYS_NO_PATHCONV docker run --rm busybox ls /foo
ls: C:/Program Files/Git/foo: No such file or directory
CAUTION: I've seen people adding MSYS_NO_PATHCONV=1
permanently to their environment in their .bashrc
file to always disable path conversion via
export MSYS_NO_PATHCONV=1
However, this can have some unintended side effects. When I tried it out, my local installation of the gcloud
cli stopped working with the error
$ MSYS_NO_PATHCONV=1 gcloud version
C:\Users\Pascal\AppData\Local\Programs\Python\Python39\python.exe: can't open file 'C:\c\Users\Pascal\AppData\Local\Google\Cloud SDK\google-cloud-sdk\lib\gcloud.py': [Errno 2] No such file or directory
So instead I recommend setting MSYS_NO_PATHCONV=1
either selectively per command or scope it to the use case. I do this for example in my Makefiles by only exporting it for the scope of make
(and all scripts make
invokes) by putting the following code in the beginning of the Makefile:
# OS is a defined variable for WIN systems, so "uname" will not be executed
OS?=$(shell uname)
# Values of OS:
# Windows => Windows_NT
# Mac => Darwin
# Linux => Linux
ifeq ($(OS),Windows_NT)
export MSYS_NO_PATHCONV=1
endif
The path conversion is also documented for MSYS2 at "Filesystem Paths: Automatic Unix ⟶ Windows Path Conversion" and can be disabled via the MSYS2_ARG_CONV_EXCL
environment variable:
[...] For these cases you can exclude certain arguments via the
MSYS2_ARG_CONV_EXCL
environment
variable:
[...]
MSYS2_ARG_CONV_EXCL
can either be * to mean exclude everything, or a list of one ore more
arguments prefixes separated by ;, likeMSYS2_ARG_CONV_EXCL=--dir=;--bla=;/test
. It matches
the prefix against the whole argument string.
I.e. setting the variable as MSYS2_ARG_CONV_EXCL="*"
should disable the path conversion completely. I myself have never had to use this, though. Using MSYS_NO_PATHCONV
was always sufficient.
Fixing the path conversion issue for winpty
Unfortunately, winpty
suffers from this path conversion issue as well. In the standard installation of Git for Windows we can even see this by simply using echo
:
$ winpty echo /
C:/Program Files/Git
The behavior is known and flagged as a bug e.g. in GH issue #411: Path conversion with and without winpty differs.
Remember the example I gave in section The role of winpty
e.g. when using docker
?
$ winpty docker run --rm -it busybox sh
/ #
Now let's extend this and throw a volume into the mix:
$ winpty docker run --rm -v foo:/foo -it busybox sh
docker: Error response from daemon: create foo;C: "foo;C" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
winpty
converts /foo
to C:/Program Files/Git/foo
so that the volume definition becomes -v foo:C:/Program Files/Git/foo
- which is of course invalid.
Using an additional /
as a prefix does work here as well:
$ winpty docker run --rm -v foo://foo -it busybox sh
/ #
But there is no environment variable that we could use. The only way to "fix" the path conversion is using a newer release of winpty
and replace the one that is shipped together with Git for Windows as proposed by the maintainer of winpty
.
This comment outlines the full process to replace winpty
and is (slightly adapted) as follows:
# create temporary directory
mkdir temp
cd temp
# download a newer release
curl -L https://github.com/rprichard/winpty/releases/download/0.4.3/winpty-0.4.3-msys2-2.7.0-x64.tar.gz --output winpty.tar.gz
# extract the archive
tar -xvf winpty.tar.gz
# copy the content of the bin/ folder to `/usr/bin`
# (which resolves to e.g `C:/Program Files/Git/usr/bin`; replaces any existing files)
cp winpty-0.4.3-msys2-2.7.0-x64/bin/* /usr/bin
# delete the temporary directory
cd ..
rm -rf temp/
Once the new version is installed, the path conversion does not happen any longer (even without specifying any environment variables).
Related comments:
- https://github.com/docker/for-win/issues/1588#issuecomment-594938988
- https://github.com/docker/for-win/issues/1588#issuecomment-698080757
Caution
After updating MinGW, the fix for winpty
is "gone"!
I.e. you need to re-run the steps above every time you run an update.
Miscellaneous
Some stuff that I need from time to time - not necessarily only relevant for Git Bash.
Change the bash
custom prompt to a $
Via PS1=" $"
:
Pascal@LAPTOP-0DNL2Q02 MINGW64 ~
$ PS1="$ "
$
See How to Change / Set up bash custom prompt (PS1) in Linux
Top comments (1)
Ha. The path thingy was bugging me for ages!