Advent Day 13: Setting Files Executable on Windows

December 13, 2018

This is day 13 of my Git Tips and Tricks Advent Calendar. If you want to see the whole list of tips as they're published, see the index.

When you're working on cross-platform projects, you often want to create a single set of scripts that works on all the platforms that you're targeting: Linux, Windows, macOS, maybe even some more exotic or legacy Unix systems. There are a number of scripting languages that will work on all of those: now that PowerShell targets .NET Core, that could be a good option. Or now that Windows Subsystem for Linux exists, maybe you're doing shell scripting everywhere.

But whatever scripting language you choose, one thing is certain: you'll need to set those files executable on Unix platforms, and that's simply not a concept that exists on Windows. So if you're creating new scripts on Windows, you'll need to find a way to set those files executable when you commit them to support running the scripts on Unix machines.

Thankfully, Git has you covered. Previously, you had to do this in two steps: first, you had to first git add the file to the index, then you could set the file as executable using git update-index --chmod=+x. A few years ago, though, git added that --chmodoption directly to the git add command itself.

So now you can create a new file and run:

git add --chmod=+x build.sh

Now when you commit the file, it will have the executable bit set. You can see that by inspecting the file in the index:

% git ls-files --stage build.sh
100755 a0ae8f4d9e882fbb94ddb578e982fcdb30c61904 0	build.sh

If you're familiar with Unix permissions, then that 100755 will look familiar: mode 0755 in octal maps to an executable file in Git. Now when a user on a Unix system checks out that change, they will see that file as executable.

% git pull --quiet
% ls -Flas build.sh
4 -rwxr-xr-x  1 ethomson  staff  462 Oct 20 20:43 build.sh*

So even though Windows doesn't have a concept of an executable file, you can still set file executable in your Git repository so that Unix systems - which do have that concept - will see that file as an executable.