You wrote a shell script (script.sh
), say for a database backup or to regularly remove old files, and committed and pushed it to your Git repository. You go to your server, do git pull
to pull the latest commit and try to execute the script with ./script.sh
. Uh, oh, Permission denied
, the script won’t run. Ah, no problem, you think, I’ll just change the permissions on the file with chmod
. You do that, the script runs, all is peachy. Or so you think.
Next time you push another code update into your repo and then do another git pull
, you’ll get this error:
error: Your local changes to the following files would be overwritten by merge: script.sh Please, commit your changes or stash them before you can merge.
But I didn’t change the code on the server, you say. No, you didn’t, but you changed the executable permissions on the file which is something that Git keeps track off. You can resolve the above error by resetting the repo clone to the latest commit:
git fetch origin master git reset --hard FETCH_HEAD
Great, the error goes away, git pull
works as before, but when you try to execute the script you realize you’re getting the Permission denied
again – resetting the clone also reset the file permissions and made the script non-executable again.
Since you don’t want to be repeatedly changing the file permissions every time you update your code, what’s the solution?
As I mentioned above, whether the executable bit is on or off is something that Git tracks, so we need to make sure that we flag the file as executable when committing it to the repo in the first place. On your local machine, where you’re writing the code and committing it to the repo, do:
# Stage the script.sh file git add script.sh # Flag it as executable git update-index --chmod=+x script.sh # Commit the change git commit -m "Make script.sh executable." # Push the commit git push
Then go to your remote (server), do git pull
and try to execute the script. The permissions should be properly set and the script should run without any issues.
Similarly, if you later wanted to remove the executable permission from the file, you would do
git update-index --chmod=-x script.sh
followed by commit and push.
I used this to fix all files in a repo:
git ls-files “*.sh” | xargs git update-index –add –chmod=+x
git ls-files “*.exe” | xargs git update-index –add –chmod=+x
Great, thanks for sharing, Niels.
If this command seems hard to remember
git update-index –chmod=-x script.sh
You can do it in usual way.
chmod -x script.sh
git add script.sh
git commit script -m “mark script non-executable”
git push
Yup, that should work. Thank you for sharing 🙂