377

I would git commit a .sh file, but would like it to be executable when I checkout that same file in another server.

Is there a way to do so without manually chmod u+x that file in the servers that checkout the file?

blackraven
  • 5,284
  • 7
  • 19
  • 45
Henley
  • 21,258
  • 32
  • 119
  • 207

4 Answers4

622

According to official documentation, you can set or remove the "executable" flag on any tracked file using update-index sub-command.

To set the flag, use following command:

git update-index --chmod=+x path/to/file

To remove it, use:

git update-index --chmod=-x path/to/file

Under the hood

While this looks like the regular unix files permission system, actually it is not. Git maintains a special "mode" for each file in its internal storage:

  • 100644 for regular files
  • 100755 for executable ones

You can visualize it using ls-file subcommand, with --stage option:

$ git ls-files --stage
100644 aee89ef43dc3b0ec6a7c6228f742377692b50484 0       .gitignore
100755 0ac339497485f7cc80d988561807906b2fd56172 0       my_executable_script.sh

By default, when you add a file to a repository, Git will try to honor its filesystem attributes and set the correct filemode accordingly. You can disable this by setting core.fileMode option to false:

git config core.fileMode false

Troubleshooting

If at some point the Git filemode is not set but the file has correct filesystem flag, try to remove mode and set it again:

git update-index --chmod=-x path/to/file
git update-index --chmod=+x path/to/file

Bonus

Starting with Git 2.9, you can stage a file AND set the flag in one command:

git add --chmod=+x path/to/file
Antwane
  • 20,760
  • 7
  • 51
  • 84
  • When I do that to test.sh, git commit and push, and checkout in another server, these are the perms of that file: -rw-rw-r-- 1 user user 12 Dec 5 11:42 test.sh – Henley Dec 05 '16 at 16:47
  • I just performed the test on one of my repository and it works as expected. The permissions were set on the file using the provided command under Windows. On one of my server (Debian) the file had -rw-r--r-- permissions before, now set to -rwxr-xr-x. What git version do you use on local and remote machines ? – Antwane Dec 05 '16 at 16:57
  • git version 1.9.5 in my local, and git 1.7.1 in the server doing the checkout. – Henley Dec 05 '16 at 16:58
  • Just tried to clone on another (older) server with git 1.7.10, it still works well, the file has x permissions. Maybe you made a mistake at some point, or you have permission issues with the user who cloned on the remote server – Antwane Dec 05 '16 at 17:07
  • 1
    Note that you can only change (set or clear) execute permission. Git does not track any other permission (such as read or write permission). – Dan Anderson Jun 12 '19 at 21:02
  • on my machine using Git for Windows, the setting isn't actually true by default. `git config core.fileMode` outputs `false`. So on Windows, git might be indicating that it makes little sense to 'trust filesystem executable bits', due to how different permission systems are between the OSes? – almondandapricot Jun 15 '20 at 05:22
  • 1
    It won't work if you use a "." in the commit command (git commit -m "bla-bla" .). – Alexander Samoylov Mar 30 '21 at 13:37
52

Antwane's answer is correct, and this should be a comment but comments don't have enough space and do not allow formatting. :-) I just want to add that in Git, file permissions are recorded only1 as either 644 or 755 (spelled (100644 and 100755; the 100 part means "regular file"):

diff --git a/path b/path
new file mode 100644

The former—644—means that the file should not be executable, and the latter means that it should be executable. How that turns into actual file modes within your file system is somewhat OS-dependent. On Unix-like systems, the bits are passed through your umask setting, which would normally be 022 to remove write permission from "group" and "other", or 002 to remove write permission only from "other". It might also be 077 if you are especially concerned about privacy and wish to remove read, write, and execute permission from both "group" and "other".


1Extremely-early versions of Git saved group permissions, so that some repositories have tree entries with mode 664 in them. Modern Git does not, but since no part of any object can ever be changed, those old permissions bits still persist in old tree objects.

The change to store only 0644 or 0755 was in commit e44794706eeb57f2, which is before Git v0.99 and dated 16 April 2005.

torek
  • 448,244
  • 59
  • 642
  • 775
7

To set the executeable flag to all files in the repository:

git ls-files --stage |grep 100644 | cut -f2 | xargs -d '\n' git update-index --chmod=+x

To unset the executeable flag to all files do the reverse

git ls-files --stage | grep 100755 | cut -f2 | xargs -d '\n' git update-index --chmod=-x

... and to set all the .sh-scripts executable, maybe this is your way:

git ls-files --stage | grep  ".sh$" | cut -f2 | xargs -d '\n' git update-index --chmod=+x
Matthieu Riegler
  • 31,918
  • 20
  • 95
  • 134
Max
  • 531
  • 6
  • 12
7

On linux, do not forget to

set sudo chmod +x /path/to/file

locally beside doing the git update otherwise the git will always bring the index back to 644 which set by default on the local machine !

In Windows Powershell, you can use

icacls .\path\to\file /grant Everyone:F
H0R5E
  • 65
  • 6
Kashkashio
  • 487
  • 5
  • 10
  • In PowerShell you would do `icacls .\path\to\file /grant Everyone:F` – H0R5E Dec 09 '21 at 12:51
  • @H0R5E TY Suggest it as edit in my answer il put it in – Kashkashio Dec 09 '21 at 14:24
  • edit suggested as requested! – H0R5E Dec 10 '21 at 16:35
  • 2
    NOTE: Annoyingly, Windows user groups are localized, so "Everyone" might not work. You can use `icacls build.sh /grant *S-1-1-0:F` instead, see https://learn.microsoft.com/en-us/windows/security/identity-protection/access-control/special-identities to find other group SIDs – yyny Apr 26 '22 at 21:52
  • 1
    Same on Mac, I had to first set "chmod +x /path/to/file" on my local file system. Only then I could change it for the git index with "git add --chmod=+x filename". Otherwise the git index kept being reset to non-executable. – Flavio Caduff Jan 04 '23 at 09:04
  • using Windows 10, i used attrib +x H:\path\to\file, it seemed to do the trick while setting chmod +x /h/path/to/file in Git bash wasn't working – Erwan Leroux Jan 14 '23 at 23:25