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 through
winpty
(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
Wanna stay in touch?
Since you ended up on this blog, chances are pretty high that you're into Software Development (probably PHP, Laravel, Docker or Google Big Query) and I'm a big fan of feedback and networking.
So - if you'd like to stay in touch, feel free to shoot me an email with a couple of words about yourself and/or connect with me on LinkedIn or Twitter or simply subscribe to my RSS feed or go the crazy route and subscribe via mail and don't forget to leave a comment :)