Skip to content
shellhacks.dev
CI/CD

Run a script from the repo

Run a repository script from a workflow with run: ./script.sh only if Git stores it as executable. Otherwise the step fails with Permission denied, status 126.

2 min read
Summarize in AI

A script runs fine on your Mac and the workflow stops with "Permission denied" on the first line that calls it.

Shell
git init -q repo && cd repo
printf '#!/bin/sh\necho "deploying"\n' > deploy.sh
chmod -x deploy.sh
git add deploy.sh
git ls-files -s deploy.sh | cut -d' ' -f1
git -c user.name=t -c user.email=t@t commit -qm "add deploy"
git clone -q . ../runner && cd ../runner
./deploy.sh; echo "status $?"
cd ../repo
git update-index --chmod=+x deploy.sh
git ls-files -s deploy.sh | cut -d' ' -f1
git -c user.name=t -c user.email=t@t commit -qm "make deploy executable"
git clone -q . ../runner2 && cd ../runner2
./deploy.sh; echo "status $?"
Text
100644
bash: line 8: ./deploy.sh: Permission denied
status 126
100755
deploying
status 0

Git records only one permission bit, the executable flag, as mode 100755 or 100644. A runner checks the repository out fresh, so a script that was committed with 100644 is not executable there, and calling it directly fails with status 126. git update-index --chmod=+x sets the flag in the index regardless of the local file system, which matters on Windows. The modes are listed in the git-update-index manual.

run: bash deploy.sh avoids the issue, since the file only has to be readable, and it also sets the interpreter explicitly. Check git ls-files -s before pushing a script that someone created on Windows, or in a ZIP. Scripts called from a Docker action or a different checkout path have the same rule.

Share

More snippets

CI/CD

Check what changed in a pull request

List the files a pull request changed with git diff --name-only origin/main...HEAD. Three dots compare against the merge base, and a shallow checkout cannot do it.

2 min read
CI/CD

Group log lines in GitHub Actions

Fold log output in GitHub Actions by printing ::group::Title and ::endgroup::. A wrapper function keeps the pair together and passes the command's status on.

1 min read
CI/CD

Print a warning annotation

Print ::warning file=...,line=...::message from a step to show an annotation on the run and in the pull request diff. Newlines in the text must be encoded.

1 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.