Source -> Visit the author
Zsh on Windows via MSYS2
This also helped me a lot HERE
set CHERE_INVOKING=1 &
set MSYSTEM=MINGW64 &
set MSYS2_PATH_TYPE=inherit &
set "MSYS2_PATH=D:\Users\USER\scoop\apps\msys2\current" &
set "PATH=%MSYS2_PATH%\usr\bin;%MSYS2_PATH%\mingw64\bin;%PATH%" &
"%ConEmuBaseDirShort%\conemu-msys2-64.exe" "/usr/bin/bash.exe" --login -i -new_console:p:C:"%MSYS2_PATH%\msys2.ico"
I have quite a long history trying to get “Linux-y” environment working on Windows (yes, I’m stuck on that platform), from enhanced cmd.exe
to WSL to Git Bash.
I still think that Git Bash is the best middle ground for most people: super-easy to install (comes with Git for Windows), has very few issues and you can do almost anything you’d want on a Linux / macOS machine, e.g., rm -rf node_modules
, single quotes, Bash scripting, etc.
The only limitation is that Git Bash comes with a fixed set of utilities — understandably as the project only maintains tools directly related to Git. So when you’re hunting for rsync
, you're on your own. Same for zsh, and basically everything else.
I recently started using Mac besides my Windows machine and some unification is crucial for my sanity, so especially zsh became a priority. And while I was at it, I reconsidered my tool chain on Windows. In the end, I switched to MSYS2, installed Git for Windows into it but it also unlocked a world of other packages for me. This is the best setup I found so far so I’d like to share it.
Note on WSL: I love it in theory and think that it might make Windows the best development platform in the future (true Linux utilities, native Docker, etc.) but using it in practice feels quite cumbersome to me, as one simply is in a different operating system. For example, tools installed in WSL are not that easy to access from Windows, users are different, syncing system settings between machines works differently, updates are separate, etc. With MSYS2, there is just a single operating system: Windows.
MSYS2
Git for Windows builds on (is a friendly fork) of MSYS2 and the key to this whole setup is to turn it around: start from MSYS2 and install Git for Windows into it. This will allow us to then continue beyond its boundaries, with tools like rsync
or make
.
MSYS2 is the underlying goodness so it’s vital to understand what it is. The project has a nice (and short!) introduction on their wiki, in essence:
- MSYS2 (usually upper case) consists of three relatively separate subsystems: msys2 , mingw32 and mingw64.
- msys2 (sometimes called just msys) is an emulation layer — fully POSIX compatible but slow.
- mingw subsystems provide native Windows binaries, with Linux calls rewritten at compile time to their Windows equivalents. For example, Git for Windows is a
mingw64
binary (unlike msys Git which utilizes the compatibility layer and is therefore slow). - Each subsystem has its own shell and it’s important to be in the right one. The msys shell has a PATH starting with
/usr/local/bin:/usr/bin:/bin:...
while the mingw64 shell adds/mingw64/bin
before it. This means that/mingw64/bin/git.exe
is only available in the mingw64 shell. - MSYS2 comes with Pacman, a package manager ported from Arch Linux, and many packages installable by
pacman -S <package>
.
Install MSYS2 by downloading the 64bit version from https://www.msys2.org/, then check “Run MSYS2” and run this:
pacman -Syu # repeat if necessary
pacman -Su
When asked, close the terminal entirely and start it again via the start menu shortcut “MSYS2 MSYS”.
You now have the basic environment installed and updated. Close the terminal.
$HOME
By default, $HOME
is /home/You
(C:\msys64\home\You
). Let's switch it to C:\Users\You
as usual so that for example your standard .gitconfig
works.
The best way is to use the Windows dialog; add this (use the standard Windows format, not MSYS2 path /c/...
):
HOME = C:\Users\You
I also tried other ways, e.g., updating C:\msys64\etc\profile
or C:\msys64\etc\bash.bashrc
, but they are less universal (depend on a specific shell, loading order, etc.).
UPDATE: for openssh (and maybe other programs) to work, also update the db_home
line in C:\msys64\etc\nsswitch.conf
to look like this:
db_home: windows cygwin desc
ConEmu with mingw shell
Let’s switch to a better terminal app, ConEmu.
I’ll recommend one controversial thing here: to only use the mingw64 shell from now on. This is in contrast with the official wiki which recommends to run Pacman in the msys shell but:
- I didn’t hit any issues installing packages from the mingw shell.
- I did hit issues installing
mingw-w64-x86_64-git-lfs
from the msys shell, because it usesgit
as part of its installation which is not in msys’ PATH. - Worrying about two shells, two ConEmu tasks, two PATH configurations, etc. is IMO not worth it until proven otherwise.
So in this section, we’ll only setup a ConEmu taks for mingw64. If you ever need the msys shell, use the “MSYS2 MSYS” shortcut in the Windows start menu.
My MSYS2::mingw
ConEmu task looks like this:
set CHERE_INVOKING=1 & set MSYSTEM=MINGW64 & set MSYS2_PATH_TYPE=inherit & set “PATH=%ConEmuDrive%\msys64\mingw64\bin;%ConEmuDrive%\msys64\usr\bin;%PATH%” & %ConEmuBaseDirShort%\conemu-msys2–64.exe -new_console:p %ConEmuDrive%\msys64\usr\bin\bash.exe — login -i -new_console:C:”%ConEmuDrive%\msys64\msys2.ico”
It’s a copy of the default {Bash::Msys2-64}
task with the MSYSTEM
variable set (making it a mingw shell) and the PATH
expanded to contain the full Windows path so that system-wide binaries like node
, yarn
or kubectl
are accessible.
If you ever need to confirm which shell you’re in, run echo $MSYSTEM
.
Essential utilities
Let’s install some basic utilities:
pacman -S man vim nano
pacman -S openssh rsync make
pacman -S zip unzip
pacman -S mingw64/mingw-w64-x86_64-jq
Notice how easy it is to install things. For example, adding rsync
to Windows is historically not easy at all — you end up going through various ports, forks, etc. This is much easier.
Note about
sudo
: MSYS2 doesn't provide it. See this question or imachug/win-sudo.
Git for Windows
Now let’s install GfW to MSYS2. Most of the instructions come from this wiki page but I had to customize it a bit (it seems that the wiki page sets up the full SDK environment).
First, edit C:\msys64\etc\pacman.conf
and add this:
[git-for-windows]
Server = https://wingit.blob.core.windows.net/x86-64
It needs to be the first repository, above [mingw32]
, so that packages from it are installed first.
Authorize a signing key:
curl -L https://raw.githubusercontent.com/git-for-windows/build-extra/master/git-for-windows-keyring/git-for-windows.gpg |
pacman-key --add - &&
pacman-key --lsign-key 1A9F3986
Now update the installation with the new repository in place:
pacman -Syu
This will guide you through installing a newer msys2 runtime. You will have to exit the terminal entirely and run the update command again, as before. Repeat pacman -Syu
until there are no more things to update.
Now install Git for Windows:
pacboy
is used here. It is a small wrapper that saves some typing, for example,pacboy sync git:x
is equivalent topacman -S mingw-w64-x86_64-git
(the ":x" means we want the x64 version).
pacboy sync git:x git-credential-manager:x git-lfs:x git-doc-html:x git-doc-man:x
Verify that everything is working:
$ git --version
git version 2.18.0.windows.1$ git config --list --show-origin
# ... verifies that your ~/.gitconfig is read
You should be able to pull from GitHub, credential helper should store your HTTPS password, all should be working as expected.
Update Windows path
To make Git and other tools like cp
or rm -rf
available also in cmd.exe
and other shells, add this to your PATH in this order (I recommend system PATH which is loaded first):
C:\msys64\mingw64\bin
C:\msys64\usr\bin
Verify:
Microsoft Windows [Version 10.0.17134.112]
(c) 2018 Microsoft Corporation. All rights reserved.C:\Users\Borek>git --version
git version 2.18.0.windows.1C:\Users\Borek>ls -la
...
Zsh
Finally, zsh! Let’s install it:
pacman -S zsh
ConEmu task is similar to what we created before, just with zsh.exe
instead of bash.exe
. This is my {MSYS2:zsh}
task:
set CHERE_INVOKING=1 & set MSYSTEM=MINGW64 & set MSYS2_PATH_TYPE=inherit & set “PATH=%ConEmuDrive%\msys64\mingw64\bin;%ConEmuDrive%\msys64\usr\bin;%PATH%” & %ConEmuBaseDirShort%\conemu-msys2–64.exe -new_console:p %ConEmuDrive%\msys64\usr\bin\zsh.exe — login -i -new_console:C:”%ConEmuDrive%\msys64\msys2.ico”
This article has an example of a ConEmu task that builds on mintty but I think that conemu-msys2-64.exe
is the preferred way, see here.
At this point, zsh is technically working but still needs some love.
Oh My Zsh
While omz feels a bit bloated to me (for example, enabling its git
plugin registers about a million aliases), it is also easy to appreciate its value once you don’t have it. So I like to enable omz to get all the useful stuff it has in its lib
folder but don’t enable any plugins or themes.
My preferred way to install omz and other things is via Antigen. As a start, add this to your .zshrc
:
Actually, my
~/.zshrc
just sources$HOME/GDrive/Settings/zsh/.zshrc
so that it’s synced between computers. I'll probably switch to a versioned dotfiles approach soon.
# Use the path where you installed Antigen
source "${funcsourcetrace[1]%/*}/antigen.zsh"# Load Oh My Zsh
antigen use oh-my-zsh# Example of how to add other useful things
antigen bundle zsh-users/zsh-completionsantigen apply
Some other essential things for me in .zshrc
are:
# Make /c/... autocompletion work, see Alexpux/MSYS2-packages#38
zstyle ':completion:*' fake-files /: '/:c'# Convenient path navigation, e.g., `cd vp`
setopt CDABLE_VARS
vp="/c/Dev/VersionPress/versionpress"
temp="/c/Dev/temp"# VSCode as an editor
if [[ -n $SSH_CONNECTION ]]; then
export EDITOR='vim'
else
export EDITOR='code-insiders --wait'
fi
Prompt
The grand finale!
There are million zsh prompts out there but as expected, none is quite perfect. I want a couple of key things from a prompt:
- It should be simple, like Pure.
- It must be asynchronous so that querying Git info doesn’t block the actual work.
The second point is relatively hard to fulfill on Windows as most async prompts (incl. Pure) depend on zsh-async
which depends on zsh/zpty
which doesn't work in MSYS2 (until some fallback is implemented, see mafredri/zsh-async#26).
The only async prompt I found working on Windows is agkozak/agkozak-zsh-theme (awesome work!). I didn’t like some specifics about it, e.g., Git info being in the right prompt, so I have my own small fork of it (no prompt I saw thus far is truly customizable without forking; makes me sad). In my .zshrc
:
antigen theme borekb/agkozak-zsh-theme@prompt-customization
It looks like this:
What you cannot see in a static image is how the Git info is loaded in the background; it is really really cool.
Ok, that’s it, we now have a fully working environment with MSYS2, zsh, Oh My Zsh, Git for Windows and Pacman where adding new packages is as simple as pacman -S <something>
. This is the best setup I found so far, if you have any tips please let me know in the comments below.
And big thanks to all the people involved in MSYS2 & Git for Windows projects, you make the life of a developer on Windows bearable!